OPENGL2_基本框架
阅读原文时间:2023年07月15日阅读:1

一些概念

HDC:设备描述句柄(窗口着色描述表句柄),是WINDOWS的一种数据类型,HDC定义的变量指向一块内存,这块内存用来描述一个设备的相关的内容(设备描述表).

HGLRC:OpenGL渲染环境句柄(OpenGL渲染描述表句柄).所有OpenGL命令要通过HRC执行,每个使用OpenGL调用的线程必须有且只有一个当前渲染环境HRC,OpenGL通过渲染环境HRC与Windows窗口系统连接。单个窗口可以使用多个RC,但单一线程只能有一个当前RC.使一个RC成为当前RC需要3步:1设置窗口像素格式,2产生RC,3设置为当前RC.

GDI:Graphics Deveice Interface,图形设备接口.用GDI编程,可以不考虑硬件的具体特性,GDI函数都要求有一个HDC类型的句柄,可直接调用Windows API中的图形处理函数

GDI就是Windows自身api绘制函数,需要HDC,跟OpenGL无关。

而使用OpenGL API需要HRC,而HRC又需要和HDC绑定来连接OpenGL与Windows

框架概述

跟opengl和游戏相关的用蓝字

创建窗口

1定义windows类

2注册windows类

3设置全屏参数

4创建窗口

5设置当前HRC

   5.1设置窗口像素格式

                1定义窗口像素格式

                2从窗口获取HDC

                3使用HDC和之前定义的像素格式,在Windows中寻找匹配像素格式,并保存

                4设置像素格式

   5.2使用HDC创建HRC

   5.3激活渲染环境HRC(绑定HRC到HDC)

6显示窗口

7OpenGL初始化(设定Opengl视口等信息ReSizeGLScene(),设定Opengl初始环境InitGL())

主循环

1 事件消息处理

2 OpenGL渲染(在主循环中渲染而不在windows事件中渲染,更加灵活,适合游戏开发)

事件回调

按键按下获取按键值,窗口大小调整时调整opengl视口大小等

框架代码

以下使用的是nehe的opengl框架代码

引自http://www.yakergong.net/nehe/

#include "stdafx.h"
#include "Nehe_Base.h"

#include "GL.H" // Header File For The OpenGL32 Library
#include "GLU.H" // Header File For The GLu32 Library
#include "GLAUX.H" // Header File For The Glaux Library

HDC hDC=NULL; // Private GDI Device Context
HGLRC hRC=NULL; // Permanent Rendering Context
HWND hWnd=NULL; // Holds Our Window Handle
HINSTANCE hInstance; // Holds The Instance Of The Application

bool keys[256]; // Array Used For The Keyboard Routine
bool active=TRUE; // Window Active Flag Set To TRUE By Default
bool fullscreen=TRUE; // Fullscreen Flag Set To Fullscreen Mode By Default

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc

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  

//指定了观察的视景体
// Calculate The Aspect Ratio Of The Window
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);

glMatrixMode(GL\_MODELVIEW);                            // Select The Modelview Matrix  
glLoadIdentity();                                   // Reset The Modelview Matrix  

}

int InitGL(GLvoid) // All Setup For OpenGL Goes Here
{
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
return TRUE; // Initialization Went OK
}

int DrawGLScene(GLvoid) // Here's Where We Do All The Drawing
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
glLoadIdentity(); // Reset The Current Modelview Matrix

// move back 5 units and rotate about all 3 axes  
glTranslatef(0.0, 0.0, -5.0f);  
glRotatef(0.0f, 1.0f, 0.0f, 0.0f);  
glRotatef(0.0f, 0.0f, 1.0f, 0.0f);  
glRotatef(0.0f, 0.0f, 0.0f, 1.0f);

// lime greenish color  
glColor3f(0.7f, 1.0f, 0.3f);

// draw the triangle such that the rotation point is in the center  
glBegin(GL\_TRIANGLES);  
glVertex3f(1.0f, -1.0f, 0.0f);  
glVertex3f(-1.0f, -1.0f, 0.0f);  
glVertex3f(0.0f, 1.0f, 0.0f);  
glEnd();

