Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

GMSAPR

.pdf
Скачиваний:
11
Добавлен:
16.03.2016
Размер:
9.01 Mб
Скачать

171

LONG height, width; double resx, resy;

// Перерасчет размера изображения под разрешение принтера width=pCurPic->GetBMWidth(); height=pCurPic->GetBMHeight();

resx=((double)pCurPic->GetBMInfoPtr()-> bmiHeader.biXPelsPerMeter);

resy=((double)pCurPic->GetBMInfoPtr()-> bmiHeader.biYPelsPerMeter);

//Переводим в dpi resx*=(25.4/1000); resy*=(25.4/1000);

//Приведем к разумным пределам

if(resx<=0 || resx> 3000) resx=72; if(resy<=0 || resy> 3000) resy=72; width=(int)(((double)width)*DXRes/resx+0.5);

height=(int)(((double)height)*DYRes/resy+0.5);

// Выводим изображение, соответственно новым размерам pCurPic->DrawBitmap(pDC, 0, 0, width, height);

};

В методе OnPrint() сначала получаем разрешение печатающего устройства с помощью метода CDC::GetDeviceCaps(). Этот метод возвращает разрешение в точках на дюйм (dots per inch - dpi). Растровая картинка тоже имеет характеристику «разрешение», которая записана в заголовке растра BITMAPINFOHEADER в полях biXPelsPerMeter и biYPelsPerMeter. Названия этих полей говорят о том, что разрешение в них записано в точках на метр. Это не может испугать нас, так как мы знаем, что в дюйме ровно 25,4 мм. Поэтому далее разрешение картинки приводится к единицам измерения «точек на дюйм». К сожалению, далеко не все программы, создающие растровые изображения, заполняют поля biXPelsPerMeter и biYPelsPerMeter значениями. Бывает, что программы пишут в такое поле

172

значение 0, а бывает, что оставляют его и вовсе неинициализированным, и там содержится какое-нибудь случайное значение. Эта ситуация проверяется на следующем этапе. Затем размеры картинки масштабируются пропорционально соотношению разрешений картинки и принтера. И, наконец, используются возможности метода CRaster::OnDraw() по выводу изображения на контекст с масштабированием до заданного размера.

В принципе, в метод OnPrint() можно вставить вызов диалога, в котором пользователь мог бы задать нужные ему размеры отпечатка.

Результат работы программы с новым методом OnPrint() показан на рис. 32. Предварительно, с помощью стандартного диалога, вызываемого командой File | Print Setup, установлена альбомная (Landscape) ориентация листа.

Рис. 32. Предварительный просмотр отпечатка

6.15 Заключение

Да, глава получилась не маленькая, но рассмотрено, конечно, далеко не все, чем богаты теория и практика цифровых изображений. Это и хорошо — есть простор для экспериментов. Надеемся, программа BMViewer может

173

послужить полигоном для испытания ваших идей. Приведенную программную реализацию можно, несомненно, значительно улучшить. В текущей реализации количество фильтров ограничено, они «жестко» прописаны в классе CBMDoc.

Можно было бы придумать схему динамического подключения фильтров к программе. В этом случае фильтры можно реализовывать в динамически загружаемых библиотеках (DLL). Это позволило бы расширять возможности программы уже после ее написания. Такая модель реализована в Adobe Photoshop и многих других программах. Конечно, «динамический» подход требует более серьезного осмысления задачи и планирования архитектуры приложения. Однако, даже та схема, что заложена в программу BMViewer, подразумевает возможность расширения функциональности программы. Так что, желаем успехов!

174

7 Создание приложения с использованием библиотек OpenGL

При программировании сложных, больших приложений целесообразно сконцентрировать основное внимание на задачах проекта и использовать для визуализации готовые графические библиотеки, которые позволяют избавиться от массы рутинной работы. Одна из них — OpenGL, описываемая в обзорной части данного пособия.

Необходимость создания специализированных библиотек для работы с графическими данными была обусловлена не только желанием сократить объем труда, но также и тем фактом, что стандартные средства GDI Windows работают с графикой довольно медленно.

Приводится пример использования OpenGL для вывода на экран трехмерной сцены.

Приложение FirstGL, описываемое в данной главе понадобится для выполнения одной из лабораторных работ.

7.1 Общая схема использования библиотеки OpenGL

