编写 OpenGL 程序的基本步骤 之 为三角体和立方体贴上位图 (0分)

  • 主题发起人 小雨哥
  • 开始时间

小雨哥

Unregistered / Unconfirmed
GUEST, unregistred user!
{***************************************************************
* Name : Project7.dpr ; LoadTex.pas ; Texture.bmp
* Purpose : 解释编写基本 OpenGL 程序的步骤及其程序的一般结构
* Author : 小雨哥 by 2003.1.12 DFW
* History : 绘制旋转的一个立体三角和一个立方体并贴图和透明
***************************************************************}
program Project7;

uses
Windows, Messages, OpenGL, LoadTex;

{--------------------------------------------------------------}
{ 下面定义一些全局变量 }
{--------------------------------------------------------------}
const
WND_TITLE = 'OpenGL First Texture Map'; // 窗口标题
var
h_Wnd : HWND; // 窗口句柄
h_DC : HDC; // 设备描述表
h_RC : HGLRC; // OpenGL 着色描述表
keys : Array[0..255] of Boolean; // 监控键盘动作的数组
active:Boolean; // 窗口活动标志
fullscreen:Boolean; // 全屏幕标志
rtri:GLfloat; // 控制三角形的旋转角度
TRIANGLES_Z, // 控制三角前后移动
QUADS_Z, // 控制立方前后移动
Axis_X, // 控制整体左右移动
xrot,yrot,zrot:GLfloat; // 控制立方 X Y Z 旋转量
Transparence:Boolean; // 控制是否打开透明选项
Texture:GLuint; // 存储一个纹理

// {$R *.RES}

{--------------------------------------------------------------}
{ 下面代码的作用是当窗口大小变化时重新设置 OpenGL 场景的大小 }
{--------------------------------------------------------------}
procedure glResizeWnd(Width, Height : Integer);
begin
if (Height = 0) then // 防止在设置透视时被 0 除
Height := 1; // 将 Height 设为 1
glViewport(0, 0, Width, Height); // 重置当前的视口
glMatrixMode(GL_PROJECTION); // 选择投影矩阵
glLoadIdentity(); // 重置投影矩阵
gluPerspective(45.0, Width/Height, 1.0, 100.0); // 安排透视。按 45 度透视角记算,1.0
// 和 100.0 是场景中所能绘制深度的起点和终点
glMatrixMode(GL_MODELVIEW); // 选择模型观察矩阵
glLoadIdentity(); // 重置模型观察矩阵
end;

