NeHe Tutorials Народный учебник по OpenGL
Урок X6. OpenGL

Около двух месяцев назад я опубликовал на англоязычном сайте GameDev.net статью об объединении уроков по OpenGL от NeHe в один проект Visual C++ MFC( перевод моей статьи с русского). С некоторым удивлением я обнаружил, что большинство пользователей чувствуют что-то вроде паники при упоминании об MFC (некоторые называют это даже отвращением). Независимо от того идея уроков по OpenGL от NeHe остается очень хорошей и коды, представленные на этом сайте, применимы в любой среде независимо от платформы. Поэтому я проделал ту же работу для Win32 Visual C++ Visual Stulio 2010-2012 pro.

 

Демо и коды доступны по ссылке: загрузить исходные файлы.

 

 Я полагаю, что объединие всех уроков в один проект может быть очень полезно для начинаюших в начале изучения OpenGL. Расположнеие кодов уроков поблизости один от другого позволяет проследить развитие процедур шаг за шагом от урока к уроку. Подробные инструкции имеются на этом сайте и в оригиналах на NeHe.GameDev.Net. Кроме того, объединие всех уроков в один проект позволяет использовать и комбинировать процедуры от отдельных уроков, а также разрабатывать собственные игровые приложения на базе существующих уроков.

 

В процессе адаптации я столкнулся с тем, что возникают конфликты при переводе проектов из одной модификации Microsoft Visual Studio в другую. В конце концов, в демонстрационных целях я разработал проект OpenGLWin32_2010. Здесь 2010 означает, что проекты предназначены для Microsoft Visual Studio Professional 2010. Впрочем, они безболезненно адаптируются к версии 2012, но для нее нужен уже Windows 7, версия 2010 работает и там, и в Windows XP.

 

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

 

Эти коды могут также здорово помочь тем, кто начинает изучать Visual C++ с самого начала.Не стоит и говорить, что лучший способ изучения любого компиллятора - это начать изучение с помощью готовых работающих проектов. Изложение этого урока относится к Visual Studio 2010 pro. Впрочем, в версии 2012 особых отличий не будет.

 

            Содержимое директории OpenGLWin32_2010:

Для обзора и редактирования текстов запускается OpenGLWin32.sln. Даже если у вас нет большого опыта использования Visual C++, можете начать его изучение с запуска этого (или любого другого прилагаемого) проекта..

 

Список подпрограмм,которые задействованы в проекте, находятся по закладке Обозреватель решений(Solution Explorer)  (меню View->Solution Explorer).) Выбрав любой *.h или *.cpp файл, можно его просмотреть и(или) редактировать. На первый взгляд, файлов этих очень много, но при ближайшем рассмотрении все оказывается довольно простым.

 

Для построения всех проектов использйте команду  меню Build->Build Solution. Если все правильно сделано, то в окне Вывода(Output) результат должен быть: успешно: 49, с ошибками: 3 , пропущено: 0. С ошибками прошли построение сам OpenGLWin32(у него нет точки входа) и проекты Lesson43/Lesson48. К сожалению, я не имею большого опыта работы с OpenGL, и некоторые уроки мне не удалось вполне адаптировать к MS VS. Я надеюсь, что уважаемым авторам оригинальных текстов уроков не составит труда подправить мои коды, чтобы в полной мере привести их к их первоначальным замыслам.

 

Для запуска любого проекта назначьте его запукскающим (правая клавиша мыши - меню Appoint as Starting Project ). Если все правильно сделано, то будет запущена демонстрация одного из уроков. Если запускающим проектом был назначен GLSummary, то начнется демонстрация того урока, чьё название хранится в файле LastNum.txt в папке GLSummary. Для демонстрации любого другого урока обратитесь в меню File->Lesson... Появится диалоговое окно:

 

Select Lesson Dialog

Вы можете выбрать любой другой урок из списка для демонстрации. Если вы начали с отдельного урока, то программа вызовет ваыбранный урок, а саму себя остановит. Если вы начали с GLSummary, то будет вызван один из содержащмхся в нем уроков. Уроки Lesson43/Lesson48 тоже могут быть запущены, но вы не сможете вызвать из них другой урок: это оригиналы, любезно предоставленные на сайте NeHe.GameDev.Net.

 

      Для формирования самостоятельного приложения:

