Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Dokument1.doc
Скачиваний:
14
Добавлен:
05.09.2019
Размер:
705.02 Кб
Скачать

3. Приложения

Приложение 1

Инструкция для пользователя

Минимальные технические требования: процессор Pentium II, 16Мб оперативной памяти, OpenGL-совместимая видеокарта, 2Мб на жестком диске. В системе должен быть установлен шрифт Bookman Old Style.

Программа имитации бомбометания состоит из одного исполняемого файла (bomber.exe) и не требует установки. После запуска указанного файла на экране появляется окно настроек имитационной модели:

В списке «Размер окна вывода ролика» выбирается размер окна, в который будет выводиться имитационный ролик. Качество вывода ролика зависит от возможностей видеокарты. На слабых видеокартах при больших размерах окна может наблюдаться прерывистость вывода ролика. На современных машинах при любых размерах окна ролик будет выводиться плавно.

В списке «Количество сбрасываемых бомб» выбирается число сбрасываемых самолетом бомб. Их число варьируется от одной до четырех.

В списке «Тип бомбометания» выбирается тип имитации: либо серийное бомбометание по мосту с последовательным углом захода самолета от 0 до 90 градусов, либо одиночное бомбометание с углом захода, выбранном в списке «Угол захода самолета на мост».

После нажатия кнопки «Имитация» появится окно, в которое и будет выводиться ролик:

Помимо визуализации самого бомбометания в окно выводится угол захода самолета и вероятность разрушения моста.

После каждого захода самолета и визуализации падения бомб, на экран выводится окно результатов бомбардировки:

Окно содержит информацию об угле захода самолета, координат падения бомб, качестве бомбометания (отношение количества попавших бомб к общему их количеству) и схему падения бомб относительно моста.

Приложение 2

Блок-схема алгоритма

Ниже приведены блок-схемы алгоритма генерации случайных чисел, распределенных по нормальному закону распределения (слева) и блок-схема алгоритма имитации серийного бомбометания (справа):

Приложение 3

Листинг программы

program bomber;

{$r dialog.res}

{$r models.res}

{$r textures.res}

uses

bm_core in 'bm_core.pas',

bm_wind in 'bm_wind.pas',

bm_rend in 'bm_rend.pas',

bm_timer in 'bm_timer.pas',

bm_river in 'bm_river.pas',

bm_scene in 'bm_scene.pas',

bm_file in 'bm_file.pas',

bm_tga in 'bm_tga.pas',

bm_mem in 'bm_mem.pas',

bm_graph in 'bm_graph.pas',

bm_model in 'bm_model.pas',

bm_dlg in 'bm_dlg.pas',

bm_brid in 'bm_brid.pas',

bm_plane in 'bm_plane.pas',

bm_math in 'bm_math.pas',

bm_effct in 'bm_effct.pas',

bm_expl in 'bm_expl.pas';

begin

Randomize ();

Bomber_Simulate ();

end.

unit bm_core;

interface

const

FULL_SCREEN = FALSE;

DEBUG_MODE = FALSE;

DEBUG_FONT_FACE = 'Bookman Old Style';

DEBUG_FONT_SIZE = 11;

RENDER_FOV = 45.0;

RENDER_DISTANCE = 1000;

BRIDGE_LENGTH = 110;

BRIDGE_WIDTH = 10;

var

WINDOW_WIDTH: INTEGER = 640;

WINDOW_HEIGHT: INTEGER = 480;

DEBUG_FONT_HEIGHT: INTEGER = 13;

procedure Bomber_FatalError (Text: STRING);

function Bomber_Simulate (): BOOLEAN;

function Bomber_KeyDown (key: BYTE): BOOLEAN;

function IntToStr (l: LONGINT): STRING;

function FloatToStr (e: EXTENDED; precision, digits: INTEGER): STRING;

implementation

uses

Windows,

Messages,

OpenGL,

bm_dlg,

bm_timer,

bm_wind,

bm_rend,

bm_model,

bm_brid,

bm_plane,

bm_river,

bm_expl,

bm_scene,

bm_effct;

function CoreInitialize (): BOOLEAN;

begin

if (not Bomber_DialogExecute ()) then

begin

result := FALSE;

Exit;

end;

if (not Bomber_TimerInitialize ()) then

begin

result := FALSE;

Exit;

end;

if (not Bomber_WindowInitialize ()) then

begin

result := FALSE;

Exit;

end;

if (not Bomber_RendInitialize ()) then

begin

result := FALSE;

Exit;

end;

if (not Bomber_ModelInitialize ()) then

begin

result := FALSE;

Exit;

end;

if (not Bomber_BridgeInitialize ()) then

begin

result := FALSE;

Exit;

end;

if (not Bomber_PlaneInitialize ()) then

begin

result := FALSE;

Exit;

end;

if (not Bomber_RiverInitialize ()) then

begin

result := FALSE;

Exit;

end;

if (not Bomber_ExploInitialize ()) then

begin

result := FALSE;

Exit;

end;

if (not Bomber_EffectInitialize ()) then

begin

result := FALSE;

Exit;

end;

if (not Bomber_SceneInitialize ()) then

begin

result := FALSE;

Exit;

end;

result := TRUE;

end;

procedure CoreRelease ();

begin

Bomber_SceneRelease ();

Bomber_RiverRelease ();

Bomber_BridgeRelease ();

Bomber_ModelRelease ();

Bomber_RendRelease ();

Bomber_WindowRelease ();

Bomber_TimerRelease ();

end;

procedure CoreRunLoop ();

var

msg: TMSG;

dc: HDC;

begin

dc := wglGetCurrentDC ();

Bomber_TimerStart ();

while (TRUE) do

begin

if (PeekMessage (msg, 0, 0, 0, PM_REMOVE)) then

if (msg.message <> WM_QUIT) then

begin

TranslateMessage (msg);

DispatchMessage (msg);

end

else

Break;

if (not Bomber_SceneDraw ()) then

Break;

glViewPort (0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);

Bomber_EffectDraw ();

if (DEBUG_MODE) then

Bomber_RendDrawText (0, 10, 'fps: ' + IntToStr (Round (Bomber_TimerGetFps ())));

Bomber_TimerWait ();

SwapBuffers (dc);

end;

end;

function Bomber_Simulate (): BOOLEAN;

begin

if (CoreInitialize ()) then

begin

CoreRunLoop ();

CoreRelease ();

result := TRUE;

end

else

begin

CoreRelease ();

result := FALSE;

end;

end;

function Bomber_KeyDown (key: BYTE): BOOLEAN;

begin

result := GetAsyncKeyState (key) and $8000 <> 0;

end;

procedure Bomber_FatalError (Text: STRING);

begin

MessageBox (0, PCHAR (Text), 'Ошибка', MB_OK or MB_ICONERROR or MB_TASKMODAL);

end;

function IntToStr (l: LONGINT): STRING;

var

s: STRING;

begin

Str (l, s);

result := s;

end;

function FloatToStr (e: EXTENDED; precision, digits: INTEGER): STRING;

var

s: STRING;

begin

Str (e : precision : digits, s);

result := s;

end;

end.

unit bm_wind;

interface

function Bomber_WindowInitialize (): BOOLEAN;

procedure Bomber_WindowRelease ();

implementation

uses

Windows,

Messages,

OpenGL,

bm_core;

const

CLASS_NAME = 'BOMBER_CLASS';

var

wndClass: TWNDCLASS;

handle: HWND;

dc: HDC;

glrc: HGLRC;

function GetMaxFreq (): DWORD;

var

devMode: TDEVMODE;

mode, freq: INTEGER;

begin

mode := 0;

freq := -1;

ZeroMemory (@devMode, sizeof (devMode));

devMode.dmSize := sizeof (devMode);

while (EnumDisplaySettings (nil, mode, devMode)) do

begin

if (devMode.dmBitsPerPel = 32)

and (INTEGER (devMode.dmPelsWidth) = WINDOW_WIDTH)

and (INTEGER (devMode.dmPelsHeight) = WINDOW_HEIGHT)

and (LONGINT (devMode.dmDisplayFrequency) > freq) then

freq := devMode.dmDisplayFrequency;

inc (mode);

end;

result := freq;

end;

function OnCreate (wnd: HWND): BOOLEAN;

var

pfd: PIXELFORMATDESCRIPTOR;

format: DWORD;

begin

ZeroMemory (@pfd, sizeof (pfd));

pfd.nSize := sizeof (pfd);

pfd.nVersion := 1;

pfd.dwFlags := PFD_DOUBLEBUFFER or PFD_SUPPORT_OPENGL or PFD_DRAW_TO_WINDOW;

pfd.cColorBits := 32;

pfd.cDepthBits := 24;

pfd.iLayerType := PFD_MAIN_PLANE;

pfd.iPixelType := PFD_TYPE_RGBA;

dc := GetDC (wnd);

if (dc = 0) then

begin

Bomber_FatalError ('Ошибка получения DC. Код '+IntToStr (GetLastError()));

result := FALSE;

Exit;

end;

format := ChoosePixelFormat (dc, @pfd);

if (format = 0) then

begin

Bomber_FatalError ('Ошибка выбора формата пикселя. Код '+IntToStr (GetLastError()));

result := FALSE;

Exit;

end;

if (not SetPixelFormat (dc, format, @pfd)) then

begin

Bomber_FatalError ('Ошибка установки формата пикселя. Код '+IntToStr (GetLastError()));

result := FALSE;

Exit;

end;

glrc := wglCreateContext (dc);

