第一篇笔记中的OpenGL框架其实很简单,大致有如下几个步骤:<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
1,取得窗口的实例,然后定义窗口类
2,注册窗口类
3,创建窗口
4,描述像素格式
5,获取设备描述表
6,找到与此前我们选定的象素格式相对应的象素格式
7,设置象素格式
8,取得绘制描述表
9,激活绘制描述表
10,显示窗口
11,将屏幕的宽度和高度设置给透视OpenGL屏幕(设置视口,进行投影,模型透视)
其他就是对窗口事件的处理了,尤其是重画事件(WM_PAINT等),但只是画了一个空窗口,现在加一些代码来画简单的基本图元。:
OpenGL框架完整代码
<!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>-->
#include<windows.h>
#include<GL/gl.h>
#include<GL/glu.h>
#include<GL/glaux.h>

HINSTANCEhInstance;//当前程序实例
HDChDC=NULL;//设备环境
HGLRChRC=NULL;//绘制环境
HWNDhWnd=NULL;//窗口句柄

boolkeys[256];
boolactive=TRUE;

LRESULTCALLBACKWndProc(HWND,UINT,WPARAM,LPARAM);


GLvoidReSizeGLScene(GLsizeiwidth,GLsizeiheight)//ResizeAndInitializeTheGLWindow


{
if(height==0)//PreventADivideByZeroBy


{
height=1;//MakingHeightEqualOne
}

glViewport(0,0,width,height);//ResetTheCurrentViewport

glMatrixMode(GL_PROJECTION);//SelectTheProjectionMatrix
glLoadIdentity();//ResetTheProjectionMatrix

//CalculateTheAspectRatioOfTheWindow
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);

glMatrixMode(GL_MODELVIEW);//SelectTheModelviewMatrix
glLoadIdentity();//ResetTheModelviewMatrix
}


intInitGL(GLvoid)//AllSetupForOpenGLGoesHere


{
glShadeModel(GL_SMOOTH);//EnableSmoothShading
glClearColor(0.3f,0.0f,0.5f,0.5f);//BlackBackground
glClearDepth(1.0f);//DepthBufferSetup
glEnable(GL_DEPTH_TEST);//EnablesDepthTesting
glDepthFunc(GL_LEQUAL);//TheTypeOfDepthTestingToDo
glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);//ReallyNicePerspectiveCalculations
returnTRUE;//InitializationWentOK
}

intDrawGLScene(GLvoid)//Here'sWhereWeDoAllTheDrawing


{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);//ClearScreenAndDepthBuffer
glLoadIdentity();

glTranslatef(-1.5f,0.0f,-6.0f);//MoveLeft1.5UnitsAndIntoTheScreen6.0
glBegin(GL_TRIANGLES);//DrawingUsingTriangles
glVertex3f(0.0f,1.0f,0.0f);//Top
glVertex3f(-1.0f,-1.0f,0.0f);//BottomLeft
glVertex3f(1.0f,-1.0f,0.0f);//BottomRight

glEnd();//FinishedDrawingTheTriangle
glTranslatef(3.0f,0.0f,0.0f);//MoveRight3Units
glBegin(GL_QUADS);//DrawAQuad
glVertex3f(-1.0f,1.0f,0.0f);//TopLeft
glVertex3f(1.0f,1.0f,0.0f);//TopRight
glVertex3f(1.0f,-1.0f,0.0f);//BottomRight
glVertex3f(-1.0f,-1.0f,0.0f);//BottomLeft
glEnd();//DoneDrawingTheQuad//ResetTheCurrentModelviewMatrix
returnTRUE;//EverythingWentOK
}


GLvoidKillGLWindow(GLvoid)//ProperlyKillTheWindow


{
if(hRC)//DoWeHaveARenderingContext?


{
if(!wglMakeCurrent(NULL,NULL))//AreWeAbleToReleaseTheDCAndRCContexts?


{
MessageBox(NULL,"ReleaseOfDCAndRCFailed.","SHUTDOWNERROR",MB_OK|MB_ICONINFORMATION);
}

if(!wglDeleteContext(hRC))//AreWeAbleToDeleteTheRC?


{
MessageBox(NULL,"ReleaseRenderingContextFailed.","SHUTDOWNERROR",MB_OK|MB_ICONINFORMATION);
}
hRC=NULL;//SetRCToNULL
}

if(hDC&&!ReleaseDC(hWnd,hDC))//AreWeAbleToReleaseTheDC


{
MessageBox(NULL,"ReleaseDeviceContextFailed.","SHUTDOWNERROR",MB_OK|MB_ICONINFORMATION);
hDC=NULL;//SetDCToNULL
}

if(hWnd&&!DestroyWindow(hWnd))//AreWeAbleToDestroyTheWindow?


{
MessageBox(NULL,"CouldNotReleasehWnd.","SHUTDOWNERROR",MB_OK|MB_ICONINFORMATION);
hWnd=NULL;//SethWndToNULL
}

if(!UnregisterClass("OpenGL",hInstance))//AreWeAbleToUnregisterClass


{
MessageBox(NULL,"CouldNotUnregisterClass.","SHUTDOWNERROR",MB_OK|MB_ICONINFORMATION);
hInstance=NULL;//SethInstanceToNULL
}
}