-        создайте отдельную папку (например, GLTest);

-        скопируйте  в  эту новую папку все *.exe файлы,которые находится в папках../Lesson*/Release и ../GLSummary/Release;

-     скопируйте в эту же папку папки HelpText и Data, и приложения готовы, и они должны работать точно также, как и примеры из DemoLessons.

 

 

Подпрограммы CreateGLWindow, ResizeGLScene, WndProcи GlobWinMain являются общими для всех уроков и находятся в файле GlobUse/GLRoutine.cpp.


    Подпрограмма CreateGLWindow почти такая же, как в оригиналах от NeHe.

 

В подпрограмму ResizeGLScene внесены ряд изменений:

 

GLvoid ReSizeGLScene(GLsizei width, GLsizei height) // Resize And Initialize The GL Window

{

if (height==0) // Prevent A Divide By Zero By

{

height=1; // Making Height Equal One

}

glViewport(0,0,width,height); // Reset The Current Viewport

glMatrixMode(GL_PROJECTION); // Select The Projection Matrix

glLoadIdentity(); // Reset The Projection Matrix

if(m_bOrtho)

glOrtho(0.0f,width,height,0.0f,-1.0f,1.0f); // Create Ortho (0,0 At Top Left)

else

// Calculate The Aspect Ratio Of The Window

gluPerspective(fViewAngle,(GLfloat)width/(GLfloat)height,fNearPlane,fFarPlane);

glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix

glLoadIdentity(); // Reset The Modelview Matrix

HWND hWin = GetDlgItem(hWnd, IDC_MAIN_TOOL);

if(hWin != NULL)

{ //ToolBar Adjusted to Main window

RECT rect;

GetWindowRect(hWin, &rect);

BOOL bVisible = IsWindowVisible(hWin);

MoveWindow(hWin, rect.left, rect.top, rect.bottom - rect.top, width, TRUE);

}

HWND hSt = GetDlgItem(hWnd, IDC_MAIN_STATUS);

if(hSt != NULL)

{ //SttusBar Adjusted to Main window

RECT rect;

GetWindowRect(hSt, &rect);

BOOL bVisible = IsWindowVisible(hSt);

MoveWindow(hSt, rect.left, height + rect.top - rect.bottom, rect.bottom - rect.top, width, TRUE);

}

m_boxWidth = width; //remember current width and height in global variables.

m_boxHeight = height;

}

 

В процедуре gluPerspective появляются глобальные переменные fViewAngle,fNearPlane,fFarPlane. В большинстве уроков по умолчанию установлены величины:

GLfloat fViewAngle = 45, fNearPlane = 0.01f, fFarPlane = 100;

 

Однако в уроках 30,31,34,36,44,45,46 эти значения должны быть изменены.

Также глобальная переменная m_bOrtho вызывает glOrtho преобразование, где это необходимо(уроки 21 и 24). 

Положение строки инструментов и строки статуса подгоняется под главное окно тоже в подпрограмме ResizeGLScene.

 

Подпрограммы WndProc и GlobWinMain также имеют некоторые изменения для обработки диалогов и строки инструментов. Вы можете посмотреть на эти изменения в GlobUse/GLRoutine.cpp: ничего специального, обычная рутина.

 

Переход в полноэкранный режим в отличие от исходных уроков осуществляется одновременным нажатием клавиш Ctrl+Enter .

 

Клавиша F1 в отличие от исходных уроков задействована по своему стандартному назначению для вызова помощи по программе (меню Help->Help Dialog)

Select Lesson Dialog

Диалоговое окно Help Dialog является немодальным, что позволяет осуществлять управление программой, как из этого окна, так и другими способами.

 

Из уважения к авторам оригинальных кодов About Dialog (меню Help->About...) содержит исходные тексты NeHe's ReadMe:

Select Lesson Dialog

 

 

Это диалоговое окно About Dialog доступно из других диалогов по клавише About...

 

 