if (glrc = 0) then

begin

Bomber_FatalError ('Ошибка создания GLRC. Код '+IntToStr (GetLastError()));

result := FALSE;

Exit;

end;

if (not wglMakeCurrent (dc, glrc)) then

begin

Bomber_FatalError ('Ошибка установки GLRC. Код '+IntToStr (GetLastError()));

result := FALSE;

Exit;

end;

result := TRUE;

end;

procedure OnDestroy ();

begin

if (glrc <> 0) then

begin

wglMakeCurrent (0, 0);

wglDeleteContext (glrc);

glrc := 0;

end;

if (dc <> 0) then

begin

ReleaseDC (handle, dc);

dc := 0;

end;

end;

function WndProc (wnd: HWND; msg: UINT; wpar: WPARAM; lpar: LPARAM): LRESULT; stdcall;

begin

case (msg) of

WM_CREATE:

begin

if (not OnCreate (wnd)) then

begin

result := -1;

Exit;

end;

end;

WM_DESTROY:

begin

OnDestroy ();

end;

WM_CLOSE:

begin

PostQuitMessage (0);

end;

else

begin

result := DefWindowProc (wnd, msg, wpar, lpar);

Exit;

end;

end;

result := 0;

end;

function Bomber_WindowInitialize (): BOOLEAN;

var

devMode: TDEVMODE;

style, exStyle: DWORD;

rc: TRECT;

begin

ZeroMemory (@wndClass, sizeof (wndClass));

wndClass.style := CS_OWNDC;

wndClass.lpfnWndProc := @WndProc;

wndClass.hInstance := GetModuleHandle (nil);

wndClass.hIcon := LoadIcon (0, IDI_APPLICATION);

wndClass.hCursor := LoadCursor (0, IDC_ARROW);

wndClass.hbrBackground := GetStockObject (BLACK_BRUSH);

wndClass.lpszClassName := CLASS_NAME;

if (RegisterClass (wndClass) = 0) then

begin

Bomber_FatalError ('Ошибка регистрации класса окна. Код '+IntToStr (GetLastError()));

result := FALSE;

Exit;

end;

if (FULL_SCREEN) then

begin

ZeroMemory (@devMode, sizeof (devMode));

devMode.dmSize := sizeof (devMode);

devMode.dmFields := DM_PELSWIDTH or DM_PELSHEIGHT or DM_BITSPERPEL or DM_DISPLAYFREQUENCY;

devMode.dmPelsWidth := WINDOW_WIDTH;

devMode.dmPelsHeight := WINDOW_HEIGHT;

devMode.dmBitsPerPel := 32;

devMode.dmDisplayFrequency := GetMaxFreq ();

if (ChangeDisplaySettings (devMode, CDS_FULLSCREEN) <> 0) then

begin

Bomber_FatalError ('Ошибка установки режима экрана');

result := FALSE;

Exit;

end;

style := WS_POPUP;

exStyle := WS_EX_TOPMOST;

rc.Left := 0;

rc.Top := 0;

rc.Right := WINDOW_WIDTH;

rc.Bottom := WINDOW_HEIGHT;

end

else

begin

style := WS_POPUP;

exStyle := WS_EX_DLGMODALFRAME;

rc.Left := GetSystemMetrics (SM_CXSCREEN) div 2 - WINDOW_WIDTH div 2;

rc.Top := GetSystemMetrics (SM_CYSCREEN) div 2 - WINDOW_HEIGHT div 2;

rc.Right := rc.Left + WINDOW_WIDTH;

rc.Bottom := rc.Top + WINDOW_HEIGHT;

AdjustWindowRectEx (rc, style, FALSE, exStyle);

end;

style := style or WS_CLIPSIBLINGS or WS_CLIPCHILDREN;

handle := CreateWindowEx (exStyle, wndClass.lpszClassName, 'Bridge Bomber',style,

rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, 0, 0, wndClass.hInstance, nil);

if (handle = 0) then

begin

Bomber_FatalError ('Ошибка создания окна. Код '+IntToStr (GetLastError()));

result := FALSE;

Exit;

end;

ShowWindow (handle, SW_SHOW);

SetForegroundWindow (handle);

result := TRUE;

end;

procedure Bomber_WindowRelease ();

begin

if (handle <> 0) then

begin

ShowWindow (handle, SW_HIDE);

DestroyWindow (handle);

handle := 0;

end;

if (@wndClass.lpszClassName <> nil) then

begin

UnregisterClass (wndClass.lpszClassName, wndClass.hInstance);

ZeroMemory (@wndClass, sizeof (wndClass));

end;

end;

end.

unit bm_rend;

interface

function Bomber_RendInitialize (): BOOLEAN;

function Bomber_RendRelease (): BOOLEAN;

function Bomber_RendSet2dMode (): BOOLEAN;

function Bomber_RendSet3dMode (): BOOLEAN;

function Bomber_RendDrawText (x, y: INTEGER; Text: STRING; WhiteColor: BOOLEAN = TRUE): BOOLEAN;

implementation

uses

Windows,

OpenGL,

bm_core;

var

fontList: DWORD;

mode3d: BOOLEAN;

function Bomber_RendInitialize (): BOOLEAN;

var

font, oldFont: HFONT;

logFont: TLOGFONT;

dc: HDC;

begin

dc := wglGetCurrentDC ();

if (dc = 0) then

begin

Bomber_FatalError ('Ошибка инициализации рендерера. Код' + IntToStr (GetLastError()));

result := FALSE;

Exit;

end;

fontList := glGenLists (256);

if (fontList = 0) then

begin

Bomber_FatalError ('Ошибка инициализации рендерера');

result := FALSE;

Exit;

end;

ZeroMemory (@logFont, sizeof (logFont));

logFont.lfHeight := -MulDiv (DEBUG_FONT_SIZE, GetDeviceCaps (dc, LOGPIXELSY), 72);

logFont.lfCharSet := RUSSIAN_CHARSET;

logFont.lfFaceName := DEBUG_FONT_FACE;

logFont.lfWeight := FW_BOLD;

DEBUG_FONT_HEIGHT := -logFont.lfHeight;

font := CreateFontIndirect (logFont);

oldFont := SelectObject (dc, font);

wglUseFontBitmaps (dc, 0, 256, fontList);

DeleteObject (SelectObject (dc, oldFont));

glViewport (0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);

glMatrixMode (GL_PROJECTION);

glLoadIdentity ();

gluPerspective (RENDER_FOV, WINDOW_WIDTH / WINDOW_HEIGHT, 0.01, RENDER_DISTANCE);

glMatrixMode (GL_MODELVIEW);

glLoadIdentity ();

mode3D := TRUE;

glDepthFunc (GL_LEQUAL);

glShadeModel (GL_SMOOTH);

glEnable (GL_DEPTH_TEST);

glEnable (GL_TEXTURE_2D);

glEnable (GL_LIGHTING);

result := TRUE;

end;

function Bomber_RendRelease (): BOOLEAN;

begin

if (fontList <> 0) then

begin

glDeleteLists (fontList, 256);

fontList := 0;

end;

result := TRUE;

end;

function Bomber_RendSet2dMode (): BOOLEAN;

begin

if (not mode3d) then

begin

result := FALSE;

Exit;

end;

glMatrixMode (GL_PROJECTION);

glPushMatrix ();

glLoadIdentity ();

glOrtho (0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0, 1);

glMatrixMode (GL_MODELVIEW);

glPushMatrix ();

glLoadIdentity ();

mode3d := FALSE;

result := TRUE;

end;

function Bomber_RendSet3dMode (): BOOLEAN;

begin

if (mode3d) then

begin

result := FALSE;

Exit;

end;

glMatrixMode (GL_PROJECTION);

glPopMatrix ();

glMatrixMode (GL_MODELVIEW);

glPopMatrix ();

mode3d := TRUE;

result := TRUE;

end;

function Bomber_RendDrawText (x, y: INTEGER; Text: STRING; WhiteColor: BOOLEAN = TRUE): BOOLEAN;

begin

Bomber_RendSet2dMode ();

glPushAttrib (GL_ALL_ATTRIB_BITS);

glDisable (GL_DEPTH);

glDisable (GL_LIGHTING);

glDisable (GL_TEXTURE_2D);

if (WhiteColor) then

glColor3f (1.0, 1.0, 1.0);

glListBase (fontList);

glRasterPos2i (x, y);

glCallLists (Length (Text), GL_UNSIGNED_BYTE, @Text [1]);

glPopAttrib ();

Bomber_RendSet3dMode ();

result := TRUE;

end;

end.

unit bm_timer;

interface

function Bomber_TimerInitialize (): BOOLEAN;

procedure Bomber_TimerRelease ();

procedure Bomber_TimerStart ();

function Bomber_TimerGetTick (): INT64;

procedure Bomber_TimerSleep (milliseconds: INT64);

procedure Bomber_TimerWait ();

function Bomber_TimerGetFps (): SINGLE;

implementation

uses

Windows,

bm_core;

const

MAX_FPS = 24;

FRAME_COUNT = 30;

var

frequency: INT64;

startTick: INT64;

lastTick: INT64;

nominalTick: INT64;

frames: ARRAY [0..FRAME_COUNT-1] OF INT64;

function Bomber_TimerInitialize (): BOOLEAN;

var

counter: INT64;

begin

if (MAX_FPS <> 1) then

nominalTick := 1000 div MAX_FPS

else

nominalTick := 1;

if not ((QueryPerformanceFrequency (frequency))

or (QueryPerformanceCounter (counter))) then