BOOLCreateGLWindow(char*title,intwidth,intheight,intbits)


{/**//*title:窗口标题;width:窗口宽度;height:窗口高度;bits:每象素所选的色彩深度*/
GLuintPixelFormat;
WNDCLASSwc;
DWORDdwExStyle;
DWORDdwStyle;
RECTWindowRect;
WindowRect.left=(long)0;
WindowRect.right=(long)width;
WindowRect.top=(long)0;
WindowRect.bottom=(long)height;

hInstance=GetModuleHandle(NULL);
wc.style=CS_HREDRAW|CS_VREDRAW|CS_OWNDC;
wc.lpfnWndProc=(WNDPROC)WndProc;
wc.cbClsExtra=0;
wc.cbWndExtra=0;
wc.hInstance=hInstance;
wc.hIcon=LoadIcon(NULL,IDI_WINLOGO);
wc.hCursor=LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground=NULL;
wc.lpszMenuName=NULL;
wc.lpszClassName="OpenGL";

if(!RegisterClass(&wc))


{
MessageBox(NULL,"无法注册窗口类!!!","ERROR",MB_OK|MB_ICONEXCLAMATION);
returnFALSE;
}

dwExStyle=WS_EX_APPWINDOW|WS_EX_WINDOWEDGE;
dwStyle=WS_OVERLAPPEDWINDOW;

AdjustWindowRectEx(&WindowRect,dwExStyle,FALSE,dwStyle);

if(!(hWnd=CreateWindowEx(dwExStyle,//ExtendedStyleForTheWindow
"OpenGL",//ClassName
title,//WindowTitle
dwStyle|//DefinedWindowStyle
WS_CLIPSIBLINGS|//RequiredWindowStyle
WS_CLIPCHILDREN,//RequiredWindowStyle
0,0,//WindowPosition
WindowRect.right-WindowRect.left,//CalculateWindowWidth
WindowRect.bottom-WindowRect.top,//CalculateWindowHeight
NULL,//NoParentWindow
NULL,//NoMenu
hInstance,//Instance
NULL)))//DontPassAnythingToWM_CREATE


{
MessageBox(NULL,"创建窗口失败","ERROR",MB_OK|MB_ICONEXCLAMATION);
returnFALSE;
}


staticPIXELFORMATDESCRIPTORpfd=//pfdTellsWindowsHowWeWantThingsToBe


{
sizeof(PIXELFORMATDESCRIPTOR),//SizeOfThisPixelFormatDescriptor
1,//VersionNumber
PFD_DRAW_TO_WINDOW|//FormatMustSupportWindow
PFD_SUPPORT_OPENGL|//FormatMustSupportOpenGL
PFD_DOUBLEBUFFER,//MustSupportDoubleBuffering
PFD_TYPE_RGBA,//RequestAnRGBAFormat
bits,//SelectOurColorDepth
0,0,0,0,0,0,//ColorBitsIgnored
0,//NoAlphaBuffer
0,//ShiftBitIgnored
0,//NoAccumulationBuffer
0,0,0,0,//AccumulationBitsIgnored
16,//16BitZ-Buffer(DepthBuffer)
0,//NoStencilBuffer
0,//NoAuxiliaryBuffer
PFD_MAIN_PLANE,//MainDrawingLayer
0,//Reserved
0,0,0//LayerMasksIgnored
};

if(!(hDC=GetDC(hWnd)))


{
KillGLWindow();
MessageBox(NULL,"无法创建GL设备环境.","ERROR",MB_OK|MB_ICONEXCLAMATION);
returnFALSE;
}

if(!(PixelFormat=ChoosePixelFormat(hDC,&pfd)))//DidWindowsFindAMatchingPixelFormat?


{
KillGLWindow();//ResetTheDisplay
MessageBox(NULL,"无法找到合适的像素格式.","ERROR",MB_OK|MB_ICONEXCLAMATION);
returnFALSE;//ReturnFALSE
}


if(!SetPixelFormat(hDC,PixelFormat,&pfd))//AreWeAbleToSetThePixelFormat?


{
KillGLWindow();//ResetTheDisplay
MessageBox(NULL,"像素格式无法设置.","ERROR",MB_OK|MB_ICONEXCLAMATION);
returnFALSE;//ReturnFALSE
}

if(!(hRC=wglCreateContext(hDC)))//AreWeAbleToGetARenderingContext?


{
KillGLWindow();//ResetTheDisplay
MessageBox(NULL,"无法创建一个绘制环境.","ERROR",MB_OK|MB_ICONEXCLAMATION);
returnFALSE;//ReturnFALSE
}

if(!wglMakeCurrent(hDC,hRC))//TryToActivateTheRenderingContext


{
KillGLWindow();//ResetTheDisplay
MessageBox(NULL,"无法激活绘制环境.","ERROR",MB_OK|MB_ICONEXCLAMATION);
returnFALSE;//ReturnFALSE
}

ShowWindow(hWnd,SW_SHOW);
SetForegroundWindow(hWnd);
SetFocus(hWnd);


ReSizeGLScene(width,height);
if(!InitGL())//初始化新建的GL窗口


{
KillGLWindow();//重置显示区
MessageBox(NULL,"InitializationFailed.","ERROR",MB_OK|MB_ICONEXCLAMATION);
returnFALSE;//返回FALSE
}

returnTRUE;


}

LRESULTCALLBACKWndProc(HWNDhWnd,//HandleForThisWindow
UINTuMsg,//MessageForThisWindow
WPARAMwParam,//AdditionalMessageInformation
LPARAMlParam)//AdditionalMessageInformation


{
switch(uMsg)//CheckForWindowsMessages


{
caseWM_ACTIVATE://WatchForWindowActivateMessage


{
if(!HIWORD(wParam))//CheckMinimizationState


{
active=TRUE;//ProgramIsActive
}
else


{
active=FALSE;//ProgramIsNoLongerActive
}

return0;//ReturnToTheMessageLoop
}

caseWM_SYSCOMMAND://InterceptSystemCommands


{
switch(wParam)//CheckSystemCalls


{
caseSC_SCREENSAVE://ScreensaverTryingToStart?
caseSC_MONITORPOWER://MonitorTryingToEnterPowersave?
return0;//PreventFromHappening
}
break;//Exit
}

caseWM_CLOSE://DidWeReceiveACloseMessage?


{
PostQuitMessage(0);//SendAQuitMessage
return0;//JumpBack
}

caseWM_KEYDOWN://IsAKeyBeingHeldDown?


{
keys[wParam]=TRUE;//IfSo,MarkItAsTRUE
return0;//JumpBack
}

caseWM_KEYUP://HasAKeyBeenReleased?


{
keys[wParam]=FALSE;//IfSo,MarkItAsFALSE
return0;//JumpBack
}

caseWM_SIZE://ResizeTheOpenGLWindow


{
ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));//LoWord=Width,HiWord=Height
return0;//JumpBack
}
}

//PassAllUnhandledMessagesToDefWindowProc
returnDefWindowProc(hWnd,uMsg,wParam,lParam);
}

intWINAPIWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,LPSTRlpCmdLine,intnShowCmd)


{
MSGmsg;//WindowsMessageStructure
BOOLdone=FALSE;//BoolVariableToExitLoop


//CreateOurOpenGLWindow
if(!CreateGLWindow("NeHe'sOpenGLFramework",640,480,16))


{
return0;//QuitIfWindowWasNotCreated
}

while(!done)//LoopThatRunsWhiledone=FALSE


{
if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))//IsThereAMessageWaiting?


{
if(msg.message==WM_QUIT)//HaveWeReceivedAQuitMessage?


{
done=TRUE;//IfSodone=TRUE
}
else//IfNot,DealWithWindowMessages


{
TranslateMessage(&msg);//TranslateTheMessage
DispatchMessage(&msg);//DispatchTheMessage
}
}
else//IfThereAreNoMessages


{
//DrawTheScene.WatchForESCKeyAndQuitMessagesFromDrawGLScene()
if(active)//ProgramActive?


{
if(keys[VK_ESCAPE])//WasESCPressed?


{
done=TRUE;//ESCSignalledAQuit
}
else//NotTimeToQuit,UpdateScreen


{
DrawGLScene();//DrawTheScene
SwapBuffers(hDC);//SwapBuffers(DoubleBuffering)
}
}
}
}

//Shutdown
KillGLWindow();//KillTheWindow
return(msg.wParam);//ExitTheProgram


}
其中最核心的代码是:
int
DrawGLScene(GLvoid)
//
Here'sWhereWeDoAllTheDrawing

{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);//ClearScreenAndDepthBuffer
glLoadIdentity();

glTranslatef(-1.5f,0.0f,-6.0f);//MoveLeft1.5UnitsAndIntoTheScreen6.0
glBegin(GL_TRIANGLES);//DrawingUsingTriangles
glVertex3f(0.0f,1.0f,0.0f);//Top
glVertex3f(-1.0f,-1.0f,0.0f);//BottomLeft
glVertex3f(1.0f,-1.0f,0.0f);//BottomRight

