fdArchipelago.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. unit fdArchipelago;
  2. interface
  3. uses
  4. Winapi.Windows,
  5. Winapi.OpenGL,
  6. System.SysUtils,
  7. System.Classes,
  8. System.Math,
  9. Vcl.StdCtrls,
  10. Vcl.Graphics,
  11. Vcl.Controls,
  12. Vcl.ExtCtrls,
  13. Vcl.ComCtrls,
  14. Vcl.Forms,
  15. Vcl.Dialogs,
  16. Vcl.Imaging.Jpeg,
  17. Stage.OpenGLTokens,
  18. Stage.VectorTypes,
  19. Stage.VectorGeometry,
  20. Stage.TextureFormat,
  21. Stage.Keyboard,
  22. Stage.Utils,
  23. GLS.Scene,
  24. GLS.Coordinates,
  25. GLS.BaseClasses,
  26. GLS.VectorLists,
  27. GLS.XCollection,
  28. GLS.Cadencer,
  29. GLS.Objects,
  30. GLS.TerrainRenderer,
  31. GLS.HeightData,
  32. GLS.HeightTileFileHDS,
  33. GLS.Texture,
  34. GLS.HUDObjects,
  35. GLS.Material,
  36. GLS.SkyDome,
  37. GLS.SceneViewer,
  38. GLS.WindowsFont,
  39. GLS.BitmapFont,
  40. GLS.RenderContextInfo,
  41. GLS.Color,
  42. GLS.VectorFileObjects,
  43. GLS.Context,
  44. GLS.State,
  45. GLS.File3DS,
  46. GLS.Navigator;
  47. type
  48. TForm1 = class(TForm)
  49. GLSceneViewer1: TGLSceneViewer;
  50. GLScene1: TGLScene;
  51. Camera: TGLCamera;
  52. dcCamera: TGLDummyCube;
  53. TerrainRenderer: TGLTerrainRenderer;
  54. Timer1: TTimer;
  55. GLCadencer: TGLCadencer;
  56. MLTerrain: TGLMaterialLibrary;
  57. htFPS: TGLHUDText;
  58. SkyDome: TGLSkyDome;
  59. GLHeightTileFileHDS1: TGLHeightTileFileHDS;
  60. BFSmall: TGLWindowsBitmapFont;
  61. GLCustomHDS1: TGLCustomHDS;
  62. PAProgress: TPanel;
  63. ProgressBar: TProgressBar;
  64. Label1: TLabel;
  65. GLMemoryViewer1: TGLMemoryViewer;
  66. MLSailBoat: TGLMaterialLibrary;
  67. FFSailBoat: TGLFreeForm;
  68. lsSun: TGLLightSource;
  69. BFLarge: TGLWindowsBitmapFont;
  70. HTHelp: TGLHUDText;
  71. doWake: TGLDirectOpenGL;
  72. dcSailBoat: TGLDummyCube;
  73. procedure Timer1Timer(Sender: TObject);
  74. procedure GLCadencerProgress(Sender: TObject; const deltaTime,
  75. newTime: Double);
  76. procedure FormCreate(Sender: TObject);
  77. procedure FormKeyPress(Sender: TObject; var Key: Char);
  78. procedure GLCustomHDS1MarkDirtyEvent(const area: TRect);
  79. procedure GLCustomHDS1StartPreparingData(heightData: TGLHeightData);
  80. procedure GLSceneViewerBeforeRender(Sender: TObject);
  81. procedure doWakeProgress(Sender: TObject; const deltaTime,
  82. newTime: Double);
  83. procedure doWakeRender(Sender: TObject; var rci: TGLRenderContextInfo);
  84. procedure TerrainRendererHeightDataPostRender(var rci: TGLRenderContextInfo;
  85. var HeightDatas: TList);
  86. procedure FormShow(Sender: TObject);
  87. public
  88. FullScreen: Boolean;
  89. CamHeight: Single;
  90. WaterPolyCount: Integer;
  91. WaterPlane: Boolean;
  92. WasAboveWater: Boolean;
  93. HelpOpacity: Single;
  94. WakeVertices: TGLAffineVectorList;
  95. WakeStretch: TGLAffineVectorList;
  96. WakeTime: TGLSingleList;
  97. procedure ResetMousePos;
  98. function WaterPhase(const px, py: Single): Single;
  99. function WaterHeight(const px, py: Single): Single;
  100. private
  101. DataPath : TFileName;
  102. AssetPath : TFileName;
  103. end;
  104. var
  105. Form1: TForm1;
  106. implementation
  107. {$R *.DFM}
  108. const
  109. cWaterLevel = -10000;
  110. cWaterOpaqueDepth = 2000;
  111. cWaveAmplitude = 120;
  112. procedure TForm1.FormCreate(Sender: TObject);
  113. var
  114. i, j: Integer;
  115. name: string;
  116. libMat: TGLLibMaterial;
  117. begin
  118. DataPath := ExtractFilePath(ParamStr(0));
  119. DataPath := DataPath + 'Data\';
  120. SetCurrentDir(DataPath);
  121. MLTerrain.TexturePaths := DataPath;
  122. MLSailBoat.TexturePaths := DataPath;
  123. GLCustomHDS1.MaxPoolSize := 8 * 1024 * 1024;
  124. GLCustomHDS1.DefaultHeight := cWaterLevel;
  125. // load texmaps
  126. for i := 0 to 3 do
  127. for j := 0 to 3 do
  128. begin
  129. name := Format('Tex_%d_%d.bmp', [i, j]);
  130. if not FileExists(name) then
  131. begin
  132. ShowMessage('Texture file ' + name + ' not found...'#13#10
  133. + 'Did you run "splitter.exe" as said in the readme.txt?');
  134. Application.Terminate;
  135. Exit;
  136. end;
  137. libMat := MLTerrain.AddTextureMaterial(name, name, False);
  138. with libMat.Material.Texture do
  139. begin
  140. TextureMode := tmReplace;
  141. TextureWrap := twNone;
  142. Compression := tcStandard; // comment out to turn off texture compression
  143. // FilteringQuality := tfAnisotropic;
  144. end;
  145. libMat.Texture2Name := 'detail';
  146. end;
  147. // Initial camera height offset (controled with pageUp/pageDown)
  148. CamHeight := 20;
  149. // Water plane active
  150. WaterPlane := True;
  151. // load the sailboat
  152. (* lost material for sailboat
  153. FFSailBoat.LoadFromFile('sailboat.glsm');
  154. MLSailBoat.LoadFromFile('sailboat.glml');
  155. *)
  156. AssetPath := GetCurrentAssetPath() + '\model';
  157. SetCurrentDir(AssetPath);
  158. FFSailBoat.LoadFromFile('boat.3ds');
  159. FFSailBoat.Position.SetPoint(-125 * TerrainRenderer.Scale.X, 0, -100 * TerrainRenderer.Scale.Z);
  160. FFSailBoat.TurnAngle := -30;
  161. // boost ambient
  162. for i := 0 to MLSailBoat.Materials.Count - 1 do
  163. with MLSailBoat.Materials[i].Material.FrontProperties do
  164. Ambient.Color := Diffuse.Color;
  165. // Move camera starting point near the sailboat
  166. DCCamera.Position := FFSailBoat.Position;
  167. DCCamera.Translate(25, 0, -15);
  168. DCCamera.Turn(200);
  169. // Help text
  170. HTHelp.Text := 'Archipelago Demo'#13#10#13#10
  171. + '* : Increase CLOD precision'#13#10
  172. + '/ : decrease CLOD precision'#13#10
  173. + 'W : wireframe on/off'#13#10
  174. + 'S : sea surface on/off'#13#10
  175. + 'B : sailboat visible on/off'#13#10
  176. + 'Num4 & Num6 : steer the sailboat'#13#10
  177. + 'F1: show this help';
  178. HTHelp.Position.SetPoint(Screen.Width div 2 - 100,
  179. Screen.Height div 2 - 150, 0);
  180. HelpOpacity := 4;
  181. GLSceneViewer1.Cursor := crNone;
  182. SetCurrentDir(DataPath);
  183. end;
  184. procedure TForm1.ResetMousePos;
  185. begin
  186. if GLSceneViewer1.Cursor = crNone then
  187. SetCursorPos(Screen.Width div 2, Screen.Height div 2);
  188. end;
  189. procedure TForm1.GLCadencerProgress(Sender: TObject; const deltaTime,
  190. newTime: Double);
  191. var
  192. speed, alpha, f: Single;
  193. terrainHeight, surfaceHeight: Single;
  194. sbp: TGLVector;
  195. newMousePos: TPoint;
  196. begin
  197. // handle keypresses
  198. if IsKeyDown(VK_SHIFT) then
  199. speed := 100 * deltaTime
  200. else
  201. speed := 20 * deltaTime;
  202. with Camera.Position do
  203. begin
  204. if IsKeyDown(VK_UP) then
  205. DCCamera.Position.AddScaledVector(speed, Camera.AbsoluteVectorToTarget);
  206. if IsKeyDown(VK_DOWN) then
  207. DCCamera.Position.AddScaledVector(-speed, Camera.AbsoluteVectorToTarget);
  208. if IsKeyDown(VK_LEFT) then
  209. DCCamera.Position.AddScaledVector(-speed, Camera.AbsoluteRightVectorToTarget);
  210. if IsKeyDown(VK_RIGHT) then
  211. DCCamera.Position.AddScaledVector(speed, Camera.AbsoluteRightVectorToTarget);
  212. if IsKeyDown(VK_PRIOR) then
  213. CamHeight := CamHeight + speed;
  214. if IsKeyDown(VK_NEXT) then
  215. CamHeight := CamHeight - speed;
  216. if IsKeyDown(VK_ESCAPE) then
  217. Close;
  218. end;
  219. if IsKeyDown(VK_F1) then
  220. HelpOpacity := ClampValue(HelpOpacity + deltaTime * 3, 0, 3);
  221. if IsKeyDown(VK_NUMPAD4) then
  222. FFSailBoat.Turn(-deltaTime * 3);
  223. if IsKeyDown(VK_NUMPAD6) then
  224. FFSailBoat.Turn(deltaTime * 3);
  225. // mouse movements and actions
  226. if IsKeyDown(VK_LBUTTON) then
  227. begin
  228. alpha := DCCamera.Position.Y;
  229. DCCamera.Position.AddScaledVector(speed, Camera.AbsoluteVectorToTarget);
  230. CamHeight := CamHeight + DCCamera.Position.Y - alpha;
  231. end;
  232. if IsKeyDown(VK_RBUTTON) then
  233. begin
  234. alpha := DCCamera.Position.Y;
  235. DCCamera.Position.AddScaledVector(-speed, Camera.AbsoluteVectorToTarget);
  236. CamHeight := CamHeight + DCCamera.Position.Y - alpha;
  237. end;
  238. GetCursorPos(newMousePos);
  239. Camera.MoveAroundTarget((Screen.Height div 2 - newMousePos.Y) * 0.25,
  240. (Screen.Width div 2 - newMousePos.X) * 0.25);
  241. ResetMousePos;
  242. // don't drop our target through terrain!
  243. with DCCamera.Position do
  244. begin
  245. terrainHeight := TerrainRenderer.InterpolatedHeight(AsVector);
  246. surfaceHeight := TerrainRenderer.Scale.Z * cWaterLevel / 128;
  247. if terrainHeight < surfaceHeight then
  248. terrainHeight := surfaceHeight;
  249. Y := terrainHeight + CamHeight;
  250. end;
  251. // adjust fog distance/color for air/water
  252. if (Camera.AbsolutePosition.Y > surfaceHeight) or (not WaterPlane) then
  253. begin
  254. if not WasAboveWater then
  255. begin
  256. SkyDome.Visible := True;
  257. with GLSceneViewer1.Buffer.FogEnvironment do
  258. begin
  259. FogColor.Color := clrWhite;
  260. FogEnd := 1000;
  261. FogStart := 500;
  262. end;
  263. GLSceneViewer1.Buffer.BackgroundColor := clWhite;
  264. Camera.DepthOfView := 1000;
  265. WasAboveWater := True;
  266. end;
  267. end
  268. else
  269. begin
  270. if WasAboveWater then
  271. begin
  272. SkyDome.Visible := False;
  273. with GLSceneViewer1.Buffer.FogEnvironment do
  274. begin
  275. FogColor.AsWinColor := clNavy;
  276. FogEnd := 100;
  277. FogStart := 0;
  278. end;
  279. GLSceneViewer1.Buffer.BackgroundColor := clNavy;
  280. Camera.DepthOfView := 100;
  281. WasAboveWater := False;
  282. end;
  283. end;
  284. // help visibility
  285. if HelpOpacity > 0 then
  286. begin
  287. HelpOpacity := HelpOpacity - deltaTime;
  288. alpha := ClampValue(HelpOpacity, 0, 1);
  289. if alpha > 0 then
  290. begin
  291. HTHelp.Visible := True;
  292. HTHelp.ModulateColor.Alpha := alpha;
  293. end
  294. else
  295. HTHelp.Visible := False;
  296. end;
  297. // rock the sailboat
  298. sbp := TerrainRenderer.AbsoluteToLocal(FFSailBoat.AbsolutePosition);
  299. alpha := WaterPhase(sbp.X + TerrainRenderer.TileSize * 0.5, sbp.Y + TerrainRenderer.TileSize * 0.5);
  300. FFSailBoat.Position.Y := (cWaterLevel + Sin(alpha) * cWaveAmplitude) * (TerrainRenderer.Scale.Z / 128)
  301. + 4;
  302. f := cWaveAmplitude * 0.01;
  303. FFSailBoat.Up.SetVector(Cos(alpha) * 0.02 * f, 1, (Sin(alpha) * 0.02 - 0.005) * f);
  304. FFSailBoat.Move(deltaTime * 2);
  305. end;
  306. procedure TForm1.TerrainRendererHeightDataPostRender(
  307. var rci: TGLRenderContextInfo; var HeightDatas: TList);
  308. var
  309. i, x, y, s, s2: Integer;
  310. t: Single;
  311. hd: TGLHeightData;
  312. const
  313. r = 0.75;
  314. g = 0.75;
  315. b = 1;
  316. procedure IssuePoint(rx, ry: Integer);
  317. var
  318. px, py: Single;
  319. alpha, colorRatio, ca, sa: Single;
  320. begin
  321. px := x + rx + s2;
  322. py := y + ry + s2;
  323. if hd.DataState = hdsNone then
  324. begin
  325. alpha := 1;
  326. end
  327. else
  328. begin
  329. alpha := (cWaterLevel - hd.SmallIntHeight(rx, ry)) * (1 / cWaterOpaqueDepth);
  330. alpha := ClampValue(alpha, 0.5, 1);
  331. end;
  332. SinCos(WaterPhase(px, py), sa, ca);
  333. colorRatio := 1 - alpha * 0.1;
  334. glColor4f(r * colorRatio, g * colorRatio, b, alpha);
  335. glTexCoord2f(px * 0.01 + 0.002 * sa, py * 0.01 + 0.0022 * ca - t * 0.002);
  336. glVertex3f(px, py, cWaterLevel + cWaveAmplitude * sa);
  337. end;
  338. begin
  339. if not WaterPlane then
  340. Exit;
  341. t := GLCadencer.CurrentTime;
  342. MLTerrain.ApplyMaterial('water', rci);
  343. repeat
  344. with rci.GLStates do
  345. begin
  346. if not WasAboveWater then
  347. InvertFrontFace;
  348. Disable(stLighting);
  349. Disable(stNormalize);
  350. SetStencilFunc(cfAlways, 1, 255);
  351. StencilWriteMask := 255;
  352. Enable(stStencilTest);
  353. SetStencilOp(soKeep, soKeep, soReplace);
  354. glNormal3f(0, 0, 1);
  355. for i := 0 to heightDatas.Count - 1 do
  356. begin
  357. hd := TGLHeightData(heightDatas.List[i]);
  358. if (hd.DataState = hdsReady) and (hd.HeightMin > cWaterLevel) then
  359. continue;
  360. x := hd.XLeft;
  361. y := hd.YTop;
  362. s := hd.Size - 1;
  363. s2 := s div 2;
  364. glBegin(GL_TRIANGLE_FAN);
  365. IssuePoint(s2, s2);
  366. IssuePoint(0, 0);
  367. IssuePoint(s2, 0);
  368. IssuePoint(s, 0);
  369. IssuePoint(s, s2);
  370. IssuePoint(s, s);
  371. IssuePoint(s2, s);
  372. IssuePoint(0, s);
  373. IssuePoint(0, s2);
  374. IssuePoint(0, 0);
  375. glEnd;
  376. end;
  377. SetStencilOp(soKeep, soKeep, soKeep);
  378. Disable(stStencilTest);
  379. end;
  380. if not WasAboveWater then
  381. rci.GLStates.InvertFrontFace;
  382. WaterPolyCount := heightDatas.Count * 8;
  383. until not MLTerrain.UnApplyMaterial(rci);
  384. end;
  385. procedure TForm1.Timer1Timer(Sender: TObject);
  386. begin
  387. htFPS.Text := Format('%.1f FPS - %d - %d',
  388. [GLSceneViewer1.FramesPerSecond,
  389. TerrainRenderer.LastTriangleCount,
  390. WaterPolyCount]);
  391. GLSceneViewer1.ResetPerformanceMonitor;
  392. end;
  393. procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
  394. var
  395. i: Integer;
  396. pm: TGLPolygonMode;
  397. begin
  398. case Key of
  399. 'w', 'W':
  400. begin
  401. with MLTerrain do
  402. begin
  403. if Materials[0].Material.PolygonMode = pmLines then
  404. pm := pmFill
  405. else
  406. pm := pmLines;
  407. for i := 0 to Materials.Count - 1 do
  408. Materials[i].Material.PolygonMode := pm;
  409. end;
  410. with MLSailBoat do
  411. for i := 0 to Materials.Count - 1 do
  412. Materials[i].Material.PolygonMode := pm;
  413. FFSailBoat.StructureChanged;
  414. end;
  415. 's', 'S': WaterPlane := not WaterPlane;
  416. 'b', 'B': FFSailBoat.Visible := not FFSailBoat.Visible;
  417. '*': with TerrainRenderer do
  418. if CLODPrecision > 1 then
  419. CLODPrecision := Round(CLODPrecision * 0.8);
  420. '/': with TerrainRenderer do
  421. if CLODPrecision < 1000 then
  422. CLODPrecision := Round(CLODPrecision * 1.2 + 1);
  423. end;
  424. Key := #0;
  425. end;
  426. procedure TForm1.FormShow(Sender: TObject);
  427. begin
  428. TerrainRenderer.Up.SetVector(0, 0, 1);
  429. TerrainRenderer.Direction.SetVector(0, 1, 0);
  430. end;
  431. procedure TForm1.GLCustomHDS1MarkDirtyEvent(const area: TRect);
  432. begin
  433. GLHeightTileFileHDS1.MarkDirty(area);
  434. end;
  435. procedure TForm1.GLCustomHDS1StartPreparingData(heightData: TGLHeightData);
  436. var
  437. htfHD: TGLHeightData;
  438. i, j, n: Integer;
  439. offset: TTexPoint;
  440. begin
  441. htfHD := GLHeightTileFileHDS1.GetData(heightData.XLeft, heightData.YTop, heightData.Size, heightData.DataType);
  442. if (htfHD.DataState = hdsNone) then //or (htfHD.HeightMax <= cWaterLevel - cWaterOpaqueDepth) then
  443. heightData.DataState := hdsNone
  444. else
  445. begin
  446. i := (heightData.XLeft div 128);
  447. j := (heightData.YTop div 128);
  448. if (Cardinal(i) < 4) and (Cardinal(j) < 4) then
  449. begin
  450. heightData.MaterialName := format('Tex_%d_%d.bmp', [i, j]);
  451. heightData.TextureCoordinatesMode := tcmLocal;
  452. n := ((heightData.XLeft div 32) and 3);
  453. offset.S := n * 0.25;
  454. n := ((heightData.YTop div 32) and 3);
  455. offset.T := -n * 0.25;
  456. heightData.TextureCoordinatesOffset := offset;
  457. heightData.TextureCoordinatesScale := TexPointMake(0.25, 0.25);
  458. heightData.DataType := hdtSmallInt;
  459. htfHD.DataType := hdtSmallInt;
  460. heightData.Allocate(hdtSmallInt);
  461. Move(htfHD.SmallIntData^, heightData.SmallIntData^, htfHD.DataSize);
  462. heightData.DataState := hdsReady;
  463. heightData.HeightMin := htfHD.HeightMin;
  464. heightData.HeightMax := htfHD.HeightMax;
  465. end
  466. else
  467. heightData.DataState := hdsNone
  468. end;
  469. GLHeightTileFileHDS1.Release(htfHD);
  470. end;
  471. procedure TForm1.GLSceneViewerBeforeRender(Sender: TObject);
  472. var
  473. i, n: Integer;
  474. begin
  475. PAProgress.Left := (Width - PAProgress.Width) div 2;
  476. PAProgress.Visible := True;
  477. n := MLTerrain.Materials.Count;
  478. ProgressBar.Max := n - 1;
  479. try
  480. for i := 0 to n - 1 do
  481. begin
  482. ProgressBar.Position := i;
  483. MLTerrain.Materials[i].Material.Texture.Handle;
  484. PAProgress.Repaint;
  485. end;
  486. finally
  487. ResetMousePos;
  488. PAProgress.Visible := False;
  489. GLSceneViewer1.BeforeRender := nil;
  490. end;
  491. end;
  492. function TForm1.WaterPhase(const px, py: Single): Single;
  493. begin
  494. Result := GLCadencer.CurrentTime * 1 + px * 0.16 + py * 0.09;
  495. end;
  496. function TForm1.WaterHeight(const px, py: Single): Single;
  497. var
  498. alpha: Single;
  499. begin
  500. alpha := WaterPhase(px + TerrainRenderer.TileSize * 0.5,
  501. py + TerrainRenderer.TileSize * 0.5);
  502. Result := (cWaterLevel + Sin(alpha) * cWaveAmplitude) * (TerrainRenderer.Scale.Z * (1 / 128));
  503. end;
  504. procedure TForm1.doWakeProgress(Sender: TObject; const deltaTime,
  505. newTime: Double);
  506. var
  507. i: Integer;
  508. sbp, sbr: TGLVector;
  509. begin
  510. if WakeVertices = nil then
  511. begin
  512. WakeVertices := TGLAffineVectorList.Create;
  513. WakeStretch := TGLAffineVectorList.Create;
  514. WakeTime := TGLSingleList.Create;
  515. end;
  516. // enlarge current vertices
  517. with WakeVertices do
  518. begin
  519. i := 0;
  520. while i < Count do
  521. begin
  522. CombineItem(i, WakeStretch.List[i shr 1], -0.45 * deltaTime);
  523. CombineItem(i + 1, WakeStretch.List[i shr 1], 0.45 * deltaTime);
  524. Inc(i, 2);
  525. end;
  526. end;
  527. // Progress wake
  528. if newTime > DOWake.TagFloat then
  529. begin
  530. if DOWake.TagFloat = 0 then
  531. begin
  532. DOWake.TagFloat := newTime + 0.2;
  533. Exit;
  534. end;
  535. DOWake.TagFloat := newTime + 1;
  536. sbp := VectorCombine(FFSailBoat.AbsolutePosition, FFSailBoat.AbsoluteDirection, 1, 3);
  537. sbr := FFSailBoat.AbsoluteRight;
  538. // add new
  539. WakeVertices.Add(VectorCombine(sbp, sbr, 1, -2));
  540. WakeVertices.Add(VectorCombine(sbp, sbr, 1, 2));
  541. WakeStretch.Add(VectorScale(sbr, (0.95 + Random * 0.1)));
  542. WakeTime.Add(newTime * 0.1);
  543. if WakeVertices.Count >= 80 then
  544. begin
  545. WakeVertices.Delete(0);
  546. WakeVertices.Delete(0);
  547. WakeStretch.Delete(0);
  548. WakeTime.Delete(0);
  549. end;
  550. end;
  551. end;
  552. procedure TForm1.doWakeRender(Sender: TObject; var rci: TGLRenderContextInfo);
  553. var
  554. i: Integer;
  555. p: PAffineVector;
  556. sbp: TGLVector;
  557. c: Single;
  558. begin
  559. if not Assigned(WakeVertices) then
  560. Exit;
  561. if (not FFSailBoat.Visible) or (not WaterPlane) then
  562. Exit;
  563. MLTerrain.ApplyMaterial('wake', rci);
  564. repeat
  565. with rci.GLStates do
  566. begin
  567. Disable(stLighting);
  568. Disable(stFog);
  569. Enable(stBlend);
  570. SetBlendFunc(bfOne, bfOne);
  571. SetStencilFunc(cfEqual, 1, 255);
  572. StencilWriteMask := 255;
  573. Enable(stStencilTest);
  574. SetStencilOp(soKeep, soKeep, soKeep);
  575. Disable(stDepthTest);
  576. if not WasAboveWater then
  577. InvertFrontFace;
  578. glBegin(GL_TRIANGLE_STRIP);
  579. for i := 0 to WakeVertices.Count - 1 do
  580. begin
  581. p := @WakeVertices.List[i xor 1];
  582. sbp := TerrainRenderer.AbsoluteToLocal(VectorMake(p^));
  583. if (i and 1) = 0 then
  584. begin
  585. c := (i and $FFE) * 0.2 / WakeVertices.Count;
  586. glColor3f(c, c, c);
  587. glTexCoord2f(0, WakeTime[i div 2]);
  588. end
  589. else
  590. glTexCoord2f(1, WakeTime[i div 2]);
  591. glVertex3f(p.X, WaterHeight(sbp.X, sbp.Y), p.Z);
  592. end;
  593. glEnd;
  594. if not WasAboveWater then
  595. InvertFrontFace;
  596. Disable(stStencilTest);
  597. end;
  598. until not MLTerrain.UnApplyMaterial(rci);
  599. end;
  600. end.