{--------------------------------------------------------------}
{ 窗口过程。响应和处理所有的窗口消息 }
{--------------------------------------------------------------}
function WndProc(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
begin
Result := 0;
case (Msg) of
WM_CREATE:
begin
// 窗口创建时需要执行的代码可以放在这里
end;
WM_ACTIVATE:
begin
if (LOWORD(wParam)=WA_INACTIVE) or (HIWORD(wParam)<>0) then // 窗口不是活动的或窗口是最小化的
active:=FALSE
else
active:=True;
end;
WM_CLOSE:
begin
PostQuitMessage(0);
Result := 0
end;
WM_KEYDOWN: // 当键盘按下时,以 WParam 值做下标,填写 keys 数组,标识按下了哪个键
begin
keys[wParam] := True;
Result := 0;
end;
WM_KEYUP: // 当键盘释放时,将 WParam 值为下标的 keys 数组单元复位
begin
keys[wParam] := False;
Result := 0;
end;
WM_SIZE: // 缩放窗口后需要对 OpenGL 进行一些初始化
begin
glResizeWnd(LOWORD(lParam),HIWORD(lParam));
Result := 0;
end;
else
Result := DefWindowProc(hWnd, Msg, wParam, lParam);
end;
end;

{--------------------------------------------------------------}
{ 下面的代码将对 OpenGL 进行所有的初始化处理 }
{--------------------------------------------------------------}
procedure glInit();
begin
if not LoadTexture('Texture.bmp', Texture) then // 加载纹理位图(纹理位图的宽高必须 < 256 个象素且
// 是 2^n 倍,如 8,16,32,64,128,256,本例使用 64*64)
MessageBox(0, PChar('错误的图片数据'), PChar('OpenGL Init'), MB_OK);

glEnable(GL_TEXTURE_2D); // 启用纹理映射

glShadeModel(GL_SMOOTH); // 启用阴影平滑
glClearColor(0.5, 0.0, 0.0, 0.0); // 设置清除屏幕所用的颜色(红,绿,蓝,Alpha)
glClearDepth(1.0); // 设置深度缓存
glEnable(GL_DEPTH_TEST); // 启用深度测试
glDepthFunc(GL_LESS); // 所作深度测试的类型
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 告诉 OpenGL 作精细的透视修正

glBlendFunc(GL_SRC_ALPHA,GL_ONE); // 基于源象素 Alpha 通道值的半透明混合函数
end;

{--------------------------------------------------------------}
{ OpenGL 所有的绘图处理,其实都在下面 }
{--------------------------------------------------------------}
procedure glDraw();
begin
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度缓存
glLoadIdentity(); // 重置当前的模型观察矩阵

glBindTexture(GL_TEXTURE_2D, texture); // 选择纹理

glTranslatef(Axis_X-1.7,0.0,TRIANGLES_Z); // 左移 1.7 单位,并移入屏幕 7.0
// glRotatef(rtri,0.0,1.0,0.0); // 绕Y轴旋转三角形
glRotatef(rtri,1.0,0.5,-1.0); // 绕Y轴旋转三角形

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); // 纹理混合对象背景环境

glBegin(GL_TRIANGLES); // 绘制三角形 (仅有一面贴图) (GL_TRIANGLES 必须是三个顶点为一组地画)
glColor3f(1.0,0.0,0.0); // 红色
glTexCoord2f(1.0, 1.0); // 针对上顶点贴纹理
glVertex3f( 0.0, 1.0, 0.0); // 三角形的上顶点 (前侧面)
glColor3f(0.0,1.0,0.0); // 绿色
glTexCoord2f(0.0, 0.0); // 针对左下顶点贴纹理
glVertex3f(-1.0,-1.0, 1.0); // 三角形的左下顶点 (前侧面)
glColor3f(0.0,0.0,1.0); // 蓝色
glTexCoord2f(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,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); // 三角形的右下顶点 (后侧面)

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(); // 重置模型观察矩阵
glTranslatef(Axis_X+1.7,0.0,QUADS_Z); // 右移1.7单位,并移入屏幕 8.0,比前面例子移动多一点

glRotatef(xrot,1.0,0.0,0.0); // 绕X轴旋转
glRotatef(yrot,0.0,1.0,0.0); // 绕Y轴旋转
glRotatef(zrot,0.0,0.0,1.0); // 绕Z轴旋转

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); // 纹理不混合对象背景环境