return TRUE;                                        // Everything Went OK  

}

GLvoid KillGLWindow(GLvoid) // Properly Kill The Window
{
if (fullscreen) // Are We In Fullscreen Mode?
{
ChangeDisplaySettings(NULL,0); // If So Switch Back To The Desktop
ShowCursor(TRUE); // Show Mouse Pointer
}

if (hRC)                                            // Do We Have A Rendering Context?  
{  
    if (!wglMakeCurrent(NULL,NULL))//2参数空则1参数被忽略,作用是尝试分离HRC与HDC// Are We Able To Release The DC And RC Contexts?  
    {  
        MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB\_OK | MB\_ICONINFORMATION);  
    }

    if (!wglDeleteContext(hRC))                     // Are We Able To Delete The RC?  
    {  
        MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB\_OK | MB\_ICONINFORMATION);  
    }  
    hRC=NULL;                                       // Set RC To NULL  
}

if (hDC && !ReleaseDC(hWnd,hDC))                    // Are We Able To Release The DC  
{  
    MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB\_OK | MB\_ICONINFORMATION);  
    hDC=NULL;                                       // Set DC To NULL  
}

if (hWnd && !DestroyWindow(hWnd))                   // Are We Able To Destroy The Window?  
{  
    MessageBox(NULL,"Could Not Release hWnd.","SHUTDOWN ERROR",MB\_OK | MB\_ICONINFORMATION);  
    hWnd=NULL;                                      // Set hWnd To NULL  
}

if (!UnregisterClass("OpenGL",hInstance))           // Are We Able To Unregister Class  
{  
    MessageBox(NULL,"Could Not Unregister Class.","SHUTDOWN ERROR",MB\_OK | MB\_ICONINFORMATION);  
    hInstance=NULL;                                 // Set hInstance To NULL  
}  

}

/* This Code Creates Our OpenGL Window. Parameters Are: *
* title - Title To Appear At The Top Of The Window *
* width - Width Of The GL Window Or Fullscreen Mode *
* height - Height Of The GL Window Or Fullscreen Mode *
* bits - Number Of Bits To Use For Color (8/16/24/32) *
* fullscreenflag - Use Fullscreen Mode (TRUE) Or Windowed Mode (FALSE) */

BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)
{
//当我们要求Windows为我们寻找相匹配的象素格式时,Windows寻找结束后将模式值保存在变量PixelFormat中。
GLuint PixelFormat; // Holds The Results After Searching For A Match

WNDCLASS    wc;                     // Windows Class Structure  
DWORD       dwExStyle;              // Window Extended Style  
DWORD       dwStyle;                // Window Style  
RECT        WindowRect;             // Grabs Rectangle Upper Left / Lower Right Values  
WindowRect.left=(long)0;            // Set Left Value To 0  
WindowRect.right=(long)width;       // Set Right Value To Requested Width  
WindowRect.top=(long)0;             // Set Top Value To 0  
WindowRect.bottom=(long)height;     // Set Bottom Value To Requested Height

fullscreen=fullscreenflag;          // Set The Global Fullscreen Flag

hInstance           = GetModuleHandle(NULL);                // Grab An Instance For Our Window  
wc.style            = CS\_HREDRAW | CS\_VREDRAW | CS\_OWNDC;    // Redraw On Size, And Own DC For Window.  
wc.lpfnWndProc      = (WNDPROC) WndProc;                    // WndProc Handles Messages  
wc.cbClsExtra       = 0;                                    // No Extra Window Data  
wc.cbWndExtra       = 0;                                    // No Extra Window Data  
wc.hInstance        = hInstance;                            // Set The Instance  
wc.hIcon            = LoadIcon(NULL, IDI\_WINLOGO);         // Load The Default Icon  
wc.hCursor          = LoadCursor(NULL, IDC\_ARROW);         // Load The Arrow Pointer  
wc.hbrBackground    = NULL;                                 // No Background Required For GL  
wc.lpszMenuName     = NULL;                                 // We Don't Want A Menu  
wc.lpszClassName    = "OpenGL";                             // Set The Class Name

if (!RegisterClass(&wc))                                    // Attempt To Register The Window Class  
{  
    MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB\_OK|MB\_ICONEXCLAMATION);  
    return FALSE;                                           // Return FALSE  
}

