Спасибо, что скачали книгу в бесплатной электронной библиотеке BooksCafe.Net
   Все книги автора
   Эта же книга в других форматах
 
   Приятного чтения!
 

 
 

MFC и OpenGL


MFC и OpenGL

   "Подать сюда MFС!!! – кричил он, топая всеми 4-мя лапами."

   Сижу тут как-то, программку сочиняю, тут смотрю, царь зверей пожаловал. Вопрос задать пришел. Спрашивает как же OpenGL в MFC то вставить? Сначала думал отмажусь, потом смотрю, настойчивый такой царь попался. Письма шлет, желает знать как же все-таки её туда вставить-то. Вот и решил я примерчик на MFC состроить дабы цари меньше утруждали себя, а больше на солнышке бы нежились, чтоб у царей спокойно и хорошо все было, тогда и нам, простым зверушкам жить хорошо будет. И так поехали.
   Для начала сделаем приложение MFC как диалог. Я назвал его BitScroll. Как это делать? Смотрите шаги по MFC.
   Теперь, при помощи визарда добавим функцию
   BOOL CBitScrollDlg::PreCreateWindow(CREATESTRUCT& cs) {
    cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
    return CDialog::PreCreateWindow(cs);
   }
   Помните, мы устанавливали слиль окна в функции CreateWindow? Так вот это действие по смыслу тоже самое. Напомню как это выглядело в Win32API:
   hWnd = CreateWindow("Skeleton", "Skeleton", WS_OVERLAPPEDWINDOW |  WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 50, 50, 700, 400, NULL, NULL, hInst, NULL);
   Теперь обратимся к функции OnInitDialog(). В ней сначала вызывается функция базового класса, т.е. CDialog, а потом устанавливаются иконки для диалога. Давайте вставим наш код между иконками и CDialog::OnInitDialog().
   SetWindowPos(&wndTop, 0, 0, WIDTH, HEIGHT, SWP_NOMOVE);
   pDC = GetDC();
   CenterWindow();
   Init(); SetTimer(1,SPEED, NULL);
   Теперь посмотрим, что мы сделали. Сначала сделаем окно нужного нам размера (макросы WIDTH и HEIGHT объявлены так #define WIDTH 640 и #define HEIGHT 480 в заголовочном файле).
   Затем получим контекст для рисования. Установимся в центр вселенной и… вот, тут самое интересное, тут мы вызываем нашу собственную функцию, которая будет инициализировать OpenGL (напоминаю, что тоже самое делала функция Initial в программе на Win32API).
   А потом включаем таймер, чтобы обеспечить анимацию. Обратимся теперь к Init(). Выглядит она итак:
   void CBitScrollDlg::Init() {
    CRect rect;
    HGLRC hrc;
    if (!bSetupPixelFormat()) return;
    hrc = wglCreateContext(pDC->GetSafeHdc());
    ASSERT(hrc != NULL);
    wglMakeCurrent(pDC->GetSafeHdc(), hrc);
    GetClientRect(&rect);
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClearDepth(1.0);
    glDepthFunc(GL_LESS);
    glEnable(GL_DEPTH_TEST);
    glShadeModel(GL_SMOOTH);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0f, (GLfloat)rect.right / (GLfloat)rect.bottom, 0.1f, 100.0f);
    glMatrixMode(GL_MODELVIEW);
   }
   Что мы тут делаем? Прежде всего вызываем ф-ию SetupPixelFormat(), это опять наша функция и мы посмотрим ее чуть позже.
   Далее, как и раньше, получаем контекст рендеринга (маленькая деталь, ранее pDC(а точнее эта переменная называлась hDC) была объявлена как static HDC hDC, сейчас контекст рисования является пременной типа CDC, а ф-ция wglCreateContext и другие функции OpenGL требуют в качестве аргумента переменную типа HDC. Поэтому мы получаем этот hardware context с помощью pDC->GetSafeHdc()).
   Затем делаем этот контекст текущим и настраиваем область отображения, так как это делалось в Initial() (Win32API)
   Функция bSetupPixelFormat() содержит следующее:
   BOOL CBitScrollDlg::bSetupPixelFormat() {
    static PIXELFORMATDESCRIPTOR pfd = {
     sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
     1, // version number
     PFD_DRAW_TO_WINDOW | // support window
     PFD_SUPPORT_OPENGL | // support OpenGL
     PFD_DOUBLEBUFFER, // double buffered
     PFD_TYPE_RGBA, // RGBA type
     24, // 24-bit color depth
     0, 0, 0, 0, 0, 0, // color bits ignored
     0, // no alpha buffer
     0, // shift bit ignored
     0, // no accumulation buffer
     0, 0, 0, 0, // accum bits ignored
     32, // 32-bit z-buffer
     0, // no stencil buffer
     0, // no auxiliary buffer
     PFD_MAIN_PLANE, // main layer
     0, // reserved
     0, 0, 0 // layer masks ignored
    };
    int pixelformat;
    if ((pixelformat = ChoosePixelFormat(pDC->GetSafeHdc(), &pfd)) == 0) {
     MessageBox("ChoosePixelFormat failed");
     return FALSE;
    }
    if (SetPixelFormat(pDC->GetSafeHdc(), pixelformat, &pfd) == FALSE) {
     MessageBox("SetPixelFormat failed");
     return FALSE;
    }
    return TRUE;
   }
   Как не трудно заметить, она почти полностью взята из Win32API приложения за исключением того, что hDC заменена на pDC->GetSafeHdc().
   Теперь добавим в нашу программку обработчик от таймера (мы его недавно сделали в ф-ции Init())
   void CBitScrollDlg::OnTimer(UINT nIDEvent) {
    DrawScene();
    CDialog::OnTimer(nIDEvent);
   }
   Все тривиально. По смыслу ясно, что каждый раз, когда срабатывает обработчик таймера (а делает он это часто) рисуется сцена. Таким образом получается анимация. Посмотрим на эту функцию:
   void CBitScrollDlg::DrawScene() {
    static GLfloat angle = 0;
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    glTranslatef(0.0f, 0.0f, –2.0f);
    glRotatef(angle, 1.0f, 0.5f, 0.3f);
    glBegin(GL_QUADS);
    glColor3f(1.0f, 0.0f, 1.0f);
    glVertex3f(-0.5f, 0.5f, 0.0f);
    glColor3f(1.0f, 1.0f, 1.0f);
    glVertex3f(0.5f, 0.5f, 0.0f);
    glColor3f(0.0f, 1.0f, 1.0f);
    glVertex3f(0.5f, –0.5f, 0.0f);
    glColor3f(0.0f, 0.0f, 1.0f);
    glVertex3f(-0.5f, –0.5f, 0.0f);
    glEnd();
    glFinish();
    SwapBuffers(wglGetCurrentDC());
    angle += 0.5f;
   }
   По моему проще уже некуда. Я надеюсь, что все ясно.
   Ну вот казалось бы и все. Единственное, что остается сделать – убраться за собой. Т.е. надо при выходе удалить контекст рендеринга и убить таймер.
   Эти вещи надо сделать в 2-х обработчиках OnClose и OnDestroy. Посмотрим на них:
   void CBitScrollDlg::OnClose() {
    // TODO: Add your message handler code here and/or call default
    HGLRC hrc;
    KillTimer(1);
    hrc = ::wglGetCurrentContext();
    ::wglMakeCurrent(NULL, NULL);
    if (hrc) ::wglDeleteContext(hrc);
    CDialog::OnClose();
   }
   и
   void CBitScrollDlg::OnDestroy() {
    CDialog::OnDestroy();
    // TODO: Add your message handler code here
    HGLRC hrc;
    KillTimer(1);
    hrc = ::wglGetCurrentContext();
    ::wglMakeCurrent(NULL, NULL);
    if (hrc) ::wglDeleteContext(hrc);
   }
   Она практически одинаковые. Работают так же как и case WM_CLOSE в Win32API. Т.е. убиваем таймер, получаем контекст рендеринга, если он есть – удаляем его.
   Ну вот и все. Еще добавлю, что в проекте есть функция OnSize для обработки изменений размеров окна. В данном случае она не нужна, но если вставлять OpenGL в SDI или MDI, то она вам понадобится.

   Спасибо, что скачали книгу в бесплатной электронной библиотеке BooksCafe.Net
   Оставить отзыв о книге
   Все книги автора