在Win32中使用OpenGL

在Win32下使用OpenGL

http://blog.csdn.net/t_w_s/article/details/11021357
  
1.win32程序的框架是winMain+WndProc。winMain中创建窗口同时实现消息循环,WndProc中实现的是消

息的处理。

2.win32程序运行时的过程主要是1:创建窗口2:捕获窗口中的消息并处理

win32下要使用OpenGL的话,在创建窗口时,要增加此窗口对OpenGL的扩展的支持。那么在窗口创建的什

么时候增加此窗口对Opengl的扩展呢?

在窗口创建时,有WM_CREATE、WM_SIZE、WM_PAINT三个消息依次产生,那么我们可以在WM_CREATE中增加

此窗口对Opengl的支持的代码,同时对Opengl渲染环境进行初始化。然后在WM_SIZE中实现Opengl中的视

图变换。这样Opengl绘图操作的前置工作已经完成了,在WM_PAINT中就可以使用Opengl进行绘图了。

#include  
// #include  
// #include  
#include  
// #include  
// #include  
// #include  
  
//#pragma comment(lib,"glu32.lib")  
//pragma comment(lib,"glaux.lib")  
//pragma comment(lib,"opengl32.lib")  
  
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //窗口函数说明  
int APIENTRY WinMain(HINSTANCE hInstance, //WinMain函数说明  
    HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {  
        /* 
        建议采用Pascal的变量定义风格,即在程序(函数)开始处定义所有变量 
        虽然C++的变量定义比较灵活,本程序为了使程序易于理解,未采用这种方法 
        */  
        char lpszClassName[] = "窗口"; //窗口类名  
        char lpszTitle[] = "Win32窗口示例"; //窗口标题名  
        WNDCLASS wndclass;  
        wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; //窗口类型为缺省类型  
        wndclass.lpfnWndProc = WndProc; //窗口处理函数为WndProc  
        wndclass.cbClsExtra = 0; //窗口类无扩展  
        wndclass.cbWndExtra = 0; //窗口实例无扩展  
        wndclass.hInstance = hInstance; //当前实例句柄  
        wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); //使用缺省图标  
        wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); //窗口采用箭头光标  
        wndclass.hbrBackground = NULL; //窗口背景为白色  
        wndclass.lpszMenuName = NULL; //窗口中无菜单  
        wndclass.lpszClassName = lpszClassName; //窗口类名为'窗口实例'  
        if (!RegisterClass(&wndclass)) //注册窗口,若失败,则发出声音  
        {  
            MessageBeep(0);  
            return FALSE;  
        }  
        //创建窗口操作  
        HWND hwnd; //窗口结构  
        hwnd = CreateWindow(lpszClassName, //创建窗口,窗口类名  
            lpszTitle, //窗口实例的标题名  
            WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, //窗口的风格  
            CW_USEDEFAULT,  
            CW_USEDEFAULT, //窗口左上角坐标为缺省值  
            CW_USEDEFAULT,  
            CW_USEDEFAULT, //窗口的高度和宽度为缺省值  
            NULL, //此窗口无父窗口  
            NULL, //此窗口无主菜单  
            hInstance, //应用程序当前句柄  
            NULL); //不使用该值  
        ShowWindow(hwnd, nCmdShow); //显示窗口  
        UpdateWindow(hwnd); //绘制用户区  
        // int InitGL(GLvoid);  
        MSG msg; //消息结构  
        while (GetMessage(&msg, NULL, 0, 0)) //消息循环  
        {  
            TranslateMessage(&msg);  
            DispatchMessage(&msg);  
        }  
        return msg.wParam; //程序终止时,将信息返回操作系统  
}  
void SetupPixelFormat(HDC hDC) //为设备环境设置像素格式  
{  
    int nPixelFormat; //像素格式变量  
    static PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), //数据结构大小  
        1, //版本号,总设为1  
        PFD_DRAW_TO_WINDOW | //支持窗口  
        PFD_SUPPORT_OPENGL | //支持OpenGL  
        PFD_DOUBLEBUFFER, //支持双缓存  
        PFD_TYPE_RGBA, //RGBA颜色模式  
        32, //32位颜色模式  
        0, 0, 0, 0, 0, 0, //忽略颜色为,不使用  
        0, //无alpha缓存  
        0, //忽略偏移位  
        0, //无累积缓存  
        0, 0, 0, 0, //忽略累积位  
        16, //16位z-buffer(z缓存)大小  
        0, //无模板缓存  
        0, //无辅助缓存  
        PFD_MAIN_PLANE, //主绘制平面  
        0, //保留的数据项  
        0, 0, 0 }; //忽略层面掩模  
    //选择最匹配的像素格式,返回索引值  
    nPixelFormat = ChoosePixelFormat(hDC, &pfd);  
    //设置环境设备的像素格式  
    SetPixelFormat(hDC, nPixelFormat, &pfd);  
}  
int InitGL(GLvoid)                           // 此处开始对OpenGL进行所有设置  
{  
    glShadeModel(GL_SMOOTH);                 // 启用阴影平滑  
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);    // 黑色背景  
    glClearDepth(1.0f);                      // 设置深度缓存  
    glEnable(GL_DEPTH_TEST);                 // 启用深度测试  
    glDepthFunc(GL_LEQUAL);                  // 所作深度测试的类型  
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);// 告诉系统对透视进行修正  
    return TRUE;                             // 初始化 OK  
}  
void ChangeSize(int width, int height)  
{  
    glViewport(0, 0, width, height);         // 重置当前的视口glMatrixMode(GL_PROJECTION);  
    glMatrixMode(GL_PROJECTION);             // 选择投影矩阵  
    glLoadIdentity();                        // 重置投影矩阵  
    // 设置投影模式为透视投影  
    gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);  
    glMatrixMode(GL_MODELVIEW);  
    glLoadIdentity();  
}  
void RenderScene()  
{  
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); //清屏和清除深度缓冲区  
    glLoadIdentity();        // 重置当前的模型观察矩阵  
    glTranslatef(-1.5f,0.0f,-26.0f);       // 左移 1.5 单位,并移入屏幕 6.0  
    glBegin(GL_TRIANGLES);        // 绘制三角形  
    glVertex3f( 0.0f, 1.0f, 0.0f);      // 上顶点  
    glVertex3f(-1.0f,-1.0f, 0.0f);      // 左下  
    glVertex3f( 1.0f,-1.0f, 0.0f);      // 右下  
    glEnd();         // 三角形绘制结束  
    glTranslatef(3.0f,0.0f,0.0f);       // 右移3单位  
    glRotatef(45,1,1,0);  
    glutWireCube(2);  
    //此处添加绘图命令  
    //glutSwapBuffers();  
    // glFlush();  
}  
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {  
    static HGLRC hRC; //绘制环境  
    static HDC hDC; //设备环境  
  
    switch (message) {  
    case WM_CREATE: {  
        hDC = GetDC(hwnd); //得到当前窗口的设备环境  
        SetupPixelFormat(hDC); //调用像素格式设置函数  
        hRC = wglCreateContext(hDC); //创建OpenGL绘图环境并创建一个指向OpenGL绘制环境的句柄  
        wglMakeCurrent(hDC, hRC); //将传递过来的绘制环境设置为OpenGL将要进行绘制的当前绘制
环境  
//      SetTimer(hwnd, 33, 1, NULL);  
        InitGL();  
        return 0;  
                    }  
                    break;  
    case WM_DESTROY:  
        {  
//          KillTimer(hwnd, 101);  
            wglMakeCurrent(hDC, NULL);  
            wglDeleteContext(hRC);  
            PostQuitMessage(0); //调用该函数发出WM_QUIT消息  
        }  
        break;  
    case WM_SIZE:  
        {  
            //ChangeSize(LOWORD(lParam), HIWORD(lParam));  
            ChangeSize(LOWORD(lParam),HIWORD(lParam));  
        }  
        break;  
//  case WM_TIMER:  
//      {  
//          //IdleFunction();  
//          InvalidateRect(hwnd, NULL, FALSE);  
//      }  
//      break;  
    case WM_PAINT:  
        {  
            RenderScene();  
            SwapBuffers(hDC);  
            ValidateRect(hwnd, NULL);  
        }  
        break;  
        // case  
    default: //缺省消息处理函数  
        return DefWindowProc(hwnd, message, wParam, lParam);  
    }  
    return 0;
========

Win32 OpenGL 编程(1)Win32下的OpenGL编程必须步骤

http://blog.csdn.net/vagrxie/article/details/4602961
http://www.jtianling.com


一、    前言
 OpenGL 编程的红宝书《 OpenGL Programming Guide 》在举例子的时候

为了平台无关,使用的都是 GLUT 来管理窗口,个人感觉不爽 -_-! 要是针对 Windows 平台,个人倾向

使用 Win32(MFC 也行 ) ,要是跨平台,我还会 Qt 嘛, Qt 对 OpenGL 也有很好的支持的,为啥还折

腾个新的窗口管理组件?虽然说 GLUT 比较简单,但是还是不喜欢扭曲的适应之,何况我去看了下 GLUT 

这个东西,最新的版本都是 2001 年发布的了,什么古董级的家伙啊,更加不想用了,还是在 Windows 

平台上学习 OpenGL 吧。刚开始这样想的就这样做了,结果比我想象的稍微复杂一些,原来不光是熟悉 

Win32 API 就能随便搞掂的,当时还看到有人专门为此写了篇论文 -_-!( 不知道学历 ) 吓到我了,没

有那么高的学术研究价值吧?后来又看到 3 个研究生都开始为此写论文了


二、    提要
本文主要介绍 Win32 下的 OpenGL 编程需要的一些操作,以 Andre LaMothe 的 T3D Game Console 为 

Win32 框架实现一个 Win32 下的 OpenGL 游戏编程框架, 以参考资料 2 为蓝本,实现一些 OpenGL 示

例。以后的讲解围绕此框架展开。本文假设读者已经具备基本的 Win32 编程知识,不讲解 Win32 编程

中固有的要素,需要了解 Win32 编程的,建议学习 Charles Petzold 的《 Programming Windows 》。

三、    Win32 下 OpenGL 编程需要的操作步骤
全部源代码见我的放在 Google Code 上的 blog-sample-code 中 2009-9-27/Win32OpenGLTemplate 目

录。取回方式见本文最后的说明。

下面会用到的全局变量:

// GLOBALS ////////////////////////////////////////////////
HWND       ghWnd ; // 窗口句柄
HINSTANCE ghInstance ; // 程序实例句柄
HDC ghDC ;                             // GDI 设备环境句柄
HGLRC ghRC ;           // 渲染环境句柄

1.       头文件

#include

// OpenGL 需要的头文件
#include
#include

需要注意的就是,必须先包含 Windows.h ,然后才能包含 gl.h 和 glu.h 。因为 gl.h 与 glu.h 中可

能包含 Windows.h 中定义的宏。

2.       链接库

此步完全可以通过功能配置来完成,需要包含的库 为 opengl32.lib 何 glu32.lib ,事实上,为了方

便,可以通过如下语句来完成( VC++ 特有特性),但是我们讨论的是 Win32 下的 OpenGL ,这样也能

接受了。

// 定义程序链接时所需要调用的OpenGL 程序库, 简化工程配置
#pragma comment ( lib , "opengl32.lib" )
#pragma comment ( lib , "glu32.lib" ) 

3.       像素格式 (Pixel Format) 设置

需要用到的函数的原型:

int ChoosePixelFormat(
  
HDC 
 
hdc
,  
// device context to search for a best pixel format 
             
// match
  
CONST PIXELFORMATDESCRIPTOR * 
 
ppfd
          
// pixel format for which a best match is sought


);

BOOL SetPixelFormat(
  
HDC 
 
hdc
,  
// device context whose pixel format the function 
             
// attempts to set
  
int 
 
iPixelFormat
,
             
// pixel format index (one-based)
  
CONST PIXELFORMATDESCRIPTOR * 
 
ppfd
             
// pointer to logical pixel format specification

);

这是 Win32 下的 OpenGL 编程必做的事情之一,为 DC 设置像素的格式。

// 设置像素格式
       PIXELFORMATDESCRIPTOR pfd ;
       int iFormat ;
 
       ghDC = GetDC ( ghWnd );
 
       ZeroMemory ( & pfd , sizeof ( pfd ) );
       pfd . nSize = sizeof ( pfd ); 
       pfd . nVersion = 1;      // 版本,一般设为
       pfd . dwFlags =   PFD_DRAW_TO_WINDOW | // 一组表明象素缓冲特性的标志位
              PFD_SUPPORT_OPENGL ;
       pfd . iPixelType = PFD_TYPE_RGBA ;   // 明象素数据类型是RGBA 还是颜色索引;
       pfd . cColorBits = 32;     // 每个颜色缓冲区中颜色位平面的数目,对颜色索引方式是缓冲

区大小
       pfd . iLayerType = PFD_MAIN_PLANE ; // 被忽略,为了一致性而包含的
 
       iFormat = ChoosePixelFormat ( ghDC , & pfd ); // 选择一个像素格式
 
       SetPixelFormat ( ghDC , iFormat , & pfd ); // 设置到DC 中
 
这样的函数完成了像素格式的设置,事实上还可以进行更多的操作,比如设置缓冲区等,下面的代码就


是一个设置双重缓冲区的代码。

PIXELFORMATDESCRIPTOR pfd;
ZeroMemory( &pfd, sizeof( pfd ) );
pfd.nSize = sizeof( pfd );
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL |
              PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 32;
pfd.iLayerType = PFD_MAIN_PLANE;
int iFormat = ChoosePixelFormat( hDC, &pfd );
SetPixelFormat( hDC, iFormat, &pfd );
 
具体的每个参数的意义,最好还是去查查 MSDN 啦,查看 PIXELFORMATDESCRIPTOR 结构的解释就行。
 
4.       渲染器环境 (Render Context) 创建

调用 wglCreateContext 与 wglMakeCurrent 函数 ,这两个函数都是 Windows 下为了兼容 OpenGL 而

特别提供的接口,以 wgl 开头。

函数原型:

HGLRC wglCreateContext(

  

HDC 

 
hdc
  
// device context of device that the rendering context 
             
// will be suitable for

);


BOOL wglMakeCurrent( 
HDC 
 
hdc



// device context of device that OpenGL calls are 
                 
// to be drawn on
  
HGLRC 
 
hglrc
   
// OpenGL rendering context to be made the calling 
               
// thread's current rendering context


);


调用方式如下:

       ghRC = wglCreateContext ( ghDC );    // 创建渲染环境
       wglMakeCurrent ( ghDC , ghRC );     // 使之成为当前渲染环境
 
5.       实际绘制

这个部分就与一般的 OpenGL 一致,在后面慢慢展开讲述。

6.       释放资源

首先取消当前的渲染环境选中,然后依次删除渲染环境与设备环境。

需要调用的函数原型:

BOOL wglDeleteContext(
  
HGLRC 
 
hglrc

// handle to the OpenGL rendering context to delete

);


// 取消OpenGL ,在程序结束前调用,释放渲染环境,设备环境以及最终窗口句柄。
void DisableOpenGL ()
{
       wglMakeCurrent ( NULL , NULL );
       wglDeleteContext ( ghRC );
       ReleaseDC ( ghWnd , ghDC );
}
 
上述流程基本就是一个完整的 Win32 OpenGL 程序所需要的了。。。。。。实际上在参考 5 中,有较为


详细的论述,但是事实上,你也可以作为论文发表,见参考 3.


四、    真正的 OpenGL 相关内容
1.       静态图形显示演示:一个矩形


见参考 2 中(即所谓的 OpenGL 红宝书 The Red Book )中的例子

基本流程分两部分,初始化和实际绘制:

//OpenGL 初始化开始
void SceneInit ( int w , int h )
{
       glClearColor (0.0f, 0.0f, 0.0f, 0.0f);      // 黑色背景
 
       glMatrixMode ( GL_PROJECTION );
       glLoadIdentity ();
       glOrtho (0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
}
 
  // 这里进行所有的绘图工作
void SceneShow ( GLvoid )       
{
       glClear ( GL_COLOR_BUFFER_BIT );
 
       glColor3f (1.0, 1.0, 1.0);
       glBegin ( GL_POLYGON );
       glVertex3f (0.25, 0.25, 0.0);
       glVertex3f (0.75, 0.25, 0.0);
       glVertex3f (0.75, 0.75, 0.0);
       glVertex3f (0.25, 0.75, 0.0);
       glEnd ();
       glFlush ();
}


显示效果非常简陋,就是黑色背景窗口中一个白色的矩形。 OpenGLGL 的每个函数意义不在此文中描述


,本文的主要目的是讲述 win32 中 OpenGL 编程需要的操作。




然后就是将所有的部分串起来了,上述都是代码的片段。 全部源代码见我的放在 Google Code 上的 


blog-sample-code 中 2009-9-27/Win32OpenGLTemplate 目录。取回方式见本文最后的说明。


2.       动画演示:一个旋转的矩形


因为整体的框架使用了 Andre LaMothe 的 T3D Game Console ,所以显示动画非常简单。只不过需要注


意的是,这里为了显示效果更好利用了双缓冲,那么上面的设置像素格式一步需要用第二种设置方式。


全部的改动如下:


// 激活创建OpenGL 窗口
void EnableOpenGL ()
{
       PIXELFORMATDESCRIPTOR pfd ;
       int iFormat ;
 
       ghDC = GetDC ( ghWnd );
 
       ZeroMemory ( & pfd , sizeof ( pfd ) );
       pfd . nSize = sizeof ( pfd ); 
       pfd . nVersion = 1;      // 版本,一般设为
 
       // 一组表明象素缓冲特性的标志位
       pfd . dwFlags =   PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER ;
       pfd . iPixelType = PFD_TYPE_RGBA ;   // 明象素数据类型是RGBA 还是颜色索引;
       pfd . cColorBits = 32;     // 每个颜色缓冲区中颜色位平面的数目,对颜色索引方式是缓冲


区大小
       pfd . cDepthBits = 16;
       pfd . iLayerType = PFD_MAIN_PLANE ; // 被忽略,为了一致性而包含的
 
       iFormat = ChoosePixelFormat ( ghDC , & pfd ); // 选择一个像素格式
 
       SetPixelFormat ( ghDC , iFormat , & pfd ); // 设置到DC 中
 
       ghRC = wglCreateContext ( ghDC );    // 创建绘图描述表
       wglMakeCurrent ( ghDC , ghRC );     // 使之成为当前绘图描述表
}
 
//OpenGL 初始化开始
void SceneInit ( int w , int h )
{
       glClearColor (0.0f, 0.0f, 0.0f, 0.0f);      // 黑色背景
       glColor3f (1.0f, 1.0f, 1.0f);
 
       glShadeModel ( GL_FLAT );
       glMatrixMode ( GL_PROJECTION );
       glLoadIdentity ();
       glOrtho (-50.0f, 50.0f, -50.0f, 50.0f, -1.0f, 1.0f);
}
 
  // 这里进行所有的绘图工作
void SceneShow ( GLvoid )       
{
       // 旋转角度
       static float fSpin = 0.0f;
       fSpin += 2.0f;
       if ( fSpin > 360.0f)
       {
              fSpin -= 360.0f;
       }
 
       glClear ( GL_COLOR_BUFFER_BIT );
 
       glPushMatrix ();
       // 旋转矩形的主要函数
       glRotatef ( fSpin , 0.0f, 0.0f, 1.0f);
       glRectf (-25.0, -25.0, 25.0, 25.0);
       glPopMatrix ();
 
       // 交换缓冲区
       SwapBuffers ( ghDC );



全部源代码见我的放在 Google Code 上的 blog-sample-code 中 2009-9-28/RotateRect / 目录。取回


方式见本文最后的说明。


五、    参考资料
1.      《 OpenGL Reference Manual 》, OpenGL 参考手册


2.      《 OpenGL 编程指南》(《 OpenGL Programming Guide 》), Dave Shreiner , Mason Woo 


, Jackie Neider , Tom Davis 著,徐波译,机械工业出版社


3.      《 Win32 环境下的 OpenGL 编程 》,郑竞华,《现代电子技术》,空军雷达学院


4.      《 Win32 下使用 OpenGL 》


5.      《 OpenGL Win32 Tutorial 》,(讲解比较透彻)


6.      MSDN ,让人惊讶的是 MSDN 中有比较完整的 OpenGL 参考资料,并且还有很多是讲 X Window 


的 OpenGL 的 -_-!


六、    最后说明
本文中所有代码(如果有的话)都能用 Mercurial 在 Google Code 中下载。


文章以博文发表的日期分目录存放,下载地址为:


http://code.google.com/p/jtianling/source/checkout?repo=blog-sample-code


Mercurial 使用方法见《 分布式的,新一代版本控制系统 Mercurial的介绍及简要入门 》


========

原生 Win32 API 实现 OpenGL 教程(第一部分)

http://www.oschina.net/translate/native-win-api-opengl-tutorial-part
 
下载带exe源代码


简介


Code Project论坛上的一些用户问题让我意识到:互联网上的大多数OpenGL教程已经过时了。许多还在


参考旧的NeHe教程,自从Jeff Molofee转向GameDev之后,这个教程就再也没有更新了。


从那时到现在,已经发布了Visual Studio 2013和2015,还有Windows 7, 8 和Windows10。 所以,是


时候创建一些符合新变化的基础教程了。


我们的目标很简单 - 在OpenGL窗口中生成标准立方体旋转位图。


从Windows 98开始,所有的Windows版本都自带OpenGL,所以你无需另外安装。Windows 7,8和10自带


OpenGL 3.3.0,但是有些显卡制造商可能在他们的驱动中集成高版本的OpenGL,例如OpenGL 4.5。所以


你可以认为在当前的Windows机器中,至少会带有OpenGL 3.3。


试图使用NeHe教程的人遇到的第一个问题可能是GLAUX库已经废弃,Visual Studio中不再包含,Windows


中也没有相应的DLL。废弃的原因是其功能可以使用标准Win32 API调用替换。在本系列文章中,我们会


使用Win32 API调用。我看了所有的关于下载GLAUX头文件和编译成DLL的评论,我们将会避免这种没有前


途的做法。


我尝试使用保持简单直白的原则( Keep It Simple Stupid (KISS) ),这部分代码不是对象(Objects


)的或者框架化(Frameworks)的。不是因为我不相信这些东西,而是我们尽量让代码简单,并让它有


最广泛的用户。


代码使用标准的 接口,因此它能被 Ansi,Unicode 和宽字符模式编译。我们讨论过不保持 


KISS 原则,但这样就会限制编译模式,特别是非英语国家。因为这涉及到“char”类型与“TCHAR”的


交换,一个很小的_T语句在字符串附近,我觉得它对于理解来说是有目共睹的。




开始写代码


首先,让我们在OpenGL窗口系统中编写伪代码,我们通常是如下编写:


初始化OpenGL(调用一次)


测量OpenGL视窗(首次调用)




重复
绘制场景


把场景迁移到屏幕上


       直到视窗关闭


注意事项:如果视窗大小改变,那么测量的进程也会被调用


这个方式的原因是因为它会使得包括OpenGL部分灵活迁移到像MFC、WPF等框架上。另一个我所持的观点


是把OpenGL数据输入到一个简单的结构上作为一个属性附加到视窗本身上。在这个教程中,人们想知道


为什么只是简单的使用正常的全局变量,原因显而易见,在第二节课我们会使用多个OpenGL视窗和更多


先进的多视窗。


这是我们第一次课程要使用到的OpenGLData数据结构。这里描述的代码片段在以后的课程中也会用到,


而其他一些数据会根据需要而增减。在第一次课程中,我们会加载一张bitmap格式的图片作为纹理(结


构中的glTexture),我会把纹理绘制在立方体的表面并旋转立方体(旋转使用了结构中的xrot, yrot)





typedef struct OpenGLData {
    HGLRC Rc;                                   // 绘制的句柄 **(总是需要)
    GLuint glTexture;                           // 要绘制的纹理
    GLfloat    xrot;                            // X旋转
    GLfloat    yrot;                            // Y旋转
} GLDATABASE;
代码片段如上。


那些基础的数据结构通过SetProp API函数被附加到了窗口的句柄上,被定义为了一个string类型的静态


变量。当我们需要获取这个数据结构(OpenGLData)时,可以随时通过调用GetProp来获取。


在这个教程中我们使用的标签的值是:


static const TCHAR* DATABASE_PROPERTY = _T("OurDataStructure");
我们采用下面的代码来创建数据结构并把数据结构附加到窗口的句柄上:


GLDATABASE* db = (GLDATABASE*) malloc(sizeof(GLDATABASE)); // 分配结构内存
db->Rc = InitGL(Wnd);                                      // 初始化OpenGL保存着色环境
db->glTexture = 0;                                         // 纹理置零
db->xrot = 0.0f;                                           // 置零x旋转
db->yrot = 0.0f;                                           // 置零y旋转
SetProp(Wnd, DATABASE_PROPERTY, (HANDLE) db);              // 保存数据结构到窗口变量当中


任何我们想要获取数据的时候,我们可以创建一个像这样的简单的调用:


GLDATABASE* db = (GLDATABASE*) GetProp(Wnd, DATABASE_PROPERTY); //获取数据结构
这句代码表明,我们将会得到一个标准窗口应用的框架。既然应用窗口已经产生,WM_CREATE会被启用来


初始化OpenGL系统。返回的Render内容会被保留在我们的数据结构中。ReSizeGLScene会直接在调用


Render之后,用它来设置OpenGL系统的初始大小为创建的窗口大小。


窗口已经运行好了,我们接下来要做的就是解决窗口的WM_PAINT消息问题,代码看起来会像这样:


case WM_PAINT: {                                                   // WM_PAINT消息
   PAINTSTRUCT Ps;
   GLDATABASE* db = (GLDATABASE*) GetProp(Wnd, DATABASE_PROPERTY); // 获取数据库
   BeginPaint(Wnd, &Ps);                                           // 开始绘制
   DrawGLScene(db, Ps.hdc);                                        // 绘制OpenGL场景
   SwapBuffers(Ps.hdc);                                            // 交换缓冲区
   EndPaint(Wnd, &Ps);                                             // 结束绘制
   return 0;
}
这段代码开始于普通的BeginPaint调用,但是接下来招呼OpenGL把它的场景绘制给render内容,在返回


了之后,我们交换render的内容给PaintStructure设备,它可以给我们的窗口绘制OpenGL场景。接着,


我们清理并退出。


诀窍是渲染过程不是持续运行的,它仅仅发生在 WM_PAINT 消息提供时,因此你希望这些东西动起来,


你就需要在更改之后提供 WM_PAINT 消息。当我们启动定时器,更改旋转率,然后窗口还是无效,这时


需要创建一个 WM_PAINT 消息让窗口重绘。


这个过程是很棒的东西,像构建一个 3D 对象编辑器,除了在快速移动的游戏中不是很好,在这种场景


中需要快速不断渲染场景。在后面的课程中,我们将会处理这一过程并使用线程。


现在,运行程序并点击File菜单,选择load a bitmap并继续,你将会看到如下所示:


启动一个定时器,你的立方体应该开始旋转了,OpenGL在一个标准应用窗口中运行,这正是你想看到的


。我们第一个OpenGL教程就这样完成了。


在我们接下来的教程中,我们将会在一个MDI应用中展开更多内容。
========

在Win32环境中搭建OpenGL应用程序框架  



http://blog.163.com/lishman@126/blog/static/40377624200911493595/
Win32环境中搭建OpenGL应用程序框架


一、  安装OpenGL 开发包


在OpenGL开发包中含有如下文件
  
1


头文件


gl.h glu.h glaux.h glut.h


2


lib库文件


glut.lib glut32.dll


3


dll库文件


glut.dll glut32.dll


1.将头文件拷贝至Vc7\PlatformSDK\Include\GL\ 或者VC98\include\GL目录下


2.将库文件拷贝至Vc7\PlatformSDK\Lib\ 或者VC98\lib\ 目录下


3.将dll库文件持贝至 windows\system32\ 目录下


二、  配置项目中的OpenGL


在项目设置条目中,选择Link选项, VC 6.0中模块库中添加opengl32.lib Glut32.lib Glaux.lib 


glu32.lib;VC 2003 中Link中的高级命令行中添加上面四个静态库。


三、  其体代码如下


#include


#include


#include


#define WIDTH           400


#define HEIGHT          400 


CHAR szAppName[]="Win OpenGL";


HWND  ghWnd;


HDC   ghDC;


HGLRC ghRC;


BOOL bSetupPixelFormat(HDC);


GLvoid drawScene(GLvoid);


       LONG WINAPI MainWndProc (HWND, UINT, WPARAM, LPARAM);


int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,\


 LPSTR lpCmdLine, int nCmdShow)


{


     MSG        msg;


     WNDCLASS   wndclass;


     {


         wndclass.style         = 0;


         wndclass.lpfnWndProc   = (WNDPROC)MainWndProc;


         wndclass.cbClsExtra    = 0;


         wndclass.cbWndExtra    = 0;


         wndclass.hInstance     = hInstance;


         wndclass.hIcon         = LoadIcon (hInstance, szAppName);


         wndclass.hCursor       = LoadCursor (NULL,IDC_ARROW);


         wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);


         wndclass.lpszMenuName  = szAppName;


         wndclass.lpszClassName = szAppName;


 


         if (!RegisterClass (&wndclass) )


              return FALSE;


     }


 
ghWnd = CreateWindow (szAppName, "Generic OpenGL Sample", \


WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, CW_USEDEFAULT, \


              CW_USEDEFAULT,     WIDTH,   HEIGHT, NULL, NULL, hInstance, NULL);


 


     if (!ghWnd)   return FALSE;


     ShowWindow (ghWnd, nCmdShow);


     UpdateWindow (ghWnd);


 
          while (TRUE) {    


              while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) == TRUE)


              {


                   if (GetMessage(&msg, NULL, 0, 0) )


                   {


                        TranslateMessage(&msg);


                        DispatchMessage(&msg);


                   } else


                        return TRUE;


              }


          }   


}