glEnd();//FinishedDrawingTheTriangle
glTranslatef(3.0f,0.0f,0.0f);//MoveRight3Units
glBegin(GL_QUADS);//DrawAQuad
glVertex3f(-1.0f,1.0f,0.0f);//TopLeft
glVertex3f(1.0f,1.0f,0.0f);//TopRight
glVertex3f(1.0f,-1.0f,0.0f);//BottomRight
glVertex3f(-1.0f,-1.0f,0.0f);//BottomLeft
glEnd();//DoneDrawingTheQuad//ResetTheCurrentModelviewMatrix
returnTRUE;//EverythingWentOK
}


按照我的个人理解,,就好比照相机拍照一样,被拍的物体移动和照相机反方向移动可以得到相同的效果(使得成像的大小变化),这里的glTranslatef是用来进行造型变换的(类似移动物体却不移动照相机)。通过改变平移值的大小可以明显看出平移的效果。
这里要注意的是存在两种不同的坐标变换方式,glTranslatef(x,y,z)中的x,y,z是相对与当前所在点的位移,但glVertex(x,y,z)是相对于glTranslatef(x,y,z)移动后的新原点的位移。因而这里可以认为glTranslate移动的是坐标原点,glVertex中的点是相对最新的坐标原点的坐标值。
当调用glLoadIdentity()之后,实际上将当前点移到了屏幕中心,X坐标轴从左至右,Y坐标轴从下至上,Z坐标轴从里至外。OpenGL屏幕中心的坐标值是X和Y轴上的<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" /><chmetcnv unitname="F" sourcevalue="0" hasspace="False" negative="False" numbertype="1" tcsc="0" w:st="on"><span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">0.0f</span></chmetcnv>点。中心左面的坐标值是负值,右面是正值。移向屏幕顶端是正值,移向屏幕底端是负值。移入屏幕深处是负值,移出屏幕则是正值。
glTranslatef(x, y, z)沿着X,Y和Z轴移动。根据前面的次序,下面的代码沿着X轴左移1.5个单位,Y轴不动(<chmetcnv unitname="F" sourcevalue="0" hasspace="False" negative="False" numbertype="1" tcsc="0" w:st="on">0.0f</chmetcnv>),最后移入屏幕<chmetcnv unitname="F" sourcevalue="6" hasspace="False" negative="False" numbertype="1" tcsc="0" w:st="on"><span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">6.0f</span></chmetcnv>个单位。注意在glTranslatef(x, y, z)中当移动的时候,并不是相对屏幕中心移动,而是相对与当前所在的屏幕位置。
glTranslatef(<chmetcnv unitname="F" sourcevalue="1.5" hasspace="False" negative="True" numbertype="1" tcsc="0" w:st="on">-<chmetcnv unitname="F" sourcevalue="1.5" hasspace="False" negative="False" numbertype="1" tcsc="0" w:st="on">1.5f</chmetcnv></chmetcnv>,<chmetcnv unitname="F" sourcevalue="0" hasspace="False" negative="False" numbertype="1" tcsc="0" w:st="on">0.0f</chmetcnv>,<chmetcnv unitname="F" sourcevalue="6" hasspace="False" negative="True" numbertype="1" tcsc="0" w:st="on">-<chmetcnv unitname="F" sourcevalue="6" hasspace="False" negative="False" numbertype="1" tcsc="0" w:st="on">6.0f</chmetcnv></chmetcnv>); // 左移1.5单位,并移入屏幕6.0
现在我们已经移到了屏幕的左半部分,并且将视图推入屏幕背后足够的距离以便我们可以看见全部的场景-创建三角形。
在屏幕的左半部分画完三角形后,我们要移到右半部分来画正方形。为此要再次使用glTranslate。这次右移,所以X坐标值为正值。因为前面左移了1.5个单位,这次要先向右移回屏幕中心(1.5个单位),再向右移动1.5个单位。总共要向右移3.0个单位。
glTranslatef(<chmetcnv unitname="F" sourcevalue="3" hasspace="False" negative="False" numbertype="1" tcsc="0" w:st="on">3.0f</chmetcnv>,<chmetcnv unitname="F" sourcevalue="0" hasspace="False" negative="False" numbertype="1" tcsc="0" w:st="on">0.0f</chmetcnv>,<chmetcnv unitname="F" sourcevalue="0" hasspace="False" negative="False" numbertype="1" tcsc="0" w:st="on">0.0f</chmetcnv>); // 右移3单位
还有一点值得特别注意:我们使用顺时针次序来画正方形-左上-右上-右下-左下。采用顺时针绘制的是对象的后表面。这就是说我们所看见的是正方形的背面。逆时针画出来的正方形才是正面朝着我们的。