Создадим однодокументное MFC-приложение, которое будет выводить на экран движущуюся фигуру на фоне растрового изображения. Фигура будет представлять собой композицию из двух трехмерных объектов. Фигура будет вращаться вокруг своей оси и совершать круговые движения по экрану программы. В качестве заднего плана будем использовать растровую BMPкартинку, загружаемую в программу с помощью уже знакомого нам класса CRaster. Визуализация трехмерной картинки будет происходить с использованием алгоритма "Z-буфера" удаления невидимых линий.

Режим отображения заднего плана будем включать или выключать командой View | Background. В режиме показа заднего плана движение объекта несколько замедляется. Это связано с тем, что алгоритму визуализации прибавляется работы.

175

Для реализации графики с использованием OpenGL программа должна, прежде всего, выполнить начальную инициализацию, которая включает следующие действия.

Подобрать и установить нужные параметры контекста воспроизведения;

Создать контекст воспроизведения;

Сделать созданный контекст воспроизведения активным. Программа может иметь несколько контекстов воспроизведения, но активным

является только один.

После выполнения этих операций уже можно что-нибудь рисовать. В случае, если настройки OpenGL по умолчанию не подходят, их можно изменить с помощью функции glEnable. Можно также настроить параметры сцены, например, параметры освещения.

Следующее, о чем должна побеспокоиться ваша программа, — это обработка сообщения об изменениях размера вашего окна. В обработчике этого сообщения указывается часть окна, в которой будет располагаться контекст OpenGL. При этом контекст воспроизведения может занимать только часть окна, а остальная его часть может использоваться для размещения элементов управления (кнопки, поля ввода и т. п.) и других целей. Кроме того, требуется указать тип проекции, используемой в контексте отображения: перспективная или параллельная. В перспективной проекции две параллельные прямые сходятся вдалеке. В параллельной же проекции они всегда остаются параллельными.

Требуется установить точку наблюдения (точку, в которой находится камера или глаз наблюдателя) и точку, куда направлен "взгляд".

Задать ориентацию системы координат.

m_pDC

176

Итак, создадим заготовку простого однодокументного приложения (можно даже отказаться от панели инструментов и строки состояния). Назовем его FirstGL.

После создания каркаса приложения, подключим к проекту библиотечные файлы OpenGL. Для этого открываем диалоговое окно свойств проекта

(команда Project | Settings) и вкладку Linker. В поле Addition Dependencies

добавим имена файлов opengl32.lib, glu32.lib и glaux.lib (имена файлов разделяются пробелами без запятых). В файл StdAfx.h добавим строчки, подключающие заголовочные файлы:

#include <gl/gl.h>

#include <gl/glu.h>

#include <gl/glaux.h>

7.2 Модификация класса облика

В классе CFirstGLView объявим переменную m_hGLRC типа HGLRC

(указатель на контекст воспроизведения OpenGL) и переменную

(указатель на объект CclientDC). В класс CFirstGLView добавим также объявления нескольких методов и переменных, назначение которых рассмотрим далее.

class CFirstGLView : public CView

{

protected: // create from serialization only

CFirstGLView();

DECLARE_DYNCREATE(CFirstGLView)

public:

CFirstGLDoc* GetDocument();

// Данные

 

 

 

 

CClientDC *m_pDC;

// Контекст устройства

рисования

HGLRC

m_hGLRC; //

Контекст

воспроизведения

OpenGL

double

m_dProportion; // Коэффициент пропорции размеров экрана

BOOL

m_bViewBackground;

// Флаг "рисовать фон"

177

//Операции

// Установка параметров воспроизведения

int

SetWindowPixelFormat(HDC);

 

void

Display(); // Вывод всего изображения

void

DisplayBackground(); //

Вывод фона

//Overrides

// ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CFirstGLView)

public:

virtual void OnDraw(CDC* pDC); // overridden to draw this view protected:

virtual BOOL OnPreparePrinting(CPrintInfo* pInfo); virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo); virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);

//}}AFX_VIRTUAL

//Implementation public:

virtual ~CFirstGLView(); #ifdef _DEBUG

virtual void AssertValid() const;

virtual void Dump(CDumpContext& dc) const; #endif

protected:

//Generated message map functions

protected: //{{AFX_MSG(CFirstGLView)

afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnDestroy();

afx_msg void OnSize(UINT nType, int cx, int cy); afx_msg void OnViewBackground();

afx_msg void OnUpdateViewBackground(CCmdUI* pCmdUI); //}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

#ifndef _DEBUG // debug version in Firstvw.cpp