if (fullscreen)                                             // Attempt Fullscreen Mode?  
{  
    DEVMODE dmScreenSettings;                               // Device Mode  
    memset(&dmScreenSettings,0,sizeof(dmScreenSettings));   // Makes Sure Memory's Cleared  
    dmScreenSettings.dmSize=sizeof(dmScreenSettings);       // Size Of The Devmode Structure  
    dmScreenSettings.dmPelsWidth    = width;                // Selected Screen Width  
    dmScreenSettings.dmPelsHeight   = height;               // Selected Screen Height  
    dmScreenSettings.dmBitsPerPel   = bits;                 // Selected Bits Per Pixel  
    dmScreenSettings.dmFields=DM\_BITSPERPEL|DM\_PELSWIDTH|DM\_PELSHEIGHT;

    // Try To Set Selected Mode And Get Results.  NOTE: CDS\_FULLSCREEN Gets Rid Of Start Bar.  
    if (ChangeDisplaySettings(&dmScreenSettings,CDS\_FULLSCREEN)!=DISP\_CHANGE\_SUCCESSFUL)  
    {  
        // If The Mode Fails, Offer Two Options.  Quit Or Use Windowed Mode.  
        if (MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By\\nYour Video Card. Use Windowed Mode Instead?","NeHe GL",MB\_YESNO|MB\_ICONEXCLAMATION)==IDYES)  
        {  
            fullscreen=FALSE;       // Windowed Mode Selected.  Fullscreen = FALSE  
        }  
        else  
        {  
            // Pop Up A Message Box Letting User Know The Program Is Closing.  
            MessageBox(NULL,"Program Will Now Close.","ERROR",MB\_OK|MB\_ICONSTOP);  
            return FALSE;                                   // Return FALSE  
        }  
    }  
}

if (fullscreen)                                             // Are We Still In Fullscreen Mode?  
{  
    dwExStyle=WS\_EX\_APPWINDOW;                                // Window Extended Style  
    dwStyle=WS\_POPUP;                                      // Windows Style  
    ShowCursor(FALSE);                                      // Hide Mouse Pointer  
}  
else  
{  
    dwExStyle=WS\_EX\_APPWINDOW | WS\_EX\_WINDOWEDGE;           // Window Extended Style  
    dwStyle=WS\_OVERLAPPEDWINDOW;                           // Windows Style  
}

AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);     // Adjust Window To True Requested Size

// Create The Window  
if (!(hWnd=CreateWindowEx(  dwExStyle,                          // Extended Style For The Window  
                            "OpenGL",                           // Class Name  
                            title,                              // Window Title  
                            dwStyle |                           // Defined Window Style  
                            WS\_CLIPSIBLINGS |                  // Required Window Style  
                            WS\_CLIPCHILDREN,                   // Required Window Style  
                            0, 0,                               // Window Position  
                            WindowRect.right-WindowRect.left,   // Calculate Window Width  
                            WindowRect.bottom-WindowRect.top,   // Calculate Window Height  
                            NULL,                               // No Parent Window  
                            NULL,                               // No Menu  
                            hInstance,                          // Instance  
                            NULL)))                             // Dont Pass Anything To WM\_CREATE  
{  
    KillGLWindow();                             // Reset The Display  
    MessageBox(NULL,"Window Creation Error.","ERROR",MB\_OK|MB\_ICONEXCLAMATION);  
    return FALSE;                               // Return FALSE  
}