glBegin(GL_QUADS); // 绘制正方形 (GL_QUADS 必须是四个顶点为一组地画)
// 前面
glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, -1.0, 1.0); // 纹理和四边形的左下
glTexCoord2f(1.0, 0.0); glVertex3f( 1.0, -1.0, 1.0); // 纹理和四边形的右下
glTexCoord2f(1.0, 1.0); glVertex3f( 1.0, 1.0, 1.0); // 纹理和四边形的右上
glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, 1.0, 1.0); // 纹理和四边形的左上
// 后面
glTexCoord2f(1.0, 0.0); glVertex3f(-1.0, -1.0, -1.0); // 纹理和四边形的右下
glTexCoord2f(1.0, 1.0); glVertex3f(-1.0, 1.0, -1.0); // 纹理和四边形的右上
glTexCoord2f(0.0, 1.0); glVertex3f( 1.0, 1.0, -1.0); // 纹理和四边形的左上
glTexCoord2f(0.0, 0.0); glVertex3f( 1.0, -1.0, -1.0); // 纹理和四边形的左下
// 顶面
glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, 1.0, -1.0); // 纹理和四边形的左上
glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, 1.0, 1.0); // 纹理和四边形的左下
glTexCoord2f(1.0, 0.0); glVertex3f( 1.0, 1.0, 1.0); // 纹理和四边形的右下
glTexCoord2f(1.0, 1.0); glVertex3f( 1.0, 1.0, -1.0); // 纹理和四边形的右上
// 底面
glTexCoord2f(1.0, 1.0); glVertex3f(-1.0, -1.0, -1.0); // 纹理和四边形的右上
glTexCoord2f(0.0, 1.0); glVertex3f( 1.0, -1.0, -1.0); // 纹理和四边形的左上
glTexCoord2f(0.0, 0.0); glVertex3f( 1.0, -1.0, 1.0); // 纹理和四边形的左下
glTexCoord2f(1.0, 0.0); glVertex3f(-1.0, -1.0, 1.0); // 纹理和四边形的右下
// 右面
glTexCoord2f(1.0, 0.0); glVertex3f( 1.0, -1.0, -1.0); // 纹理和四边形的右下
glTexCoord2f(1.0, 1.0); glVertex3f( 1.0, 1.0, -1.0); // 纹理和四边形的右上
glTexCoord2f(0.0, 1.0); glVertex3f( 1.0, 1.0, 1.0); // 纹理和四边形的左上
glTexCoord2f(0.0, 0.0); glVertex3f( 1.0, -1.0, 1.0); // 纹理和四边形的左下
// 左面
glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, -1.0, -1.0); // 纹理和四边形的左下
glTexCoord2f(1.0, 0.0); glVertex3f(-1.0, -1.0, 1.0); // 纹理和四边形的右下
glTexCoord2f(1.0, 1.0); glVertex3f(-1.0, 1.0, 1.0); // 纹理和四边形的右上
glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, 1.0, -1.0); // 纹理和四边形的左上
glEnd(); // 正方形绘制结束

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

xrot:=xrot+1.0; // X 轴旋转
yrot:=yrot+2.0; // Y 轴旋转
zrot:=zrot+3.2; // Z 轴旋转
end;

{--------------------------------------------------------------}
{ 销毁 OpenGL 占用的资源和程序窗口,防止内存泄露 }
{--------------------------------------------------------------}
procedure glKillWnd(Fullscreen : Boolean);
begin
if Fullscreen then // 检查是否处于全屏模式
begin
ChangeDisplaySettings(devmode(nil^), 0); // 是的话,切换回桌面
ShowCursor(True); // 显示鼠标指针
end;

if (not wglMakeCurrent(h_DC, 0)) then // 可以释放着色描述表和设备描述表吗
MessageBox(0, '释放 DC 和 RC 失败', 'Error', MB_OK or MB_ICONERROR);

if (not wglDeleteContext(h_RC)) then // 能删除着色描述表吗
begin
MessageBox(0, '释放 rendering context (RC) 失败', 'Error', MB_OK or MB_ICONERROR);
h_RC := 0; // 将着色描述表设为 0
end;

if ((h_DC = 1) and (ReleaseDC(h_Wnd, h_DC) <> 0)) then // 能释放设备描述表吗
begin
MessageBox(0, '释放 device context (DC) 失败', 'Error', MB_OK or MB_ICONERROR);
h_DC := 0; // 将设备描述表设为 0
end;

if ((h_Wnd <> 0) and (not DestroyWindow(h_Wnd))) then // 能销毁窗口吗
begin
MessageBox(0, '不能销毁窗口', 'Error', MB_OK or MB_ICONERROR);
h_Wnd := 0; // 将窗口设为 0
end;

if (not UnRegisterClass('OpenGL', hInstance)) then // 能注销窗口类吗
begin
MessageBox(0, '不能注销窗口类', 'Error', MB_OK or MB_ICONERROR);
hInstance := 0; // 将 hInstance 设为 0
end;
end;

