fArchipelagoD.pas 17 KB

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