`
v5qqcom
  • 浏览: 1360289 次
文章分类
社区版块
存档分类
最新评论

NeHe的OpenGL教程5(Bang翻译Delphi版)-如何绘制立方体

 
阅读更多

NeHe的OpenGL教程5(Bang翻译Delphi版)-如何绘制立方体

在这一课里,我们把三角形变为立体的金子塔形状,把四边形变为立方体,如下图:

program lesson5a;

{
OpenGL DelphiXE
出处:根据NeHe代码翻译而来(
http://nehe.gamedev.net/)
作者:帅宏军
shuaihj@163.com
}

uses
Windows,
Messages,
OpenGL;

// 全局变量
var
h_Rc: HGLRC; // 窗口着色描述表句柄
h_Dc: HDC; // OpenGL渲染描述表句柄
h_Wnd: HWND; // 保存我们的窗口句柄
keys: array [0..255] of BOOL; // 保存键盘按键的数组
Active: bool = true; // 窗口的活动标志,缺省为TRUE
FullScreen:bool = true; // P全屏标志缺省,缺省设定成全屏模式

rtri: GLfloat; // 用于三角形的角度
rquad: GLfloat; // 用于四边形的角度


// 重置OpenGL窗口大小
procedure ReSizeGLScene(Width: GLsizei; Height: GLsizei);
begin
if (Height=0) then // 防止被零除
Height:=1; // 将Height设为1

glViewport(0, 0, Width, Height); // 重置当前的视口(和窗口大小相当)

glMatrixMode(GL_PROJECTION); // 指定"投影矩阵堆栈"是下一个矩阵操作的目标
glLoadIdentity(); // 重置当前指定的矩阵为单位矩阵

gluPerspective(45.0,Width/Height,0.1,100.0); // 设置视口的大小

glMatrixMode(GL_MODELVIEW); // 指定"模型视图矩阵堆栈"是下一个矩阵操作的目标
glLoadIdentity; // 重置当前指定的矩阵为单位矩阵
end;

// 初始化OpenGL所有设置
function InitGL:bool;
begin
glShadeModel(GL_SMOOTH); // 采用光滑着色(绘制指定两点间其他点颜色时使用过渡色)

glClearColor(0.0, 0.0, 0.0, 0.5); // 指定清除颜色缓存时使用的颜色值(黑色,0.5透明)

glClearDepth(1.0); // 指定清除深度缓存时使用的深度值
glEnable(GL_DEPTH_TEST); // 启用深度测试,对深度缓存中符合"深度比较算法"要求的像素进行重绘
glDepthFunc(GL_LEQUAL); // 指定"深度比较算法"

glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST); // 告诉系统对透视进行最高质量修正

Result:=true;
end;

// 绘制OpenGL场景(任何您所想在屏幕上显示的东东都将在此段代码中出现)
function DrawGLScene():bool;
begin
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); // 根据glClearColor和glClearDepth指定的值清除颜色和深度缓存
glLoadIdentity(); // 重置当前指定的矩阵为单位矩阵

//你自己的OpengGL绘制代码
//当您调用glLoadIdentity()之后,您实际上将当前点移到了屏幕中心,
//X坐标轴从左至右,Y坐标轴从下至上,Z坐标轴从里至外。
//OpenGL屏幕中心的坐标值是X和Y轴上的0.0f点。
//中心左面的坐标值是负值,右面是正值。移向屏幕顶端是正值,移向屏幕底端是负值。移入屏幕深处是负值,移出屏幕则是正值。
glTranslatef(-1.5,0.0,-6.0); // 左移 1.5 单位,并移入屏幕 6.0

glRotatef(rtri,0.0,1.0,0.0); // 绕Y轴旋转金字塔

glBegin(GL_TRIANGLES); // 开始绘制金字塔的各个面

//下面的代码创建一个绕者其中心轴旋转的金字塔。金字塔的上顶点高出原点一个单位,底面中心低于原点一个单位。上顶点在底面的投影位于底面的中心。
//注意所有的面-三角形都是逆时针次序绘制的。这点十分重要,在以后的课程中我会作出解释。现在,您只需明白要么都逆时针,要么都顺时针,但永远不要将两种次序混在一起,除非您有足够的理由必须这么做。
//我们开始画金字塔的前侧面。因为所有的面都共享上顶点,我们将这点在所有的三角形中都设置为红色。底边上的两个顶点的颜色则是互斥的。前侧面的左下顶点是绿色的,右下顶点是蓝色的。这样相邻右侧面的左下顶点是蓝色的,右下顶点是绿色的。这样四边形的底面上的点的颜色都是间隔排列的。
glColor3f(1.0,0.0,0.0); // 红色
glVertex3f( 0.0, 1.0, 0.0); // 三角形的上顶点 (前侧面)
glColor3f(0.0,1.0,0.0); // 绿色
glVertex3f(-1.0,-1.0, 1.0); // 三角形的左下顶点 (前侧面)
glColor3f(0.0,0.0,1.0); // 蓝色
glVertex3f( 1.0,-1.0, 1.0); // 三角形的右下顶点 (前侧面)

//现在绘制右侧面。注意其底边上的两个顶点的X坐标位于中心右侧的一个单位处。顶点则位于Y轴上的一单位处,且Z坐标正好处于底边的两顶点的Z坐标中心。右侧面从上顶点开始向外侧倾斜至底边上。
//这次的左下顶点用蓝色绘制,以保持与前侧面的右下顶点的一致。蓝色将从这个角向金字塔的前侧面和右侧面扩展并与其他颜色混合。
//还应注意到后面的三个侧面和前侧面处于同一个glBegin(GL_TRIANGLES) 和 glEnd()语句中间。因为我们是通过三角形来构造这个金字塔的。OpenGL知道每三个点构成一个三角形。当它画完一个三角形之后,如果还有余下的点出现,它就以为新的三角形要开始绘制了。OpenGL在这里并不会将四点画成一个四边形,而是假定新的三角形开始了。所以千万不要无意中增加任何多余的点。
glColor3f(1.0,0.0,0.0); // 红色
glVertex3f( 0.0, 1.0, 0.0); // 三角形的上顶点 (右侧面)
glColor3f(0.0,0.0,1.0); // 蓝色
glVertex3f( 1.0,-1.0, 1.0); // 三角形的左下顶点 (右侧面)
glColor3f(0.0,1.0,0.0); // 绿色
glVertex3f( 1.0,-1.0, -1.0); // 三角形的右下顶点 (右侧面)

//现在是后侧面。再次切换颜色。左下顶点又回到绿色,因为后侧面与右侧面共享这个角。
glColor3f(1.0,0.0,0.0); // 红色
glVertex3f( 0.0, 1.0, 0.0); // 三角形的上顶点 (后侧面)
glColor3f(0.0,1.0,0.0); // 绿色
glVertex3f( 1.0,-1.0, -1.0); // 三角形的左下顶点 (后侧面)
glColor3f(0.0,0.0,1.0); // 蓝色
glVertex3f(-1.0,-1.0, -1.0); // 三角形的右下顶点 (后侧面)

//最后画左侧面。又要切换颜色。左下顶点是蓝色,与后侧面的右下顶点相同。右下顶点是蓝色,与前侧面的左下顶点相同。
//到这里金字塔就画完了。因为金字塔只绕着Y轴旋转,我们永远都看不见底面,因而没有必要添加底面。如果您觉得有经验了,尝试增加底面(正方形),并将金字塔绕X轴旋转来看看您是否作对了。确保底面四个顶点的颜色与侧面的颜色相匹配。
glColor3f(1.0,0.0,0.0); // 红色
glVertex3f( 0.0, 1.0, 0.0); // 三角形的上顶点 (左侧面)
glColor3f(0.0,0.0,1.0); // 蓝色
glVertex3f(-1.0,-1.0,-1.0); // 三角形的左下顶点 (左侧面)
glColor3f(0.0,1.0,0.0); // 绿色
glVertex3f(-1.0,-1.0, 1.0); // 三角形的右下顶点 (左侧面)
glEnd(); // 金字塔绘制结束


glLoadIdentity(); // 重置模型观察矩阵

//注意到这次我们将立方体移地更远离屏幕了。因为立方体的大小要比金字塔大,同样移入6个单位时,立方体看起来要大的多。这是透视的缘故。越远的对象看起来越小。
glTranslatef(1.5,0.0,-7.0); // 右移3单位

glRotatef(rquad,1.0,0.0,0.0); // 绕X轴旋转立方体

glBegin(GL_QUADS); // 开始绘制立方体

//先画立方体的顶面。从中心上移一单位,注意Y坐标始终为一单位,表示这个四边形与Z轴平行。先画右上顶点,向右一单位,再屏幕向里一单位。然后左上顶点,向左一单位,再屏幕向里一单位。然后是靠近观察者的左下和右下顶点。就是屏幕往外一单位。
glColor3f(0.0,1.0,0.0); // 颜色改为蓝色
glVertex3f( 1.0, 1.0,-1.0); // 四边形的右上顶点 (顶面)
glVertex3f(-1.0, 1.0,-1.0); // 四边形的左上顶点 (顶面)
glVertex3f(-1.0, 1.0, 1.0); // 四边形的左下顶点 (顶面)
glVertex3f( 1.0, 1.0, 1.0); // 四边形的右下顶点 (顶面)

//底面的画法和顶面十分类似。只是Y坐标变成了-1。如果我们从立方体的下面来看立方体的话,您会注意到右上角离观察者最近,因此我们先画离观察者最近的顶点。然后是左上顶点最后才是屏幕里面的左下和右下顶点。
//如果您真的不在乎绘制多边形的次序(顺时针或者逆时针)的话,您可以直接拷贝顶面的代码,将Y坐标从1改成 -1,也能够工作。但一旦您进入象纹理映射这样的领域时,忽略绘制次序会导致十分怪异的结果。
glColor3f(1.0,0.5,0.0); // 颜色改成橙色
glVertex3f( 1.0,-1.0, 1.0); // 四边形的右上顶点(底面)
glVertex3f(-1.0,-1.0, 1.0); // 四边形的左上顶点(底面)
glVertex3f(-1.0,-1.0,-1.0); // 四边形的左下顶点(底面)
glVertex3f( 1.0,-1.0,-1.0); // 四边形的右下顶点(底面)

//接着画立方体的前面。保持Z坐标为一单位,前面正对着我们。
glColor3f(1.0,0.0,0.0); // 颜色改成红色
glVertex3f( 1.0, 1.0, 1.0); // 四边形的右上顶点(前面)
glVertex3f(-1.0, 1.0, 1.0); // 四边形的左上顶点(前面)
glVertex3f(-1.0,-1.0, 1.0); // 四边形的左下顶点(前面)
glVertex3f( 1.0,-1.0, 1.0); // 四边形的右下顶点(前面)

//立方体后面的绘制方法与前面类似。只是位于屏幕的里面。注意Z坐标现在保持 -1 不变。
glColor3f(1.0,1.0,0.0); // 颜色改成黄色
glVertex3f( 1.0,-1.0,-1.0); // 四边形的右上顶点(后面)
glVertex3f(-1.0,-1.0,-1.0); // 四边形的左上顶点(后面)
glVertex3f(-1.0, 1.0,-1.0); // 四边形的左下顶点(后面)
glVertex3f( 1.0, 1.0,-1.0); // 四边形的右下顶点(后面)

//还剩两个面就完成了。您会注意到总有一个坐标保持不变。这一次换成了X坐标。因为我们在画左侧面。
glColor3f(0.0,0.0,1.0); // 颜色改成蓝色
glVertex3f(-1.0, 1.0, 1.0); // 四边形的右上顶点(左面)
glVertex3f(-1.0, 1.0,-1.0); // 四边形的左上顶点(左面)
glVertex3f(-1.0,-1.0,-1.0); // 四边形的左下顶点(左面)
glVertex3f(-1.0,-1.0, 1.0); // 四边形的右下顶点(左面)

//立方体的最后一个面了。X坐标保持为一单位。逆时针绘制。您愿意的话,留着这个面不画也可以,这样就是一个盒子:)
//或者您要是有兴趣可以改变立方体所有顶点的色彩值,象金字塔那样混合颜色。您会看见一个非常漂亮的彩色立方体,各种颜色在它的各个表面流淌。
glColor3f(1.0,0.0,1.0); // 颜色改成紫罗兰色
glVertex3f( 1.0, 1.0,-1.0); // 四边形的右上顶点(右面)
glVertex3f( 1.0, 1.0, 1.0); // 四边形的左上顶点(右面)
glVertex3f( 1.0,-1.0, 1.0); // 四边形的左下顶点(右面)
glVertex3f( 1.0,-1.0,-1.0); // 四边形的右下顶点(右面)
glEnd(); // 立方体绘制结束


rtri := rtri + 0.2; // 增加三角形的旋转变量
rquad := rquad + 0.15; // 减少四边形的旋转变量


Result := true;
end;

//处理所有的窗口消息。当我们注册好窗口类之后,程序跳转到这部分代码处理窗口消息
function WndProc(hWnd: HWND; // 窗口的句柄
message: UINT; // 窗口的消息
wParam: WPARAM; // 附加的消息内容
lParam: LPARAM): // 附加的消息内容
LRESULT; stdcall;
var
scrWidth,scrHeight: integer;
rect: TRect;
begin
if message=WM_SYSCOMMAND then // 监视系统中断命令
begin
case wParam of
SC_SCREENSAVE,SC_MONITORPOWER: // 屏保要运行或显示器要进入节电模式
begin
result:=0; // 禁止命令执行
exit;
end;
end;
end;

case message of
WM_CREATE: // 监视构建窗体消息
begin
//获得屏幕尺寸
scrWidth := GetSystemMetrics(SM_CXSCREEN);
scrHeight := GetSystemMetrics(SM_CYSCREEN);

//获取窗体尺寸
GetWindowRect(hWnd,&rect);
rect.left := (scrWidth-rect.right) DIV 2;
rect.top := (scrHeight-rect.bottom) DIV 2;

//设置窗体位置(屏幕居中)
SetWindowPos(hWnd,HWND_TOP,rect.left,rect.top,rect.right,rect.bottom,SWP_SHOWWINDOW);

result:=0; // 返回消息循环
end;
WM_ACTIVATE: // 监视窗口激活消息
begin
if (Hiword(wParam)=0) then // 检查最小化状态
active:=true // 程序处于激活状态
else
active:=false; // 程序不再激活

Result:=0; // 返回消息循环
end;
WM_CLOSE: // 监视窗口关闭消息
Begin
PostQuitMessage(0); // 发出退出消息
result:=0 // 返回消息循环
end;
WM_KEYDOWN: // 监视键盘有键按下消息
begin
keys[wParam] := TRUE; // 如果是,设为TRUE
result:=0; // 返回消息循环
end;
WM_KEYUP: // 监视键盘有键抬起消息
begin
keys[wParam] := FALSE; // 如果是,设为FALSE
result:=0; // 返回消息循环
end;
WM_SIZE: // 监视窗口尺寸改变消息
begin
ReSizeGLScene(LOWORD(lParam),HIWORD(lParam)); // 重置OpenGL窗口大小
result:=0; // 返回消息循环
end
else
// 其余无关的消息被传递给DefWindowProc,让Windows自行处理
begin
Result := DefWindowProc(hWnd, message, wParam, lParam);
end;
end;
end;

//正常销毁窗口(在程序退出之前调用,依次释放着色描述表,设备描述表和窗口句柄)
procedure KillGLWindow;
begin
if FullScreen then // 处于全屏模式吗?
begin
ChangeDisplaySettings(devmode(nil^),0); // 回到原始桌面
showcursor(true); // 显示鼠标指针
end;

if h_rc<> 0 then // 拥有OpenGL渲染描述表吗?
begin
if (not wglMakeCurrent(h_Dc,0)) then // 释放DC和RC描述表
MessageBox(0,'Release of DC and RC failed.',' 关闭错误',MB_OK or MB_ICONERROR);
if (not wglDeleteContext(h_Rc)) then // 删除RC
begin
MessageBox(0,'释放RC失败.',' 关闭错误',MB_OK or MB_ICONERROR);
h_Rc:=0; // 将RC设为 NULL
end;
end;

if (h_Dc=1) and (releaseDC(h_Wnd,h_Dc)<>0) then // 释放 DC
begin
MessageBox(0,'释放DC失败.',' S关闭错误',MB_OK or MB_ICONERROR);
h_Dc:=0; // 将 DC 设为 NULL
end;

if (h_Wnd<>0) and (not destroywindow(h_Wnd))then // 销毁窗口
begin
MessageBox(0,'释放窗口句柄失败.',' 关闭错误',MB_OK or MB_ICONERROR);
h_Wnd:=0; // 将 hWnd 设为 NULL
end;

if (not UnregisterClass('OpenGL',hInstance)) then // 注销类
begin
MessageBox(0,'不能注销窗口类.','关闭错误',MB_OK or MB_ICONINFORMATION);
end;
end;

//创建我们的OpenGL窗口
function CreateGlWindow(title:Pchar; width,height,bits:integer;FullScreenflag:bool):boolean stdcall;
var
Pixelformat: GLuint; // 当我们要求Windows为我们寻找相匹配的象素格式时,Windows寻找结束后将模式值保存在变量PixelFormat中
wc:TWndclass; // 窗口类结构
dwExStyle:dword; // 扩展窗口风格
dwStyle:dword; // 窗口风格
pfd: pixelformatdescriptor; // 象素格式描述
dmScreenSettings: Devmode; // 设备模式
h_Instance:hinst; // 窗口的实例
WindowRect: TRect; // 取得矩形的左上角和右下角的坐标值
begin
//取得矩形的左上角和右下角的坐标值。
//我们将使用这些值来调整我们的窗口使得其上的绘图区的大小恰好是我们所需的分辨率的值。
//通常如果我们创建一个640x480的窗口,窗口的边框会占掉一些分辨率的值。
WindowRect.Left := 0; // 将Left 设为 0
WindowRect.Top := 0; // 将Right 设为要求的宽度
WindowRect.Right := width; // 将Top 设为 0
WindowRect.Bottom := height; // 将Bottom 设为要求的高度

FullScreen:=FullScreenflag; // 设置全局全屏标志

//我们取得窗口的实例,然后定义窗口类
h_instance:=GetModuleHandle(nil); // 取得我们窗口的实例
with wc do
begin
style := CS_HREDRAW or CS_VREDRAW or CS_OWNDC; // 移动时重画,并为窗口取得DC
lpfnWndProc:=@WndProc; // WndProc消息处理函数回调
cbClsExtra:=0; // 无额外窗口数据
cbWndExtra:=0; // 无额外窗口数据
hInstance:=h_Instance; // 设置窗口实例
hIcon:=LoadIcon(0,IDI_WINLOGO); // 装入缺省图标
hCursor:=LoadCursor(0,IDC_ARROW); // 装入鼠标指针
hbrBackground:=0; // GL不需要背景
lpszMenuName:=nil; // 不需要菜单
lpszClassName:='OpenGl'; // 设定类名字
end;

//注册窗口类
if RegisterClass(wc)=0 then // 注册窗口类
begin
MessageBox(0,'注册窗口失败.','错误',MB_OK or MB_ICONERROR);
Result:=false;
exit;
end;

//尝试全屏模式
if FullScreen then
begin
//分配用于存储视频设置的空间;设定屏幕的宽,高,色彩深度
ZeroMemory( @dmScreenSettings, sizeof(dmScreenSettings) ); // 初始化内存
with dmScreensettings do //设备模式
begin
dmSize := sizeof(dmScreenSettings); // Devmode 结构的大小
dmPelsWidth := width; // 所选屏幕宽度
dmPelsHeight := height; // 所选屏幕高度
dmBitsPerPel := bits; // 每象素所选的色彩深度
dmFields := DM_BITSPERPEL or DM_PELSWIDTH or DM_PELSHEIGHT;
end;

// 尝试设置显示模式并返回结果。注: CDS_FULLSCREEN 移去了状态条。
if (ChangeDisplaySettings(dmScreenSettings, CDS_FULLSCREEN))<>DISP_CHANGE_SUCCESSFUL THEN
Begin
// 若全屏模式失败,提供两个选项:退出或在窗口内运行
if MessageBox(0,'全屏模式在当前显卡上设置失败!\n使用窗口模式?'
,'OpenGL',MB_YESNO or MB_ICONEXCLAMATION)= IDYES then
FullScreen:=false // 选择窗口模式(Fullscreen=FALSE)
else
begin
// 弹出一个对话框,告诉用户程序结束
MessageBox(0,'程序将被关闭.','错误',MB_OK or MB_ICONERROR);
Result:=false; // 退出并返回 FALSE
exit;
end;
end;
end;

//由于全屏模式可能失败,用户可能决定在窗口下运行,
//我们需要在设置屏幕/窗口之前,再次检查fullscreen的值是TRUE或FALSE
if FullScreen then
begin
dwExStyle:=WS_EX_APPWINDOW; // 扩展窗体风格(窗体可见时处于最前面)
dwStyle:=WS_POPUP or WS_CLIPSIBLINGS or WS_CLIPCHILDREN; // 窗体风格(没有边框)
Showcursor(false); // 隐藏鼠标指针
end
else
begin
dwExStyle:=WS_EX_APPWINDOW or WS_EX_WINDOWEDGE; // 扩展窗体风格(增强窗体的3D感观)
dwStyle:=WS_OVERLAPPEDWINDOW or WS_CLIPSIBLINGS or WS_CLIPCHILDREN; // 窗体风格(带标题栏、可变大小的边框、菜单和最大化/最小化按钮的窗体)
end;

AdjustWindowRectEx(WindowRect,dwStyle,false,dwExStyle); // 调整窗口达到真正要求的大小

// 开始创建窗口并检查窗口是否成功创建
H_wnd:=CreateWindowEx(dwExStyle, // 扩展窗体风格
'OpenGl', // 类名字
Title, // 窗口标题
dwStyle, // 窗体风格
0,0, // 窗口位置
WindowRect.Right-WindowRect.Left, // 计算调整好的窗口宽度
WindowRect.Bottom-WindowRect.Top, // 计算调整好的窗口高度
0, // 无父窗口
0, // 无菜单
hinstance, // 窗口实例
nil); // 不向WM_CREATE传递任何东东

if h_Wnd=0 then // 窗口是否正常创建
begin
KillGlWindow(); // 重置显示区
MessageBox(0,'不能创建一个窗口设备描述表.','错误',MB_OK or MB_ICONEXCLAMATION);
Result:=false; // 返回 FALSE
exit;
end;

//描述象素格式
with pfd do
begin
nSize:= SizeOf( PIXELFORMATDESCRIPTOR ); // 象素描述符的大小
nVersion:= 1; // 版本号

dwFlags:= PFD_DRAW_TO_WINDOW // 格式必须支持窗口
or PFD_SUPPORT_OPENGL // 格式必须支持OpenGL
or PFD_DOUBLEBUFFER; // 格式必须支持双缓冲

iPixelType:= PFD_TYPE_RGBA; // 申请 RGBA 格式
cColorBits:= bits; // 选定色彩深度

cRedBits:= 0; // 忽略的色彩位
cRedShift:= 0;
cGreenBits:= 0;
cBlueBits:= 0;
cBlueShift:= 0;

cAlphaBits:= 0; // 无Alpha缓存
cAlphaShift:= 0; // 忽略Shift Bit
cAccumBits:= 0; // 无累加缓存

cAccumRedBits:= 0; // 忽略聚集位
cAccumGreenBits:= 0;
cAccumBlueBits:= 0;
cAccumAlphaBits:= 0;

cDepthBits:= 16; // 16位 Z-缓存 (深度缓存)
cStencilBits:= 0; // 无蒙板缓存
cAuxBuffers:= 0; // 无辅助缓存
iLayerType:= PFD_MAIN_PLANE; // 主绘图层

bReserved:= 0; // Reserved

dwLayerMask:= 0; // 忽略层遮罩
dwVisibleMask:= 0;
dwDamageMask:= 0;
end;

//尝试取得OpenGL设备描述表
h_Dc := GetDC(h_Wnd);
if h_Dc=0 then
begin
KillGLWindow(); // 重置显示区
MessageBox(0,'不能创建一种相匹配的像素格式.','错误',MB_OK or MB_ICONEXCLAMATION);
Result:=false; // 返回 FALSE
exit;
end;

//找到对应与此前我们选定的象素格式的象素格式
PixelFormat := ChoosePixelFormat(h_Dc, @pfd);
if (PixelFormat=0) then
begin
KillGLWindow(); // 重置显示区
MessageBox(0,'不能找到像素格式.','错误',MB_OK or MB_ICONEXCLAMATION);
Result:=false; // 返回 FALSE
exit;
end;

//尝试设置象素格式
if (not SetPixelFormat(h_Dc,PixelFormat,@pfd)) then
begin
KillGLWindow(); // 重置显示区
MessageBox(0,'不能设置像素格式.','错误',MB_OK or MB_ICONEXCLAMATION);
Result:=false; // 返回 FALSE
exit;
end;

//尝试取得着色描述表
h_Rc := wglCreateContext(h_Dc); // 尝试取得着色描述表
if (h_Rc=0) then
begin
KillGLWindow(); // 重置显示区
MessageBox(0,'不能创建OpenGL渲染描述表.','错误',MB_OK or MB_ICONEXCLAMATION);
Result:=false; // 返回 FALSE
exit;
end;

//激活着色描述表
if (not wglMakeCurrent(h_Dc, h_Rc)) then
begin
KillGLWindow(); // 重置显示区
MessageBox(0,'不能激活当前的OpenGL渲然描述表.','错误',MB_OK or MB_ICONEXCLAMATION);
Result:=false; // 返回 FALSE
exit;
end;

//显示创建完成的OpenGL窗口
ShowWindow(h_Wnd,SW_SHOW); // 显示创建完成的OpenGL窗口
SetForegroundWindow(h_Wnd); // 设为前端窗口(给它更高的优先级)
SetFocus(h_Wnd); // 并将焦点移至此窗口
ReSizeGLScene(width,height); // 设置透视 GL 屏幕

//初始化OpenGL(设置光照、纹理、等等任何需要设置的东东)
if (not InitGl()) then // 初始化OpenGL
begin
KillGLWindow(); // 重置显示区
MessageBox(0,'初始化失败.','错误',MB_OK or MB_ICONEXCLAMATION);
Result:=false; // 返回 FALSE
exit;
end;

Result:=true; // 成功
end;

//Windows程序的入口(调用窗口创建例程,处理窗口消息,并监视人机交互)
function WinMain(hInstance: HINST; // 当前窗口实例
hPrevInstance: HINST; // 前一个窗口实例
lpCmdLine: PChar; // 命令行参数
nCmdShow: integer): // 窗口显示状态
integer; stdcall;
var
msg: TMsg; // 用来检查是否有消息等待处理
done: Bool; // 用来检查否完程序完成运行
begin
done:=false; //用来退出循环的Bool 变量

// 选择窗口是否全屏
if MessageBox(0,'你想在全屏模式下运行么?','全屏',
MB_YESNO or MB_ICONQUESTION)=IDNO then
FullScreen:=false
else
FullScreen:=true;

// 创建OpenGL窗口
if not CreateGLWindow('我的OpenGL 框架',640,480,16,FullScreen) then
begin
Result := 0; // 失败退出
exit;
end;

// 下面是消息循环的开始。只要done保持FALSE,循环一直进行
while not done do
begin
if (PeekMessage(msg, 0, 0, 0, PM_REMOVE)) then // 检查是否有消息在等待
begin
if msg.message=WM_QUIT then // 收到退出消息?
done:=true
else // 如果不是退出消息,我们翻译消息,然后发送消息(使得WndProc() 或 Windows能够处理他们)
begin
TranslateMessage(msg); // 翻译消息
DispatchMessage(msg); // 发送消息
end;
end
else
begin
// J如果没有消息,绘制我们的OpenGL场景失败,或者ESC 发出退出信号直接退出程序
if (active and not(DrawGLScene()) or keys[VK_ESCAPE]) then
done:=true
else
SwapBuffers(h_Dc); // 交换缓存 (双缓存)

if keys[VK_F1] then // 允许用户按下F1键在全屏模式和窗口模式间切换
begin
Keys[VK_F1] := false; // 若是,使对应的Key数组中的值为 FALSE
KillGLWindow(); // 销毁当前的窗口
FullScreen := not FullScreen; // 切换 全屏 / 窗口 模式

// 重建 OpenGL 窗口
CreateGLWindow('我的OpenGL 框架',640,480,16,fullscreen);
end;
end;
end;

// 关闭程序
killGLwindow(); // 销毁窗口
result:=msg.wParam; // 退出程序
end;

begin
WinMain(hInstance, HPrevInst, CmdLine, CmdShow); // 程序开始运行
end.

分享到:
评论

相关推荐

    OpenGL教程Nehe版-中文版.pdf_opengl教程_opengl_tutorial_becamexai_

    Nehe 的入门级别 OpenGL 教程,深入浅出,实践性强,具有很高的学习价值

    NeHe_OpenGL.zip_NEHE opengl教程_nehe opengl_nehe-opengl_opengl_ope

    "NeHe_OpenGL.zip"包含了NeHe的OpenGL教程,这是一个非常宝贵的资料,尤其是对于那些想要学习或深化OpenGL编程技能的人来说。 这个教程集以CHM(Compiled Help Manual)电子书的形式呈现,CHM是一种由Microsoft开发...

    NeHe OpenGL教程(中文版)

    NeHe OpenGL教程 中文版 NeHe OpenGL教程 中文版 NeHe OpenGL教程 中文版 NeHe OpenGL教程 中文版

    NeHe OpenGL 教程 NeHe OpenGL 教程 NeHe OpenGL 教程

    NeHe OpenGL 教程 NeHe OpenGL 教程 NeHe OpenGL 教程

    OPENGL_NEHE中文教程---

    NEHE(New Era Hobbyist Environment)是由Jeff Molofee创建的一系列开源OpenGL教学教程,旨在帮助初学者理解并掌握OpenGL编程。这些教程在全球范围内广受欢迎,为无数开发者奠定了图形编程的基础。 "OPENGL_NEHE...

    OpenGL-Nehe完整中文教程.pdf

    NeHe OpenGL教程是一系列针对初学者的OpenGL学习资源,由NeHe创作,旨在通过简单的示例和课程让新手理解OpenGL的基础知识。这个教程强调了OpenGL编程的实用性和易学性,适合希望快速掌握OpenGL编程的读者。 在教程...

    NeHe OpenGL NeHe OpenGL NeHe OpenGL NeHe OpenGL

    NeHe OpenGL NeHe OpenGL NeHe OpenGL NeHe OpenGL

    NeHe OpenGL教程中文版及全部代码

    著名的NeHe OpenGL教程中文版,包括48课教程及所有课程代码,由浅入深,编写精良,结合代码可以快速上手OpenGL。

    Qt5版Nehe OpenGL教程1-5

    【Qt5版Nehe OpenGL教程1-5】是一系列针对初学者的教程,旨在通过Qt5框架教授OpenGL图形编程的基本概念和技术。OpenGL是一种强大的跨平台图形库,用于渲染2D和3D图形,而Qt5则是一个流行的开发框架,支持多种操作...

    OpenGL教程Nehe版-中文版

    ### OpenGL教程Nehe版-中文版 #### 一、引言 NeHe的OpenGL教程是一套专门为初学者设计的学习资源,旨在帮助读者轻松地入门OpenGL编程。教程作者明确表示,虽然教程可能存在一些错误或不足之处,但他尽力确保内容对...

    Nehe-OpenGL教程源码

    2. 基本几何体绘制:学习如何使用顶点数组、顶点指针等绘制2D和3D图形,如矩形、立方体等。 3. 着色与颜色管理:理解颜色混合、透明度控制,以及颜色空间的转换。 4. 纹理映射:学会如何加载和应用纹理,包括纹理...

    NeHe OpenGL中文教程.CHM相关源码38-48

    NeHe OpenGL中文教程.CHM相关源码38-48

    NeHe OpenGL经典教程 中文版

    NeHe教程是OpenGL学习者入门的基石,尤其对于中文使用者,这个中文版的NeHe教程更是宝贵的资源。NeHe Productions由Jeffrey Ventrella创建,提供了大量的OpenGL编程教程,覆盖了从基础到高级的各种主题。 这个教程...

    OpenGL Nehe 教程Delphi源码

    OpenGL Nehe 教程Delphi源码

    NeHe OpenGL教程 学习笔记1

    总的来说,NeHe OpenGL教程的学习笔记1主要涵盖了OpenGL环境的初始化、基本几何形状的绘制、颜色设定、视口与投影以及渲染流程的基础概念。通过理解和实践这些基本操作,开发者可以逐步构建更复杂的3D场景。

    NeHe OpenGL(delphi)

    ### NeHe OpenGL(delphi)教程知识点解析 #### 一、简介 NeHe的OpenGL教程是学习OpenGL编程的经典资源之一,该教程最初是针对C++语言编写的。而在Delphi环境中移植这一教程,使得使用Delphi作为开发工具的学习者也能...

    OpenGL—Nehe完整版中文教程及源码

    OpenGL—Nehe完整版中文教程及源码,内含教程PDF+教程源代码(共48讲)

    NeHe_OpenGL_VC版本1-48课全部教程以及源码

    NeHe_OpenGL_VC版本1-48课全部教程以及源码

    Qt5版NeHe OpenGL教程6-10

    这个Qt5版的NeHe OpenGL教程6-10将深入探讨如何在Qt5框架下利用OpenGL进行图形渲染。 第六课主要讲解了颜色索引纹理映射。颜色索引是一种早期的纹理映射技术,通过颜色表来查找对应的颜色值。在这一课中,我们将...

    nehe+openGL教程的源代码---lessons21

    "lessons21"指的是NEHE教程系列中的第21课,这通常涵盖了一些高级或特定主题,帮助开发者进一步深化对OpenGL的理解。 Lesson21是一个小游戏,它结合了多个关键的OpenGL技术和概念。首先,线在计算机图形学中是非常...

Global site tag (gtag.js) - Google Analytics