{--------------------------------------------------------------}
{ 创建程序窗口和进行 OpenGL 设置 }
{--------------------------------------------------------------}
function glCreateWnd(Width, Height : Integer; Fullscreen : Boolean; PixelDepth : Integer) : Boolean;
var
wndClass : TWndClass;
dwStyle : DWORD;
dwExStyle : DWORD;
dmScreenSettings : DEVMODE;
PixelFormat : GLuint;
h_Instance : HINST;
pfd : TPIXELFORMATDESCRIPTOR;
begin
h_Instance := GetModuleHandle(nil); // 取得窗口的实例
ZeroMemory(@wndClass, SizeOf(wndClass)); // 清除原有的窗口类内容

with wndClass do // 填充窗口类的内容
begin
style := CS_HREDRAW or // 无论何时只要窗口发生变化时就强制重画
CS_VREDRAW or // 无论何时只要窗口发生变化时就强制重画
CS_OWNDC; // 意味着 DC 不能在程序间共享
lpfnWndProc := @WndProc; // 窗口过程以处理消息
hInstance := h_Instance; // 设置实例
hCursor := LoadCursor(0, IDC_ARROW); // 装入鼠标指针
lpszClassName := 'OpenGL'; // 设定类名字
end;

if (RegisterClass(wndClass) = 0) then // 尝试注册窗口类
begin
MessageBox(0, '注册窗口类失败', 'Error', 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 or DM_PELSHEIGHT or DM_BITSPERPEL; // 指明有效域
end;

if (ChangeDisplaySettings(dmScreenSettings, CDS_FULLSCREEN) = DISP_CHANGE_FAILED) then // 尝试设置显示模式并返回结果
begin
MessageBox(0, '无法切换为全屏幕显示', 'Error', MB_OK or MB_ICONERROR);
Fullscreen := False;
end;
end;

if (Fullscreen) then // 仍处于全屏模式吗
begin // 下面的窗口风格在全屏幕时使用
dwStyle := WS_POPUP or // 弹出式
WS_CLIPCHILDREN // OpenGL 程序,必须要有这个风格
or WS_CLIPSIBLINGS; // OpenGL 程序,必须要有这个风格
dwExStyle := WS_EX_APPWINDOW; // 顶级窗体风格
ShowCursor(False); // 隐藏鼠标指针
end
else // 下面的窗口风格在非全屏幕时使用
begin
dwStyle := WS_OVERLAPPEDWINDOW or // 普通窗口
WS_CLIPCHILDREN or // OpenGL 程序,必须要有这个风格
WS_CLIPSIBLINGS; // OpenGL 程序,必须要有这个风格
dwExStyle := WS_EX_APPWINDOW or // 顶级窗体风格
WS_EX_WINDOWEDGE; // 有边框
end;

// 下面创建实际的程序窗口
h_Wnd := CreateWindowEx(dwExStyle, // 窗口的扩展风格
'OpenGL', // 窗口类名
WND_TITLE, // 窗口标题
dwStyle, // 窗口风格
0, 0, // 窗口位置
Width, Height, // 窗口大小
0, // 没有父窗口
0, // 没有菜单
h_Instance, // Instance
nil);
if h_Wnd = 0 then // 检查窗口是否正常创建
begin
glKillWnd(Fullscreen); // 清除所有已经建立的对象
MessageBox(0, '不能创建窗口', 'Error', MB_OK or MB_ICONERROR);
Result := False;
Exit;
end;

// 试着取得 DC
h_DC := GetDC(h_Wnd);
if (h_DC = 0) then
begin
glKillWnd(Fullscreen);
MessageBox(0, '不能取得 device context (DC)', 'Error', MB_OK or MB_ICONERROR);
Result := False;
Exit;
end;

// 下面设置 OpenGL 的内容
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; // 选定 OpenGL 色彩深度
cRedBits := 0; // 红色彩位
cRedShift := 0; // 忽略红色彩位
cGreenBits := 0; // 绿色彩位
cGreenShift := 0; // 忽略绿色彩位
cBlueBits := 0; // 蓝色彩位
cBlueShift := 0; // 忽略蓝色彩位
cAlphaBits := 0; // 不支持 Alpha 位
cAlphaShift := 0; // 忽略 Alpha 位
cAccumBits := 0; // 无积聚缓存
cAccumRedBits := 0; // 忽略红积聚缓存
cAccumGreenBits := 0; // 忽略绿积聚缓存
cAccumBlueBits := 0; // 忽略蓝积聚缓存
cAccumAlphaBits := 0; // 忽略 Alpha 积聚缓存
cDepthBits := 16; // 确定 16位 Z-缓存 (深度缓存)
cStencilBits := 0; // 无模板缓存
cAuxBuffers := 0; // 无辅助缓存
iLayerType := PFD_MAIN_PLANE; // 主绘图层
bReserved := 0; // 保留
dwLayerMask := 0; // 忽略遮罩层
dwVisibleMask := 0; // 忽略透明色
dwDamageMask := 0; // 忽略 Damage 遮罩层
end;

PixelFormat := ChoosePixelFormat(h_DC, @pfd); // 系统找到相应的象素格式了吗
if (PixelFormat = 0) then
begin
glKillWnd(Fullscreen);
MessageBox(0, '找不到相配的象素格式', 'Error', MB_OK or MB_ICONERROR);
Result := False;
Exit;
end;

if (not SetPixelFormat(h_DC, PixelFormat, @pfd)) then // 设置象素格式
begin
glKillWnd(Fullscreen);
MessageBox(0, '无法设置到指定的象素格式', 'Error', 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 着色描述表', 'Error', MB_OK or MB_ICONERROR);
Result := False;
Exit;
end;

if (not wglMakeCurrent(h_DC, h_RC)) then // 尝试激活着色描述表
begin
glKillWnd(Fullscreen);
MessageBox(0, '无法激活 OpenGL 着色描述表', 'Error', MB_OK or MB_ICONERROR);
Result := False;
Exit;
end;

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;
Done : Boolean;
begin
Done := False;
if (MessageBox(0,'希望运行在全屏幕模式?', 'Start FullScreen?',MB_YESNO or MB_ICONQUESTION))=IDYES then
fullscreen:=True;

if not glCreateWnd(640,480,fullscreen, 32) then
begin
Result := 0;
Exit;
end;

{ 其他需要初始化项目,如声音等,可以放在这个位置 }

// 下面进入主消息循环
while not Done do
begin
if (PeekMessage(msg, 0, 0, 0, PM_REMOVE)) then // 选择属于自己的消息
begin
if (keys[VK_ESCAPE]) then // ESC 键按下了吗
Done := True;

if (keys[VK_F4]) then // F4 键按下了吗(允许使用 F4 键在全屏模式和窗口模式间切换)
begin
keys[VK_F4]:=False; // 使对应的 Keys 数组中的值为 FALSE
glKillWnd(fullscreen); // 销毁当前的窗口
fullscreen:=not fullscreen; // 切换 全屏/窗口 模式
if not glCreateWnd(640,480,fullscreen, 32) then // 重建 OpenGL 窗口
begin
Result := 0;
Exit;
end;
end;

if (keys[VK_UP]) then // 前后移动三角
TRIANGLES_Z:=TRIANGLES_Z-0.5;
if (keys[VK_DOWN]) then
TRIANGLES_Z:=TRIANGLES_Z+0.5;

if (keys[VK_PRIOR]) then // 前后移动立方
QUADS_Z:=QUADS_Z-0.5;
if (keys[VK_NEXT]) then
QUADS_Z:=QUADS_Z+0.5;

if (keys[VK_LEFT]) then // 整体左右移动
Axis_X:=Axis_X-0.2;
if (keys[VK_RIGHT]) then
Axis_X:=Axis_X+0.2;

if (keys[Ord('R')]) then // 使各轴复位
begin
TRIANGLES_Z:=-7.0;
QUADS_Z:=-8.0;
Axis_X:=0.0;
end;

if (keys[Ord('T')]) then // 控制透明与否
begin
keys[Ord('T')]:=False;
Transparence:=not Transparence;
if Transparence then
glEnable(GL_BLEND) // 打开透明选项
else glDisable(GL_BLEND); // 关闭透明选项
end;

{ 其他键盘控制代码可以放在这个位置 }

if (msg.message = WM_QUIT) then // 是退出命令
Done := True
else
begin // 进入消息循环
TranslateMessage(msg);
DispatchMessage(msg);
end;
end
else
if active then
begin
glDraw; // 绘制场景
SwapBuffers(h_DC); // 将绘好的画面显示出来(交换缓存)
end
else
begin
SwapBuffers(h_DC); // 重绘非活化时的窗口内容
WaitMessage;
end;
end; // while 循环结束

glKillWnd(fullscreen);
Result := msg.wParam;
end;

{--------------------------------------------------------------}
{ 程序开始 }
{--------------------------------------------------------------}
begin
TRIANGLES_Z:=-7.0;
QUADS_Z:=-8.0;
Axis_X:=0.0;
WinMain( hInstance, hPrevInst, CmdLine, CmdShow );
end.

////////////////////////////////////////////////////////////////////////////
//----------------------------------------------------------------------------
// Author : 改编自 Jan Horn 的 OpenGL 工具函数库 [jhorn@global.co.za]
// Description : 为 OpenGL 建立位图纹理.作为纹理的位图必须是 2^n 且不大于 256
// Usage : LoadTexture(Filename, TextureName);
//----------------------------------------------------------------------------
unit LoadTex;

interface

uses
Windows, OpenGL;

function LoadTexture(Filename: String; var Texture: GLuint): Boolean;
function gluBuild2DMipmaps(Target: GLenum; Components, Width, Height: GLint; Format, atype: GLenum; Data: Pointer): GLint; stdcall; external glu32;
procedure glGenTextures(n: GLsizei; var textures: GLuint); stdcall; external opengl32;
procedure glBindTexture(target: GLenum; texture: GLuint); stdcall; external opengl32;

implementation

{--------------------------------}
{ 将位图的 BGR 格式转换为 RGB }
{--------------------------------}
procedure SwapRGB(data : Pointer; Size : Integer);
asm
mov ebx, eax
mov ecx, size

@@loop :
mov al,[ebx+0]
mov ah,[ebx+2]
mov [ebx+2],al
mov [ebx+0],ah
add ebx,3
dec ecx
jnz @@loop
end;

{------------}
{ 创建纹理 }
{------------}
function CreateTexture(Width, Height, Format : Word; pData : Pointer) : Integer;
var
Texture : GLuint;
begin
glGenTextures(1, Texture); // 产生纹理
glBindTexture(GL_TEXTURE_2D, Texture); // 绑定纹理

{ 过滤类型如下: }
{ GL_NEAREST - 基本类型 }
{ GL_LINEAR - 双线性 }
{ GL_LINEAR_MIPMAP_NEAREST - 基本的 mipmapped 类型 }
{ GL_LINEAR_MIPMAP_LINEAR - 双线性的 Mipmapped 类型 }

{ // 使用 mipmapped 纹理
if Format = GL_RGBA then
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, pData)
else
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, Width, Height, GL_RGB, GL_UNSIGNED_BYTE, pData);
}

