Chapter 7
Инициализация или как написать приложение с нуля

7.4  MFC-приложение - MFC AppWizard

     Этот тип приложения обладает всеми достоинствами и недостатками WinAPI-приложения, рассмотренного выше, так как MFC - это библиотека классов С++, т.е. надстройка над WinAPI. Кто-нибудь, конечно, скажет, что приложение на плюсах немерено большое, работает медленно и MFC для ленивых. В общем, тут у каждого свое мнение. Каждый по-своему прав. Тем не менее, я считаю, что для каждой задачи требуется свой инструмент. Где-то лучше использовать MFC, где-то WinAPI. Кричать, что первое или второе является незаменимым средством на все случаи жизни было бы неверно. У MFC есть свои особенности, отнести которые к достоинствам или недостаткам однозначно нельзя. В зависимости от решаемой задачи они идут в плюс или минус. Согласитесь,что глупо забивать сапожный гвоздь кувалдой или же скобу сапожным молотком.

Создаем проект:

  1. Запустите MSVisualC++6.0
  2. Щелкните меню File->New->MFC AppWizard(exe).
  3. Выберете каталог и имя проекта задайте mfc, щелкните OK.
  4. Step1: Поставьте переключатель на Single document, далее OK.
  5. Step3: Уберите флажок ActiveX Controls, далее OK.
  6. Щелкните Finish.
  7. Щелкните Build->Set Active Configuration и установите тип проекта MFC - Win32 Release
  8. Далее щелкаете Project->Settings->Link->Object/library modules: и добавьте туда opengl32.lib, glu32.lib и glaux.lib

В CMFCView объявите закрытую(private) переменную hGLRC типа HGLRC. Там же объявите функцию int SetWindowPixelFormat(HDC) и открытую(public) функцию display. Вот что должно получится:

 
 class CMFCView : public CView
{
private:
CClientDC *pdc;
HGLRC hGLRC;
int SetWindowPixelFormat(HDC);

public:
        void display();
...

     Вставьте код этой функции в файл MFCView.cpp. Код возьмите из предыдущего раздела. Отредактируйте функцию CMFCView::PreCretaeWindow следующим образом:

BOOL CMFCView::PreCreateWindow(CREATESTRUCT& cs)
{
        // TODO: Modify the Window class or styles here by modifying
        //  the CREATESTRUCT cs
    cs.style |= (WS_CLIPCHILDREN | WS_CLIPSIBLINGS); 
        return CView::PreCreateWindow(cs);
}
Добавьте также функцию display сюда:
void CMFCView::display()
{
  glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

        glTranslated(0.01,0,0); 
        glColor3d(1,0,0);
        auxSolidSphere( 1 );


  glFinish();
  SwapBuffers(wglGetCurrentDC());
}
Теперь запустите View->Class Wizard и добавьте обработчик WM_CREATE,WM_DESTROY и WM_SIZE в класс CMFCView. Отредактируйте их следующим образом:
int CMFCView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
        if (CView::OnCreate(lpCreateStruct) == -1)
                return -1;
        
        pdc = new CClientDC(this);

        if(SetWindowPixelFormat(pdc->m_hDC)==FALSE)
        return -1;


         hGLRC = wglCreateContext(pdc->m_hDC);
    if(hGLRC == NULL)
        return -1;

    if(wglMakeCurrent(pdc->m_hDC, hGLRC)==FALSE)
        return -1;

    glEnable(GL_ALPHA_TEST);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_COLOR_MATERIAL);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    float pos[4] = {3,3,3,1};
    float dir[3] = {-1,-1,-1};
    glLightfv(GL_LIGHT0, GL_POSITION, pos);
    glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, dir);

        return 0;
}

void CMFCView::OnDestroy() 
{
 if(wglGetCurrentContext()!=NULL) 
   wglMakeCurrent(NULL, NULL) ;
   

    if(hGLRC!=NULL)
        {
      wglDeleteContext(hGLRC);
      hGLRC = NULL;
    }

        delete pdc;

        CView::OnDestroy();
}

void CMFCView::OnSize(UINT nType, int cx, int cy) 
{
        CView::OnSize(nType, cx, cy);
        
   glViewport(0,0,cx,cy);
   glMatrixMode( GL_PROJECTION );
   glLoadIdentity();
   glOrtho(-5,5, -5,5, 2,12);   
   gluLookAt( 0,0,5, 0,0,0, 0,1,0 );
   glMatrixMode( GL_MODELVIEW );
        
}
Пояснения смотри в предыдущих разделах. В StdAfx.h включите заголовочные файлы после строчки #include <afxext.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glaux.h>
Запустите еще раз Class Wizard и добавьте функцию OnIdle в класс CMFCApp. Эта функция вызывается всякий раз, когда очередь сообщений окна пуста. Отредактируйте ее:
BOOL CMFCApp::OnIdle(LONG lCount) 
{
 ( (CMFCView*) ((CMainFrame*)m_pMainWnd)->GetActiveView() )->display(); 
        return 1;//CWinApp::OnIdle(lCount);
}


Исходный файл смотрите здесь. Исполняемый файл здесь.