begin

Bomber_FatalError ('Высокочастотный таймер не поддерживается');

result := FALSE;

end

else

result := TRUE

end;

procedure Bomber_TimerRelease ();

begin

end;

procedure Bomber_TimerStart ();

begin

QueryPerformanceCounter (startTick);

end;

function Bomber_TimerGetTick (): INT64;

var

tick: INT64;

begin

QueryPerformanceCounter (tick);

result := (tick - startTick) div (frequency div 1000);

end;

procedure Bomber_TimerSleep (milliseconds: INT64);

var

tick: INT64;

begin

tick := Bomber_TimerGetTick ();

while (Bomber_TimerGetTick () - tick < milliseconds) do;

end;

procedure Bomber_TimerWait ();

var

tick: INT64;

i: INTEGER;

begin

tick := Bomber_TimerGetTick ();

if (tick - lastTick < nominalTick) then

begin

Bomber_TimerSleep (nominalTick - tick + lastTick);

tick := Bomber_TimerGetTick ();

end;

for i := FRAME_COUNT - 1 downto 0 do

frames [i] := frames [i-1];

frames [0] := tick - lastTick;

lastTick := tick;

end;

function Bomber_TimerGetFps (): SINGLE;

var

i: INTEGER;

sum, res: SINGLE;

begin

sum := 0;

for i := 0 to FRAME_COUNT-1 do

sum := sum + frames [i];

res := 1000 / (sum / FRAME_COUNT);

if (res < 1) then

result := 1

else

result := res;

end;

end.

unit bm_river;

interface

function Bomber_RiverInitialize (): BOOLEAN;

procedure Bomber_RiverRelease ();

procedure Bomber_RiverDraw ();

function Bomber_RiverGetLevel (): SINGLE;

implementation

uses

Windows,

OpenGL,

Math,

bm_graph,

bm_core,

bm_tga,

bm_timer;

const

TEXTURE_WATER = 'water.tga';

TEXTURE_GRASS = 'grass.tga';

TEXTURE_SLOPE = 'slope.tga';

TEXTURE_BOTTOM = 'bottom.tga';

var

bankList: DWORD;

waterList: DWORD;

waterTex: DWORD;

grassTex: DWORD;

slopeTex: DWORD;

bottomTex: DWORD;

xValue: SINGLE = 0;

zValue: SINGLE = 0;

xSign: SINGLE = 1;

zSign: SINGLE = 1;

procedure BuildList ();

var

x1, x2, x3, z1: SINGLE;

begin

x1 := RENDER_DISTANCE / 2;

x2 := 50;

x3 := 45;

z1 := RENDER_DISTANCE / 2;

glNewList (bankList, GL_COMPILE);

glPushAttrib (GL_ALL_ATTRIB_BITS);

// Grass

glBindTexture (GL_TEXTURE_2D, grassTex);

glBegin (GL_QUADS);

// Left bank

glTexCoord2f (20.0, 50.0);

glNormal3f (0.0, 1.0, 0.0);

glVertex3f (-x2, 0.0, -z1);

glTexCoord2f (0.0, 50.0);

glNormal3f (0.0, 1.0, 0.0);

glVertex3f (-x1, 0.0, -z1);

glTexCoord2f (0.0, 0.0);

glNormal3f (0.0, 1.0, 0.0);

glVertex3f (-x1, 0.0, z1);

glTexCoord2f (20.0, 0.0);

glNormal3f (0.0, 1.0, 0.0);

glVertex3f (-x2, 0.0, z1);

// Right bank

glTexCoord2f (20.0, 50.0);

glNormal3f (0.0, 1.0, 0.0);

glVertex3f (x1, 0.0, -z1);

glTexCoord2f (0.0, 50.0);

glNormal3f (0.0, 1.0, 0.0);

glVertex3f (x2, 0.0, -z1);

glTexCoord2f (0.0, 0.0);

glNormal3f (0.0, 1.0, 0.0);

glVertex3f (x2, 0.0, z1);

glTexCoord2f (20.0, 0.0);

glNormal3f (0.0, 1.0, 0.0);

glVertex3f (x1, 0.0, z1);

glEnd ();

// Bank slopes

glBindTexture (GL_TEXTURE_2D, slopeTex);

glBegin (GL_QUADS);

// Left slope

glTexCoord2f (1.0, 50.0);

glNormal3f (0.5, 0.5, 0.0);

glVertex3f (-x3, -5.0, -z1);

glTexCoord2f (0.0, 50.0);

glNormal3f (0.5, 0.5, 0.0);

glVertex3f (-x2, 0.0, -z1);

glTexCoord2f (0.0, 0.0);

glNormal3f (0.5, 0.5, 0.0);

glVertex3f (-x2, 0.0, z1);

glTexCoord2f (1.0, 0.0);

glNormal3f (0.5, 0.5, 0.0);

glVertex3f (-x3, -5.0, z1);

// Right slope

glTexCoord2f (1.0, 50.0);

glNormal3f (-0.5, 0.5, 0.0);

glVertex3f (x2, 0.0, -z1);

glTexCoord2f (0.0, 50.0);

glNormal3f (-0.5, 0.5, 0.0);

glVertex3f (x3, -5.0, -z1);

glTexCoord2f (0.0, 0.0);

glNormal3f (-0.5, 0.5, 0.0);

glVertex3f (x3, -5.0, z1);

glTexCoord2f (1.0, 0.0);

glNormal3f (-0.5, 0.5, 0.0);

glVertex3f (x2, 0.0, z1);

glEnd ();

// River bottom

glBindTexture (GL_TEXTURE_2D, bottomTex);

glBegin (GL_QUADS);

glTexCoord2f (10.0, 50.0);

glNormal3f (0.0, 1.0, 0.0);

glVertex3f (x3, -5.0, -z1);

glTexCoord2f (0.0, 50.0);

glNormal3f (0.0, 1.0, 0.0);

glVertex3f (-x3, -5.0, -z1);

glTexCoord2f (0.0, 0.0);

glNormal3f (0.0, 1.0, 0.0);

glVertex3f (-x3, -5.0, z1);

glTexCoord2f (10.0, 0.0);

glNormal3f (0.0, 1.0, 0.0);

glVertex3f (x3, -5.0, z1);

glEnd ();

glPopAttrib ();

glEndList ();

// River water

glNewList (waterList, GL_COMPILE);

glPushAttrib (GL_ALL_ATTRIB_BITS);

glBindTexture (GL_TEXTURE_2D, waterTex);

glEnable (GL_BLEND);

glColor4f (0.25, 0.25, 0.25, 0.5);

glBlendFunc (GL_ONE, GL_SRC_ALPHA);

glBegin (GL_QUADS);

glTexCoord2f (10.0, 50.0);

glNormal3f (0.0, 1.0, 0.0);

glVertex3f (x2, -1.5, -z1);

glTexCoord2f (0.0, 50.0);

glNormal3f (0.0, 1.0, 0.0);

glVertex3f (-x2, -1.5, -z1);

glTexCoord2f (0.0, 0.0);

glNormal3f (0.0, 1.0, 0.0);

glVertex3f (-x2, -1.5, z1);

glTexCoord2f (10.0, 0.0);

glNormal3f (0.0, 1.0, 0.0);

glVertex3f (x2, -1.5, z1);

glEnd ();

glDisable (GL_BLEND);

glPopAttrib ();

glEndList ();

end;

function Bomber_RiverInitialize (): BOOLEAN;

begin

bankList := glGenLists (1);

if (bankList = 0) then

begin

Bomber_FatalError ('Ошибка инициализации рендерера');

result := FALSE;

Exit;

end;

waterList := glGenLists (1);

if (waterList = 0) then

begin

Bomber_FatalError ('Ошибка инициализации рендерера');

result := FALSE;

Exit;

end;

waterTex := Bomber_TgaLoad (TEXTURE_WATER);

grassTex := Bomber_TgaLoad (TEXTURE_GRASS);

slopeTex := Bomber_TgaLoad (TEXTURE_SLOPE);

bottomTex := Bomber_TgaLoad (TEXTURE_BOTTOM);

BuildList ();

result := TRUE;

end;

procedure Bomber_RiverRelease ();

begin

if (waterList <> 0) then

begin

glDeleteLists (waterList, 1);

waterList := 0;

end;

if (bankList <> 0) then

begin

glDeleteLists (bankList, 1);

bankList := 0;

end;

end;

procedure Bomber_RiverDraw ();

begin

xValue := xValue + (20 / Bomber_TimerGetFps ());

zValue := zValue + (10 / Bomber_TimerGetFps ());

if (xValue >= 360.0) then

xValue := 0;

if (zValue >= 360.0) then

zValue := 0;

glPushAttrib (GL_ALL_ATTRIB_BITS);

glPushMatrix ();

glCallList (bankList);

glTranslatef (sin (DegToRad (xValue)), sin (DegToRad (xValue + zValue)) * 0.25, sin (DegToRad (zValue)));

glDisable (GL_LIGHTING);

glCallList (waterList);

glPopMatrix ();

glPopAttrib ();

end;

function Bomber_RiverGetLevel (): SINGLE;

begin

result := sin (DegToRad (xValue + zValue)) * 0.25;

end;

end.

unit bm_scene;

interface

var

ALFA_VALUE: SINGLE = 0;

SERIAL_BOMBING: BOOLEAN = TRUE;

function Bomber_SceneInitialize (): BOOLEAN;

procedure Bomber_SceneRelease ();

function Bomber_SceneDraw (): BOOLEAN;