{创建可以使用的纹理}
glTexImage2D(GL_TEXTURE_2D, // 告诉 OpenGL 此纹理是一个 2D 纹理
0, // 数字零代表图像的详细程度
3, // 数据的成分数。因为图像是由红色数据,绿色数据,蓝色数据三种组分组成
Width, // 纹理的宽度
Height, // 纹理的高度
0, // 边框的值
GL_RGB, // 告诉 OpenGL 图像数据由红、绿、蓝三色数据组成
GL_UNSIGNED_BYTE, // 指出组成图像的数据是无符号字节类型
pData); // 告诉 OpenGL 纹理数据的来源
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR); // 缩小时使用线形滤波
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR); // 放大时也使用线形滤波
result :=Texture;
end;

{------------------------}
{ 载入 BMP 格式的纹理 }
{------------------------}
function LoadBMPTexture(Filename: String; var Texture : GLuint) : Boolean;
var
FileHeader: BITMAPFILEHEADER;
InfoHeader: BITMAPINFOHEADER;
Palette: array of RGBQUAD;
BitmapFile: THandle;
BitmapLength: LongWord;
PaletteLength: LongWord;
ReadBytes: LongWord;
Width, Height : Integer;
pData : Pointer;
begin
result :=FALSE;

BitmapFile := CreateFile(PChar(Filename), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
if (BitmapFile = INVALID_HANDLE_VALUE) then begin
MessageBox(0, PChar('无法载入位图' + Filename), PChar('BMP Unit'), MB_OK);
Exit;
end;

// 取得纹理位图的头信息
ReadFile(BitmapFile, FileHeader, SizeOf(FileHeader), ReadBytes, nil);
ReadFile(BitmapFile, InfoHeader, SizeOf(InfoHeader), ReadBytes, nil);

// 取得纹理位图的调色板数据
PaletteLength := InfoHeader.biClrUsed;
SetLength(Palette, PaletteLength);
ReadFile(BitmapFile, Palette, PaletteLength, ReadBytes, nil);
if (ReadBytes <> PaletteLength) then begin
MessageBox(0, PChar('不能读调色板'), PChar('BMP Unit'), MB_OK);
Exit;
end;

Width := InfoHeader.biWidth;
Height := InfoHeader.biHeight;
BitmapLength := InfoHeader.biSizeImage;
if BitmapLength = 0 then
BitmapLength := Width * Height * InfoHeader.biBitCount Div 8;

// 取得实际的象素格式
GetMem(pData, BitmapLength);
ReadFile(BitmapFile, pData^, BitmapLength, ReadBytes, nil);
if (ReadBytes <> BitmapLength) then begin
MessageBox(0, PChar('无法读取位图数据'), PChar('BMP Unit'), MB_OK);
Exit;
end;
CloseHandle(BitmapFile);

// 将位图的 BGR 格式转换为 RGB, 调换 R 和 B 的位置.
SwapRGB(pData, Width*Height);

Texture :=CreateTexture(Width, Height, GL_RGB, pData);
FreeMem(pData);
result :=TRUE;
end;

{----------------------}
{ 进行文件格式检查 }
{----------------------}
function LoadTexture(Filename: String; var Texture : GLuint) : Boolean;
function UpperCase(const S: string): string; // 从 SysUtils 单元取出这个函数的目的仅为减小程序体积
var
Ch: Char;
L: Integer;
Source, Dest: PChar;
begin
L := Length(S);
SetLength(Result, L);
Source := Pointer(S);
Dest := Pointer(Result);
while L <> 0 do
begin
Ch := Source^;
if (Ch >= 'a') and (Ch <= 'z') then Dec(Ch, 32);
Dest^ := Ch;
Inc(Source);
Inc(Dest);
Dec(L);
end;
end;
begin
result := False;
if copy(Uppercase(filename), length(filename)-3, 4) = '.BMP' then // 判断 Filename 的扩展名是 .bmp ?
begin
LoadBMPTexture(Filename, Texture);
result :=TRUE;
end;
end;
end.

上面的代码,分别保存为 Project7.dpr 和 LoadTex.pas,同时找一张 64X64 象素的位
图,保存为 Texture.bmp ,放到同一目录下。使用 Delphi5 编译并执行。
其中各按键的作用如下:
Esc : 关闭程序
F4 : 切换 全屏幕/窗口 显示模式
R : 使各个三维轴恢复到初始状态
PageUP : 控制立方体向屏幕内移动
PageDown:控制立方体向屏幕外移动
箭头上 : 控制三角体向屏幕内移动
箭头下 : 控制三角体向屏幕外移动
箭头左 : 画面整体向左移动
箭头右 : 画面整体向右移动
T : 控制半透明效果
=========================================================================
原始问题链接:
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1590427
 
好东西 研究一番 多谢[:)]
 
接受答案了.
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
顶部