Ещё одно отличие от исходных уроков в том, что все процедуры работы с текстурами собраны в файле GlobGLTexture.cpp в директории GlobUse. Только вместо подпрограммы auxDibImageLoad для загрузки текстур я написал следующие процедуры с использованием класса CImage:

 

HBITMAP GetImgBitmap(CImage * nImg)

{

if(nImg == NULL)

return NULL;

CImage * pImg = new CImage;

pImg->Create(nImg->GetWidth(),nImg->GetHeight(), 24);

nImg->BitBlt(pImg->GetDC(),CPoint(0,0));

HDC hdc = CreateCompatibleDC(pImg->GetDC());

HBITMAP hbm = CreateCompatibleBitmap(pImg->GetDC(), pImg->GetWidth(), pImg->GetHeight());

HBITMAP bmOld = (HBITMAP) SelectObject(hdc,hbm);

pImg->BitBlt(hdc, CPoint(0,0));

//DeleteDC(hdc);

pImg->ReleaseDC();

delete pImg;

return hbm;

}

//////////////////////////////////////////////////////////////////////////

HBITMAP LoadMyBitmap(char * fName)

{

if(!isFileExist(fName))

{

char strk[_MAX_PATH];

_getcwd(str, _MAX_PATH);

sprintf_s(strk, "LoadMyBitmap\nNo File exist:\n%s\nin Directory:\n%s", fName, str);

MessageBox(NULL, strk, "No File:", MB_OK | MB_ICONINFORMATION);

return NULL;

}

CImage * pImg = new CImage;

pImg->Load(fName);

HBITMAP bm = GetImgBitmap(pImg);

delete pImg;

pImg = NULL;

return bm;

}

//////////////////////////////////////////////////////////////////////////////

 

Файл GlobGLTexture.cpp можно скопировать и использовать при создании любых приложений, использующих OpenGL для любых типов файлов изображений, принятых в Windows.

 

Сами уроки в этом приложении собраны в директории NeHeProgs и начинаются с "01_","02_",..."X5_" в соответствии с номерами уроков. Это как раз те коды, которые были любезно предоставлены на NeHe.GameDev(Grant Games), и я старался, насколько это возможно не менять их  в процессе адаптации к современным версиям Visual Studio.

 

Единственное большое изменение – это то, что я взял на себя смелость исключить из всех проектов библиотеку Glaux.lib. Но, я думаю, авторы оригинальных текстов не будут на меня в обиде. Не могли же они ожидать от разработчиков MS VS такой подлости, как исключение библиотеки Glaux.lib, начиная с 10-й версии. И, если к 10-й версии её ещё можно привязать, то в 11-й она вовсе не работает.

 

Собрание всех основных уроков в отдельную директорию ClobUse позволяет применять и совмещать общие подпрограммы в отдельных уроках, а также разрабатывать собственые приложения путем компиляции отдельных подпрограмм, собранных в NeHeProgs и GlobUse. Примеры разработки таких приложений приведены в предлагаемых уроках: Урок X4.Игры с УФО (проект lessonX4/UFOgame) и Урок X5.Боксер (проект lessonX5/BoxMan).

 

Урок X4.Игры с УФО создан из уроков 07, 11, 30, 32, 34. Урок X5.Боксер демонстрирует возможность создания фигур и их движений во внешнем текстовом файле, причем пользователю не нужно знать программистских деталей, достаточно только пространственного воображения.

 

Однако этот последний урок выявляет одну проблему, связанную с одновременным использованием <windows.h> и <afxwin.h>.Конфликт был подавлен в окне свойств проекта Configuration Propeties->Linker->General->Force Output. Ошибка ушла, но предупреждение осталось, и исполняемый файл оказался очень большим по размеру. В MFC таких проблем не возникает.

 

Мне представляется, что знакомство с OpenGL с помощью готовых рабочих кодов вполне вписывается в концепцию Народного учебника по OpenGL. Я надеюсь, что предоставленные проекты составят хорошую поддержку учебникам и пособиям по OpenGL .

 

Код к уроку

 

OpenGLWin32_2010.7z (4.8 Mb)

© Владимир Петров
petrov@msun.ru

PMG  13 декабря 2013