分享
 
 
 

NeHe的opengl教程delphi版(1)----基本框架

王朝delphi·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

将CKER翻译的NeHe的VC 的OPENGL框架转成了Delphi版,

希望对用Delphi学习OPENGL的兄弟有所帮助,

不知为什么,我的Delphi环境下无法直接运行,但是在别的机器上好像没问题

我的机器只能编译后运行EXE文件。

感谢NeHe提供的这么好的框架,感谢CKER翻译的VC的资料

Program Project1;

Uses

opengl,

windows,

Messages;

Const

WND_TITLE = 'OPenGl 基本框架'; //标题

Var

//===========================================================================

// 每一个OpenGL都被连接到一个着色描述表上。着色描述表将所有的OpenGL调用命令连

// 接到Device Context(设备描述表)上,将OpenGL的着色描述表定义为hRC ,要让程序能

// 够绘制窗口的话,还需要创建一个设备描述表,Windows的设备描述表被定义为 hDC,

// DC将窗口连接到GDI(Graphics Device Interface图形设备接口)。而RC将OpenGL连接

// 到DC。

//===========================================================================

h_RC : HGLRC; // Rendering Context(着色描述表)。

h_DC : HDC; // Device Context(设备描述表)

h_Wnd : HWND; // 窗口句柄

h_Instance : HINST; // 程序Instance(实例)。

keys : Array[0..255] Of Boolean; // 用于键盘例程的数组

{$R *.res}

//==============================================================================

//重新设置OpenGL场景的大小,而不管窗口的大小是否已经改变(假定没有使用全屏模式)。

//甚至无法改变窗口的大小时(例如在全屏模式下),它至少仍将运行一次————————

//在程序开始时设置透视图。OpenGL场景的尺寸将被设置成它显示时所在窗口的大小。

//==============================================================================

Procedure glResizeWnd(Width, Height: Integer); // 重置并初始化GL窗口大小

Begin

If (Height = 0) Then // 防止高度为0,产生除0异常

Height := 1;

glViewport(0, 0, Width, Height); // 重置当前的视口(Viewport)

//下面几行为透视图设置屏幕。意味着越远的东西看起来越小。这么做创建了一个现实

//外观的场景。此处透视按照基于窗口宽度和高度的45度视角来计算。0.1f,100.0f是

//我们在场景中所能绘制深度的起点和终点。

//glMatrixMode(GL_PROJECTION)指明接下来的两行代码将影响projection matrix(投影矩阵)。

//投影矩阵负责为我们的场景增加透视。

//glLoadIdentity()近似于重置。它将所选的矩阵状态恢复成其原始状态。

//调用 glLoadIdentity()之后我们为场景设置透视图。

glMatrixMode(GL_PROJECTION); // 选择投影矩阵

glLoadIdentity(); // 重置投影矩阵

gluPerspective(45.0, Width / Height, 0.1, 100.0); // 计算窗口的外观比例

//glMatrixMode(GL_MODELVIEW)指明任何新的变换将会影响 modelview matrix(模型观察矩阵)。

//模型观察矩阵中存放了我们的物体讯息。

glMatrixMode(GL_MODELVIEW); // 选择模型观察矩阵

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

//如果现在还不能理解这些术语的含义,请别着急。

//只要知道如果想获得一个精彩的透视场景的话,必须这么做。

End;

//==============================================================================

// 对OpenGL进行所有的设置。将设置清除屏幕所用的颜色,打开深度缓存,

// 启用smooth shading(阴影平滑),等等。这个例程直到OpenGL窗口创建之后才会被调用。

// 此过程将有返回值。但此处的初始化没那么复杂,现在还用不着担心这个返回值。

//==============================================================================

Procedure glInit();

Begin

//设置清除屏幕时所用的颜色。如果对色彩的工作原理不清楚的话,快速解释一下。

//色彩值的范围从0.0f到1.0f。0.0f代表最黑的情况,1.0f就是最亮的情况。

