📄 basicelectric.dpr
字号:
program basicElectric;
uses
Windows,MMSystem,Messages,OpenGL,SysUtils;
const
APP_TITLE = 'OpenGL小游戏_源自Jan Horn';
FPS_TIMER = 1; // 计算每秒的帧数
FPS_INTERVAL = 1000; // 每秒计算一次帧数
STEPS = 32;
var
h_Wnd : HWND; // 全局窗口句柄
h_DC : HDC; // 全局设备环境变量
h_RC : HGLRC; // OpenGL渲染设备变量
SndHandle : THandle; // 声音设备
keys : Array[0..255] of Boolean; // 处理击键事件
FPSCount : Integer = 0; //每秒帧数的计算器
ElapsedTime : Integer; //帧与帧之间的间隔
background : glUint; //Opengl材质变量
SparkCount : Integer; //闪电次数
y : Array[0..STEPS] of glFloat; //闪电的y和z轴的位置
{$R sound.res}
procedure SwapRGB(data : Pointer; Size : Integer);
asm //将位图格式从BGR转化为RGB
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;
// 加载位图
procedure LoadBitmap(Filename: String; out Width: Cardinal; out Height: Cardinal; out pData: Pointer);
var
FileHeader: TBITMAPFILEHEADER;
InfoHeader: TBITMAPINFOHEADER;
Palette: array of RGBQUAD;
BitmapFile: THandle;
BitmapLength: LongWord;
PaletteLength: LongWord;
ReadBytes: LongWord;
begin
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('错误提示1'), 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('错误提示2'), 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('错误提示3'), MB_OK);
Exit;
end;
CloseHandle(BitmapFile);
SwapRGB(pData, Width*Height); // 位图信息保存为BGR模式,而不是RGB模式
end;
//加载BMP材质
function LoadTexture(Filename: String; var Texture: GLuint): Boolean;
var
pData: Pointer;
Width: LongWord;
Height: LongWord;
begin
pData :=nil;
LoadBitmap(Filename, Width, Height, pData);
if (Assigned(pData)) then
Result := True
else
begin
Result := False;
MessageBox(0, PChar('不能打开文件:' + filename), '加载材质', MB_OK);
Halt(1);
end;
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); //材质和对象背景混合
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, Width, Height, GL_RGB, GL_UNSIGNED_BYTE, pData);
end;
procedure glDraw(); //绘制真实场景
var I, J : Integer;
rnd : glFloat;
begin
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度缓冲区
glLoadIdentity(); // 重新设置视图
glTranslatef(0.0, 0.0, -3);
// 画背景
glEnable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glColor3f(Random(10)/10,0.5,1); //场景颜色不断变化
glBegin(GL_QUADS);
glTexCoord(0, 0); glVertex(-4, -4, -5);
glTexCoord(1, 0); glVertex( 4, -4, -5);
glTexCoord(1, 1); glVertex( 4, 4, -5);
glTexCoord(0, 1); glVertex(-4, 4, -5);
glEnd;
glrotate(ElapsedTime/40, 0, 1, 0); // 旋转场景
for I :=1 to STEPS-2 do // 计算新的Y坐标
begin
y[I] :=y[I] + 0.1*(random-0.5);
if y[I] > y[I-1] + 0.075 then y[I] :=y[I-1]+0.075;
if y[I] < y[I-1] - 0.075 then y[I] :=y[I-1]-0.075;
if y[I] > y[I+1] + 0.075 then y[I] :=y[I+1]+0.075;
if y[I] < y[I+1] - 0.075 then y[I] :=y[I+1]-0.075;
if y[I] > 0.5 then y[I] :=0.5;
if y[I] < -0.5 then y[I] :=-0.5;
end;
// 绘制闪电
glDisable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glColor3f(Random(10)/10, Random(10)/20+0.3, 0.6); //闪电颜色不断变化
for I :=1 to SparkCount do
begin
glBegin(GL_TRIANGLE_STRIP);
for J :=0 to STEPS-1 do
begin
rnd :=0.04*(Random-0.5);
glVertex3f(-1 + 2*J/STEPS + rnd, -0.01 + y[J] + rnd, rnd);
glVertex3f(-1 + 2*J/STEPS + rnd, +0.01 + y[J] + rnd, rnd);
end;
glEnd();
end;
end;
procedure glInit(); //初始化Opengl
begin
glClearColor(0.0, 0.0, 0.0, 0.0); // 指定Opengl背景颜色
glShadeModel(GL_SMOOTH); // 指定平滑颜色阴影
glClearDepth(1.0); // 深度缓冲设置
glEnable(GL_DEPTH_TEST); // 激活深度缓冲
glDepthFunc(GL_LESS); //指定深度测试类型
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); //实际视角计算
glEnable(GL_TEXTURE_2D); // 激活材质映射
LoadTexture('background.bmp', background); //可以加载自定义位图文件
//使闪电的起点和终点都指向0
SparkCount :=16;
y[0] :=0.0;
y[STEPS-1] :=0.0;
end;
procedure glResizeWnd(Width, Height : Integer); //处理窗口事件
begin
if (Height = 0) then
Height := 1;
glViewport(0, 0, Width, Height); // 设置OpenGL视口
glMatrixMode(GL_PROJECTION); // 改变工程的矩阵模式
glLoadIdentity(); // 重新设置视图
gluPerspective(45.0, Width/Height, 1.0, 100.0); //进行视角计算
glMatrixMode(GL_MODELVIEW); // 返回模型视图矩阵
glLoadIdentity(); // 重新设置视图
end;
//处理键盘信息
procedure ProcessKeys;
begin
if Keys[VK_ADD] then //处理"+"键
begin
Inc(SparkCount);
Keys[VK_ADD] :=FALSE;
end;
if Keys[VK_SUBTRACT] then //处理"-"键
begin
Dec(SparkCount);
if SparkCount < 1 then
SparkCount :=1;
Keys[VK_SUBTRACT] :=FALSE;
end;
end;
//处理程序信息
function WndProc(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
begin
case (Msg) of
WM_CLOSE: //程序关闭
begin
PostQuitMessage(0);
Result := 0
end;
WM_KEYDOWN: // 处理"↓"键
begin
keys[wParam] := True;
Result := 0;
end;
WM_KEYUP: // 处理"↑"键
begin
keys[wParam] := False;
Result := 0;
end;
WM_SIZE: // 重新设置窗口大小
begin
glResizeWnd(LOWORD(lParam),HIWORD(lParam));
Result := 0;
end;
WM_TIMER : // 设置定时器
begin
if wParam = FPS_TIMER then
begin
FPSCount :=Round(FPSCount * 1000/FPS_INTERVAL); // 计算帧数
SetWindowText(h_Wnd, PChar(APP_TITLE + ',[' + IntToStr(FPSCount) + ' 帧/秒],线程=' + intToStr(SparkCount)));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -