fArchipelagoD.pas 18 KB

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