implementation

uses

Windows,

OpenGL,

bm_core,

bm_rend,

bm_brid,

bm_plane,

bm_river,

bm_timer,

bm_expl,

bm_math;

const

SPLASH_LINE_COUNT = 6;

splashText: ARRAY [1..SPLASH_LINE_COUNT, 1..2] OF STRING =

(

('',''),

('ТРОИЦКНАУЧФИЛЬМ','представляет'),

('БОМБОМЕТАНИЕ','ПО ЖЕЛЕЗНОДОРОЖНОМУ МОСТУ'),

('фильм курсантов 331 группы ТАТК ГА','ГАЛИМОВА А. и КОЗЛОВА А.'),

('по заказу','СМОЛЯКОВОЙ Г.Н.'),

('','')

);

var

fFogColor: ARRAY [0..3] OF SINGLE = (0.6, 0.6, 0.6, 1.0);

fSplashColor: ARRAY [0..3] OF SINGLE = (0.25, 0.25, 0.25, 1.0);

fLampDifColor: ARRAY [0..3] OF SINGLE = (0.8, 0.8, 0.8, 1.0);

fLampAmbColor: ARRAY [0..3] OF SINGLE = (0.5, 0.5, 0.5, 1.0);

fLampPosition: ARRAY [0..3] OF SINGLE = (0.0, 5000.0, 0.0, 1.0);

fLampDirection: ARRAY [0..2] OF SINGLE = (0.0, 0.0, 0.0);

resultFrame: INTEGER;

splashFrame: INTEGER = -1;

splashLine: INTEGER = 1;

exploSetup: BOOLEAN = TRUE;

function Bomber_SceneInitialize (): BOOLEAN;

begin

glClearColor (fFogColor [0], fFogColor [1], fFogColor [2], fFogColor [3]);

glFogfv (GL_FOG_COLOR, @fFogColor);

glFogi (GL_FOG_MODE, GL_LINEAR);

glFogf (GL_FOG_START, RENDER_DISTANCE * 0.4);

glFogf (GL_FOG_END, RENDER_DISTANCE * 0.75);

glFogf (GL_FOG_DENSITY, 1.0);

glEnable (GL_FOG);

glLightModelf (GL_LIGHT_MODEL_LOCAL_VIEWER, 1);

glLightfv (GL_LIGHT0, GL_AMBIENT, @fLampAmbColor);

glLightfv (GL_LIGHT0, GL_DIFFUSE, @fLampDifColor);

glLightfv (GL_LIGHT0, GL_SPOT_DIRECTION, @fLampDirection);

glLightfv (GL_LIGHT0, GL_POSITION, @fLampPosition);

glEnable (GL_LIGHT0);

result := TRUE;

end;

procedure Bomber_SceneRelease ();

begin

end;

function SplashDraw (cl: SINGLE): BOOLEAN;

var

sz: TSize;

begin

if (splashLine > SPLASH_LINE_COUNT) then

begin

result := FALSE;

Exit;

end;

if (splashFrame = -1) then

begin

splashFrame := 45;

end

else

dec (splashFrame);

if (splashFrame = 0) then

begin

splashFrame := Round (5 * Bomber_TimerGetFps ());

inc (splashLine);

if (splashLine > SPLASH_LINE_COUNT) then

begin

result := FALSE;

Exit;

end;

end;

glClearColor (fSplashColor [0], fSplashColor [1], fSplashColor [2], fSplashColor [3]);

glClear (GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

glColor3f (0.8 + cl, 0.8 + cl, 0.8 + cl);

GetTextExtentPoint32 (wglGetCurrentDC (), PCHAR (splashText [splashLine, 1]), Length (splashText [splashLine, 1]), sz);

Bomber_RendDrawText (WINDOW_WIDTH div 2 - sz.cx div 2,

WINDOW_HEIGHT div 2 - sz.cy, splashText [splashLine, 1], FALSE);

GetTextExtentPoint32 (wglGetCurrentDC (), PCHAR (splashText [splashLine, 2]), Length (splashText [splashLine, 2]), sz);

Bomber_RendDrawText (WINDOW_WIDTH div 2 - sz.cx div 2,

WINDOW_HEIGHT div 2 + sz.cy, splashText [splashLine, 2], FALSE);

result := TRUE;

end;

procedure DrawBridgeScheme (cl: SINGLE);

var

xc, yc: SINGLE;

x, y: SINGLE;

d, l: SINGLE;

i: INTEGER;

begin

xc := WINDOW_WIDTH - WINDOW_WIDTH div 4;

yc := WINDOW_HEIGHT div 2;

d := BRIDGE_LENGTH * 1.5;

l := BRIDGE_WIDTH * 1.5;

Bomber_RendSet2dMode ();

glPushAttrib (GL_ALL_ATTRIB_BITS);

glDisable (GL_LIGHTING);

glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);

glColor3f (0.8 + cl, 0.8 + cl, 0.8 + cl);

glLineWidth (2);

glBegin (GL_QUADS);

glVertex2f (xc + l / 2, yc - d / 2);

glVertex2f (xc - l / 2, yc - d / 2);

glVertex2f (xc - l / 2, yc + d / 2);

glVertex2f (xc + l / 2, yc + d / 2);

glEnd ();

glLineWidth (1);

glBegin (GL_LINES);

glVertex2f (xc, yc - 100);

glVertex2f (xc, yc + 100);

glVertex2f (xc - 100, yc);

glVertex2f (xc + 100, yc);

glEnd ();

glBegin (GL_LINES);

for i := 1 to BOMB_COUNT do

begin

x := xc + bombPos [Round (ALFA_VALUE) div 10, i-1].x * 1.5;

y := yc - bombPos [Round (ALFA_VALUE) div 10, i-1].y * 1.5;

glVertex2f (x - 3, y - 3);

glVertex2f (x + 3, y + 3);

glVertex2f (x - 3, y + 3);

glVertex2f (x + 3, y - 3);

end;

glEnd ();

glPopAttrib ();

Bomber_RendSet3dMode ();

end;

function ShowResults (cl: SINGLE): BOOLEAN;

var

i, n, h: INTEGER;

begin