//glClearColor 后的第一个参数是Red Intensity(红色分量),第二个是绿色,第三个是蓝色。

//最大值也是1.0f,代表特定颜色分量的最亮情况。最后一个参数是Alpha值。

//当它用来清除屏幕的时候,不用关心第四个数字。现在让它为0.0f。

//通过混合三种原色(红、绿、蓝),可以得到不同的色彩

//因此,使用glClearColor(0.0f,0.0f,1.0f,0.0f),您蓝色来清除屏幕。

//如果用 glClearColor(0.5f,0.0f,0.0f,0.0f)的话,将使用中红色来清除屏幕。

//不是最亮(1.0f),也不是最暗 (0.0f)。要得到白色背景,应该将所有的颜色设成最亮(1.0f)。

//要黑色背景的话,该将所有的颜色设为最暗(0.0f)。

glClearColor(0.0, 0.0, 0.0, 0.0); // 黑色背景

//阴影平滑通过多边形精细的混合色彩,并对外部光进行平滑。

glShadeModel(GL_SMOOTH); // 启用阴影平滑

//接下来必须做的是关于depth buffer(深度缓存)的。将深度缓存设想为屏幕后面的层。

//深度缓存不断的对物体进入屏幕内部有多深进行跟踪。本程序其实没有真正使用深度缓存,

//但几乎所有在屏幕上显示3D场景OpenGL程序都使用深度缓存。它的排序决定那个物体先画。

//这样您就不会将一个圆形后面的正方形画到圆形上来。深度缓存是OpenGL十分重要的部分。

glClearDepth(1.0); // 设置深度缓存

glEnable(GL_DEPTH_TEST); // 启用深度测试

glDepthFunc(GL_LESS); // 所作深度测试的类型

//接着告诉OpenGL我们希望进行最好的透视修正。

//这会十分轻微的影响性能。但使得透视图看起来好一点。

glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 真正精细的透视修正

End;

//==============================================================================

//所有的绘图代码。任何您所想在屏幕上显示的东东都将在此段代码中出现。

//以后的每个程序会在此处增加新的代码。

//==============================================================================

Procedure glDraw();

Begin