178

inline CFirstGLDoc* CFirstGLView::GetDocument()

{ return (CFirstGLDoc*)m_pDocument; }

#endif

Метод CFirstGLView::SetWindowPixelFormat() предназначен

для установки параметров воспроизведения OpenGL.

int CFirstGLView::SetWindowPixelFormat(HDC hDC)

{

int GLPixelIndex;

//PIXELFORMATDESCRIPTOR — структура, определяющая

//характеристики контекста воспроизведения. Инициализируем

//структуру значениями для полноцветного RGB-режима

PIXELFORMATDESCRIPTOR pfd =

 

 

{

 

 

sizeof(PIXELFORMATDESCRIPTOR),

// размер структуры

1,

 

// номер версии

PFD_DRAW_TO_WINDOW |

// вывод в окно или на устройство

PFD_SUPPORT_OPENGL |

// поддержка OpenGL

PFD_DOUBLEBUFFER,

// двойная буферизация

PFD_TYPE_RGBA,

// режим RGB

24,

// 24-битовая глубина цвета

0, 0, 0, 0, 0, 0,

// игнорируем установки для битовых

 

// плоскостей и их смещения

0,

// без

альфа-буфера

0,

// без

смещения битов

0,

// без

буфера-накопителя

0, 0, 0, 0,

// без

смещения бит в буфере

32,

// размер z-буфера

0,

// без

буфера-трафарета и

0,

// без

вспомогательного буфера

PFD_MAIN_PLANE,

// основная плоскость

0,

// резервный компонент

0, 0, 0

// без

масок слоев

};

 

 

179

//Находит формат пикселов контекста устройства (монитора),

//наиболее близкий к заданному формату пикселов

//GLPixelIndex — номер поддерживаемого пиксельного формата

GLPixelIndex = ChoosePixelFormat( hDC, &pfd); if(GLPixelIndex==0) // Выбираем индекс формата по умолчанию

{

GLPixelIndex = 1;

// Получаем параметры режима if(DescribePixelFormat(hDC,GLPixelIndex,

sizeof(PIXELFORMATDESCRIPTOR),&pfd)==0) return 0;

}

// Устанавливаем режим

if (SetPixelFormat( hDC, GLPixelIndex, &pfd)==FALSE) return 0;

return 1;

}

Метод SetWindowPixelFormat() вызывается из метода-обработчика сообщения WM_CREATE, добавленного в класс CFirstGLView. В методе

OnCreate() создаются контекст Windows-окна программы и совместимый с ним контекст OpenGL, а также устанавливаются параметры визуализации трехмерной сцены.

int CFirstGLView::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

if (CView::OnCreate(lpCreateStruct) == -1) return -1;

// Создаем контекст клиентской части окна if( (m_pDC = new CClientDC(this))==NULL)

return -1;

// Устанавливаем формат пикселов if(SetWindowPixelFormat(m_pDC->m_hDC)==FALSE)

return -1;

180

// Создаем контекст отображения OpenGL

if( (m_hGLRC = wglCreateContext(m_pDC->m_hDC)) == NULL) return -1;

// Делаем контекст отображения активным if(wglMakeCurrent(m_pDC->m_hDC, m_hGLRC)==FALSE)

return -1;

//Устанавливаем параметры отображения

//Параметры материала

//отражение фонового света

GLfloat mat_ambient[4] = {0.2, 0.2, 0.2, 1.0}; // диффузионное отображение

GLfloat mat_diffuse[4] = {0.8, 0.8, 0.8, 1.0}; // зеркальное отражение

GLfloat mat_specular[4] = {1.0, 1.0, 1.0, 1.0}; // интенсивность зеркального отражения

GLfloat mat_shineness = 50.0;

// Устанавливаем параметры материала glMaterialfv(GL_FRONT,GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT,GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT,GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT,GL_SHININESS, &mat_shineness);

// Задаем положение источника света

GLfloat pos[4] = {-100, 100, 100, 0}; glLightfv(GL_LIGHT0, GL_POSITION, pos);

//Активизируем настройки:

//использовать текущий цвет для задания свойств материала

glEnable(GL_COLOR_MATERIAL);

// для вычисления цвета использовать текущие параметры glEnable(GL_LIGHTING);

//учитывать источник света №0 glEnable(GL_LIGHT0);

//проводить тест глубины

glEnable(GL_DEPTH_TEST);

// выводить на экран пикселы с наименьшими z-координатами

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]