GXS.OceanWaves.pas 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. unit GXS.OceanWaves;
  2. (*
  3. Omar: TgxTwoWavesOceanSurface
  4. TGBEPlaneExtend has one wave. Added a second to TgxTwoWavesOceanSurface
  5. actually 3 waves... and counting
  6. set21: increased the wave system from 3 to 5 waves
  7. *)
  8. interface
  9. uses
  10. System.SysUtils,
  11. System.Classes,
  12. System.Math,
  13. System.Types,
  14. System.Threading,
  15. System.Math.Vectors,
  16. System.Generics.Collections,
  17. System.RTLConsts,
  18. FMX.Types,
  19. FMX.Controls3D,
  20. FMX.Objects3D,
  21. FMX.Types3D,
  22. FMX.MaterialSources,
  23. GBE.PlaneExtend; // TGBEPlaneExtend and WaveRec
  24. type
  25. TgxWaveSystem = class(TComponent)
  26. // collection of sea surface sinoid waves (3 for now)
  27. private
  28. fTime: Single; // Om: movd stuff to protected
  29. // wave params
  30. fAmplitude, fLongueur, fVitesse: Single; // wave 1
  31. fOrigine: TPoint3D;
  32. fAmplitude2, fLongueur2, fVitesse2: Single;
  33. fOrigine2: TPoint3D;
  34. fAmplitude3, fLongueur3, fVitesse3: Single;
  35. fOrigine3: TPoint3D;
  36. fAmplitude4, fLongueur4, fVitesse4: Single;
  37. fOrigine4: TPoint3D;
  38. fAmplitude5, fLongueur5, fVitesse5: Single;
  39. fOrigine5: TPoint3D;
  40. protected
  41. function GetWaveParams1: TPoint3D;
  42. function GetWaveParams2: TPoint3D;
  43. function GetWaveParams3: TPoint3D;
  44. function GetWaveParams4: TPoint3D;
  45. function GetWaveParams5: TPoint3D;
  46. public
  47. constructor Create(AOwner: TComponent); override;
  48. destructor Destroy; override;
  49. procedure IncTime;
  50. Property WaveTime: Single read fTime write fTime;
  51. published
  52. property Origine: TPoint3D read fOrigine write fOrigine; // wave 1
  53. property Amplitude: Single read fAmplitude write fAmplitude;
  54. property Longueur: Single read fLongueur write fLongueur;
  55. property Vitesse: Single read fVitesse write fVitesse;
  56. property Origine2: TPoint3D read fOrigine2 write fOrigine2; // wave 2
  57. property Amplitude2: Single read fAmplitude2 write fAmplitude2;
  58. property Longueur2: Single read fLongueur2 write fLongueur2;
  59. property Vitesse2: Single read fVitesse2 write fVitesse2;
  60. property Origine3: TPoint3D read fOrigine3 write fOrigine3; // wave 3
  61. property Amplitude3: Single read fAmplitude3 write fAmplitude3;
  62. property Longueur3: Single read fLongueur3 write fLongueur3;
  63. property Vitesse3: Single read fVitesse3 write fVitesse3;
  64. property Origine4: TPoint3D read fOrigine4 write fOrigine4; // wave 4
  65. property Amplitude4: Single read fAmplitude4 write fAmplitude4;
  66. property Longueur4: Single read fLongueur4 write fLongueur4;
  67. property Vitesse4: Single read fVitesse4 write fVitesse4;
  68. property Origine5: TPoint3D read fOrigine5 write fOrigine5; // wave 5
  69. property Amplitude5: Single read fAmplitude5 write fAmplitude5;
  70. property Longueur5: Single read fLongueur5 write fLongueur5;
  71. property Vitesse5: Single read fVitesse5 write fVitesse5;
  72. end;
  73. TgxOceanSurface = class(TPlane)
  74. private
  75. fWaveSystem: TgxWaveSystem;
  76. procedure CalcWaves;
  77. protected
  78. fNbMesh: integer; // number of tiles in the mesh
  79. fActiveWaves, fShowlines, fUseTasks: boolean;
  80. fDivPerM: TPoint3D;
  81. fMaterialLignes: TColorMaterialSource;
  82. public
  83. fVirtualSeaOrigin: TPoint3D; // position of the origin of the virtual sea
  84. constructor Create(AOwner: TComponent); override;
  85. destructor Destroy; override;
  86. // Property Data; //om: publica
  87. function calcWaveAmplitudeAndPitch(P: TPoint3D; const aCap: Single;
  88. var aAmplitude, aPitch: Single): boolean; // Om:
  89. procedure Render; override;
  90. procedure MoveTextureBy(var dx, dy: Single);
  91. procedure GetPointsTexCoordinates(var P, TC: String);
  92. // W1,W2 = Point3D(Amplitude, Longueur, Vitesse)
  93. published
  94. property ActiveWaves: boolean read fActiveWaves write fActiveWaves;
  95. property ShowLines: boolean read fShowlines write fShowlines;
  96. property WaveSystem: TgxWaveSystem read fWaveSystem write fWaveSystem;
  97. property MaterialLines: TColorMaterialSource read fMaterialLignes
  98. write fMaterialLignes;
  99. property DivPerM: TPoint3D read fDivPerM;
  100. end;
  101. TgxWindArrowSurface = class(TPlane)
  102. // Ondulating wind arrow. Less CPU intensive then OceanSurface
  103. private
  104. fVersion: integer;
  105. fWaveSystem: TgxWaveSystem; // using only wave 1 here
  106. procedure CalcArrowMesh;
  107. procedure setVersion(const Value: integer);
  108. protected
  109. fNbMesh: integer; // number of tiles in the mesh
  110. fActiveWaves, fShowlines, fUseTasks: boolean;
  111. fDivPerM: TPoint3D;
  112. fMaterialLignes: TColorMaterialSource;
  113. procedure SetDepth(const Value: Single); override;
  114. public
  115. constructor Create(AOwner: TComponent); override;
  116. destructor Destroy; override;
  117. // Property Data; //om: publica
  118. procedure Render; override;
  119. published
  120. property ActiveWaves: boolean read fActiveWaves write fActiveWaves;
  121. property ShowLines: boolean read fShowlines write fShowlines;
  122. property MaterialLines: TColorMaterialSource read fMaterialLignes
  123. write fMaterialLignes;
  124. property DivPerM: TPoint3D read fDivPerM;
  125. Property version: integer read fVersion write setVersion;
  126. end;
  127. TgxTwoWavesOceanSurface = class(TgxOceanSurface); // compatibility w/ old forms
  128. procedure Register;
  129. implementation //--------------------------------------------------------------
  130. // TgxWaveSystem
  131. constructor TgxWaveSystem.Create(AOwner: TComponent);
  132. begin
  133. inherited;
  134. fTime := 0;
  135. fAmplitude := 2.5; // wave params
  136. fLongueur := 5; // Om: only 1 ?
  137. fVitesse := 5; //
  138. fOrigine := Point3D(1, 1, 2);
  139. fAmplitude2 := 1.1; // 2.5; //wave 2 params
  140. fLongueur2 := 2.1;
  141. fVitesse2 := 3;
  142. fOrigine2 := Point3D(3, 10, 2);
  143. // (SubdivisionsWidth/Width, SubdivisionsHeight/Height, 2)
  144. fAmplitude3 := 1.5; // wave 3 params
  145. fLongueur3 := 4.2;
  146. fVitesse3 := 3.2;
  147. fOrigine3 := Point3D(7, -8, 1);
  148. fAmplitude4 := 0.5; // wave 4 params
  149. fLongueur4 := 2.2;
  150. fVitesse4 := 2.2;
  151. fOrigine4 := Point3D(7, -8, 1);
  152. fAmplitude5 := 0.7; // wave 5 params
  153. fLongueur5 := 4.2;
  154. fVitesse5 := 2.2;
  155. fOrigine5 := Point3D(7, -8, 1);
  156. end;
  157. destructor TgxWaveSystem.Destroy;
  158. begin
  159. inherited;
  160. end;
  161. function TgxWaveSystem.GetWaveParams1: TPoint3D;
  162. begin
  163. Result := Point3D(Amplitude, Longueur, Vitesse); // pack wave params
  164. end;
  165. function TgxWaveSystem.GetWaveParams2: TPoint3D;
  166. begin
  167. Result := Point3D(fAmplitude2, fLongueur2, fVitesse2);
  168. end;
  169. function TgxWaveSystem.GetWaveParams3: TPoint3D;
  170. begin
  171. Result := Point3D(fAmplitude3, fLongueur3, fVitesse3);
  172. end;
  173. function TgxWaveSystem.GetWaveParams4: TPoint3D;
  174. begin
  175. Result := Point3D(fAmplitude4, fLongueur4, fVitesse4);
  176. end;
  177. function TgxWaveSystem.GetWaveParams5: TPoint3D;
  178. begin
  179. Result := Point3D(fAmplitude5, fLongueur5, fVitesse5);
  180. end;
  181. procedure TgxWaveSystem.IncTime;
  182. begin
  183. fTime := fTime + 0.010; // advance wave time.. slow advance
  184. end;
  185. { TgxOceanSurface }
  186. constructor TgxOceanSurface.Create(AOwner: TComponent);
  187. begin
  188. inherited;
  189. fWaveSystem := nil;
  190. self.SubdivisionsHeight := 30; // plane subdivisions
  191. self.SubdivisionsWidth := 30;
  192. fNbMesh := (SubdivisionsWidth + 1) * (SubdivisionsHeight + 1);
  193. // fDivPerM = SubD / width --> units div/m
  194. fDivPerM := Point3D(SubdivisionsWidth / self.Width,
  195. SubdivisionsHeight / self.Height, 0);
  196. fUseTasks := true; // default= using tasks instead of inline mesh builds
  197. fVirtualSeaOrigin := Point3D(0, 0, 0);
  198. end;
  199. destructor TgxOceanSurface.Destroy;
  200. begin
  201. inherited;
  202. end;
  203. Function MyFrac(const n: Single): Single;
  204. begin
  205. Result := Frac(n);
  206. if (Result < 0) then
  207. Result := Result + 1.0;
  208. end;
  209. // MoveTextureBy uses existent mesh, by just displacing the tex pts
  210. procedure TgxOceanSurface.MoveTextureBy(var dx, dy: Single);
  211. // dx,dy in 3d units (m)
  212. var
  213. M: TMeshData;
  214. S: String;
  215. x, y: integer;
  216. front, back: TPointF;
  217. ixf, ixb: integer;
  218. du, dv: Single;
  219. begin
  220. M := self.Data; // get mesh
  221. fVirtualSeaOrigin := fVirtualSeaOrigin - Point3D(dx, dy, 0);
  222. // move by virtual sea coordinate system
  223. du := dx / Width; // in 0..1 range
  224. dv := dy / Height;
  225. fNbMesh := (SubdivisionsWidth + 1) * (SubdivisionsHeight + 1);
  226. for y := 0 to SubdivisionsHeight do
  227. for x := 0 to SubdivisionsWidth do
  228. begin
  229. ixf := x + (y * (SubdivisionsWidth + 1));
  230. // calc front and back point indexes
  231. ixb := fNbMesh + x + (y * (SubdivisionsWidth + 1));
  232. front := M.VertexBuffer.TexCoord0[ixf];
  233. // TexCoord0 must be in 0.0 .. 1.0 range ( UV coordinates )
  234. back := M.VertexBuffer.TexCoord0[ixb];
  235. front.x := MyFrac(front.x + du);
  236. // Frac() wraps around the texture coordinates
  237. front.y := MyFrac(front.y + dv);
  238. // TODO: this leaves the last row,column w/ inverted texture ..
  239. back.x := MyFrac(back.x + du);
  240. back.y := MyFrac(back.y + dv);
  241. M.VertexBuffer.TexCoord0[ixf] := front;
  242. M.VertexBuffer.TexCoord0[ixb] := back;
  243. end;
  244. // format TexCoordinates as a str
  245. // '0.0 0.0, 1 0, 0.0 1, 1 1';
  246. // S := FloatToStr(u) +' '+FloatToStr(v) +','+
  247. // FloatToStr(u+1)+' '+FloatToStr(v) +','+
  248. // FloatToStr(u) +' '+FloatToStr(v+1) +','+
  249. // FloatToStr(u+1)+' '+FloatToStr(v+1);
  250. // M.Points :=
  251. // M.TexCoordinates :=
  252. end;
  253. procedure TgxOceanSurface.GetPointsTexCoordinates(var P, TC: String);
  254. var
  255. M: TMeshData;
  256. begin
  257. M := self.Data; // get mesh
  258. P := M.Points;
  259. TC := M.TexCoordinates;
  260. end;
  261. procedure TgxOceanSurface.CalcWaves; // Wx = Point3D(Amplitude, Longueur, Vitesse)
  262. var
  263. M: TMeshData;
  264. x, y: integer;
  265. ax, ay: Single;
  266. somme: Single;
  267. PCenter: TPoint3D;
  268. front, back: PPoint3D;
  269. waveRec1, waveRec2, waveRec3, waveRec4, waveRec5: TWaveRec;
  270. begin
  271. if not Assigned(fWaveSystem) then
  272. exit;
  273. M := self.Data; // get mesh
  274. // init waveRecs
  275. PCenter := Point3D(SubdivisionsWidth, SubdivisionsHeight, 0) * 0.5;
  276. fDivPerM := Point3D(SubdivisionsWidth / self.Width,
  277. SubdivisionsHeight / self.Height, 0);
  278. fNbMesh := (SubdivisionsWidth + 1) * (SubdivisionsHeight + 1);
  279. // Waves 1 and 2 move with OceanSurface, like the floating stuff
  280. waveRec1.P := fWaveSystem.Origine + fVirtualSeaOrigin * fDivPerM;
  281. // calc sin wave origin position
  282. waveRec1.D := fWaveSystem.GetWaveParams1;
  283. // D = Point3D( Amplitude, Longueur, Vitesse)
  284. waveRec2.P := fWaveSystem.fOrigine2 + fVirtualSeaOrigin * fDivPerM;
  285. waveRec2.D := fWaveSystem.GetWaveParams2;
  286. // waves 3,4,5 move with the boat
  287. waveRec3.P := fWaveSystem.fOrigine3;
  288. waveRec3.D := fWaveSystem.GetWaveParams3;
  289. waveRec4.P := fWaveSystem.fOrigine4;
  290. waveRec4.D := fWaveSystem.GetWaveParams4;
  291. waveRec5.P := fWaveSystem.fOrigine5;
  292. waveRec5.D := fWaveSystem.GetWaveParams5;
  293. for y := 0 to SubdivisionsHeight do
  294. begin
  295. ay := y - PCenter.y; // + PCenter.y;
  296. for x := 0 to SubdivisionsWidth do
  297. begin
  298. ax := x - PCenter.x; // + PCenter.x; //ax,ay in div
  299. // preserve original TPlane vertice's x,y. Apply wave amplitude to z coordinate
  300. front := M.VertexBuffer.VerticesPtr[x + (y * (SubdivisionsWidth + 1))];
  301. back := M.VertexBuffer.VerticesPtr
  302. [fNbMesh + x + (y * (SubdivisionsWidth + 1))];
  303. // calc sum of wave amplitudes. Here x,y is in division units ! ( not m )
  304. somme := 0; // sum, effect of waves
  305. somme := waveRec1.Wave(somme, ax, ay, fWaveSystem.fTime); // 1 st
  306. somme := waveRec2.Wave(somme, ax, ay, fWaveSystem.fTime); // 2 nd
  307. somme := waveRec3.Wave(somme, ax, ay, fWaveSystem.fTime); // 3 rd
  308. somme := waveRec4.Wave(somme, ax, ay, fWaveSystem.fTime); // 4 nd
  309. somme := waveRec5.Wave(somme, ax, ay, fWaveSystem.fTime); // 5 nd
  310. somme := somme * 100; // scale amplitude to div x 100 ?!
  311. front^.Z := somme;
  312. back^.Z := somme;
  313. end;
  314. end;
  315. M.CalcTangentBinormals;
  316. fWaveSystem.IncTime; // adv time by 0.01 sec
  317. end;
  318. // P in m
  319. function TgxOceanSurface.calcWaveAmplitudeAndPitch(P: TPoint3D;
  320. const aCap: Single; var aAmplitude, aPitch: Single): boolean; // Om:
  321. var
  322. waveRec1, waveRec2, waveRec3, waveRec4, waveRec5: TWaveRec;
  323. aSumAmpl, aSumDeriv, D, AbsD, ax, ay: Single;
  324. // PCenter:TPoint3d;
  325. begin
  326. Result := false;
  327. if not Assigned(fWaveSystem) then
  328. exit;
  329. // init waveRecs
  330. // PCenter := Point3d( SubdivisionsWidth, SubdivisionsHeight, 0)*0.5;
  331. fDivPerM := Point3D(SubdivisionsWidth / self.Width,
  332. SubdivisionsHeight / self.Height, 0);
  333. // waves 1 n 2 Oringines move with the sea surface
  334. waveRec1.P := fWaveSystem.Origine + fVirtualSeaOrigin * fDivPerM;
  335. // calc sin wave origin position
  336. waveRec1.D := fWaveSystem.GetWaveParams1;
  337. // D = Point3D( Amplitude, Longueur, Vitesse)
  338. waveRec2.P := fWaveSystem.fOrigine2 + fVirtualSeaOrigin * fDivPerM;
  339. // + fVirtualSeaOrigin * fDivPerM;
  340. waveRec2.D := fWaveSystem.GetWaveParams2;
  341. // waves 3,4,5 move with the boat ( stationary )
  342. waveRec3.P := fWaveSystem.fOrigine3; // ugly array :(
  343. waveRec3.D := fWaveSystem.GetWaveParams3;
  344. waveRec4.P := fWaveSystem.fOrigine4;
  345. waveRec4.D := fWaveSystem.GetWaveParams4;
  346. waveRec5.P := fWaveSystem.fOrigine5;
  347. waveRec5.D := fWaveSystem.GetWaveParams5;
  348. // Sum amplitudes. Note that the derivative of a sum is the sum of the derivatives
  349. // f(x)=g(x)+h(x) ---> f'(x)=g'(x)+h'(x)
  350. ax := (P.x - Position.x) * fDivPerM.x; // ax,ay in div
  351. ay := (P.Z + Position.Z) * fDivPerM.y;
  352. aSumAmpl := 0;
  353. aSumDeriv := 0;
  354. if waveRec1.calcWaveAmplitudeAndPitch(aCap, ax, ay, fWaveSystem.fTime,
  355. { out: } aSumAmpl, aSumDeriv) and // x,y in divs
  356. waveRec2.calcWaveAmplitudeAndPitch(aCap, ax, ay, fWaveSystem.fTime,
  357. { out: } aSumAmpl, aSumDeriv) and waveRec3.calcWaveAmplitudeAndPitch(aCap,
  358. ax, ay, fWaveSystem.fTime, { out: } aSumAmpl, aSumDeriv) and
  359. waveRec4.calcWaveAmplitudeAndPitch(aCap, ax, ay, fWaveSystem.fTime,
  360. { out: } aSumAmpl, aSumDeriv) and waveRec5.calcWaveAmplitudeAndPitch(aCap,
  361. ax, ay, fWaveSystem.fTime, { out: } aSumAmpl, aSumDeriv) then
  362. begin
  363. Result := true;
  364. aAmplitude := aSumAmpl * 100;
  365. // scale amplitude x 100, as was done creating the mesh
  366. // calc pitch in degrees
  367. D := aSumDeriv * 100 * 3; // scale deriv by 1000 ( cause amplitudes )
  368. AbsD := Abs(D);
  369. if (AbsD > 1) then
  370. D := D / AbsD;
  371. if (D >= -1.0) and (D <= 1.0) then
  372. aPitch := ArcSin(D) * 180 / Pi; // ad hoc formula
  373. if aPitch < -25 then
  374. aPitch := -25 // limit pitch to 25 deg
  375. else if aPitch > 25 then
  376. aPitch := 25;
  377. end;
  378. end;
  379. // function TgxOceanSurface.calcWaveAmplitudeAndPitch(P:TPoint3d; const aCap:Single; var aAmplitude,aPitch:Single ):boolean; //Om:
  380. // var
  381. // M:TMeshData;
  382. // x,y,z,x1,y1,z1 : integer;
  383. // front, back, next : PPoint3D;
  384. // P1:TPoint3d;
  385. // aAng,D,AbsD:Single;
  386. //
  387. // begin
  388. // M := Data;
  389. //
  390. // x := Round( P.x - Position.x + SubdivisionsHeight/2 );
  391. // y := Round( P.z - Position.z + SubdivisionsWidth/2 );
  392. //
  393. // aAng := -aCap*Pi/180; // cap to radians
  394. //
  395. // P1 := Point3D(x,y,0) + 1.0 * Point3d( sin(aAng), cos(aAng), 0); // P1 = pto futuro, for pitch calculation
  396. // x1 := Round( P1.x );
  397. // y1 := Round( P1.y );
  398. //
  399. // if (x>=0) and (x<SubdivisionsWidth) and (y>0) and (y<SubdivisionsHeight) then
  400. // begin
  401. // front := M.VertexBuffer.VerticesPtr[x + (y * (SubdivisionsWidth+1))];
  402. // // back := M.VertexBuffer.VerticesPtr[fNbMesh + X + (Y * (SubdivisionsWidth+1))];
  403. // aAmplitude := front^.Z; // +back^.Z)/2; //??
  404. // Result := true;
  405. //
  406. // if (x1>=0) and (x1<SubdivisionsWidth) and (y1>0) and (y1<SubdivisionsHeight) then
  407. // begin
  408. // next := M.VertexBuffer.VerticesPtr[x1 + (y1 * (SubdivisionsWidth+1))];
  409. // D := (next^.Z-aAmplitude)/1.5;
  410. // // AbsD := Abs(D);
  411. // // if (AbsD>1) then D:=D/AbsD;
  412. // // 0.8 is dynamic dampening
  413. // if (D>=-1.0) and (D<=1.0) then aPitch := ArcSin( D )*180/Pi * 1.0; // ad hoc formula
  414. // if aPitch<-25 then aPitch:=-25 // limit pitch to 25 deg
  415. // else if aPitch>25 then aPitch:=25;
  416. // end
  417. // else aPitch:=0; //no pitch
  418. // end
  419. // else Result := false;
  420. // end;
  421. procedure TgxOceanSurface.Render;
  422. begin
  423. inherited;
  424. if Assigned(fWaveSystem) and fActiveWaves then
  425. begin
  426. if fUseTasks then
  427. begin
  428. TTask.Create(
  429. procedure
  430. begin
  431. CalcWaves; // recalc mesh
  432. end).start;
  433. end
  434. else
  435. begin
  436. CalcWaves;
  437. end;
  438. end;
  439. if ShowLines then
  440. Context.DrawLines(self.Data.VertexBuffer, self.Data.IndexBuffer,
  441. TMaterialSource.ValidMaterial(fMaterialLignes), 1);
  442. end;
  443. { TgxWindArrowSurface }
  444. constructor TgxWindArrowSurface.Create(AOwner: TComponent);
  445. begin
  446. inherited; // TPlane.Create
  447. // create an own wave system
  448. fWaveSystem := TgxWaveSystem.Create(nil);
  449. fWaveSystem.Amplitude := 0.8; // set wave 1
  450. fWaveSystem.Vitesse := 20.0;
  451. fWaveSystem.Longueur := 1.1;
  452. fWaveSystem.Origine := Point3D(0, -10, 0); // to have ondulation on y axis
  453. fWaveSystem.Amplitude2 := 0; // don't need those
  454. fWaveSystem.Amplitude3 := 0;
  455. fWaveSystem.Amplitude4 := 0;
  456. fWaveSystem.Amplitude5 := 0;
  457. SubdivisionsHeight := 25; // default plane subdivisions
  458. SubdivisionsWidth := 2;
  459. fNbMesh := (SubdivisionsWidth + 1) * (SubdivisionsHeight + 1);
  460. // fDivPerM = SubD / width --> units div/m
  461. fDivPerM := Point3D(SubdivisionsWidth / self.Width,
  462. SubdivisionsHeight / self.Height, 0);
  463. fUseTasks := true; // default= using tasks instead of inline mesh builds
  464. fVersion := 0;
  465. end;
  466. destructor TgxWindArrowSurface.Destroy;
  467. begin
  468. fWaveSystem.Free;
  469. inherited;
  470. end;
  471. // transforms a plane into an arrow, by squeezing the x coordinate
  472. procedure TgxWindArrowSurface.CalcArrowMesh; //
  473. var // 0.0
  474. M: TMeshData; // Y /\ 0.5
  475. x, y: integer; // / \
  476. front, back: PPoint3D; // / \
  477. somme, h, Dh, Z, ah, al, ax, ay: Single; // +-- --+ 0.3
  478. waveRec1: TWaveRec; // | |
  479. PCenter: TPoint3D; // | |
  480. // | | 0
  481. function _xArrowFunction(const aAx, aAy: Single): Single;
  482. // takes a plane mesh // | |
  483. begin // and turns it into // | |
  484. if (aAy >= 0.3) then
  485. Result := aAx * (0.5 - aAy) / 0.1
  486. // an arrow // + + +--+ -0.5 X >
  487. else
  488. Result := aAx / 1.6;
  489. // for y in -0.5..0.4, slim the mesh // -0.5 0 0.5
  490. end;
  491. begin
  492. // sail params sanity test
  493. if (SubdivisionsHeight <= 0) or (SubdivisionsWidth <= 0) then
  494. exit; // invalid subdiv values
  495. M := self.Data; // use default TPlane mesh
  496. fNbMesh := (SubdivisionsWidth + 1) * (SubdivisionsHeight + 1);
  497. // recalc mesh number of vertices
  498. // mesh is calculated to fit into [-0.5,-0.5..0.5,0.5] interval.
  499. h := -0.5;
  500. Dh := 1.0 / SubdivisionsHeight;
  501. // this will create an arrow mesh in h range -0.5 .. 0.5
  502. PCenter := Point3D(SubdivisionsWidth / self.Width,
  503. SubdivisionsHeight / self.Height, 0);
  504. // Wave 1
  505. waveRec1.P := fWaveSystem.Origine; // calc sin wave origin position
  506. waveRec1.D := fWaveSystem.GetWaveParams1;
  507. // D = Point3D( Amplitude, Longueur, Vitesse)
  508. for y := 0 to SubdivisionsHeight do
  509. begin
  510. somme := 0; // arrow ondulation
  511. somme := waveRec1.Wave(somme, 0, y, fWaveSystem.fTime) * 1000;
  512. for x := 0 to SubdivisionsWidth do // L
  513. begin //
  514. front := M.VertexBuffer.VerticesPtr[x + (y * (SubdivisionsWidth + 1))];
  515. back := M.VertexBuffer.VerticesPtr
  516. [fNbMesh + x + (y * (SubdivisionsWidth + 1))];
  517. ax := -0.5 + x / SubdivisionsWidth;
  518. ax := _xArrowFunction(ax, h); // L,h in -0.5..0.5 range
  519. ay := h;
  520. front^.x := ax;
  521. front^.y := ay;
  522. back^.x := ax;
  523. back^.y := ay;
  524. // add some sail side movement ( camber ) //
  525. front^.Z := somme;
  526. back^.Z := somme;
  527. end;
  528. h := h + Dh; // inc h
  529. end;
  530. M.CalcTangentBinormals;
  531. // fTime := fTime + 0.01; //??
  532. fWaveSystem.IncTime; // adv time by 0.01 sec
  533. end;
  534. procedure TgxWindArrowSurface.Render;
  535. begin
  536. inherited;
  537. if Assigned(fWaveSystem) and fActiveWaves then
  538. begin
  539. if fUseTasks then
  540. begin
  541. TTask.Create(
  542. procedure
  543. begin
  544. CalcArrowMesh; // recalc mesh
  545. end).start;
  546. end
  547. else
  548. begin
  549. CalcArrowMesh;
  550. end;
  551. end;
  552. if ShowLines then
  553. Context.DrawLines(self.Data.VertexBuffer, self.Data.IndexBuffer,
  554. TMaterialSource.ValidMaterial(fMaterialLignes), 1);
  555. end;
  556. procedure TgxWindArrowSurface.setVersion(const Value: integer);
  557. begin
  558. if (fVersion <> Value) then
  559. begin
  560. CalcArrowMesh; // recalc mesh
  561. fVersion := Value;
  562. end;
  563. end;
  564. procedure TgxWindArrowSurface.SetDepth(const Value: Single);
  565. // override TPlane tendency to set Depth to 0.01
  566. begin
  567. if (self.fDepth <> Value) then // this copies what TPlane removed
  568. begin
  569. self.fDepth := Value;
  570. Resize3D;
  571. if (fDepth < 0) and (csDesigning in ComponentState) then
  572. begin
  573. fDepth := Abs(fDepth);
  574. FScale.Z := -FScale.Z;
  575. end;
  576. if not(csLoading in ComponentState) then
  577. Repaint;
  578. end;
  579. end;
  580. //----------------------------------------------------------------------------
  581. procedure Register;
  582. begin
  583. RegisterComponents('GLXEngine', [TgxWaveSystem, TgxOceanSurface,
  584. TgxTwoWavesOceanSurface, TgxWindArrowSurface]);
  585. end;
  586. end.