//像素格式明确了OpenGL绘制平面的特性,如象素缓冲区是单缓冲还是双缓冲,数据是 RGBA方式还是Color Index方式等。  
//每个OpenGL显示设备一般用名为PIXELFORMATDESCRIPTOR的结构来表示某个的像素格式  
static  PIXELFORMATDESCRIPTOR pfd=              // pfd Tells Windows How We Want Things To Be  
{  
    sizeof(PIXELFORMATDESCRIPTOR),              // Size Of This Pixel Format Descriptor  
    1,                                          // Version Number  
    PFD\_DRAW\_TO\_WINDOW |                     // Format Must Support Window  
    PFD\_SUPPORT\_OPENGL |                      // Format Must Support OpenGL  
    PFD\_DOUBLEBUFFER,                          // Must Support Double Buffering  
    PFD\_TYPE\_RGBA,                                // Request An RGBA Format  
    bits,                                       // Select Our 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,                                 // Accumulation Bits Ignored  
    16,                                         // 16Bit Z-Buffer (Depth Buffer)  
    0,                                          // No Stencil Buffer  
    0,                                          // No Auxiliary Buffer  
    PFD\_MAIN\_PLANE,                               // Main Drawing Layer  
    0,                                          // Reserved  
    0, 0, 0                                     // Layer Masks Ignored  
};

if (!(hDC=GetDC(hWnd)))                         // Did We Get A Device Context?  
{  
    KillGLWindow();                             // Reset The Display  
    MessageBox(NULL,"Can't Create A GL Device Context.","ERROR",MB\_OK|MB\_ICONEXCLAMATION);  
    return FALSE;                               // Return FALSE  
}

if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd))) // Did Windows Find A Matching Pixel Format?  
{  
    KillGLWindow();                             // Reset The Display  
    MessageBox(NULL,"Can't Find A Suitable PixelFormat.","ERROR",MB\_OK|MB\_ICONEXCLAMATION);  
    return FALSE;                               // Return FALSE  
}

if(!SetPixelFormat(hDC,PixelFormat,&pfd))       // Are We Able To Set The Pixel Format?  
{  
    KillGLWindow();                             // Reset The Display  
    MessageBox(NULL,"Can't Set The PixelFormat.","ERROR",MB\_OK|MB\_ICONEXCLAMATION);  
    return FALSE;                               // Return FALSE  
}

if (!(hRC=wglCreateContext(hDC)))               // Are We Able To Get A Rendering Context?  
{  
    KillGLWindow();                             // Reset The Display  
    MessageBox(NULL,"Can't Create A GL Rendering Context.","ERROR",MB\_OK|MB\_ICONEXCLAMATION);  
    return FALSE;                               // Return FALSE  
}

if(!wglMakeCurrent(hDC,hRC))                    // Try To Activate The Rendering Context  
{  
    KillGLWindow();                             // Reset The Display  
    MessageBox(NULL,"Can't Activate The GL Rendering Context.","ERROR",MB\_OK|MB\_ICONEXCLAMATION);  
    return FALSE;                               // Return FALSE  
}

ShowWindow(hWnd,SW\_SHOW);                      // Show The Window  
SetForegroundWindow(hWnd);                      // Slightly Higher Priority  
SetFocus(hWnd);                                 // Sets Keyboard Focus To The Window  
ReSizeGLScene(width, height);                   // Set Up Our Perspective GL Screen

if (!InitGL())                                  // Initialize Our Newly Created GL Window  
{  
    KillGLWindow();                             // Reset The Display  
    MessageBox(NULL,"Initialization Failed.","ERROR",MB\_OK|MB\_ICONEXCLAMATION);  
    return FALSE;                               // Return FALSE  
}

return TRUE;                                    // Success  

}

