Не так давно я обнаружил этот сайт и взялся за изучение OpenGL с его помощью. Народный учебник по OpenGL - очень хорошая идея. Я надеюсь, что этот урок поможет многим пользователям в освоении OpenGL. Я пооследовательно адаптировал коды этих уроков к Microsoft Visual Studio , и в процессе возникла идея объединения их с тем, чтобы использовать для компиляции собственных программ.
Уже после того, как это было сделано, я обнаружил, что на сайте NeHe GameDev имеется адаптация всех уроков к MS Studio .NET (Grant James), но не в MFC. По моему мнению, в MFC гораздо больше возможностей для разработки приложений. Я адаптировал почти все уроки к MFC в директории LessonsGLCode и свел их в одну общую программу GLSummary. В процессе адаптации я столкнулся с тем, что возникают конфликты при переводе проектов из одной модификации Microsoft Visual Studio в другую. В конце концов, в демонстрационных целях я остановился на следующих вариантах (ссылки на меня приветствуются, но не обязательны):
- GLSummaryCode_2010 – один проект, обобщающий все уроки;
- LessonsGLCode_2010 – все проекты, но из каждого можно вызвать любой другой.
Здесь 2010 означает, что проекты предназначены для Microsoft Visual Studio Professional 2010. Впрочем, они безболезненно адаптируются к версии 2012, но для нее нужен уже Windows 7, версия 2010 работает и там, и в Windows XP.
Эти коды могут также здорово помочь тем, кто начинает изучать Visual C++, однако в дальнейшем изложении я предполагаю, что у читащего этот текст имеются базовые навыки работы с этим компиллятором. Прилагаемые коды можно сразу компиллировать в указанной среде, и, если они запущены в соответствующей версии MS VS, то должны сработать с одного пинка.
Изложение этого урока относится к GLSummaryCode_2010. Впрочем, в версии 2012 особых отличий не будет.
Коды адаптированных мною проектов собраны в директории GLSummaryCode_2010. Основной проект для данного урока GLSummary. Все иcходные данные для этого проекта и всех прочих находятся в папке Data. Для редактирования текстов запускается GLSummary.sln. Даже если у вас нет большого опыта использования Visual C++, можете начать его изучение с запуска этого (или любого другого прилагаемого) проекта. Общие для всех проектов подпрограммы расположены в папке GlobUse.
Список подпрограмм, которые задействованы в проекте, находятся по закладке Обозреватель решений(Solution Explorer (меню View->Solution Explorer).) Выбрав любой *.h или *.cpp файл, можно его просмотреть и(или) редактировать. На первый взгляд, файлов этих очень много, но при ближайшем рассмотрении все оказывается довольно простым.
Скомпиллируйте программу(меню Build->Build Solution) и запустите программу (меню Debud->Start Without Debugging). Если все правильно сделано, то будет запущена демонстрация одного из уроков (того, чьё название хранится в файле LastNum.txt в папке LessonsGL/GLSummary). Для демонстрации любого другого урока обратитесь в меню File->Lesson... Появится диалоговое окно:
Вы можете выбрать любой другой урок из списка для демонстрации.
Для формирования самостоятельного приложения:
- создайте отдельную папку (например, GLTest);
- скопируйте в эту новую папку программу GLSummary.exe, которая находится в папке ../GLSummary/Release;
- скопируйте в эту же папку папки HelpText, Data, Art и BoxData, и приложение готово.
Файлы GLSummary.cpp, GLSummaryDoc.cpp,GLSummaryView.cpp, GLSummary.rc, resource.h были созданы компиллятором Visual C++ 7.0 при создании проекта. Mainfrm.cpp первоначально тоже создавалась компиллятором, но затем она была перенесена в папку GlobUse для использования всеми проектами в директории LessonsGL.
В файле GLSummaryView.cpp и и во всех других проектах в *View.cpp процедура CreateGLWindow вызывается по прерыванию OnCreate.
int CGLSummaryView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
CreateGLWindow(this,32);
return 0;
}
Процедура инициализации InitGLn вызывается в OnInitialUpdate:
void CGLSummaryView::OnInitialUpdate()
{
CView::OnInitialUpdate();
FILE * f = fopen("LastNum.txt","rt"); //Get last lesson name
if(f != NULL)
{
fgets(str, 256, f);
fclose(f);
CString tString = str;
m_strNum = strtok(str, ". _-:");
m_strLesson = tString;
m_pDlgTitle = new CDlgTitle;
m_pDlgTitle->SetTitle(tString);
}
InitGLn();
GetDocument()->SetTitle(GetLessonName(m_strNum));
}
Символьная переменная m_strNum является глобальной и служит идентификатором выбранного урока.
Процедура ResizeGLScene вызывается по прерыванию OnSize:
void CGLSummaryView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
ReSizeGLScene(cx,cy);
GetMainFrameGlob->SetTitlePos();
}
Собственно изображение осуществляется процедурой DrawGLSceneN по прерыванию OnDraw:
void CGLSummaryView::OnDraw(CDC* /*pDC*/)
{
DrawGLSceneN();
}
или по прерыванию OnTimer:
void CMainFrame::OnTimer(UINT nIDEvent)
{
switch(nIDEvent)
{
case TIMER_PLAY:
UpdateGLScene();
DrawGLSceneN();
break;
}
CFrameWnd::OnTimer(nIDEvent);
}
или при выполнении установленных для пользователя действий. Смена атрибутов, формирующих изображение, производится процедурой UpdateGLScene по прерыванию OnTimer.
Процедуры WndProc и WinMain в MFC не нужны.
Для управления изображением вместо WinMain в исходных уроках используется обработка событий, принятая в Visual C++.
Например, обработка нажатия клавиши 'L' выполняется процедурой CGLSummaryView::OnVkL.
void CGLSummaryView::OnVkL(){ProcessKeyboardN("L");}
Организация этой процедуры была произведена при помощи AppStudio(меню View->Resource View). Я не буду подробно описывать процесс создания этой процедуры, он описан в MSDN Library.
Переход в полноэкранный режим в отличие от исходных уроков осуществляется одновременным нажатием клавиш Ctrl+Enter и выполняется процедурой CMainFrame::OnVkReturnCtrl:
void CMainFrame::OnVkReturnCtrl()
{
m_bFullScreen = ! m_bFullScreen;
if (m_bFullScreen)
{
ModifyStyle(WS_CAPTION, 0);
m_wndToolBar.ShowWindow(SW_HIDE);
m_wndStatusBar.ShowWindow(SW_HIDE);
ShowWindow(SW_SHOWMAXIMIZED);
HideMenu();
}
else
{
ModifyStyle(WS_CAPTION, WS_OVERLAPPED | WS_CAPTION | FWS_ADDTOTITLE
| WS_THICKFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_MAXIMIZE);
ShowMenu();
m_wndToolBar.ShowWindow(SW_SHOWNORMAL);
m_wndStatusBar.ShowWindow(SW_SHOWNORMAL);
ShowWindow(SW_SHOWNORMAL);
}//if (m_bFullScreen)
}
Клавиша F1 в отличие от исходных уроков задействована по своему стандартному назначению для вызова помощи по программе (меню Help->GL Help Summary) и выполняется процедурой CMainFrame::OnHelp():
void CMainFrame::OnHelp()
{
if(m_pAboutDlg == NULL)
m_pAboutDlg = new CAboutDlg();
m_pAboutDlg->ShowWindow(SW_SHOWNORMAL);
}
Диалоговое окно m_pAboutDlg является немодальным, что позволяет осуществлять управление программой, как из этого окна, так и другими способами:
Ещё одно отличие от исходных уроков в том, что все процедуры работы с текстурами собраны в файле GlobGLTexture.cpp в директории GlobUse. Я только добавил в эти процедуру LoadGLTextureImage(CString fName), которая позволяет загрузить в текстуру файл с изображением любого типа, используя класс CImage:
int LoadGLTextureImage(CString fName)
{
if(!isFileExist(fName))
{
AfxMessageBox("LoadGLTextureImage\nNo File exist:\n" + fName);
return FALSE;
}
CImage * pImg = new CImage;
pImg->Load(fName);
CBitmap * pBm = GetImgBitmap(pImg);
if(pBm == NULL)
return FALSE;
BITMAP BMP;
pBm->GetBitmap(&BMP);
GLuint nt = LoadGLTexture(BMP.bmWidth, BMP.bmHeight,GL_BGR_EXT, BMP.bmBits);
delete pBm;delete pImg;
pImg = NULL;
return nt;
}
Файл GlobGLTexture.cpp можно скопировать и использовать при создании любых приложений, использующих OpenGL.
Сами уроки в этом приложении представлены на закладке Solution Explorer в виде файлов *DrawInit.cpp. Это как раз те коды, которые были любезно предоставлены на NeHe.GameDev, и я старался, насколько это возможно не менять их в процессе адаптации к MFC.
Единственное большое изменение – это то, что я взял на себя смелость исключить из всех проектов библиотеку Glaux.lib. Но, я думаю, авторы оригинальных текстов не будут на меня в обиде. Не могли же они ожидать от разработчиков MS VS такой подлости, как исключение библиотеки Glaux.lib, начиная с 10-й версии. И, если к 10-й версии её ещё можно привязать, то в 11-й она вовсе не работает.
Собрание всех основных уроков в отдельную директорию ClobUse позволяет применять и совмещать общие подпрограммы в отдельных уроках, а также разрабатывать собственые приложения путем компиляции отдельных подпрограмм, собранных в LessonsGL. Примеры разработки таких приложений приведены в предлагаемых уроках: Урок X4.Игры с УФО (проект lessonX4/UFOgame) и Урок X5.Боксер (проект lessonX5/BoxMan).
Урок X4.Игры с УФО создан из уроков 07, 11, 30, 32, 34. Урок X5.Боксер демонстрирует возможность создания фигур и их движений во внешнем текстовом файле, причем пользователю не нужно знать программистских деталей, достаточно только пространственного воображения.
Мне представляется, что знакомство с OpenGL с помощью готовых рабочих кодов вполне вписывается в концепцию Народного учебника по OpenGL. Я не имею большого опыта работы с OpenGL, и некоторые уроки мне не удалось вполне адаптировать к MS VS. Я надеюсь, что уважаемым авторам оригинальных текстов уроков не составит труда подправить мои коды, чтобы в полной мере привести их к их первоначальным замыслам.
Код к уроку
LessonsCode_2010.7z (5.09 Mb)
© Владимир Петров
petrov@msun.ru
Моя страница