glClear(GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度缓存

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

End;

Function WndProc(hWnd: HWND; // 窗口的句柄

Msg: UINT; // 窗口的消息

wParam: WPARAM; // 附加的消息内容

lParam: LPARAM // 附加的消息内容

): LRESULT; stdcall;

Begin

Result := 0;

Case (Msg) Of // 检查Windows消息

WM_ACTIVATE: // 监视窗口激活消息

Begin

End;

WM_CREATE: // 创建

Begin

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: //调整OpenGL窗口大小

Begin

glResizeWnd(LOWORD(lParam), HIWORD(lParam)); //LoWord=Width,HiWord=Height

Result := 0;

End;

WM_TIMER: //timers

Begin

End;

Else //其余的让Windows自行处理。

Result := DefWindowProc(hWnd, Msg, wParam, lParam); //向DefWindowProc传递所有未处理的消息。

End;

End;

//==============================================================================

// 只在程序退出之前调用。作用是依次释放着色描述表,设备描述表和窗口句柄。

// 加入了许多错误检查。如果程序无法销毁窗口的任意部分,都会弹出带相应错误消息的

// 讯息窗口,

//==============================================================================

Procedure glKillWnd(Fullscreen: Boolean);

Begin

//在KillGLWindow()中所作的第一件事是检查是否处于全屏模式。

//如果是,要切换回桌面。本应在禁用全屏模式前先销毁窗口,

//但在某些显卡上这么做可能会使得桌面崩溃。所以还是先禁用全屏模式。

//这将防止桌面出现崩溃,并在Nvidia和3dfx显卡上都工作的很好!

If Fullscreen Then // 处于全屏模式吗?

Begin

// 使用ChangeDisplaySettings(NULL,0)回到原始桌面。

// 将NULL作为第一个参数,

// 0作为第二个参数传递强制Windows使用当前存放在注册表中的值

// (缺省的分辨率、色彩深度、刷新频率,等等)来有效的恢复我原始桌面。

// 换回桌面后,还要使得鼠标指针重新可见。

ChangeDisplaySettings(devmode(Nil^), 0); // 是的话,切换回桌面

ShowCursor(True); //显示鼠标

End;

//是否拥有着色描述表(hRC)。

If h_RC > 0 Then

//看我们能否释放它(将 hRC从hDC分开)。

If (Not wglMakeCurrent(h_DC, 0)) Then

MessageBox(0, 'DC和RC无法被释放!', '错误', MB_OK Or

MB_ICONERROR);

// 能否删除着色描述表

If (Not wglDeleteContext(h_RC)) Then

Begin

MessageBox(0, '删除着色描述表失败!', '错误', MB_OK Or

MB_ICONERROR);

h_RC := 0;

End;

//是否存在设备描述表,如果有尝试释放它。

If ((h_DC > 0) And (ReleaseDC(h_Wnd, h_DC) = 0)) Then

Begin

MessageBox(0, '释放设备描述表失败!', '错误', MB_OK Or

MB_ICONERROR);

h_DC := 0;

End;

//是否存在窗口句柄,调用 DestroyWindow( hWnd )来尝试销毁窗口

If ((h_Wnd <> 0) And (Not DestroyWindow(h_Wnd))) Then

Begin

MessageBox(0, '无法销毁窗体!', '错误', MB_OK Or

MB_ICONERROR);

h_Wnd := 0;

End;

// 注销窗口类

//这允许我们正常销毁窗口,接着在打开其他窗口时,

//不会收到诸如"Windows Class already registered"(窗口类已注册)的错误消息。

If (Not UnRegisterClass('OpenGL', hInstance)) Then

Begin

MessageBox(0, '无法注销窗口类!', '错误', MB_OK Or

MB_ICONERROR);

hInstance := 0;

End;

End;

//==============================================================================

// 创建OpenGL窗口,

// 带有5个参数:窗口的标题栏,窗口的宽度,窗口的高度,色彩位数(16/24/32),

// 全屏标志(TRUE --全屏模式, FALSE--窗口模式 )。

// 返回的布尔值 窗口是否成功创建。

//==============================================================================

Function glCreateWnd(Width, Height: Integer; Fullscreen: Boolean; PixelDepth:

Integer): Boolean;

Var

wndClass : TWndClass; // 窗口类

dwStyle : DWORD; // 窗口风格

dwExStyle : DWORD; // 扩展窗口风格

PixelFormat : GLuint; // 象素格式

h_Instance : HINST; // 当前实例

dmScreenSettings : DEVMODE; // 设备模式

pfd : TPIXELFORMATDESCRIPTOR; //格式描述符

Begin

h_Instance := GetModuleHandle(Nil); // 取得窗口的实例

ZeroMemory(@wndClass, SizeOf(wndClass)); // 初始化内存

With wndClass Do // 设置窗口类

Begin

style := CS_HREDRAW Or // 如果长度变化,

CS_VREDRAW Or // 如果高度变化,就是只要变化就强制重画

CS_OWNDC; //CS_OWNDC为窗口创建一个私有的DC。这意味着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 := ''; // 不需要菜单

lpszClassName := 'OpenGL'; //设定类名

End;

If (RegisterClass(wndClass) = 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 := PixelDepth; // 每象素所选的色彩深度

dmFields := DM_PELSWIDTH // 设置初始标志为dmPelsWidth

Or DM_PELSHEIGHT // dmPelsHeight 和

Or DM_BITSPERPEL; // dmBitsPerPel

End;

// 转换为全屏模式 ,

//切换成与dmScreenSettings所匹配模式。

//CDS_FULLSCREEN 移去了状态条。

//并保证在来回切换时,没有移动或改变您在桌面上的窗口。

// 转换为全屏模式

If (ChangeDisplaySettings(dmScreenSettings, CDS_FULLSCREEN) =

DISP_CHANGE_FAILED) Then //转换失败

Begin

MessageBox(0, '不能转换为全屏模式!', '错误', MB_OK

Or MB_ICONERROR);

Fullscreen := False;

End;

End;

If (Fullscreen) Then // 仍在全屏模式下

Begin

dwStyle := WS_POPUP Or // 没有边框

WS_CLIPCHILDREN // 要让OpenGL正常运行,这两个属性是必须的。

Or WS_CLIPSIBLINGS; //他们阻止别的窗体在我们的窗体内/上绘图。

dwExStyle := WS_EX_APPWINDOW; // 窗体可见时处于最前面

ShowCursor(False); // 不显示鼠标

End

Else //否则

Begin

dwStyle := WS_OVERLAPPEDWINDOW Or //带标题栏、可变大小的边框、菜单和最大/小化按钮

WS_CLIPCHILDREN Or // 要让OpenGL正常运行,这两个属性是必须的。

WS_CLIPSIBLINGS; //他们阻止别的窗体在我们的窗体内/上绘图。

dwExStyle := WS_EX_APPWINDOW Or // 增强窗体的3D感观

WS_EX_WINDOWEDGE; // 边框为凸起

ShowCursor(false); // 不显示鼠标

End;

//创建一个窗体

h_Wnd := CreateWindowEx(dwExStyle, // 扩展窗体风格

'OpenGL', // 类名

WND_TITLE, // 标题

dwStyle, // 窗体属性

0, 0, // 窗体位置

Width, Height, // 窗体大小

0, // 没有父窗体

0, // 没有菜单

h_Instance, // 实例句柄

Nil); // 不向WM_CREATE传递任何东东

If h_Wnd = 0 Then // 创建失败,销毁窗体

Begin

glKillWnd(Fullscreen);

MessageBox(0, '不能创建窗体!', '错误', MB_OK Or

MB_ICONERROR);

Result := False;

Exit;

End;

// 描述象素格式

//选择了通过RGBA(红、绿、蓝、alpha通道)支持OpenGL和双缓存的格式。

//试图找到匹配选定的色彩深度(16位、24位、32位)的象素格式。

//最后设置16位Z-缓存。

//其余的参数要么未使用要么不重要

//(stencil buffer模板缓存和accumulation buffer聚集缓存除外)。

With pfd Do

Begin

nSize := SizeOf(TPIXELFORMATDESCRIPTOR); // 格式描述符大小

nVersion := 1; // 版本号

dwFlags := PFD_DRAW_TO_WINDOW // 格式必须支持窗口

Or PFD_SUPPORT_OPENGL // 格式必须支持OpenGL

Or PFD_DOUBLEBUFFER; // 必须支持双缓冲

iPixelType := PFD_TYPE_RGBA; // 申请 RGBA 格式

cColorBits := PixelDepth; // 选定色彩深度

cRedBits := 0; // 忽略的色彩位

cRedShift := 0; // 忽略的色彩位

cGreenBits := 0; // 忽略的色彩位

cGreenShift := 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; // 保留

dwLayerMask := 0; // 忽略层遮罩

dwVisibleMask := 0; // 忽略层遮罩

dwDamageMask := 0; // 忽略层遮罩

End;

//得到设备场景描述

h_DC := GetDC(h_Wnd);

If (h_DC = 0) Then

Begin

glKillWnd(Fullscreen); // 创建失败,销毁窗体

MessageBox(0, '不能得到设备场景!', '错误', MB_OK Or

MB_ICONERROR);

Result := False;

Exit;

End;

//找到相应的象素格式

PixelFormat := ChoosePixelFormat(h_DC, @pfd);

If (PixelFormat = 0) Then

Begin

glKillWnd(Fullscreen);

MessageBox(0, '找不到合适的格式', '错误', MB_OK

Or MB_ICONERROR);

Result := False;

Exit;

End;

//设置像素格式.

If (Not SetPixelFormat(h_DC, PixelFormat, @pfd)) Then

Begin

glKillWnd(Fullscreen);

MessageBox(0, '无法创建渲染格式', '错误', MB_OK Or

MB_ICONERROR);

Result := False;

Exit;

End;

//取得着色描述表

h_RC := wglCreateContext(h_DC);

If (h_RC = 0) Then

Begin

glKillWnd(Fullscreen);

MessageBox(0, '无法创建OpenGL 绘制描述表', '错误',

MB_OK Or MB_ICONERROR);

Result := False;

Exit;

End;

//已经取得了设备描述表和着色描述表。

//激活着色描述表

If (Not wglMakeCurrent(h_DC, h_RC)) Then

Begin

glKillWnd(Fullscreen);

MessageBox(0, 'Unable to activate OpenGL rendering context', 'Error',

MB_OK Or MB_ICONERROR);

Result := False;

Exit;

End;

//OpenGL窗口已经创建完成

// 显示窗体,置于最前

ShowWindow(h_Wnd, SW_SHOW); // 显示窗口

SetForegroundWindow(h_Wnd); // 略略提高优先级

SetFocus(h_Wnd); // 设置键盘的焦点至此窗口

glResizeWnd(Width, Height); // 设置透视 GL 屏幕

glInit(); // 初始化新建的GL窗口

Result := True;

End;

Function WinMain(hInstance: HINST; //实例

hPrevInstance: HINST; // 前一个实例

lpCmdLine: PChar; // 命令行参数

nCmdShow: Integer // 窗口显示状态

): Integer; stdcall;

Var

msg : TMsg; // Windowsx消息结构

finished : Boolean; // 用来退出循环的Bool 变量

Begin

finished := False;

//应用程序初始化

//glCreateWnd,创建窗体为800*600

If Not glCreateWnd(800, 600, false, 32) Then

Begin

Result := 0;

Exit;

End;

While Not finished Do

Begin

//检查一个线程消息队列,将所选的范围保存到消息纪录中

//BOOL PeekMessage(

// LPMSG lpMsg, // 消息记录的指针

// HWND hWnd, // 窗口句柄

// UINT wMsgFilterMin, // 第一个消息

// UINT wMsgFilterMax, // 最后一个消息

// UINT wRemoveMsg // 标志 Value Meaning

// ); PM_NOREMOVE 处理后保留在消息队列中

// PM_REMOVE 处理后从消息队列中清除

//要做的第一件事是检查是否有消息在等待。

//使用PeekMessage()可以在不锁住我们的程序的前提下对消息进行检查。

//许多程序使用GetMessage(),也可以很好的工作。

//但使用GetMessage(),程序在收到paint消息或其他别的什么窗口消息之前不会做任何事。

If (PeekMessage(msg, 0, 0, 0, PM_REMOVE)) Then //检查是否有消息

// wMsgFilterMin,wMsgFilterMax 这两个参数都为0,返回所有可用的消息

Begin

If (msg.message = WM_QUIT) Then // 如果是退出消息

finished := True //改变循环条件,退出

Else

Begin // 否则处理消息

// 翻译消息,然后发送消息,使得WndProc() 或 Windows能够处理他们。

TranslateMessage(msg); //翻译消息

DispatchMessage(msg); //发送消息

End;

End

Else //如果没有消息,绘制我们的OpenGL场景。

Begin

glDraw(); // 重画屏幕

SwapBuffers(h_DC); // 交换缓存 (双缓存)

If (keys[VK_ESCAPE]) Then // 如果按下了ESC键

finished := True

End;

End;

glKillWnd(FALSE); // 释放窗体

Result := msg.wParam; // 退出程序

End;

Begin

WinMain(hInstance, hPrevInst, CmdLine, CmdShow);

End.

这段代码的功能是设置一个 OpenGL窗口。它可以只是一个窗口或是全屏幕的、可以任意 大小、任意色彩深度。此处的代码很稳定且很强大,您可以在您所有的OpenGL项目中使用。我会尽量在学习NeHe教程的同时将他翻译成Delphi版的。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有