LRESULT CALLBACK WndProc( HWND hWnd, // Handle For This Window
UINT uMsg, // Message For This Window
WPARAM wParam, // Additional Message Information
LPARAM lParam) // Additional Message Information
{
switch (uMsg) // Check For Windows Messages
{
case WM_ACTIVATE: // Watch For Window Activate Message
{
if (!HIWORD(wParam)) // Check Minimization State
{
active=TRUE; // Program Is Active
}
else
{
active=FALSE; // Program Is No Longer Active
}

        return 0;                               // Return To The Message Loop  
    }

    case WM\_SYSCOMMAND:                            // Intercept System Commands  
    {  
        switch (wParam)                         // Check System Calls  
        {  
            case SC\_SCREENSAVE:                    // Screensaver Trying To Start?  
            case SC\_MONITORPOWER:              // Monitor Trying To Enter Powersave?  
            return 0;                           // Prevent From Happening  
        }  
        break;                                  // Exit  
    }

    case WM\_CLOSE:                             // Did We Receive A Close Message?  
    {  
        PostQuitMessage(0);                     // Send A Quit Message  
        return 0;                               // Jump Back  
    }

    case WM\_KEYDOWN:                           // Is A Key Being Held Down?  
    {  
        keys\[wParam\] = TRUE;                  // If So, Mark It As TRUE  
        return 0;                               // Jump Back  
    }

    case WM\_KEYUP:                             // Has A Key Been Released?  
    {  
        keys\[wParam\] = FALSE;                 // If So, Mark It As FALSE  
        return 0;                               // Jump Back  
    }

    case WM\_SIZE:                              // Resize The OpenGL Window  
    {  
        ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));  // LoWord=Width, HiWord=Height  
        return 0;                               // Jump Back  
    }  
}

// Pass All Unhandled Messages To DefWindowProc  
return DefWindowProc(hWnd,uMsg,wParam,lParam);  

}

int WINAPI WinMain( HINSTANCE hInstance, // Instance
HINSTANCE hPrevInstance, // Previous Instance
LPSTR lpCmdLine, // Command Line Parameters
int nCmdShow) // Window Show State
{
MSG msg; // Windows Message Structure
BOOL done = FALSE; // Bool Variable To Exit Loop

// Ask The User Which Screen Mode They Prefer  
if (MessageBox(NULL,"Would You Like To Run In Fullscreen Mode?", "Start FullScreen?",MB\_YESNO|MB\_ICONQUESTION)==IDNO)  
{  
    fullscreen = FALSE;                         // Windowed Mode  
}

// Create Our OpenGL Window  
if (!CreateGLWindow("NeHe's OpenGL Framework",640,480,16,fullscreen))  
{  
    return 0;                                   // Quit If Window Was Not Created  
}

while(!done)                                    // Loop That Runs While done=FALSE  
{  
    if (PeekMessage(&msg,NULL,0,0,PM\_REMOVE))  // Is There A Message Waiting?  
    {  
        if (msg.message==WM\_QUIT)              // Have We Received A Quit Message?  
        {  
            done=TRUE;                          // If So done=TRUE  
        }  
        else                                    // If Not, Deal With Window Messages  
        {  
            TranslateMessage(&msg);             // Translate The Message  
            DispatchMessage(&msg);              // Dispatch The Message  
        }  
    }  
    else                                        // If There Are No Messages  
    {  
        // Draw The Scene.  Watch For ESC Key And Quit Messages From DrawGLScene()  
        if (active)                             // Program Active?  
        {  
            if (keys\[VK\_ESCAPE\])             // Was ESC Pressed?  
            {  
                done=TRUE;                      // ESC Signalled A Quit  
            }  
            else                                // Not Time To Quit, Update Screen  
            {  
                DrawGLScene();                  // Draw The Scene  
                SwapBuffers(hDC);               // Swap Buffers (Double Buffering)  
            }  
        }

        if (keys\[VK\_F1\])                     // Is F1 Being Pressed?  
        {  
            keys\[VK\_F1\]=FALSE;                   // If So Make Key FALSE  
            KillGLWindow();                     // Kill Our Current Window  
            fullscreen=!fullscreen;             // Toggle Fullscreen / Windowed Mode  
            // Recreate Our OpenGL Window  
            if (!CreateGLWindow("NeHe's OpenGL Framework",640,480,16,fullscreen))  
            {  
                return 0;                       // Quit If Window Was Not Created  
            }  
        }  
    }  
}

// Shutdown  
KillGLWindow();                                 // Kill The Window  
return (msg.wParam);                            // Exit The Program  

}