glClear (GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

glLoadIdentity ();

h := WINDOW_HEIGHT - WINDOW_HEIGHT div 10;

DrawBridgeScheme (cl);

glColor3f (0.8 + cl, 0.8 + cl, 0.8 + cl);

Bomber_RendDrawText (40, h - 190, 'РЕЗУЛЬТАТЫ БОМБАРДИРОВКИ', FALSE);

Bomber_RendDrawText (40, h - 160, 'Угол захода самолета: ' + IntToStr (Round (ALFA_VALUE)) + #176, FALSE);

Bomber_RendDrawText (40, h - 130, 'Координаты падения бомб:', FALSE);

n := 0;

for i := 1 to BOMB_COUNT do

begin

Bomber_RendDrawText (60, h - 130 + i * DEBUG_FONT_HEIGHT, IntToStr (i) + ': ('

+ FloatToStr (bombPos [Round (ALFA_VALUE) div 10, BOMB_COUNT - i].x, 7, 3) + ';'

+ FloatToStr (bombPos [Round (ALFA_VALUE) div 10, BOMB_COUNT - i].y, 7, 3) + ')', FALSE);

if (bombPos [Round (ALFA_VALUE) div 10, BOMB_COUNT - i].crash) then

begin

Bomber_RendDrawText (240, h - 130 + i * DEBUG_FONT_HEIGHT, 'ПОПАДАНИЕ', FALSE);

inc (n);

end;

end;

Bomber_RendDrawText (40, h - 130 + DEBUG_FONT_HEIGHT * (BOMB_COUNT + 2),

'Качество бомбардировки: ' + FloatToStr ((n / BOMB_COUNT) * 100, 5, 2) + '%', FALSE);

dec (resultFrame);

if (resultFrame = 0) then

begin

if (SERIAL_BOMBING) then

begin

if (ALFA_VALUE = 90) then

begin

result := FALSE;

Exit;

end

else

ALFA_VALUE := ALFA_VALUE + 10;

end

else

begin

result := FALSE;

Exit;

end;

glClearColor (fFogColor [0], fFogColor [1], fFogColor [2], fFogColor [3]);

Bomber_PlaneRestart ();

Bomber_BridgeBuild ();

exploSetup := TRUE;

end;

result := TRUE;

end;

function Bomber_SceneDraw (): BOOLEAN;

var

yt, h: INTEGER;

cl: SINGLE;

begin

yt := random (2);

cl := (-5 + random (10)) / 100;

if (Bomber_KeyDown (VK_ESCAPE)) then

begin

result := FALSE;

Exit;

end;

glViewPort (0, yt, WINDOW_WIDTH, WINDOW_HEIGHT);

glClearColor (fFogColor [0], fFogColor [1], fFogColor [2], fFogColor [3]);

glClear (GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

glLoadIdentity ();

glTranslatef (0.0, -1.85, -150.0);

glRotatef (20.0, 0.0, 1.0, 0.0);

Bomber_BridgeDraw ();

if (SERIAL_BOMBING) and (SplashDraw (cl)) then

begin

result := TRUE;

Exit;

end;

if (exploSetup) then

begin

Bomber_ExploSetup (Round (ALFA_VALUE) div 10);

exploSetup := FALSE;

end;

if (not Bomber_PlaneDraw ()) then

begin

glClearColor (fSplashColor [0], fSplashColor [1], fSplashColor [2], fSplashColor [3]);

if (resultFrame = 0) then

resultFrame := Round (7 * Bomber_TimerGetFps ());

if (ShowResults (cl)) then

result := TRUE

else

result := FALSE;

Exit;

end;

glColor3f (0.8 + cl, 0.8 + cl, 0.8 + cl);

h := WINDOW_HEIGHT - WINDOW_HEIGHT div 10;

Bomber_RendDrawText (40, h - 130 + DEBUG_FONT_HEIGHT * 6,

'Угол захода самолета: ' + IntToStr (Trunc (ALFA_VALUE)) + #176, FALSE);

Bomber_RendDrawText (40, h - 130 + DEBUG_FONT_HEIGHT * 7,

'Вероятность разрушения моста: ' + FloatToStr (crashProbab [Trunc (ALFA_VALUE / 10)] * 100, 5, 2) + '%', FALSE);

Bomber_ExploDraw ();

Bomber_RiverDraw ();

result := TRUE;

end;

end.

unit bm_file;

interface

uses

Windows;

function Bomber_FileOpen (FileName: STRING): THANDLE;

procedure Bomber_FileClose (FileHandle: THANDLE);

function Bomber_FileRead (FileHandle: THANDLE; Buff: POINTER; Size: DWORD): DWORD;

function Bomber_FileWrite (FileHandle: THANDLE; Buff: POINTER; Size: DWORD): DWORD;

implementation

var

localDir: STRING = '';

function GetLocalDir (): STRING;

var

name: ARRAY [0..MAX_PATH+1] OF CHAR;

i: INTEGER;

begin

if (localDir <> '') then

begin

result := localDir;

Exit;

end;

GetModuleFileName (0, @name, sizeof (name));

CharLowerBuff (@name, Length (name));

for i := Length (name)-1 downto 0 do

if (name [i] = '\') then

begin

Copy (localDir, 1, i);

Break;

end;

result := localDir;

end;

function Bomber_FileOpen (FileName: STRING): THANDLE;

begin

FileName := GetLocalDir + FileName;

result := CreateFile (PCHAR (FileName), GENERIC_READ, 0, nil, OPEN_EXISTING, 0, 0);

end;

procedure Bomber_FileClose (FileHandle: THANDLE);

begin

CloseHandle (FileHandle);

end;

function Bomber_FileRead (FileHandle: THANDLE; Buff: POINTER; Size: DWORD): DWORD;

var

read: DWORD;

begin

ReadFile (FileHandle, Buff^, Size, read, nil);

result := read;

end;

function Bomber_FileWrite (FileHandle: THANDLE; Buff: POINTER; Size: DWORD): DWORD;

var

written: DWORD;

begin

WriteFile (FileHandle, Buff^, Size, written, nil);

result := written;

end;

end.

unit bm_tga;

interface

uses

Windows;

function Bomber_TgaLoad (FileName: STRING): DWORD;

implementation

uses

OpenGL,

bm_graph,

bm_core,

bm_file,

bm_mem;

const

TARGA_TRUECOLOR_IMAGE = 2;

TARGA_TRUECOLOR_RLE_IMAGE = 10;

type

TGAFILEHEADER = packed record

idFieldLength: BYTE;

colorMapType: BYTE;

imageType: BYTE;

firstColorMapEntry: WORD;

colorMapLength: WORD;

colorMapEntrySize: BYTE;

imageXOrigin: WORD;

imageYOrigin: WORD;

imageWidth: WORD;

imageHeight: WORD;

bitsPerPixel: BYTE;

imageDescriptorBits: BYTE;

end;

procedure SwapColors (data: PBYTE; dataSize: DWORD; bpp: BYTE);

var

i: DWORD;

t: BYTE;

begin

if (bpp = 24) then

begin

i := 0;

while (i < dataSize) do

begin

t := PBYTE (DWORD (data) + i + 0)^;

PBYTE (DWORD (data) + i + 0)^ := PBYTE (DWORD (data) + i + 2)^;

PBYTE (DWORD (data) + i + 2)^ := t;

inc (i, 3);

end;

Exit;

end;

if (bpp = 32) then

begin

i := 0;

while (i < dataSize) do

begin

t := PBYTE (DWORD (data) + i + 0)^;

PBYTE (DWORD (data) + i + 0)^ := PBYTE (DWORD (data) + i + 2)^;

PBYTE (DWORD (data) + i + 2)^ := t;

inc (i, 4);

end;

Exit;

end;

end;

procedure FlipImage (data: PBYTE; width, height: DWORD; bpp: BYTE);

var

t, k: BYTE;

x, y: DWORD;

begin

k := bpp div 8;

width := width * k;

for y := 0 to height div 2 - 1 do

for x := 0 to width - 1 do

begin

t := PBYTE (DWORD (data) + y * width + x)^;

PBYTE (DWORD (data) + y * width + x)^ := PBYTE (DWORD (data) + (height - y - 1) * width + x)^;

PBYTE (DWORD (data) + (height - y - 1) * width + x)^ := t;

end;

end;

function Bomber_TgaLoad (FileName: STRING): DWORD;

var

res: HRSRC;

resPtr: HGLOBAL;

resPos: DWORD;

header: TGAFILEHEADER;

dataSize: DWORD;

data: PBYTE;

format: DWORD;

texture: DWORD;

formatbyte: DWORD;

begin

if (Pos ('.', FileName) <> 0) then

FileName := 'T_' + Copy (FileName, 1, Pos ('.', FileName) - 1);

res := FindResource (0, PCHAR (FileName), RT_RCDATA);

if (res = 0) then

begin

result := 0;

Exit;

end;

resPos := 0;

resPtr := LoadResource (0, res);

if (resPtr = 0) then

begin

result := 0;

Exit;

end;

CopyMemory (@header, POINTER (resptr + resPos), sizeof (header));

inc (resPos, sizeof (header));

if (header.imageType <> TARGA_TRUECOLOR_IMAGE)

and (header.imageType <> TARGA_TRUECOLOR_RLE_IMAGE) then

begin

result := 0;

Exit;

end;

dataSize := header.imageWidth * header.imageHeight * (header.bitsPerPixel div 8);

data := Bomber_MemAlloc (dataSize);

if (data = nil) then

begin

result := 0;

Exit;

end;

if (header.imageType = TARGA_TRUECOLOR_IMAGE) then

CopyMemory (data, POINTER (resPtr + resPos), dataSize);

SwapColors (data, dataSize, header.bitsPerPixel);

if (header.imageDescriptorBits and $20 = $20) then

FlipImage (data, header.imageWidth, header.imageHeight, header.bitsPerPixel);

if (header.bitsPerPixel = 24) then

begin

format := GL_RGB;

formatbyte := 3;

end

else

begin

format := GL_RGBA;

formatbyte := 4;

end;

glPushAttrib (GL_TEXTURE_BIT);

glGenTextures (1, texture);

glBindTexture (GL_TEXTURE_2D, texture);

glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);

glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

if (Pos ('GL_SGIS_generate_mipmap', glGetString (GL_EXTENSIONS)) <> 0) then

begin

glTexParameteri (GL_TEXTURE_2D, $8191, 1);

glTexImage2D (GL_TEXTURE_2D, 0, formatbyte, header.imageWidth, header.imageHeight,

0, format, GL_UNSIGNED_BYTE, data);

end

else

begin

gluBuild2DMipmaps (GL_TEXTURE_2D, header.bitsPerPixel div 8,

header.imageWidth, header.imageHeight, format, GL_UNSIGNED_BYTE, data);

end;

glPopAttrib ();

ПОВТиАС

Bomber_MemFree (data);

result := texture;

end;

end.

unit bm_mem;

interface

uses

Windows;

function Bomber_MemAlloc (size: DWORD): POINTER;

procedure Bomber_MemFree (ptr: POINTER);

implementation

function Bomber_MemAlloc (size: DWORD): POINTER;

begin

result := POINTER (GlobalAlloc (GPTR, size));

end;

procedure Bomber_MemFree (ptr: POINTER);

begin

GlobalFree (HGLOBAL (ptr));

end;

end.

unit bm_graph;

interface

uses

OpenGL;

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.dll';

procedure glBindTexture(target: GLenum; texture: GLuint); stdcall; external 'OpenGL32.dll';

implementation

end.

unit bm_model;

interface

function Bomber_ModelInitialize (): BOOLEAN;

procedure Bomber_ModelRelease ();

function Bomber_ModelLoad (FileName: STRING): INTEGER;

procedure Bomber_ModelDraw (model: INTEGER; x, y, z: SINGLE; ya, za: SINGLE);

implementation

uses

Windows,

OpenGL,

bm_file,

bm_graph,

bm_tga;

const

MAX_MODEL_COUNT = 15;

INVALID_MODEL_INDEX = -1;

const

FILE_ID = $004D5354;

FILE_VER = $0010;

MAX_MATERIAL_COUNT = 65535;

MAX_VERTEX_COUNT = 65535;

MAX_NORMAL_COUNT = 65535;

MAX_COORD_COUNT = 65535;

MAX_GROUP_COUNT = 65535;

MAX_FACE_COUNT = 65535;

type

HEADER_T = packed record

FileId: DWORD;

FileVer: WORD;

MaterialCount: WORD;

VertexCount: WORD;

CoordCount: WORD;

NormalCount: WORD;

GroupCount: WORD;

end;

MATERIAL_T = packed record

AmbientColor: ARRAY [0..3] OF SINGLE;

DiffuseColor: ARRAY [0..3] OF SINGLE;

SpecularColor: ARRAY [0..3] OF SINGLE;

Shininess: SINGLE;

TextureName: ARRAY [0..15] OF CHAR;

end;

GROUP_T = packed record

Material: WORD;

FaceCount: WORD;

end;

FACE_ITEM_T = packed record

VertexIndex: WORD;

CoordIndex: WORD;

NormalIndex: WORD;

end;

FACE_T = packed record

Item: ARRAY [0..2] OF FACE_ITEM_T;

end;

VERTEX_T = packed record

x, y, z: SINGLE;

end;

COORD_T = packed record

s, t: SINGLE;

end;

NORMAL_T = packed record

nx, ny, nz: SINGLE;

end;

var

material: ARRAY [1..MAX_MATERIAL_COUNT] OF MATERIAL_T;

vertex: ARRAY [1..MAX_VERTEX_COUNT] OF VERTEX_T;

texCoord: ARRAY [1..MAX_COORD_COUNT] OF COORD_T;

normal: ARRAY [1..MAX_NORMAL_COUNT] OF NORMAL_T;

modelList: ARRAY [0..MAX_MODEL_COUNT-1] OF DWORD;

modelIndex: INTEGER = 0;

function Bomber_ModelInitialize (): BOOLEAN;

begin

ZeroMemory (@modelList, sizeof (modelList));

ZeroMemory (@material, sizeof (material));

ZeroMemory (@texCoord, sizeof (texCoord));

ZeroMemory (@normal, sizeof (normal));

result := TRUE;

end;

procedure Bomber_ModelRelease ();

var

i: INTEGER;

begin

for i := 0 to MAX_MODEL_COUNT-1 do

if (modelList [i] <> 0) then

begin

glDeleteLists (modelList [i], 1);

modelList [i] := 0;

end;

end;

function GetFreeIndex (): INTEGER;

begin

if (modelIndex < MAX_MODEL_COUNT) then

begin

result := modelIndex;

inc (modelIndex);

end

else

result := INVALID_MODEL_INDEX;

end;

function Bomber_ModelLoad (FileName: STRING): INTEGER;

var

res: HRSRC;

resPtr: HGLOBAL;

resPos: DWORD;

hdr: HEADER_T;

ghdr: GROUP_T;

size: DWORD;

g, f: INTEGER;

index: INTEGER;

item: FACE_ITEM_T;

fColor: ARRAY [0..3] OF SINGLE;

begin

index := GetFreeIndex ();

if (index = INVALID_MODEL_INDEX) then

begin

result := -1;

Exit;

end;

if (Pos ('.', FileName) <> 0) then

FileName := 'M_' + Copy (FileName, 1, Pos ('.', FileName) - 1);

res := FindResource (0, PCHAR (FileName), RT_RCDATA);

if (res = 0) then

begin

result := -1;

Exit;

end;

resPos := 0;

resPtr := LoadResource (0, res);

if (resPtr = 0) then

begin

result := -1;

Exit;

end;

CopyMemory (@hdr, POINTER (resPtr + resPos), sizeof (hdr));

inc (resPos, sizeof (hdr));

if (hdr.FileId <> FILE_ID) or (hdr.FileVer <> FILE_VER) then

begin

result := -1;

Exit;

end;

size := sizeof (material [1]) * hdr.MaterialCount;

CopyMemory (@material [1], POINTER (resPtr + resPos), size);

inc (resPos, size);

size := sizeof (vertex [1]) * hdr.VertexCount;

CopyMemory (@vertex [1], POINTER (resPtr + resPos), size);

inc (resPos, size);

size := sizeof (texCoord [1]) * hdr.CoordCount;

CopyMemory (@texCoord [1], POINTER (resPtr + resPos), size);

inc (resPos, size);

size := sizeof (normal [1]) * hdr.NormalCount;

CopyMemory (@normal [1], POINTER (resPtr + resPos), size);

inc (resPos, size);

modelList [index] := glGenLists (1);

glNewList (modelList [index], GL_COMPILE);

glPushAttrib (GL_ALL_ATTRIB_BITS);

glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);

for g := 1 to hdr.GroupCount do

begin

CopyMemory (@ghdr, POINTER (resPtr + resPos), sizeof (ghdr));

inc (resPos, sizeof (ghdr));

if (ghdr.Material <> 0) then

begin

glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, @material [ghdr.Material].AmbientColor [0]);

glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, @material [ghdr.Material].DiffuseColor [0]);

glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, @material [ghdr.Material].SpecularColor [0]);

