fArchipelagoD.pas 18 KB

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