fArchipelagoD.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. unit fArchipelagoD;
  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. MaterialLibrary: 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. AssetPath := GetCurrentAssetPath() + '\texture';
  119. // SetCurrentDir(AssetPath); // for loading from assets dir
  120. DataPath := ExtractFilePath(ParamStr(0));
  121. DataPath := DataPath + 'Data\';
  122. SetCurrentDir(DataPath);
  123. MaterialLibrary.TexturePaths := DataPath;
  124. MLSailBoat.TexturePaths := DataPath;
  125. GLCustomHDS1.MaxPoolSize := 8 * 1024 * 1024;
  126. GLCustomHDS1.DefaultHeight := cWaterLevel;
  127. // load texmaps
  128. for i := 0 to 3 do
  129. for j := 0 to 3 do
  130. begin
  131. name := Format('Tex_%d_%d.bmp', [i, j]);
  132. if not FileExists(name) then
  133. begin
  134. ShowMessage('Texture file ' + name + ' not found...'#13#10
  135. + 'Did you run "splitter.exe" as said in the readme.txt?');
  136. Application.Terminate;
  137. Exit;
  138. end;
  139. libMat := MaterialLibrary.AddTextureMaterial(name, name, False);
  140. with libMat.Material.Texture do
  141. begin
  142. TextureMode := tmReplace;
  143. TextureWrap := twNone;
  144. Compression := tcStandard; // comment out to turn off texture compression
  145. // FilteringQuality := tfAnisotropic;
  146. end;
  147. libMat.Texture2Name := 'detail';
  148. end;
  149. // Initial camera height offset (controled with pageUp/pageDown)
  150. CamHeight := 20;
  151. // Water plane active
  152. WaterPlane := True;
  153. // load the sailboat
  154. (* lost material for sailboat
  155. FFSailBoat.LoadFromFile('sailboat.glsm');
  156. MLSailBoat.LoadFromFile('sailboat.glml');
  157. *)
  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. end;
  183. procedure TForm1.ResetMousePos;
  184. begin
  185. if GLSceneViewer1.Cursor = crNone then
  186. SetCursorPos(Screen.Width div 2, Screen.Height div 2);
  187. end;
  188. procedure TForm1.GLCadencerProgress(Sender: TObject; const deltaTime,
  189. newTime: Double);
  190. var
  191. speed, alpha, f: Single;
  192. terrainHeight, surfaceHeight: Single;
  193. sbp: TGLVector;
  194. newMousePos: TPoint;
  195. begin
  196. // handle keypresses
  197. if IsKeyDown(VK_SHIFT) then
  198. speed := 100 * deltaTime
  199. else
  200. speed := 20 * deltaTime;
  201. with Camera.Position do
  202. begin
  203. if IsKeyDown(VK_UP) then
  204. DCCamera.Position.AddScaledVector(speed, Camera.AbsoluteVectorToTarget);
  205. if IsKeyDown(VK_DOWN) then
  206. DCCamera.Position.AddScaledVector(-speed, Camera.AbsoluteVectorToTarget);
  207. if IsKeyDown(VK_LEFT) then
  208. DCCamera.Position.AddScaledVector(-speed, Camera.AbsoluteRightVectorToTarget);
  209. if IsKeyDown(VK_RIGHT) then
  210. DCCamera.Position.AddScaledVector(speed, Camera.AbsoluteRightVectorToTarget);
  211. if IsKeyDown(VK_PRIOR) then
  212. CamHeight := CamHeight + speed;
  213. if IsKeyDown(VK_NEXT) then
  214. CamHeight := CamHeight - speed;
  215. if IsKeyDown(VK_ESCAPE) then
  216. Close;
  217. end;
  218. if IsKeyDown(VK_F1) then
  219. HelpOpacity := ClampValue(HelpOpacity + deltaTime * 3, 0, 3);
  220. if IsKeyDown(VK_NUMPAD4) then
  221. FFSailBoat.Turn(-deltaTime * 3);
  222. if IsKeyDown(VK_NUMPAD6) then
  223. FFSailBoat.Turn(deltaTime * 3);
  224. // mouse movements and actions
  225. if IsKeyDown(VK_LBUTTON) then
  226. begin
  227. alpha := DCCamera.Position.Y;
  228. DCCamera.Position.AddScaledVector(speed, Camera.AbsoluteVectorToTarget);
  229. CamHeight := CamHeight + DCCamera.Position.Y - alpha;
  230. end;
  231. if IsKeyDown(VK_RBUTTON) then
  232. begin
  233. alpha := DCCamera.Position.Y;
  234. DCCamera.Position.AddScaledVector(-speed, Camera.AbsoluteVectorToTarget);
  235. CamHeight := CamHeight + DCCamera.Position.Y - alpha;
  236. end;
  237. GetCursorPos(newMousePos);
  238. Camera.MoveAroundTarget((Screen.Height div 2 - newMousePos.Y) * 0.25,
  239. (Screen.Width div 2 - newMousePos.X) * 0.25);
  240. ResetMousePos;
  241. // don't drop our target through terrain!
  242. with DCCamera.Position do
  243. begin
  244. terrainHeight := TerrainRenderer.InterpolatedHeight(AsVector);
  245. surfaceHeight := TerrainRenderer.Scale.Z * cWaterLevel / 128;
  246. if terrainHeight < surfaceHeight then
  247. terrainHeight := surfaceHeight;
  248. Y := terrainHeight + CamHeight;
  249. end;
  250. // adjust fog distance/color for air/water
  251. if (Camera.AbsolutePosition.Y > surfaceHeight) or (not WaterPlane) then
  252. begin
  253. if not WasAboveWater then
  254. begin
  255. SkyDome.Visible := True;
  256. with GLSceneViewer1.Buffer.FogEnvironment do
  257. begin
  258. FogColor.Color := clrWhite;
  259. FogEnd := 1000;
  260. FogStart := 500;
  261. end;
  262. GLSceneViewer1.Buffer.BackgroundColor := clWhite;
  263. Camera.DepthOfView := 1000;
  264. WasAboveWater := True;
  265. end;
  266. end
  267. else
  268. begin
  269. if WasAboveWater then
  270. begin
  271. SkyDome.Visible := False;
  272. with GLSceneViewer1.Buffer.FogEnvironment do
  273. begin
  274. FogColor.AsWinColor := clNavy;
  275. FogEnd := 100;
  276. FogStart := 0;
  277. end;
  278. GLSceneViewer1.Buffer.BackgroundColor := clNavy;
  279. Camera.DepthOfView := 100;
  280. WasAboveWater := False;
  281. end;
  282. end;
  283. // help visibility
  284. if HelpOpacity > 0 then
  285. begin
  286. HelpOpacity := HelpOpacity - deltaTime;
  287. alpha := ClampValue(HelpOpacity, 0, 1);
  288. if alpha > 0 then
  289. begin
  290. HTHelp.Visible := True;
  291. HTHelp.ModulateColor.Alpha := alpha;
  292. end
  293. else
  294. HTHelp.Visible := False;
  295. end;
  296. // rock the sailboat
  297. sbp := TerrainRenderer.AbsoluteToLocal(FFSailBoat.AbsolutePosition);
  298. alpha := WaterPhase(sbp.X + TerrainRenderer.TileSize * 0.5, sbp.Y + TerrainRenderer.TileSize * 0.5);
  299. FFSailBoat.Position.Y := (cWaterLevel + Sin(alpha) * cWaveAmplitude) * (TerrainRenderer.Scale.Z / 128)
  300. + 4;
  301. f := cWaveAmplitude * 0.01;
  302. FFSailBoat.Up.SetVector(Cos(alpha) * 0.02 * f, 1, (Sin(alpha) * 0.02 - 0.005) * f);
  303. FFSailBoat.Move(deltaTime * 2);
  304. end;
  305. procedure TForm1.TerrainRendererHeightDataPostRender(
  306. var rci: TGLRenderContextInfo; var HeightDatas: TList);
  307. var
  308. i, x, y, s, s2: Integer;
  309. t: Single;
  310. hd: TGLHeightData;
  311. const
  312. r = 0.75;
  313. g = 0.75;
  314. b = 1;
  315. procedure IssuePoint(rx, ry: Integer);
  316. var
  317. px, py: Single;
  318. alpha, colorRatio, ca, sa: Single;
  319. begin
  320. px := x + rx + s2;
  321. py := y + ry + s2;
  322. if hd.DataState = hdsNone then
  323. begin
  324. alpha := 1;
  325. end
  326. else
  327. begin
  328. alpha := (cWaterLevel - hd.SmallIntHeight(rx, ry)) * (1 / cWaterOpaqueDepth);
  329. alpha := ClampValue(alpha, 0.5, 1);
  330. end;
  331. SinCos(WaterPhase(px, py), sa, ca);
  332. colorRatio := 1 - alpha * 0.1;
  333. glColor4f(r * colorRatio, g * colorRatio, b, alpha);
  334. glTexCoord2f(px * 0.01 + 0.002 * sa, py * 0.01 + 0.0022 * ca - t * 0.002);
  335. glVertex3f(px, py, cWaterLevel + cWaveAmplitude * sa);
  336. end;
  337. begin
  338. if not WaterPlane then
  339. Exit;
  340. t := GLCadencer.CurrentTime;
  341. MaterialLibrary.ApplyMaterial('water', rci);
  342. repeat
  343. with rci.GLStates do
  344. begin
  345. if not WasAboveWater then
  346. InvertFrontFace;
  347. Disable(stLighting);
  348. Disable(stNormalize);
  349. SetStencilFunc(cfAlways, 1, 255);
  350. StencilWriteMask := 255;
  351. Enable(stStencilTest);
  352. SetStencilOp(soKeep, soKeep, soReplace);
  353. glNormal3f(0, 0, 1);
  354. for i := 0 to heightDatas.Count - 1 do
  355. begin
  356. hd := TGLHeightData(heightDatas.List[i]);
  357. if (hd.DataState = hdsReady) and (hd.HeightMin > cWaterLevel) then
  358. continue;
  359. x := hd.XLeft;
  360. y := hd.YTop;
  361. s := hd.Size - 1;
  362. s2 := s div 2;
  363. glBegin(GL_TRIANGLE_FAN);
  364. IssuePoint(s2, s2);
  365. IssuePoint(0, 0);
  366. IssuePoint(s2, 0);
  367. IssuePoint(s, 0);
  368. IssuePoint(s, s2);
  369. IssuePoint(s, s);
  370. IssuePoint(s2, s);
  371. IssuePoint(0, s);
  372. IssuePoint(0, s2);
  373. IssuePoint(0, 0);
  374. glEnd;
  375. end;
  376. SetStencilOp(soKeep, soKeep, soKeep);
  377. Disable(stStencilTest);
  378. end;
  379. if not WasAboveWater then
  380. rci.GLStates.InvertFrontFace;
  381. WaterPolyCount := heightDatas.Count * 8;
  382. until not MaterialLibrary.UnApplyMaterial(rci);
  383. end;
  384. procedure TForm1.Timer1Timer(Sender: TObject);
  385. begin
  386. htFPS.Text := Format('%.1f FPS - %d - %d',
  387. [GLSceneViewer1.FramesPerSecond,
  388. TerrainRenderer.LastTriangleCount,
  389. WaterPolyCount]);
  390. GLSceneViewer1.ResetPerformanceMonitor;
  391. end;
  392. procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
  393. var
  394. i: Integer;
  395. pm: TGLPolygonMode;
  396. begin
  397. case Key of
  398. 'w', 'W':
  399. begin
  400. with MaterialLibrary do
  401. begin
  402. if Materials[0].Material.PolygonMode = pmLines then
  403. pm := pmFill
  404. else
  405. pm := pmLines;
  406. for i := 0 to Materials.Count - 1 do
  407. Materials[i].Material.PolygonMode := pm;
  408. end;
  409. with MLSailBoat do
  410. for i := 0 to Materials.Count - 1 do
  411. Materials[i].Material.PolygonMode := pm;
  412. FFSailBoat.StructureChanged;
  413. end;
  414. 's', 'S': WaterPlane := not WaterPlane;
  415. 'b', 'B': FFSailBoat.Visible := not FFSailBoat.Visible;
  416. '*': with TerrainRenderer do
  417. if CLODPrecision > 1 then
  418. CLODPrecision := Round(CLODPrecision * 0.8);
  419. '/': with TerrainRenderer do
  420. if CLODPrecision < 1000 then
  421. CLODPrecision := Round(CLODPrecision * 1.2 + 1);
  422. end;
  423. Key := #0;
  424. end;
  425. procedure TForm1.FormShow(Sender: TObject);
  426. begin
  427. TerrainRenderer.Up.SetVector(0, 0, 1);
  428. TerrainRenderer.Direction.SetVector(0, 1, 0);
  429. end;
  430. procedure TForm1.GLCustomHDS1MarkDirtyEvent(const area: TRect);
  431. begin
  432. GLHeightTileFileHDS1.MarkDirty(area);
  433. end;
  434. procedure TForm1.GLCustomHDS1StartPreparingData(heightData: TGLHeightData);
  435. var
  436. htfHD: TGLHeightData;
  437. i, j, n: Integer;
  438. offset: TTexPoint;
  439. begin
  440. htfHD := GLHeightTileFileHDS1.GetData(heightData.XLeft, heightData.YTop, heightData.Size, heightData.DataType);
  441. if (htfHD.DataState = hdsNone) then //or (htfHD.HeightMax <= cWaterLevel - cWaterOpaqueDepth) then
  442. heightData.DataState := hdsNone
  443. else
  444. begin
  445. i := (heightData.XLeft div 128);
  446. j := (heightData.YTop div 128);
  447. if (Cardinal(i) < 4) and (Cardinal(j) < 4) then
  448. begin
  449. heightData.MaterialName := format('Tex_%d_%d.bmp', [i, j]);
  450. heightData.TextureCoordinatesMode := tcmLocal;
  451. n := ((heightData.XLeft div 32) and 3);
  452. offset.S := n * 0.25;
  453. n := ((heightData.YTop div 32) and 3);
  454. offset.T := -n * 0.25;
  455. heightData.TextureCoordinatesOffset := offset;
  456. heightData.TextureCoordinatesScale := TexPointMake(0.25, 0.25);
  457. heightData.DataType := hdtSmallInt;
  458. htfHD.DataType := hdtSmallInt;
  459. heightData.Allocate(hdtSmallInt);
  460. Move(htfHD.SmallIntData^, heightData.SmallIntData^, htfHD.DataSize);
  461. heightData.DataState := hdsReady;
  462. heightData.HeightMin := htfHD.HeightMin;
  463. heightData.HeightMax := htfHD.HeightMax;
  464. end
  465. else
  466. heightData.DataState := hdsNone
  467. end;
  468. GLHeightTileFileHDS1.Release(htfHD);
  469. end;
  470. procedure TForm1.GLSceneViewerBeforeRender(Sender: TObject);
  471. var
  472. i, n: Integer;
  473. begin
  474. PAProgress.Left := (Width - PAProgress.Width) div 2;
  475. PAProgress.Visible := True;
  476. n := MaterialLibrary.Materials.Count;
  477. ProgressBar.Max := n - 1;
  478. try
  479. for i := 0 to n - 1 do
  480. begin
  481. ProgressBar.Position := i;
  482. MaterialLibrary.Materials[i].Material.Texture.Handle;
  483. PAProgress.Repaint;
  484. end;
  485. finally
  486. ResetMousePos;
  487. PAProgress.Visible := False;
  488. GLSceneViewer1.BeforeRender := nil;
  489. end;
  490. end;
  491. function TForm1.WaterPhase(const px, py: Single): Single;
  492. begin
  493. Result := GLCadencer.CurrentTime * 1 + px * 0.16 + py * 0.09;
  494. end;
  495. function TForm1.WaterHeight(const px, py: Single): Single;
  496. var
  497. alpha: Single;
  498. begin
  499. alpha := WaterPhase(px + TerrainRenderer.TileSize * 0.5,
  500. py + TerrainRenderer.TileSize * 0.5);
  501. Result := (cWaterLevel + Sin(alpha) * cWaveAmplitude) * (TerrainRenderer.Scale.Z * (1 / 128));
  502. end;
  503. procedure TForm1.doWakeProgress(Sender: TObject; const deltaTime,
  504. newTime: Double);
  505. var
  506. i: Integer;
  507. sbp, sbr: TGLVector;
  508. begin
  509. if WakeVertices = nil then
  510. begin
  511. WakeVertices := TGLAffineVectorList.Create;
  512. WakeStretch := TGLAffineVectorList.Create;
  513. WakeTime := TGLSingleList.Create;
  514. end;
  515. // enlarge current vertices
  516. with WakeVertices do
  517. begin
  518. i := 0;
  519. while i < Count do
  520. begin
  521. CombineItem(i, WakeStretch.List[i shr 1], -0.45 * deltaTime);
  522. CombineItem(i + 1, WakeStretch.List[i shr 1], 0.45 * deltaTime);
  523. Inc(i, 2);
  524. end;
  525. end;
  526. // Progress wake
  527. if newTime > DOWake.TagFloat then
  528. begin
  529. if DOWake.TagFloat = 0 then
  530. begin
  531. DOWake.TagFloat := newTime + 0.2;
  532. Exit;
  533. end;
  534. DOWake.TagFloat := newTime + 1;
  535. sbp := VectorCombine(FFSailBoat.AbsolutePosition, FFSailBoat.AbsoluteDirection, 1, 3);
  536. sbr := FFSailBoat.AbsoluteRight;
  537. // add new
  538. WakeVertices.Add(VectorCombine(sbp, sbr, 1, -2));
  539. WakeVertices.Add(VectorCombine(sbp, sbr, 1, 2));
  540. WakeStretch.Add(VectorScale(sbr, (0.95 + Random * 0.1)));
  541. WakeTime.Add(newTime * 0.1);
  542. if WakeVertices.Count >= 80 then
  543. begin
  544. WakeVertices.Delete(0);
  545. WakeVertices.Delete(0);
  546. WakeStretch.Delete(0);
  547. WakeTime.Delete(0);
  548. end;
  549. end;
  550. end;
  551. procedure TForm1.doWakeRender(Sender: TObject; var rci: TGLRenderContextInfo);
  552. var
  553. i: Integer;
  554. p: PAffineVector;
  555. sbp: TGLVector;
  556. c: Single;
  557. begin
  558. if not Assigned(WakeVertices) then
  559. Exit;
  560. if (not FFSailBoat.Visible) or (not WaterPlane) then
  561. Exit;
  562. MaterialLibrary.ApplyMaterial('wake', rci);
  563. repeat
  564. with rci.GLStates do
  565. begin
  566. Disable(stLighting);
  567. Disable(stFog);
  568. Enable(stBlend);
  569. SetBlendFunc(bfOne, bfOne);
  570. SetStencilFunc(cfEqual, 1, 255);
  571. StencilWriteMask := 255;
  572. Enable(stStencilTest);
  573. SetStencilOp(soKeep, soKeep, soKeep);
  574. Disable(stDepthTest);
  575. if not WasAboveWater then
  576. InvertFrontFace;
  577. glBegin(GL_TRIANGLE_STRIP);
  578. for i := 0 to WakeVertices.Count - 1 do
  579. begin
  580. p := @WakeVertices.List[i xor 1];
  581. sbp := TerrainRenderer.AbsoluteToLocal(VectorMake(p^));
  582. if (i and 1) = 0 then
  583. begin
  584. c := (i and $FFE) * 0.2 / WakeVertices.Count;
  585. glColor3f(c, c, c);
  586. glTexCoord2f(0, WakeTime[i div 2]);
  587. end
  588. else
  589. glTexCoord2f(1, WakeTime[i div 2]);
  590. glVertex3f(p.X, WaterHeight(sbp.X, sbp.Y), p.Z);
  591. end;
  592. glEnd;
  593. if not WasAboveWater then
  594. InvertFrontFace;
  595. Disable(stStencilTest);
  596. end;
  597. until not MaterialLibrary.UnApplyMaterial(rci);
  598. end;
  599. end.