if (material [ghdr.Material].TextureName <> '') then

begin

glBindTexture (GL_TEXTURE_2D, Bomber_TgaLoad (material [ghdr.Material].TextureName));

glEnable (GL_TEXTURE_2D);

end

else

glDisable (GL_TEXTURE_2D);

end

else

begin

fColor [0] := 0.2;

fColor [1] := 0.2;

fColor [2] := 0.2;

fColor [3] := 1.0;

glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT, @fColor [0]);

fColor [0] := 0.8;

fColor [1] := 0.8;

fColor [2] := 0.8;

glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, @fColor [0]);

fColor [0] := 1.0;

fColor [1] := 1.0;

fColor [2] := 1.0;

glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, @fColor [0]);

glDisable (GL_TEXTURE_2D);

end;

glBegin (GL_TRIANGLES);

for f := 1 to ghdr.FaceCount*3 do

begin

CopyMemory (@item, POINTER (resPtr + resPos), sizeof (item));

inc (resPos, sizeof (item));

glTexCoord2fv (@texCoord [item.CoordIndex]);

glNormal3fv (@normal [item.NormalIndex]);

glVertex3fv (@vertex [item.VertexIndex]);

end;

glEnd ();

end;

glPopAttrib ();

glEndList ();

result := index;

end;

procedure Bomber_ModelDraw (model: INTEGER; x, y, z: SINGLE; ya, za: SINGLE);

begin

if (modelList [model] = 0) then

Exit;

glPushMatrix ();

glTranslatef (x, y, z);

glRotatef (ya, 0.0, 1.0, 0.0);

glRotatef (za, 0.0, 0.0, 1.0);

glCallList (modelList [model]);

glPopMatrix ();

end;

end.

unit bm_dlg;

interface

function Bomber_DialogExecute (): BOOLEAN;

implementation

uses

Windows,

Messages,

bm_math,

bm_scene,

bm_core;

const

ID_DIALOG = 1000;

IDCB_WIND_SIZE = 2003;

IDCB_BOMB_COUNT = 2005;

IDCB_TYPE = 2007;

IDST_ALFA = 2008;

IDCB_ALFA = 2009;

IDB_OK = 2010;

IDB_CANCEL = 2011;

function InitCommonControls (): BOOL; external 'comctl32.dll';

procedure ProcessControls (hDlg: HWND);

begin

case (SendDlgItemMessage (hDlg, IDCB_WIND_SIZE, CB_GETCURSEL, 0, 0)) of

0:

begin

WINDOW_WIDTH := 640;

WINDOW_HEIGHT := 480;

end;

1:

begin

WINDOW_WIDTH := 800;

WINDOW_HEIGHT := 600;

end;

2:

begin

WINDOW_WIDTH := 1024;

WINDOW_HEIGHT := 768;

end;

end;

BOMB_COUNT := SendDlgItemMessage (hDlg, IDCB_BOMB_COUNT, CB_GETCURSEL, 0, 0) + 1;

SERIAL_BOMBING := SendDlgItemMessage (hDlg, IDCB_TYPE, CB_GETCURSEL, 0, 0) = 1;

if (SERIAL_BOMBING) then

ALFA_VALUE := 0

else

ALFA_VALUE := SendDlgItemMessage (hDlg, IDCB_ALFA, CB_GETCURSEL, 0, 0) * 10;

Bomber_MathProcess ();

end;

function DialogProc (hDlg: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): BOOL; stdcall;

var

i: INTEGER;

begin

case (uMsg) of

WM_INITDIALOG:

begin

SendDlgItemMessage (hDlg, IDCB_WIND_SIZE, CB_ADDSTRING, 0, INTEGER (PCHAR ('640 x 480')));

SendDlgItemMessage (hDlg, IDCB_WIND_SIZE, CB_ADDSTRING, 0, INTEGER (PCHAR ('800 x 600')));

SendDlgItemMessage (hDlg, IDCB_WIND_SIZE, CB_ADDSTRING, 0, INTEGER (PCHAR ('1024 x 768')));

for i := 1 to 4 do

SendDlgItemMessage (hDlg, IDCB_BOMB_COUNT, CB_ADDSTRING, 0, INTEGER (PCHAR (IntToStr (i))));

SendDlgItemMessage (hDlg, IDCB_TYPE, CB_ADDSTRING, 0, INTEGER (PCHAR ('Одиночное')));

SendDlgItemMessage (hDlg, IDCB_TYPE, CB_ADDSTRING, 0, INTEGER (PCHAR ('Серийное')));

for i := 0 to 9 do

SendDlgItemMessage (hDlg, IDCB_ALFA, CB_ADDSTRING, 0, INTEGER (PCHAR (IntToStr (i * 10))));

SendDlgItemMessage (hDlg, IDCB_WIND_SIZE, CB_SETCURSEL, 0, 0);

SendDlgItemMessage (hDlg, IDCB_BOMB_COUNT, CB_SETCURSEL, 0, 0);

SendDlgItemMessage (hDlg, IDCB_TYPE, CB_SETCURSEL, 0, 0);

SendDlgItemMessage (hDlg, IDCB_ALFA, CB_SETCURSEL, 0, 0);

end;

WM_COMMAND:

begin

if (LOWORD (wParam) = IDB_CANCEL)

or (LOWORD (wParam) = IDCANCEL) then

EndDialog (hDlg, -1);

if (LOWORD (wParam) = IDB_OK) then

begin

ProcessControls (hDlg);

EndDialog (hDlg, 1);

end;

if (LOWORD (wParam) = IDCB_TYPE) then

case (SendDlgItemMessage (hDlg, IDCB_TYPE, CB_GETCURSEL, 0, 0)) of

0:

begin

EnableWindow (GetDlgItem (hDlg, IDST_ALFA), TRUE);

EnableWindow (GetDlgItem (hDlg, IDCB_ALFA), TRUE);

end;

1:

begin

EnableWindow (GetDlgItem (hDlg, IDST_ALFA), FALSE);

EnableWindow (GetDlgItem (hDlg, IDCB_ALFA), FALSE);

end;

end;

end;

WM_DESTROY:

begin

end;

else

begin

result := FALSE;

Exit;

end;

end;

result := TRUE;

end;

function Bomber_DialogExecute (): BOOLEAN;

var

res: INTEGER;

begin

InitCommonControls ();

res := DialogBox (GetModuleHandle (nil), MAKEINTRESOURCE (ID_DIALOG), 0, @DialogProc);

if (res = -1) then

result := FALSE

else

result := TRUE;

end;

end.

unit bm_brid;

interface

function Bomber_BridgeInitialize (): BOOLEAN;

procedure Bomber_BridgeRelease ();

procedure Bomber_BridgeDraw ();

procedure Bomber_BridgeBuild ();

procedure Bomber_BridgeCrashLeft ();

procedure Bomber_BridgeCrashRight ();

implementation

uses

bm_timer,

bm_model;

const

MODEL_BLOCK1 = 'bridone.tsm';

MODEL_BLOCK2 = 'bridtwo.tsm';

MODEL_SUPPORT = 'support.tsm';

type

BLOCK_STATE_T = record

model: INTEGER;

posX: SINGLE;

posY: SINGLE;

angl: SINGLE;

zangl: SINGLE;

fllspd: SINGLE;

rotspd: SINGLE;

end;

var

modelBlock1,

modelBlock2,

modelSupport: INTEGER;

bridge: ARRAY [0..7] OF BLOCK_STATE_T;

leftCrashed: BOOLEAN;

rightCrashed: BOOLEAN;

procedure Bomber_BridgeBuild ();

var

i: INTEGER;

begin

for i := 0 to 7 do

begin

if (i in [0, 3, 4, 7]) then

bridge [i].model := modelBlock1

else

bridge [i].model := modelBlock2;

bridge [i].posX := -13.75 * (4 - i) + 6.875;

bridge [i].posY := 0.0;

if (i in [3, 7]) then

bridge [i].angl := 180.0

else

bridge [i].angl := 0.0;

bridge [i].fllspd := 0;

bridge [i].zangl := 0.0;

end;

leftCrashed := FALSE;

rightCrashed := FALSE;

end;

function Bomber_BridgeInitialize (): BOOLEAN;

begin

modelBlock1 := Bomber_ModelLoad (MODEL_BLOCK1);

modelBlock2 := Bomber_ModelLoad (MODEL_BLOCK2);

modelSupport := Bomber_ModelLoad (MODEL_SUPPORT);

Bomber_BridgeBuild ();

if (modelBlock1 = -1)

or (modelBlock2 = -1)

or (modelSupport = -1) then

result := FALSE

else

result := TRUE;

end;

procedure Bomber_BridgeRelease ();

begin

end;

procedure Bomber_BridgeDraw ();

var

i: INTEGER;

begin

Bomber_ModelDraw (modelSupport, 0.0, -5.0, 0.0, 0.0, 0.0);

for i := 0 to 7 do

begin

Bomber_ModelDraw (bridge [i].model,

bridge [i].posX, bridge [i].posY, 0.0, bridge [i].angl, bridge [i].zangl);

bridge [i].posY := bridge [i].posY + bridge [i].fllspd / Bomber_TimerGetFps ();

if (bridge [i].posY <= -5.0) then

begin

bridge [i].posY := -5.0;

bridge [i].fllspd := 0.0;

end;

if (i in [0, 4]) then

bridge [i].zangl := bridge [i].zangl + bridge [i].rotspd / Bomber_TimerGetFps ()

else

bridge [i].zangl := bridge [i].zangl - bridge [i].rotspd / Bomber_TimerGetFps ();

if (abs (bridge [i].zangl) >= 45.0) then

begin

bridge [i].rotspd := 0.0;

end;

end;

end;

procedure Bomber_BridgeCrashLeft ();

begin

if not (leftCrashed) then

begin

leftCrashed := TRUE;

bridge [0].rotspd := -30 - random (30);

bridge [3].rotspd := 30 + random (30);

bridge [1].fllspd := -5 - random (5);

bridge [2].fllspd := -5 - random (5);

end;

end;

procedure Bomber_BridgeCrashRight ();

begin

if not (rightCrashed) then

begin

rightCrashed := TRUE;

bridge [4].rotspd := -30 - random (30);

bridge [7].rotspd := 30 + random (30);

bridge [5].fllspd := -5 - random (5);

bridge [6].fllspd := -5 - random (5);

end;

end;

end.

unit bm_plane;

interface

function Bomber_PlaneInitialize (): BOOLEAN;

function Bomber_PlaneDraw (): BOOLEAN;

procedure Bomber_PlaneRestart ();

implementation

uses

Windows,

OpenGL,

Math,

bm_core,

bm_timer,

bm_math,

bm_model,

bm_brid,

bm_expl,

bm_scene;

const

MODEL_BOMB = 'bomb.tsm';

MODEL_PLANE = 'biplane.tsm';

MODEL_PROP = 'prop.tsm';

type

BOMB_T = record

OnBoard: BOOLEAN;

end;

var

modelBomb: INTEGER;

modelPlane: INTEGER;

modelProp: INTEGER;

bomb: ARRAY [0..MAX_BOMB_COUNT] OF BOMB_T;

planeX: SINGLE;

planeY: SINGLE;

planeZ: SINGLE;

propAngle: SINGLE;

bombfall: SET OF BYTE;

procedure Bomber_PlaneRestart ();

var

i: INTEGER;

begin

planeX := 0.0;

planeY := 20.0;

planeZ := 150.0;

propAngle := 0.0;

bombfall := [];

for i := BOMB_COUNT+1 to 4 do

bombfall := bombfall + [i];

end;

function Bomber_PlaneInitialize (): BOOLEAN;

var

i: INTEGER;

begin

modelBomb := Bomber_ModelLoad (MODEL_BOMB);

modelPlane := Bomber_ModelLoad (MODEL_PLANE);

modelProp := Bomber_ModelLoad (MODEL_PROP);

if (modelBomb = -1)

or (modelPlane = -1)

or (modelProp = -1) then

result := FALSE

else

result := TRUE;

for i := 0 to MAX_BOMB_COUNT-1 do

bomb [i].OnBoard := TRUE;

Bomber_PlaneRestart ();

end;

procedure DropBomb (i: INTEGER);

var

a: INTEGER;

begin

a := Round (ALFA_VALUE / 10);

if (bombpos [a, BOMB_COUNT - i].crash) then

begin

if (bombpos [a, BOMB_COUNT - i].y > 0) then

Bomber_BridgeCrashLeft ()

else

Bomber_BridgeCrashRight ();

end;

Bomber_ExploEnable (BOMB_COUNT - i + 1);

bombfall := bombfall + [i];

end;

function Bomber_PlaneDraw (): BOOLEAN;

var

fps: SINGLE;

x, z: SINGLE;

alfa: SINGLE;

i: INTEGER;

begin

if (planeZ > -100.0) then

begin

for i := 1 to 4 do

if (planeZ <= -i*10)

and (not (i in bombfall)) then

DropBomb (i);

alfa := 90 + ALFA_VALUE;

x := planeX * cos (DegToRad (alfa)) - planeZ * sin (DegToRad (90-alfa));

z := planeX * sin (DegToRad (alfa)) + planeZ * cos (DegToRad (90-alfa));

Bomber_ModelDraw (modelPlane, x, planeY, z, alfa + 90, 0.0);

Bomber_ModelDraw (modelProp, x, planeY, z, alfa + 90, propAngle);

fps := Bomber_TimerGetFps ();

propAngle := propAngle + 720.0 / fps;

if (propAngle >= 360.0) then

propAngle := propAngle - 360.0;

planeZ := planez - 33.3 / fps;

if (planeZ < 25) then

planeY := planeY + 5.0 / fps;

result := TRUE

end

else

result := FALSE;

end;

end.

unit bm_math;

interface

const

MAX_BOMB_COUNT = 4;

MONTE_CARLO_ITERATIONS = 1000;

type

BOMB_POS_T = record

x, y: SINGLE;

crash: BOOLEAN;

end;

var

BOMB_COUNT: INTEGER = 4;

bombPos: ARRAY [0..9, 0..MAX_BOMB_COUNT-1] OF BOMB_POS_T;

crashProbab: ARRAY [0..9] OF SINGLE;

procedure Bomber_MathProcess ();

function GenerateRandomX (a, sigma: SINGLE): SINGLE;

implementation

uses

Windows,

Math,

bm_core;

const

DELTA_L = 10; // Интервал между бомбами в серии

S_X_PR = 25; // СКО ошибки прицеливания по X

S_Y_PR = 40; // СКО ошибки прицеливания по Y

S_X_T = 10; // Техническое рассеивание по X

S_Y_T = 5; // Техническое рассеивание по Y

var

holdrand: CARDINAL = 0;

function GenerateRandomX (a, sigma: SINGLE): SINGLE;

const

k = 10;

var

r1, r2, v1, v2, s, res: SINGLE;

n: INTEGER;

begin

res := 0;

for n := 1 to k do

begin

repeat

r1 := random (100) / 100;

r2 := random (100) / 100;

v1 := 2 * r1 - 1;

v2 := 2 * r2 - 1;

s := v1 * v1 + v2 * v2;

until (not ((s > 1) or (s = 0)));

res := res + (a + sigma * (v1 * sqrt ((-2 * log10 (s)) / s)));

end;

result := res / k;

end;

procedure Bomber_MathProcess ();

var

i, k: INTEGER;

xpr, ypr: SINGLE;

dx, dy: SINGLE;

x, y: SINGLE;

n, m: INTEGER;

f: BOOLEAN;

begin

holdrand := GetTickCount ();

ZeroMemory (@bombPos, sizeof (bombPos));

ZeroMemory (@crashProbab, sizeof (crashProbab));

for n := 1 to MONTE_CARLO_ITERATIONS do

for i := 0 to 9 do

begin

f := TRUE;

for k := 1 to BOMB_COUNT do

begin

xpr := GenerateRandomX (0, S_X_PR);

ypr := GenerateRandomX (0, S_Y_PR);

dx := GenerateRandomX (0, S_X_T);

dy := GenerateRandomX (0, S_Y_T);

bombPos [i, k-1].x := xpr + (((BOMB_COUNT-1) / 2) - k + 1) * DELTA_L + dx;

bombPos [i, k-1].y := ypr + dy;

x := bombPos [i, k-1].x * cos (DegToRad (i * 10))

- bombPos [i, k-1].y * sin (DegToRad (i * 10));

y := bombPos [i, k-1].x * sin (DegToRad (i * 10))

- bombPos [i, k-1].y * cos (DegToRad (i * 10));

bombPos [i, k-1].x := x;

bombPos [i, k-1].y := y;

bombPos [i, k-1].crash :=

(abs (x) <= BRIDGE_WIDTH div 2)

and (abs (y) <= BRIDGE_LENGTH div 2);

if (bombPos [i, k-1].crash) and (f) then

begin

crashProbab [i] := crashProbab [i] + 1;

f := FALSE;

end;

end;

end;

for i := 0 to 9 do

crashProbab [i] := crashProbab [i] / MONTE_CARLO_ITERATIONS;

end;

end.

unit bm_effct;

interface

function Bomber_EffectInitialize (): BOOLEAN;

procedure Bomber_EffectDraw ();

implementation

uses

OpenGL,

bm_core,

bm_rend;

const

LINES_COUNT = 2;

EFFECT_COUNT = 2;

type

LINE_T = record

xpos: SINGLE;

lifetime: INTEGER;

end;

var

line: ARRAY [0..LINES_COUNT-1] OF LINE_T;

function Bomber_EffectInitialize (): BOOLEAN;

var

i: INTEGER;

begin

for i := 0 to LINES_COUNT-1 do

begin

line [i].xpos := random (WINDOW_WIDTH);

line [i].lifetime := random (5);

end;

result := TRUE;

end;

procedure Bomber_EffectDraw ();

var

i: INTEGER;

x, y: SINGLE;

begin

Bomber_RendSet2dMode ();

glBegin (GL_LINES);

for i := 0 to LINES_COUNT-1 do

begin

glVertex2f (line [i].xpos, 0.0);

glVertex2f (line [i].xpos, WINDOW_HEIGHT);

line [i].xpos := line [i].xpos - 5 + random (10);

if (line [i].xpos < 0) then

line [i].xpos := WINDOW_WIDTH + line [i].xpos;

if (line [i].xpos > WINDOW_WIDTH) then

line [i].xpos := line [i].xpos - WINDOW_WIDTH;

dec (line [i].lifetime);

if (line [i].lifetime <= 0) then

begin

line [i].xpos := random (WINDOW_WIDTH);

line [i].lifetime := random (10);

end;

end;

glEnd ();

for i := 0 to EFFECT_COUNT-1 do

begin

x := random (WINDOW_WIDTH);

y := random (WINDOW_HEIGHT);

glBegin (GL_LINE_STRIP);

glVertex2f (x, y);

glVertex2f (x + random (15), y + random (15));

glVertex2f (x + random (15), y + random (15));

glVertex2f (x + random (15), y + random (15));

glEnd ();

end;

glBegin (GL_QUADS);

glVertex2f (WINDOW_WIDTH, 0);

glVertex2f (0, 0);

glVertex2f (0, WINDOW_HEIGHT / 10);

glVertex2f (WINDOW_WIDTH, WINDOW_HEIGHT / 10);

glVertex2f (WINDOW_WIDTH, WINDOW_HEIGHT - WINDOW_HEIGHT / 10);

glVertex2f (0, WINDOW_HEIGHT - WINDOW_HEIGHT / 10);

glVertex2f (0, WINDOW_HEIGHT);

glVertex2f (WINDOW_WIDTH, WINDOW_HEIGHT);

glEnd ();

Bomber_RendSet3dMode ();

end;

end.

unit bm_expl;

interface

function Bomber_ExploInitialize (): BOOLEAN;

procedure Bomber_ExploSetup (index: INTEGER);

procedure Bomber_ExploDraw ();

procedure Bomber_ExploEnable (bomb: BYTE);

implementation

uses

Windows,

OpenGL,

bm_timer,

bm_math;

const

MAX_PARTICLE_COUNT = 2000;

type

PARTICLE_T = record

enabled: BOOLEAN;

method: BYTE;

x, y, z: SINGLE;

sx, sy, sz: SINGLE;

end;

var

particle: ARRAY [1..MAX_BOMB_COUNT, 1..MAX_PARTICLE_COUNT] OF PARTICLE_T;

function Bomber_ExploInitialize (): BOOLEAN;

begin

ZeroMemory (@particle, sizeof (particle));

result := TRUE;

end;

procedure Bomber_ExploSetup (index: INTEGER);

var

b, i: INTEGER;

x, y: SINGLE;

begin

for b := 1 to MAX_BOMB_COUNT do

for i := 1 to MAX_PARTICLE_COUNT do

begin

x := bombPos [index, b-1].x;

y := bombPos [index, b-1].y;

if (abs (y) <= 50) and ((x > 5) or (x < -5)) then

particle [b, i].method := 1

else

particle [b, i].method := 2;

particle [b, i].enabled := FALSE;

particle [b, i].x := -y + (-30 + random (60)) / 7;

particle [b, i].z := -x + (-30 + random (60)) / 7;

if (particle [b, i].method = 1) then

begin

particle [b, i].y := -3.0;

particle [b, i].sx := 0;

particle [b, i].sy := random (750) / 10;

particle [b, i].sz := 0;

end;

if (particle [b, i].method = 2) then

begin

particle [b, i].y := 0;

particle [b, i].sx := -5 + random (10);

particle [b, i].sy := random (250) / 10;

particle [b, i].sz := -5 + random (10);

end;

end;

end;

procedure Bomber_ExploDraw ();

var

b, i: INTEGER;

begin

glPushAttrib (GL_ALL_ATTRIB_BITS);

glDisable (GL_LIGHTING);

glEnable (GL_BLEND);

glBlendFunc (GL_ONE, GL_SRC_ALPHA);

glBegin (GL_LINES);

for b := 1 to MAX_BOMB_COUNT do

for i := 1 to MAX_PARTICLE_COUNT do

if (particle [b, i].enabled) then

begin

if (particle [b, i].method = 1) then

begin

glColor4f (0.5, 0.5, 0.5, 0.25);

particle [b, i].y := particle [b, i].y + particle [b, i].sy / Bomber_TimerGetFps ();

particle [b, i].sy := particle [b, i].sy - 75 / Bomber_TimerGetFps ();

if (particle [b, i].y < -3.0) then

particle [b, i].enabled := FALSE

else

begin

glVertex3f (particle [b, i].x - 0.5, particle [b, i].y, particle [b, i].z);

glVertex3f (particle [b, i].x, particle [b, i].y, particle [b, i].z + 0.5);

end;

end;

if (particle [b, i].method = 2) then

begin

glColor4f (0.1, 0.1, 0.1, 0.25);

particle [b, i].x := particle [b, i].x + particle [b, i].sz / Bomber_TimerGetFps ();

particle [b, i].y := particle [b, i].y + particle [b, i].sy / Bomber_TimerGetFps ();

particle [b, i].z := particle [b, i].z + particle [b, i].sx / Bomber_TimerGetFps ();

particle [b, i].sy := particle [b, i].sy - 10 / Bomber_TimerGetFps ();

if (particle [b, i].y < 0.0) then

begin

particle [b, i].enabled := FALSE;

end

else

begin

glVertex3f (particle [b, i].x - 0.5, particle [b, i].y, particle [b, i].z);

glVertex3f (particle [b, i].x, particle [b, i].y, particle [b, i].z + 0.5);

end;

end;

end;

glEnd ();

glPopAttrib ();

end;

procedure Bomber_ExploEnable (bomb: BYTE);

var

i: INTEGER;

begin

for i := 1 to MAX_PARTICLE_COUNT do

particle [bomb, i].enabled := TRUE;

end;

end.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]