LONG WINAPI MainWndProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)


{


  LONG    lRet = 1;


  PAINTSTRUCT    ps;


  RECT rect;


 


  switch (uMsg)


  { 


  case WM_CREATE:


       ghDC = GetDC(hWnd);


       if (!bSetupPixelFormat(ghDC))


            PostQuitMessage (0);


 


       ghRC = wglCreateContext(ghDC);


       wglMakeCurrent(ghDC, ghRC);


       GetClientRect(hWnd, &rect);


       break;


 


  case WM_PAINT:


       BeginPaint(hWnd, &ps);


EndPaint(hWnd, &ps);


       drawScene();


          break;


 


  case WM_SIZE:         


       drawScene();


       break;


 


  case WM_CLOSE:


       if (ghRC)


            wglDeleteContext(ghRC);


       if (ghDC)


            ReleaseDC(hWnd, ghDC);


       ghRC = 0;


       ghDC = 0;


       DestroyWindow (hWnd);


       break;


 


  case WM_DESTROY:


       if (ghRC)


            wglDeleteContext(ghRC);


       if (ghDC)


            ReleaseDC(hWnd, ghDC);


 


       PostQuitMessage (0);


       break;


 


  default:


       lRet = DefWindowProc (hWnd, uMsg, wParam, lParam);


       break;


  }


 


  return lRet;


}


 


BOOL bSetupPixelFormat(HDC hdc)


{


  PIXELFORMATDESCRIPTOR pfd, *ppfd;


  int pixelformat;


 


  ppfd = &pfd;


 


  ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);


  ppfd->nVersion = 1;


  ppfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER ;


  ppfd->dwLayerMask = PFD_MAIN_PLANE;


  ppfd->iPixelType = PFD_TYPE_RGBA;


  ppfd->cColorBits = 8;


  ppfd->cDepthBits = 32;


  ppfd->cAccumBits = 0;


  ppfd->cStencilBits = 0;


  pixelformat = ChoosePixelFormat(hdc, ppfd);


 


  if ( (pixelformat = ChoosePixelFormat(hdc, ppfd)) == 0 )
  {


       MessageBox(NULL, "ChoosePixelFormat failed", "Error", MB_OK);


       return FALSE;
  }


 


  if (SetPixelFormat(hdc, pixelformat, ppfd) == FALSE)
  {


       MessageBox(NULL, "SetPixelFormat failed", "Error", MB_OK);


       return FALSE;
  }


 


  return TRUE;


}




GLvoid drawScene(GLvoid)
{


  glClearColor(0, 1.0, 0, 0);


  glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);


  glBegin(GL_TRIANGLES);


       glColor3f(1.0, 0.0, 0.0);


       glVertex3f(100,    100, 0);


       glColor3f(0.0, 1.0, 0.0);


       glVertex3f(25, 100, 0);


       glColor3f(0.0, 0.0, 1.0);


       glVertex3f(0, 0, 0);


  glEnd();


  glFinish();
}


========

你可能感兴趣的:(VC++,图形学和3D)