fdSailboat.pas 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611
  1. unit fdSailboat; // the Sailboat 3d view - Used by SailboatDemo and OPYC game
  2. // ------------------// a FMX 3d sailboat simulation, w/ waves, ship, clouds, birds..
  3. interface
  4. { ..$DEFINE OPYC } // false for SailboatDemo, true for OPYC game
  5. uses
  6. System.SysUtils,
  7. System.Types,
  8. System.UITypes,
  9. System.Classes,
  10. System.Variants,
  11. System.Math,
  12. System.Math.Vectors,
  13. FMX.Forms,
  14. {$IFDEF USE_SKIA} // tried SKIA but didnt work (app hangs)
  15. // FMX.Types,
  16. // Skia.FMX,
  17. {$ENDIF USE_SKIA}
  18. FMX.Types,
  19. FMX.Controls,
  20. FMX.Graphics,
  21. FMX.Dialogs,
  22. FMX.Ani,
  23. FMX.MaterialSources,
  24. FMX.Controls3D,
  25. FMX.Objects3D,
  26. FMX.Viewport3D,
  27. FMX.StdCtrls,
  28. FMX.Controls.Presentation,
  29. FMX.Objects,
  30. FMX.Layouts,
  31. FMX.Edit,
  32. FMX.EditBox,
  33. FMX.SpinBox,
  34. FMX.Types3D,
  35. FMX.ListBox,
  36. FMX.Gestures,
  37. {$IFDEF OPYC}
  38. fmxStateBox,
  39. // TfmxStateBox - component persists form control states to ini file
  40. // Note: fmxStateBox.pas must be installed as a design component, prior to loading this form
  41. {$ENDIF OPYC}
  42. GXS.SailSurface,
  43. GXS.OceanWaves,
  44. GBE.Clouds,
  45. GBE.Heightmap;
  46. const
  47. // For some reason, the 3d world boat is 3m long, while the box2d boat is 10 m long
  48. // The correct thing to do is to match scales
  49. // as a workaround I used this scale factor ( 0.3 )
  50. B2Dto3Dscale = 0.30;
  51. // OPYC characters, 3d style
  52. charDolphin = 1;
  53. charWhiteBirds = 2;
  54. charBrownBirds = 3;
  55. charBoiaCross = 4;
  56. charPelican = 5;
  57. charPurpleBoat = 6;
  58. charContainer = 7;
  59. charRock = 8; // rock w/ lighthouse
  60. charBarril = 9; // floating barrel
  61. charWhale = 10; // jumping humpback whale
  62. numMarks = 4; // up to 8 simultaneous marks
  63. type
  64. TPointF_Array = array of System.Types.TPointF;
  65. // yet another ... for sail segments exports
  66. TFormSailboatDemo = class(TForm)
  67. Viewport3D1: TViewport3D;
  68. FloatAnimation1: TFloatAnimation;
  69. tbAmplitude: TTrackBar;
  70. Label1: TLabel;
  71. Label2: TLabel;
  72. tbWaveLenght: TTrackBar;
  73. Label3: TLabel;
  74. tbVitesse: TTrackBar;
  75. Label4: TLabel;
  76. SpinBox1: TSpinBox;
  77. Label5: TLabel;
  78. SpinBox2: TSpinBox;
  79. Label6: TLabel;
  80. SpinBox3: TSpinBox;
  81. ColorMaterialSource1: TColorMaterialSource;
  82. cbShowLines: TSwitch;
  83. Label7: TLabel;
  84. Label8: TLabel;
  85. tbOpacite: TTrackBar;
  86. textureOceanSurface: TLightMaterialSource;
  87. Light1: TLight;
  88. OceanSurface: TgxOceanSurface;
  89. modelBoat: TModel3D;
  90. Camera1: TCamera;
  91. Label9: TLabel;
  92. tbCap: TTrackBar;
  93. tbHeel: TTrackBar;
  94. Label10: TLabel;
  95. dummyBoatCap: TDummy;
  96. cubeBoat: TCube;
  97. tbSelObjY: TTrackBar;
  98. tbSelObjZ: TTrackBar;
  99. labSelObjY: TLabel;
  100. labSelObjZ: TLabel;
  101. labBoatPitch: TLabel;
  102. modelBoatMat01: TLightMaterialSource;
  103. modelBoatMat11: TLightMaterialSource;
  104. modelBoatMat12: TLightMaterialSource;
  105. MainSail: TgxSailSurface;
  106. JibSail: TgxSailSurface;
  107. materialMainSail: TLightMaterialSource;
  108. texJibSail: TLightMaterialSource;
  109. Label11: TLabel;
  110. cbMoveSea: TSwitch;
  111. Label12: TLabel;
  112. cbDesignCamera: TSwitch;
  113. tbSelObjX: TTrackBar;
  114. labSelObjX: TLabel;
  115. comboSelObj: TComboBox;
  116. dummyBoatPitch: TDummy;
  117. labxxx: TLabel;
  118. tbAngleOfView: TTrackBar;
  119. dummyJib: TDummy;
  120. dummyBoom: TDummy;
  121. Label13: TLabel;
  122. tbMainRot: TTrackBar;
  123. Label14: TLabel;
  124. tbJibRot: TTrackBar;
  125. Label15: TLabel;
  126. tbBoatSpeed: TTrackBar;
  127. sphereRock: TSphere;
  128. materialBoia: TLightMaterialSource;
  129. dummyBoatHeel: TDummy;
  130. cubeJibStay: TCube;
  131. materialSilver: TColorMaterialSource;
  132. cylinderBoom: TCylinder;
  133. planeBoiaMan: TPlane;
  134. materialBoiaMan: TLightMaterialSource;
  135. dummyBoiaMan: TDummy;
  136. materialPelican: TLightMaterialSource;
  137. dummyPelican: TDummy;
  138. planePelican: TPlane;
  139. diskBubble: TDisk;
  140. listboxControls: TListBox;
  141. lbiBoatControls: TListBoxItem;
  142. lbiWaveSettings: TListBoxItem;
  143. lbiSelectedObject: TListBoxItem;
  144. lbiCameraControls: TListBoxItem;
  145. lbiTerrain: TListBoxItem;
  146. labMainRot: TLabel;
  147. labJibRot: TLabel;
  148. labBoatSpeed: TLabel;
  149. LabHeel: TLabel;
  150. labCap: TLabel;
  151. labAmplitude: TLabel;
  152. labLongueur: TLabel;
  153. labVitesse: TLabel;
  154. labOpacite: TLabel;
  155. labCameraViewAngle: TLabel;
  156. comboWave: TComboBox;
  157. WaveSystem1: TgxWaveSystem;
  158. OceanSurfaceTop: TgxOceanSurface;
  159. diskSeaHorizon: TDisk;
  160. OceanSurfaceLeft: TgxOceanSurface;
  161. cylinderLighthouse: TCylinder;
  162. materialFarol: TLightMaterialSource;
  163. cylinderLighthouseTop: TCylinder;
  164. textureRock: TLightMaterialSource;
  165. labCountTerrainBuilds: TLabel;
  166. labDataTexCoordinates: TLabel;
  167. dummyRock: TDummy;
  168. btnToggleControls: TSpeedButton;
  169. dummyMain: TDummy;
  170. texMainSail: TLightMaterialSource;
  171. texCodeZero: TLightMaterialSource;
  172. texSpinaker: TLightMaterialSource;
  173. dummyCameraTarget: TDummy;
  174. Label18: TLabel;
  175. tbCameraAz: TTrackBar;
  176. labCameraAz: TLabel;
  177. text3dNorth: TText3D;
  178. Label19: TLabel;
  179. tbCameraElev: TTrackBar;
  180. labCameraElev: TLabel;
  181. WaveSystem2: TgxWaveSystem;
  182. OceanSurfaceBot: TgxOceanSurface;
  183. OceanSurfaceRight: TgxOceanSurface;
  184. text3dSouth: TText3D;
  185. btnRandomizeWaveSystem1: TSpeedButton;
  186. btnCloseControls: TSpeedButton;
  187. labFPS: TLabel;
  188. timerOneSecondTick: TTimer;
  189. Light2: TLight;
  190. text3DWest: TText3D;
  191. text3DEast: TText3D;
  192. textureSeaPhoto: TLightMaterialSource;
  193. materialBrownBirds: TLightMaterialSource;
  194. materialPurpleBoat: TLightMaterialSource;
  195. materialDolphinsTrio: TLightMaterialSource;
  196. materialWhiteBirds: TLightMaterialSource;
  197. dummyBrownBirds: TDummy;
  198. planeBrownBirds: TPlane;
  199. dummy3Dolphins: TDummy;
  200. dummyPurpleBoat: TDummy;
  201. planePurplaBoat: TPlane;
  202. dummyWhiteBirds: TDummy;
  203. planeWhiteBirds: TPlane;
  204. materialMAERSK: TLightMaterialSource;
  205. dummyContainer: TDummy;
  206. cubeContainer: TCube;
  207. btnSetWaveOrigine: TSpeedButton;
  208. materialFlag: TLightMaterialSource;
  209. birutaSail: TgxSailSurface;
  210. ImageTerrain: TImage;
  211. heightmapTerrain: TGBEHeightmap;
  212. Label16: TLabel;
  213. cbUseRamp: TSwitch;
  214. materialTerrain: TLightMaterialSource;
  215. materialTerrainRamp: TLightMaterialSource;
  216. dummyTerrain: TDummy;
  217. materialCloud1: TTextureMaterialSource;
  218. materialCloud2: TTextureMaterialSource;
  219. materialCloud3: TTextureMaterialSource;
  220. GBEClouds1: TGBEClouds;
  221. Label17: TLabel;
  222. cbClouds: TSwitch;
  223. rectBitmapCenter: TRectangle;
  224. dummyBarril: TDummy;
  225. cylinderBarril: TCylinder;
  226. textureSeaSurfaceLargeScale: TLightMaterialSource;
  227. cylinderBuoy: TCylinder;
  228. colorBuoy: TColorMaterialSource;
  229. dummyMark: TDummy;
  230. lightmaterialMark: TLightMaterialSource;
  231. rectBlackListboxBackground: TRectangle;
  232. Container: TLayout;
  233. ContainerMaterials: TLayout;
  234. btnClose3dview: TButton;
  235. modelBoatMat13: TLightMaterialSource;
  236. modelBoatMat14: TLightMaterialSource;
  237. modelBoatMat02: TLightMaterialSource;
  238. dummyRudder: TDummy;
  239. cylinderRudder: TCylinder;
  240. dummyCrew: TDummy;
  241. planeChuck: TPlane;
  242. materialChuck: TLightMaterialSource;
  243. materialIvone: TLightMaterialSource;
  244. materialWheel: TLightMaterialSource;
  245. materialCatraca: TLightMaterialSource;
  246. planeIvone: TPlane;
  247. textureWindArrow: TLightMaterialSource;
  248. dummyWindArrow: TDummy;
  249. WindArrow1: TgxWindArrowSurface;
  250. dummyShip: TDummy;
  251. modelShip: TModel3D;
  252. modelShipMat01: TLightMaterialSource;
  253. modelDolphin: TModel3D;
  254. modelDolphinMat01: TLightMaterialSource;
  255. LabXX: TLabel;
  256. cbShowDolphin: TSwitch;
  257. Label20: TLabel;
  258. cbShowWindArrow: TSwitch;
  259. dummyWhale: TDummy;
  260. modelWhale: TModel3D;
  261. modelWhaleMat01: TLightMaterialSource;
  262. labDerivative: TLabel;
  263. procedure FloatAnimation1Process(Sender: TObject);
  264. procedure FormCreate(Sender: TObject);
  265. procedure tbAmplitudeTracking(Sender: TObject);
  266. procedure tbWaveLenghtTracking(Sender: TObject);
  267. procedure tbVitesseTracking(Sender: TObject);
  268. procedure SpinBox1ChangeClick(Sender: TObject);
  269. procedure cbShowLinesSwitch(Sender: TObject);
  270. procedure tbOpaciteTracking(Sender: TObject);
  271. procedure tbCapTracking(Sender: TObject);
  272. procedure tbHeelTracking(Sender: TObject);
  273. procedure tbSelObjYTracking(Sender: TObject);
  274. procedure tbSelObjZTracking(Sender: TObject);
  275. procedure cbDesignCameraSwitch(Sender: TObject);
  276. procedure tbSelObjXTracking(Sender: TObject);
  277. procedure comboSelObjChange(Sender: TObject);
  278. procedure tbAngleOfViewTracking(Sender: TObject);
  279. procedure tbMainRotTracking(Sender: TObject);
  280. procedure tbJibRotTracking(Sender: TObject);
  281. procedure tbBoatSpeedTracking(Sender: TObject);
  282. procedure comboWaveChange(Sender: TObject);
  283. procedure lbTexCoordXTracking(Sender: TObject);
  284. procedure btnToggleControlsClick(Sender: TObject);
  285. procedure tbCameraAzTracking(Sender: TObject);
  286. procedure tbCameraElevTracking(Sender: TObject);
  287. procedure FormMouseWheel(Sender: TObject; Shift: TShiftState;
  288. WheelDelta: Integer; var Handled: Boolean);
  289. procedure btnRandomizeWaveSystem1Click(Sender: TObject);
  290. procedure timerOneSecondTickTimer(Sender: TObject);
  291. procedure Viewport3D1Paint(Sender: TObject; Canvas: TCanvas;
  292. const ARect: TRectF);
  293. procedure cbUseRampSwitch(Sender: TObject);
  294. procedure cbCloudsSwitch(Sender: TObject);
  295. procedure btnClose3dviewClick(Sender: TObject);
  296. procedure FormGesture(Sender: TObject; const EventInfo: TGestureEventInfo;
  297. var Handled: Boolean);
  298. procedure Viewport3D1MouseDown(Sender: TObject; Button: TMouseButton;
  299. Shift: TShiftState; X, Y: Single);
  300. procedure Viewport3D1MouseMove(Sender: TObject; Shift: TShiftState;
  301. X, Y: Single);
  302. procedure Viewport3D1MouseUp(Sender: TObject; Button: TMouseButton;
  303. Shift: TShiftState; X, Y: Single);
  304. procedure FormActivate(Sender: TObject);
  305. procedure FormDestroy(Sender: TObject);
  306. procedure cbShowDolphinSwitch(Sender: TObject);
  307. procedure cbShowWindArrowSwitch(Sender: TObject);
  308. private
  309. fFirstShow: Boolean;
  310. fBowSail: Integer;
  311. fLastFPS: TDatetime; // last time fPS was computed
  312. fLastFPScount: Integer;
  313. fFPS: Single;
  314. fFrameCount: Integer; // Viewport paint count
  315. fMarks: Array [1 .. numMarks] of TDummy; // fixed number of gater marks
  316. // gesture related vars
  317. fLastDistance: Integer; // last distance between fingers
  318. fLastPanLocation: TPointF;
  319. fMouseDragBeginPt: TPointF;
  320. fMouseDragging: Boolean;
  321. fTimeDolphinAnim: Single; // in sec
  322. function getSelected3DObject: TControl3d;
  323. function getSelectedWave: Integer;
  324. procedure setBowSail(const Value: Integer);
  325. procedure WaveSystem1RandomOrigines;
  326. procedure LoadTerrain;
  327. procedure InitClouds;
  328. procedure CreateMarks;
  329. procedure handlePan(EventInfo: TGestureEventInfo);
  330. procedure handleZoom(EventInfo: TGestureEventInfo);
  331. procedure handlePanDelta(aDelta: TPointF);
  332. procedure ScaleSailsForDemo;
  333. public
  334. fWasInsideSeasurface: Boolean;
  335. center: TPoint3D;
  336. fBoatAttitude: TPoint3D; // (pitch, yaw, roll)
  337. // OPYC automation ( that is Box2D simulation controlling everything from 2D world )
  338. procedure SetBoatState(const aCap, aHeel, aSpeed, aBoomAngle, aRudderAngle,
  339. aWindDir, aWindSpeed: Single);
  340. procedure SetSailShape(ixSail: Integer; aPtArray: TPointF_Array);
  341. procedure Set3DcharacterState(ix: Integer; const X, Y, alfa: Single);
  342. // ix = which char
  343. procedure Set3dMarks(ix: Integer; const ax, ay: Single);
  344. procedure CrewRandomPositions; // move Ivone and Chuck along the boat lenght
  345. procedure Begin3DChange;
  346. procedure End3DChange;
  347. procedure ChangeZoom(WheelDelta: Integer); // changes Angle of view
  348. procedure DoSaveState;
  349. procedure SetTerrainBitmap(bVisible: Boolean; aBMP: TBitmap);
  350. property BowSail: Integer read fBowSail write setBowSail;
  351. end;
  352. var
  353. FormSailboatDemo: TFormSailboatDemo = nil;
  354. implementation //-------------------------------------------------------------
  355. {$IFDEF OPYC}
  356. // undef for SailboatDemo, define for OPYC ( integration to sailing game )
  357. uses
  358. fSailboatApp;
  359. {$ENDIF OPYC}
  360. {$R *.fmx}
  361. function RandomFloat(const lo, hi: Single): Single;
  362. begin
  363. Result := (hi - lo) * Random + lo;
  364. end;
  365. { TForm1 }
  366. procedure TFormSailboatDemo.CrewRandomPositions;
  367. begin
  368. // move characters along the boat length. x in this case
  369. planeChuck.Position.X := RandomFloat(-1.3, 0.1);
  370. planeChuck.RotationAngle.Y := RandomFloat(45, 120);
  371. planeIvone.Position.X := RandomFloat(-1.2, 0.9);
  372. planeIvone.RotationAngle.Y := RandomFloat(450, 150);
  373. dummy3Dolphins.Position.X := RandomFloat(-2, 4);
  374. dummy3Dolphins.Position.Y := RandomFloat(-4, 2);
  375. // dummyWhale.Position.x := RandomFloat( -10, 8 );
  376. // dummyWhale.Position.y := RandomFloat( -10, 5 );
  377. end;
  378. procedure TFormSailboatDemo.FormActivate(Sender: TObject);
  379. begin
  380. if fFirstShow then
  381. // on first show, retrieve control states ( and all extra persistent form state )
  382. begin
  383. {$IFDEF OPYC}
  384. try
  385. StateBox.ReadStateFromIni; // retrieve state
  386. except // ignore read state error // possibly not saved ( first use or file not found )
  387. end;
  388. tbAngleOfViewTracking(nil);
  389. // update camera w/ retrieved camera state. call tracking events
  390. tbCameraAzTracking(nil);
  391. tbCameraElevTracking(nil);
  392. {$ENDIF OPYC}
  393. {$IFNDEF OPYC} // not OPYC --> is SailboatDemo
  394. ScaleSailsForDemo; // set default boat state and adjust sail sizes
  395. {$ENDIF OPYC}
  396. fFirstShow := false; // reset 1st show
  397. end;
  398. end;
  399. procedure TFormSailboatDemo.FormCreate(Sender: TObject);
  400. begin
  401. fFirstShow := true;
  402. // init trackbars w/ selected wave
  403. tbAmplitude.Value := WaveSystem1.Amplitude;
  404. tbWaveLenght.Value := WaveSystem1.Longueur;
  405. tbVitesse.Value := WaveSystem1.Vitesse;
  406. tbOpacite.Value := OceanSurface.Opacity;
  407. fBoatAttitude := Point3D(0, 0, 0); // (pitch, yaw, roll)
  408. fWasInsideSeasurface := true; // start inside
  409. FloatAnimation1.Start;
  410. // the wave system Origines are not editable at design time. So we set defauts here
  411. WaveSystem1RandomOrigines;
  412. CrewRandomPositions;
  413. // make crew move around ( front and aft, mostly doing nothing in this state-of-the-art sailboat )
  414. // WaveSystem1.Origine := Point3D(0,0,0);
  415. // WaveSystem1.Origine2 := Point3D(0,0,20000);
  416. // WaveSystem1.Origine3 := Point3D(-10000,0,-5000);
  417. fBowSail := 0; // 0=jib 1=genoa 2=spi 3=main only
  418. fLastFPS := 0; // never
  419. fLastFPScount := 0;
  420. fFPS := 0;
  421. fFrameCount := 0; // boat simulation paintbox paint count
  422. fTimeDolphinAnim := 0;
  423. fLastPanLocation := PointF(0, 0);
  424. LoadTerrain;
  425. InitClouds;
  426. CreateMarks;
  427. rectBlackListboxBackground.Visible := true;
  428. // controls shown by default at runtime
  429. fMouseDragBeginPt := PointF(0, 0);
  430. fMouseDragging := false;
  431. // gbePlaneWindArrow.Origine := Point3d(0, -10,0); // Origina cannot be set at design time !! :(
  432. // set WindArrow Origine to have a wave ging forward
  433. end;
  434. procedure TFormSailboatDemo.FormDestroy(Sender: TObject);
  435. begin
  436. {$IFDEF MSWINDOWS} // on windows use form destroy to save state (desktop + controls)
  437. DoSaveState;
  438. {$ENDIF MSWINDOWS}
  439. end;
  440. procedure TFormSailboatDemo.handlePanDelta(aDelta: TPointF);
  441. var
  442. aValue: Single;
  443. begin
  444. if (aDelta.X <> 0) then // horiz pan --> change Camera Az
  445. begin
  446. aValue := tbCameraAz.Value;
  447. aValue := aValue + aDelta.X / 5; // linear pan - 5 ad hoc
  448. if aValue > tbCameraAz.Max then
  449. aValue := aValue - tbCameraAz.Max
  450. else if aValue < tbCameraAz.Min then
  451. aValue := tbCameraAz.Max + aValue; // ?
  452. tbCameraAz.Value := aValue;
  453. end;
  454. if (aDelta.Y <> 0) then // vert pan, chg elev
  455. begin
  456. aValue := tbCameraElev.Value;
  457. aValue := aValue * (1 + aDelta.Y / 100);
  458. // this gives a quadratic elevation pan
  459. if aValue > tbCameraElev.Max then
  460. aValue := tbCameraElev.Max
  461. else if aValue < tbCameraElev.Min then
  462. aValue := tbCameraElev.Min;
  463. tbCameraElev.Value := aValue;
  464. end;
  465. end;
  466. procedure TFormSailboatDemo.handlePan(EventInfo: TGestureEventInfo);
  467. var
  468. Delta: System.Types.TPointF;
  469. begin
  470. if (TInteractiveGestureFlag.gfBegin in EventInfo.Flags) then
  471. // begin. save inicial state
  472. begin
  473. fLastPanLocation := EventInfo.Location; // save (center?) point
  474. end
  475. else if (TInteractiveGestureFlag.gfEnd in EventInfo.Flags) then
  476. // end. do nothing
  477. begin
  478. // nada
  479. end
  480. else
  481. begin
  482. // inicialize last, if needed (should not)
  483. if (fLastPanLocation.X = 0) and (fLastPanLocation.Y = 0) then
  484. fLastPanLocation := EventInfo.Location;
  485. Delta := EventInfo.Location - fLastPanLocation;
  486. handlePanDelta(Delta);
  487. // save new previous
  488. fLastPanLocation := EventInfo.Location;
  489. end;
  490. end;
  491. // gesture zoom controls camera ViewAngle
  492. procedure TFormSailboatDemo.handleZoom(EventInfo: TGestureEventInfo);
  493. var
  494. aScale, K, aValue: Single;
  495. begin
  496. if (not(TInteractiveGestureFlag.gfBegin in EventInfo.Flags)) and
  497. (not(TInteractiveGestureFlag.gfEnd in EventInfo.Flags)) then
  498. begin
  499. if (fLastDistance > 0) then // sanity test
  500. begin
  501. aValue := tbAngleOfView.Value;
  502. K := EventInfo.Distance / fLastDistance; // chg zoom factor
  503. if (K > 0) then
  504. begin
  505. aValue := aValue * K;
  506. if aValue > tbAngleOfView.Max then
  507. aValue := tbAngleOfView.Max
  508. else if aValue < tbAngleOfView.Min then
  509. aValue := tbAngleOfView.Min;
  510. tbAngleOfView.Value := aValue;
  511. end;
  512. end;
  513. end;
  514. fLastDistance := EventInfo.Distance;
  515. end;
  516. procedure TFormSailboatDemo.FormGesture(Sender: TObject;
  517. const EventInfo: TGestureEventInfo; var Handled: Boolean);
  518. var
  519. LObj: IControl;
  520. begin
  521. if (EventInfo.GestureID = igiPan) then
  522. Label12.Text := 'pan'
  523. else if (EventInfo.GestureID = igiZoom) then
  524. Label12.Text := 'zoom'
  525. else
  526. Label12.Text := 'gesture?';
  527. LObj := Self.ObjectAtPoint(ClientToScreen(EventInfo.Location));
  528. if (LObj is TViewport3D) then
  529. begin
  530. if (EventInfo.GestureID = igiPan) then
  531. handlePan(EventInfo)
  532. else if (EventInfo.GestureID = igiZoom) then
  533. handleZoom(EventInfo);
  534. Handled := true;
  535. end;
  536. end;
  537. procedure TFormSailboatDemo.CreateMarks;
  538. var
  539. aDummy: TDummy;
  540. aProxy: TProxyObject;
  541. i: Integer;
  542. begin
  543. for i := 1 to numMarks do
  544. begin
  545. aDummy := TDummy.Create(Self); // fixed number of gater marks
  546. aDummy.Visible := false;
  547. aProxy := TProxyObject.Create(Self);
  548. aDummy.AddObject(aProxy);
  549. OceanSurface.AddObject(aDummy);
  550. aProxy.SourceObject := cylinderBuoy; // insert a proxy
  551. aProxy.Position.Point := Point3D(0, 0, 0); // center on dummy
  552. aProxy.Height := cylinderBuoy.Height; // copy buoy size
  553. aProxy.Width := cylinderBuoy.Width;
  554. aProxy.Depth := cylinderBuoy.Depth;
  555. aProxy.Opacity := 1.0;
  556. aProxy.RotationAngle.X := 90;
  557. aDummy.Position.Point := Point3D(10, -5 + i, 0);
  558. // default pos to the side ( boat at 0,0 )
  559. fMarks[i] := aDummy; // save gate dummy
  560. end;
  561. end;
  562. procedure TFormSailboatDemo.Viewport3D1MouseDown(Sender: TObject;
  563. Button: TMouseButton; Shift: TShiftState; X, Y: Single);
  564. begin
  565. fMouseDragBeginPt := PointF(X, Y);
  566. fMouseDragging := true;
  567. end;
  568. procedure TFormSailboatDemo.Viewport3D1MouseMove(Sender: TObject;
  569. Shift: TShiftState; X, Y: Single);
  570. var
  571. M, Delta: TPointF;
  572. begin
  573. if fMouseDragging then
  574. begin
  575. M := PointF(X, Y); // mouse
  576. Delta := M - fMouseDragBeginPt;
  577. fMouseDragBeginPt := M;
  578. handlePanDelta(Delta);
  579. end;
  580. end;
  581. procedure TFormSailboatDemo.Viewport3D1MouseUp(Sender: TObject;
  582. Button: TMouseButton; Shift: TShiftState; X, Y: Single);
  583. var
  584. M, Delta: TPointF;
  585. begin
  586. if fMouseDragging then
  587. begin
  588. M := PointF(X, Y); // mouse
  589. Delta := M - fMouseDragBeginPt;
  590. fMouseDragBeginPt := M;
  591. handlePanDelta(Delta); // last delta, if any
  592. fMouseDragging := false;
  593. end;
  594. end;
  595. procedure TFormSailboatDemo.Viewport3D1Paint(Sender: TObject; Canvas: TCanvas;
  596. const ARect: TRectF);
  597. begin
  598. // inc(fFrameCount);
  599. end;
  600. // randomize wave systems
  601. procedure TFormSailboatDemo.WaveSystem1RandomOrigines;
  602. begin
  603. WaveSystem1.Origine := Point3D(2000 + RandomFloat(-1500, 2400),
  604. 2000 + RandomFloat(-1200, 1300), 0);
  605. WaveSystem1.Origine2 := Point3D(450 + RandomFloat(-1320, 1340),
  606. 350 + RandomFloat(-320, 350), 0);
  607. WaveSystem1.Origine3 := Point3D(-150 + RandomFloat(-330, 1330),
  608. -150 + RandomFloat(+350, 250), 0);
  609. WaveSystem1.Origine4 := Point3D(-150 + RandomFloat(+330, 330),
  610. -150 + RandomFloat(+1350, 250), 0);
  611. WaveSystem1.Origine5 := Point3D(+150 + RandomFloat(+330, 330),
  612. -150 + RandomFloat(+350, 1250), 0);
  613. // not only origines. Randomize sizes and speeds
  614. // small Longueurs resulted in boat pitching too much
  615. WaveSystem1.Longueur := RandomFloat(0.5, 4.6); // 1= long wave
  616. WaveSystem1.Longueur2 := RandomFloat(0.3, 2.9);
  617. // lesser waves that move w/ the boat
  618. WaveSystem1.Longueur3 := RandomFloat(0.5, 2.7);
  619. WaveSystem1.Longueur4 := RandomFloat(0.5, 1.7);
  620. WaveSystem1.Longueur5 := RandomFloat(0.5, 2.1);
  621. WaveSystem1.Amplitude := RandomFloat(0.5, 1.6); // main waves (larger)
  622. WaveSystem1.Amplitude2 := RandomFloat(0.5, 1.4);
  623. WaveSystem1.Amplitude3 := RandomFloat(0.4, 2.1);
  624. WaveSystem1.Amplitude4 := RandomFloat(0.3, 1.3);
  625. WaveSystem1.Amplitude5 := RandomFloat(0.3, 1.4);
  626. WaveSystem1.Vitesse := RandomFloat(1.1, 3.6);
  627. WaveSystem1.Vitesse2 := RandomFloat(1.1, 5.7);
  628. WaveSystem1.Vitesse3 := RandomFloat(1.3, 3.5);
  629. WaveSystem1.Vitesse4 := RandomFloat(1.1, 2.1);
  630. WaveSystem1.Vitesse5 := RandomFloat(1.3, 2.0);
  631. // WaveSystem2 uses the same Wave1 as WaveSystem1
  632. // copy wave1 of WaveSystem1
  633. // WaveSystem2 powers periferic SeaSurfaces
  634. WaveSystem2.Origine := WaveSystem1.Origine;
  635. WaveSystem2.Longueur := WaveSystem1.Longueur;
  636. WaveSystem2.Amplitude := WaveSystem1.Amplitude;
  637. WaveSystem2.Vitesse := WaveSystem1.Vitesse;
  638. end;
  639. procedure TFormSailboatDemo.FormMouseWheel(Sender: TObject; Shift: TShiftState;
  640. WheelDelta: Integer; var Handled: Boolean);
  641. var
  642. aScale: Double;
  643. begin
  644. if not listboxControls.IsVisible then // only Zoom if control not visible.
  645. begin // if control visible, wheel scrolls the listbox
  646. ChangeZoom(WheelDelta);
  647. Handled := true; // we did
  648. end;
  649. end;
  650. procedure TFormSailboatDemo.ChangeZoom(WheelDelta: Integer);
  651. begin
  652. tbAngleOfView.Value := tbAngleOfView.Value - WheelDelta / 100;
  653. // - --> mesma convençao do view do box2d
  654. end;
  655. procedure TFormSailboatDemo.DoSaveState;
  656. begin // save form state
  657. {$IFDEF OPYC}
  658. try
  659. StateBox.WriteStateToIni; // save state in iOS
  660. except
  661. // report error ? // possibly unexisting app Documents folder ( installer should have created that ! )
  662. end;
  663. {$ENDIF OPYC}
  664. end;
  665. procedure TFormSailboatDemo.btnClose3dviewClick(Sender: TObject);
  666. begin
  667. {$IFDEF OPYC}
  668. if Assigned(FormSailboatApp) then
  669. FormSailboatApp.Show;
  670. Hide;
  671. {$ENDIF OPYC}
  672. end;
  673. procedure TFormSailboatDemo.btnRandomizeWaveSystem1Click(Sender: TObject);
  674. begin
  675. WaveSystem1RandomOrigines; // randomize winds
  676. CrewRandomPositions; // move crew
  677. end;
  678. procedure TFormSailboatDemo.btnToggleControlsClick(Sender: TObject);
  679. var
  680. bVisible: Boolean;
  681. begin
  682. bVisible := not listboxControls.Visible; // toggle visibility
  683. listboxControls.Visible := bVisible;
  684. rectBlackListboxBackground.Visible := bVisible;
  685. end;
  686. procedure TFormSailboatDemo.cbCloudsSwitch(Sender: TObject);
  687. begin
  688. GBEClouds1.Visible := cbClouds.IsChecked;
  689. if GBEClouds1.Visible then
  690. GBEClouds1.Position.Y := RandomFloat(-20, -10);
  691. // set cloud covert at random alltitude
  692. end;
  693. procedure TFormSailboatDemo.cbDesignCameraSwitch(Sender: TObject);
  694. begin
  695. Self.Viewport3D1.UsingDesignCamera := cbDesignCamera.IsChecked;
  696. end;
  697. procedure TFormSailboatDemo.cbUseRampSwitch(Sender: TObject);
  698. begin
  699. if cbUseRamp.IsChecked then
  700. heightmapTerrain.MaterialSource := materialTerrainRamp
  701. else
  702. heightmapTerrain.MaterialSource := materialTerrain;
  703. heightmapTerrain.UseRamp := cbUseRamp.IsChecked;
  704. end;
  705. procedure TFormSailboatDemo.comboSelObjChange(Sender: TObject);
  706. var
  707. v: Single;
  708. aObj: TControl3d;
  709. P: TPoint3D;
  710. begin
  711. aObj := getSelected3DObject;
  712. tbSelObjX.Value := aObj.Position.X;
  713. tbSelObjY.Value := aObj.Position.Y;
  714. tbSelObjZ.Value := aObj.Position.Z;
  715. end;
  716. procedure TFormSailboatDemo.comboWaveChange(Sender: TObject);
  717. begin
  718. case getSelectedWave of
  719. 0:
  720. begin
  721. tbVitesse.Value := WaveSystem1.Vitesse;
  722. tbWaveLenght.Value := WaveSystem1.Longueur;
  723. tbAmplitude.Value := WaveSystem1.Amplitude;
  724. SpinBox1.Value := WaveSystem1.Origine.X;
  725. SpinBox2.Value := WaveSystem1.Origine.Y;
  726. SpinBox3.Value := WaveSystem1.Origine.Z;
  727. end;
  728. 1:
  729. begin
  730. tbVitesse.Value := WaveSystem1.Vitesse2;
  731. tbWaveLenght.Value := WaveSystem1.Longueur2;
  732. tbAmplitude.Value := WaveSystem1.Amplitude2;
  733. SpinBox1.Value := WaveSystem1.Origine2.X;
  734. SpinBox2.Value := WaveSystem1.Origine2.Y;
  735. SpinBox3.Value := WaveSystem1.Origine2.Z;
  736. end;
  737. 2:
  738. begin
  739. tbVitesse.Value := WaveSystem1.Vitesse3;
  740. tbWaveLenght.Value := WaveSystem1.Longueur3;
  741. tbAmplitude.Value := WaveSystem1.Amplitude3;
  742. SpinBox1.Value := WaveSystem1.Origine3.X;
  743. SpinBox2.Value := WaveSystem1.Origine3.Y;
  744. SpinBox3.Value := WaveSystem1.Origine3.Z;
  745. end;
  746. 3:
  747. begin
  748. tbVitesse.Value := WaveSystem1.Vitesse4;
  749. tbWaveLenght.Value := WaveSystem1.Longueur4;
  750. tbAmplitude.Value := WaveSystem1.Amplitude4;
  751. SpinBox1.Value := WaveSystem1.Origine4.X;
  752. SpinBox2.Value := WaveSystem1.Origine4.Y;
  753. SpinBox3.Value := WaveSystem1.Origine4.Z;
  754. end;
  755. 4:
  756. begin
  757. tbVitesse.Value := WaveSystem1.Vitesse5;
  758. tbWaveLenght.Value := WaveSystem1.Longueur5;
  759. tbAmplitude.Value := WaveSystem1.Amplitude5;
  760. SpinBox1.Value := WaveSystem1.Origine5.X;
  761. SpinBox2.Value := WaveSystem1.Origine5.Y;
  762. SpinBox3.Value := WaveSystem1.Origine5.Z;
  763. end;
  764. end;
  765. end;
  766. procedure TFormSailboatDemo.SetSailShape(ixSail: Integer;
  767. aPtArray: TPointF_Array); // 0=main, 1=bow sail
  768. var
  769. aSail: TgxSailSurface;
  770. n: Integer;
  771. begin
  772. case ixSail of
  773. 0:
  774. aSail := MainSail;
  775. 1:
  776. aSail := JibSail;
  777. 2:
  778. aSail := birutaSail;
  779. // TODO: Other bow sails
  780. else
  781. aSail := nil;
  782. end;
  783. if Assigned(aSail) then
  784. begin
  785. n := Length(aPtArray) - 1;
  786. if (n > 0) then
  787. begin
  788. aSail.SubdivisionsWidth := n; // upd mesh width (Spis are wilder )
  789. aSail.SetMeshWith2Dline(GXS.SailSurface.TPointF_Array(aPtArray));
  790. end;
  791. end;
  792. end;
  793. procedure TFormSailboatDemo.Begin3DChange;
  794. begin
  795. Viewport3D1.BeginUpdate;
  796. end;
  797. procedure TFormSailboatDemo.End3DChange;
  798. begin
  799. Viewport3D1.EndUpdate;
  800. end;
  801. Procedure TFormSailboatDemo.SetTerrainBitmap(bVisible: Boolean; aBMP: TBitmap);
  802. begin
  803. if bVisible then
  804. begin
  805. ImageTerrain.Bitmap := aBMP; // use provided bmp to set terrain mesh
  806. try
  807. LoadTerrain; // from ImageTerrain
  808. except
  809. labCountTerrainBuilds.Text := 'error in terrain';
  810. exit; // ??
  811. end;
  812. labCountTerrainBuilds.Tag := labCountTerrainBuilds.Tag + 1;
  813. // Tag counts terrain builds
  814. labCountTerrainBuilds.Text := IntToStr(labCountTerrainBuilds.Tag);
  815. end;
  816. heightmapTerrain.Visible := bVisible;
  817. end;
  818. procedure TFormSailboatDemo.Set3DcharacterState(ix: Integer;
  819. const X, Y, alfa: Single);
  820. var
  821. aDummy: TDummy;
  822. Z: Single;
  823. begin
  824. aDummy := nil;
  825. case ix of
  826. charDolphin:
  827. aDummy := nil;
  828. // dummy3Dolphins; // dont chg dolphin position. Always along the boat
  829. charWhiteBirds:
  830. aDummy := dummyWhiteBirds;
  831. charBrownBirds:
  832. aDummy := dummyBrownBirds;
  833. charBoiaCross:
  834. aDummy := dummyBoiaMan;
  835. charPelican:
  836. aDummy := dummyPelican;
  837. charPurpleBoat:
  838. aDummy := dummyPurpleBoat;
  839. charContainer:
  840. aDummy := dummyContainer;
  841. charRock:
  842. aDummy := dummyRock;
  843. charBarril:
  844. aDummy := dummyBarril;
  845. charWhale:
  846. aDummy := dummyWhale;
  847. end;
  848. if Assigned(aDummy) then
  849. begin
  850. Z := aDummy.Position.Z; // save z pos set by waves
  851. aDummy.Position.Point := Point3D(X, -Y, Z);
  852. aDummy.RotationAngle.Z := alfa + 90; // ??
  853. aDummy.TagFloat := Frac(Now) * 3600 * 24;
  854. // save time last moved in TagFloat ( a Single ) in seconds since 12:00AM
  855. aDummy.Visible := true;
  856. end;
  857. end;
  858. procedure TFormSailboatDemo.Set3dMarks(ix: Integer; const ax, ay: Single);
  859. // ix 1 based
  860. var
  861. az: Single;
  862. begin
  863. if (ix < 1) or (ix > numMarks) then
  864. exit; // invalid index
  865. az := fMarks[ix].Position.Z; // keep z
  866. fMarks[ix].Position.Point := Point3D(ax, -ay, az);
  867. fMarks[ix].Visible := true;
  868. end;
  869. procedure TFormSailboatDemo.FloatAnimation1Process(Sender: TObject);
  870. // 0.2 sec tick
  871. var
  872. aAmpl, aPitch, aCap, aAng, aSpd, DHeel, aHeelAng, xb, zb, sz, dx, dy, v,
  873. Tsec: Single;
  874. D, P, Po, Pnew: TPoint3D;
  875. newBubble: TProxyObject;
  876. aControl: TControl3d;
  877. isOutside, bWasMovedRecently: Boolean;
  878. i, n: Integer;
  879. aPh, aAlt, aDeriv: Single;
  880. const
  881. CINCOSEC = 5 / 3600 / 24;
  882. // after 5 seconds w/o being moved by simulation, move by sea
  883. begin
  884. if not Visible then
  885. exit; // avoid animating if form not visible, to save CPU
  886. // keep animating would be better, but performance sucks on mobiles :(
  887. inc(fFrameCount);
  888. Begin3DChange;
  889. try
  890. // precalc stuff
  891. P := dummyBoatCap.Position.Point;
  892. // boat position on the virtual ocean surface = position ( boat is independent from sea)
  893. aCap := dummyBoatCap.RotationAngle.Y; // get boat cap
  894. aAng := aCap * Pi / 180; // cap to radians
  895. aSpd := tbBoatSpeed.Value;
  896. // get boat speed from trackbar ( em m/s max = 15)
  897. D := Point3D(-sin(aAng), 0, -cos(aAng)) * aSpd / 100;
  898. // displacement in one sec, in m
  899. dx := -D.X * B2Dto3Dscale;
  900. // B2Dto3Dscale = scale factor between Box2D and 3D world
  901. dy := D.Z * B2Dto3Dscale;
  902. // u := -(D.x/OceanSurface.SubdivisionsWidth /20); //ad hoc
  903. // v := (D.z/OceanSurface.SubdivisionsHeight/20);
  904. if cbMoveSea.IsChecked then // moving sea = moving boat
  905. begin
  906. OceanSurface.MoveTextureBy(dx, dy); // shifts virtual sea TexCoordinates
  907. OceanSurfaceTop.MoveTextureBy(dx, dy); // all of them ?
  908. OceanSurfaceLeft.MoveTextureBy(dx, dy);
  909. OceanSurfaceBot.MoveTextureBy(dx, dy);
  910. OceanSurfaceRight.MoveTextureBy(dx, dy);
  911. end;
  912. // Position boat floating on the sea surface and pitching accordingly
  913. if OceanSurface.calcWaveAmplitudeAndPitch(P, aCap, { out: } aAmpl, aPitch)
  914. then
  915. begin
  916. // when the boat heels, lift it some. In fact the center of buoyancy lifts as the boat side goes under water..
  917. aHeelAng := dummyBoatHeel.RotationAngle.Z;
  918. if (aHeelAng > 180) then
  919. aHeelAng := 360 - aHeelAng; // put in the -90..90 range
  920. aHeelAng := Abs(aHeelAng * Pi / 180); // to rad abs
  921. DHeel := -0.20 * sin(aHeelAng); // numbers ad hoc
  922. dummyBoatCap.Position.Y := aAmpl * 0.95 + DHeel; // mk boat float
  923. fBoatAttitude.X := aPitch; // pitch boat
  924. dummyBoatPitch.RotationAngle.X := aPitch * 0.6;
  925. // 0.6 avoids too much pitching
  926. labBoatPitch.Text := Format('%5.1f', [aPitch]) + 'd'; // show pitch
  927. end;
  928. // OceanSurface.Children includes wake bubbles, characters, rocks, and even terrain
  929. // those shift in x,y in sync with the sea surface, and some float on the surface
  930. Tsec := Frac(Now) * 3600 * 24; // time in seconds since 12:00AM
  931. for i := 0 to OceanSurface.ChildrenCount - 1 do
  932. // move bubbles to wave amplitude, so they stay afloat
  933. begin
  934. aControl := TControl3d(OceanSurface.Children[i]);
  935. if not aControl.Visible then
  936. continue; // ignore hiden
  937. if cbMoveSea.IsChecked then
  938. // first move then in relation to the boat at 0,0
  939. begin
  940. // some controls are moved by the box2d simulation, so we don't mess w/ them here
  941. bWasMovedRecently := (aControl.TagFloat > 0) and
  942. (Tsec - aControl.TagFloat < 10.0);
  943. if (aControl is TDummy) and (aControl.TagFloat > 0) and
  944. (not bWasMovedRecently) and (aControl <> dummyRock) and
  945. (aControl <> dummyTerrain) then // never hide rock and terrain
  946. begin // hide animations that are not being moved
  947. aControl.Visible := false; // hide
  948. continue;
  949. end;
  950. // not moved child are moved with the shifting texture
  951. if not bWasMovedRecently then
  952. // if not moved, move children with the surface
  953. begin
  954. aControl.Position.X := aControl.Position.X - dx;
  955. // move it with the shifting surface
  956. aControl.Position.Y := aControl.Position.Y - dy;
  957. end;
  958. end;
  959. if (aControl = dummyRock) or (aControl = dummyTerrain) then
  960. continue; // rock and terrain dont float :)
  961. // other stuff float: containers, barrels, even flying birds
  962. // set object z with the wave amplitude ( floating objects )
  963. P := aControl.Position.Point;
  964. // - Point3d(0.50, 0, 0.50); // set P in div units
  965. xb := P.X;
  966. zb := P.Y;
  967. // P := Point3D(xb,0,zb)/OceanSurface.SubdivisionsHeight; // to subd
  968. P := Point3D(xb, 0, zb);
  969. if OceanSurface.calcWaveAmplitudeAndPitch(P, aCap, aAmpl, aPitch) then
  970. begin
  971. aControl.Position.Z := aAmpl - 0.03; // mk bubble float
  972. // not using pitch
  973. end;
  974. end;
  975. if cbMoveSea.IsChecked then // move sea ( boat perspective )
  976. begin
  977. // emit bubbles !
  978. if (fFrameCount mod 7) = 0 then
  979. // every few ticks, add a bubble to the wake..
  980. begin
  981. newBubble := TProxyObject.Create(Self); // bubble is a proxy to a TDisk
  982. OceanSurface.AddObject(newBubble);
  983. // parent buoy to sea surface, so it moves w/ it
  984. newBubble.SourceObject := diskBubble; // sphereBuoy;
  985. newBubble.SetSize((Random(20) + 10) / 150, 0.01,
  986. (Random(20) + 10) / 150); // small flat whiote disk
  987. P := OceanSurface.Position.Point; // z makes the bubble float.
  988. newBubble.Position.Point := Point3D(-P.X, +P.Z, 0) +
  989. Point3D((Random(10) - 5) / 20, (Random(10) - 5) / 20, 0.2);
  990. // position at -P on the sea surface. some randoness too
  991. newBubble.Opacity := 0.1; // ?? doesnt work !?
  992. newBubble.RotationAngle.X := 90;
  993. if OceanSurface.ChildrenCount > 121 then
  994. // keep a maximum of 121 bubbles. If more , clear some old bubbles
  995. begin
  996. // change opacity of some
  997. n := Random(100);
  998. aControl := TControl3d(OceanSurface.Children[n]);
  999. if not(aControl is TDummy) then
  1000. aControl.Opacity := 0.4;
  1001. // aControl is TDummy --> TDummy is a permanent obj ( not a bubble )
  1002. n := Random(50);
  1003. aControl := TControl3d(OceanSurface.Children[n]);
  1004. if not(aControl is TDummy) then
  1005. aControl.Opacity := 0.2;
  1006. // dispose a few. Randomic choice
  1007. n := Random(100);
  1008. aControl := TControl3d(OceanSurface.Children[n]);
  1009. if not(aControl is TDummy) then
  1010. // dont remove dummies. These are design time characters
  1011. begin
  1012. OceanSurface.RemoveObject(aControl);
  1013. aControl.DisposeOf;
  1014. end;
  1015. n := Random(50);
  1016. aControl := TControl3d(OceanSurface.Children[n]);
  1017. if not(aControl is TDummy) then
  1018. begin
  1019. OceanSurface.RemoveObject(aControl);
  1020. aControl.DisposeOf;
  1021. end;
  1022. n := Random(20); // dispose older
  1023. aControl := TControl3d(OceanSurface.Children[n]);
  1024. if not(aControl is TDummy) then
  1025. begin
  1026. OceanSurface.RemoveObject(aControl);
  1027. aControl.DisposeOf;
  1028. end;
  1029. end;
  1030. end;
  1031. end;
  1032. if (fFrameCount mod 100 = 0) and GBEClouds1.Visible then
  1033. GBEClouds1.moveClouds;
  1034. if cbShowDolphin.IsChecked then // Animate jumping Dolphin
  1035. begin
  1036. // animate dolphin
  1037. const
  1038. DolphinWaveAmplitude = 0.35; // in m some ad-hoc factors
  1039. const
  1040. DolphinWaveSpeed = 7 * Pi; // in rad/s
  1041. aPh := DolphinWaveSpeed * fTimeDolphinAnim;
  1042. // calc wave phase at the point
  1043. aAlt := DolphinWaveAmplitude * sin(aPh); // sum sin() wave amplitude
  1044. aDeriv := cos(aPh) * 180 / Pi;
  1045. // dolphin pitch in deg derivative of sin() is cos()
  1046. modelDolphin.Position.Y := aAlt + 0.3; // set dolphin altitude
  1047. modelDolphin.RotationAngle.Z := 180 + aDeriv / 2; // set dolphin pitch
  1048. // dummyDolphin is not parented to OcceanSurface, so it doesnt float by default
  1049. // so make dummyDolphin float. more or less
  1050. // dummy3Dolphins is parented to dummyBoatCap, w/ coordinates x,y
  1051. P := modelDolphin.LocalToAbsolute3D(Point3D(0, 0, 0));
  1052. // get dolphin abs coordinates
  1053. P := Point3D(P.X, 0, P.Y); // OceanSurface uses x,z as x,y
  1054. if OceanSurface.calcWaveAmplitudeAndPitch(P, aCap, aAmpl, aPitch) then
  1055. // probe wave amplitude
  1056. dummy3Dolphins.Position.Y := aAmpl; // move dolphin dummy up and down
  1057. // animate whale
  1058. if dummyWhale.Visible then
  1059. begin
  1060. const
  1061. WhaleWaveAmplitude = 1.2; // in m some ad-hoc factors
  1062. const
  1063. WhaleWaveSpeed = 3 * Pi; // in rad/s
  1064. aPh := WhaleWaveSpeed * fTimeDolphinAnim;
  1065. // calc wave phase at the point
  1066. aAlt := WhaleWaveAmplitude * sin(aPh); // sum sin() wave amplitude
  1067. aDeriv := cos(aPh) * 180 / Pi;
  1068. // dolphin pitch in deg derivative of sin() is cos()
  1069. modelWhale.Position.Z := aAlt + 0.1; // set altitude
  1070. // modelWhale.RotationAngle.z := 180+aDeriv/2; // set pitch
  1071. modelWhale.RotationAngle.X := modelWhale.RotationAngle.X + 3;
  1072. // rotate whale on its length axis
  1073. P := modelDolphin.LocalToAbsolute3D(Point3D(0, 0, 0));
  1074. // get dolphin abs coordinates
  1075. P := Point3D(P.X, 0, P.Y); // OceanSurface uses x,z as x,y
  1076. if OceanSurface.calcWaveAmplitudeAndPitch(P, aCap, aAmpl, aPitch) then
  1077. // probe wave amplitude
  1078. modelWhale.Position.Y := aAmpl; // move dolphin dummy up and down
  1079. end;
  1080. // adv dolphin animation time.
  1081. fTimeDolphinAnim := fTimeDolphinAnim + 0.01; // in sec
  1082. end;
  1083. finally
  1084. End3DChange;
  1085. end;
  1086. // Viewport3D1.Repaint;
  1087. end;
  1088. procedure TFormSailboatDemo.SpinBox1ChangeClick(Sender: TObject);
  1089. var
  1090. P: TPoint3D;
  1091. begin
  1092. P := Point3D(SpinBox1.Value, SpinBox2.Value, SpinBox3.Value);
  1093. case getSelectedWave of
  1094. 0:
  1095. WaveSystem1.Origine := P;
  1096. 1:
  1097. WaveSystem1.Origine2 := P;
  1098. 2:
  1099. WaveSystem1.Origine3 := P;
  1100. 3:
  1101. WaveSystem1.Origine4 := P;
  1102. 4:
  1103. WaveSystem1.Origine5 := P;
  1104. end;
  1105. end;
  1106. procedure TFormSailboatDemo.cbShowDolphinSwitch(Sender: TObject);
  1107. begin
  1108. dummy3Dolphins.Visible := cbShowDolphin.IsChecked;
  1109. dummyWhale.Visible := cbShowDolphin.IsChecked;
  1110. end;
  1111. procedure TFormSailboatDemo.cbShowLinesSwitch(Sender: TObject);
  1112. begin
  1113. OceanSurface.ShowLines := cbShowLines.IsChecked;
  1114. end;
  1115. procedure TFormSailboatDemo.cbShowWindArrowSwitch(Sender: TObject);
  1116. begin
  1117. dummyWindArrow.Visible := cbShowWindArrow.IsChecked;
  1118. end;
  1119. procedure TFormSailboatDemo.tbAmplitudeTracking(Sender: TObject);
  1120. begin
  1121. case getSelectedWave of
  1122. 0:
  1123. WaveSystem1.Amplitude := tbAmplitude.Value;
  1124. 1:
  1125. WaveSystem1.Amplitude2 := tbAmplitude.Value;
  1126. 2:
  1127. WaveSystem1.Amplitude3 := tbAmplitude.Value;
  1128. 3:
  1129. WaveSystem1.Amplitude4 := tbAmplitude.Value;
  1130. 4:
  1131. WaveSystem1.Amplitude5 := tbAmplitude.Value;
  1132. end;
  1133. labAmplitude.Text := Format('%6.2f', [tbAmplitude.Value]);
  1134. end;
  1135. procedure TFormSailboatDemo.tbAngleOfViewTracking(Sender: TObject);
  1136. begin
  1137. Camera1.AngleOfView := tbAngleOfView.Value;
  1138. labCameraViewAngle.Text := Format('%5.0f', [Camera1.AngleOfView]) + 'o';
  1139. end;
  1140. procedure TFormSailboatDemo.tbBoatSpeedTracking(Sender: TObject);
  1141. begin
  1142. labBoatSpeed.Text := Format('%5.0f', [tbBoatSpeed.Value]);
  1143. end;
  1144. procedure TFormSailboatDemo.tbWaveLenghtTracking(Sender: TObject);
  1145. begin
  1146. case getSelectedWave of
  1147. 0:
  1148. WaveSystem1.Longueur := tbWaveLenght.Value;
  1149. 1:
  1150. WaveSystem1.Longueur2 := tbWaveLenght.Value;
  1151. 2:
  1152. WaveSystem1.Longueur3 := tbWaveLenght.Value;
  1153. 3:
  1154. WaveSystem1.Longueur4 := tbWaveLenght.Value;
  1155. 4:
  1156. WaveSystem1.Longueur5 := tbWaveLenght.Value;
  1157. end;
  1158. labLongueur.Text := Format('%5.1f', [tbWaveLenght.Value]);
  1159. end;
  1160. procedure TFormSailboatDemo.timerOneSecondTickTimer(Sender: TObject);
  1161. var
  1162. nFrames: Integer;
  1163. DT: TDatetime;
  1164. T: TDatetime;
  1165. begin
  1166. T := Now;
  1167. // upd FPS
  1168. nFrames := (fFrameCount - fLastFPScount);
  1169. DT := (T - fLastFPS) * 3600 * 24; // DT in secs
  1170. if (DT > 0) and (nFrames > 0) then
  1171. fFPS := nFrames / DT // upd fps
  1172. else
  1173. fFPS := 0;
  1174. fLastFPS := T; // save last state
  1175. fLastFPScount := fFrameCount;
  1176. labFPS.Text := 'fps: ' + Trim(Format('%4.0f', [fFPS]));
  1177. // upc fps display every sec
  1178. end;
  1179. procedure TFormSailboatDemo.tbVitesseTracking(Sender: TObject);
  1180. begin
  1181. case getSelectedWave of
  1182. 0:
  1183. WaveSystem1.Vitesse := tbVitesse.Value;
  1184. 1:
  1185. WaveSystem1.Vitesse2 := tbVitesse.Value;
  1186. 2:
  1187. WaveSystem1.Vitesse3 := tbVitesse.Value;
  1188. 3:
  1189. WaveSystem1.Vitesse4 := tbVitesse.Value;
  1190. 4:
  1191. WaveSystem1.Vitesse5 := tbVitesse.Value;
  1192. end;
  1193. labVitesse.Text := Format('%5.1f', [tbVitesse.Value]);
  1194. end;
  1195. procedure TFormSailboatDemo.tbOpaciteTracking(Sender: TObject);
  1196. begin
  1197. OceanSurface.Opacity := tbOpacite.Value;
  1198. labOpacite.Text := Format('%5.2f', [tbOpacite.Value]);
  1199. end;
  1200. procedure TFormSailboatDemo.tbCameraAzTracking(Sender: TObject);
  1201. begin
  1202. dummyCameraTarget.RotationAngle.Y := tbCameraAz.Value;
  1203. labCameraAz.Text := Format('%5.0f', [tbCameraAz.Value]);
  1204. end;
  1205. // exponential scale trackbar helper. Used a 100% = e^5 ( or exp(5) )
  1206. // change between trackbar value 1..100 range to exponenmtial elevatio between 0.17 and 1000
  1207. function percValueToExponential(const aValue, VMin, VMax: Single): Single;
  1208. // value in 1..100 range
  1209. const
  1210. exp5 = 148.41; // exp(5) corresponds to Value=100 --> VMax
  1211. begin
  1212. Result := VMin + Exp(aValue / 20) / exp5 * (VMax - VMin) - 3;
  1213. end;
  1214. procedure TFormSailboatDemo.tbCameraElevTracking(Sender: TObject);
  1215. var
  1216. aElev, aValue: Single;
  1217. begin
  1218. aValue := tbCameraElev.Value; // 1..100
  1219. aElev := percValueToExponential(aValue, { VMin: } -5, { VMax: } 1000);
  1220. Camera1.Position.Y := -aElev;
  1221. labCameraElev.Text := Format('%5.0f', [aElev]);
  1222. end;
  1223. procedure TFormSailboatDemo.tbCapTracking(Sender: TObject);
  1224. begin
  1225. dummyBoatCap.RotationAngle.Y := tbCap.Value; // cap = boat course
  1226. labCap.Text := Format('%5.0f', [tbCap.Value]);
  1227. end;
  1228. procedure TFormSailboatDemo.tbHeelTracking(Sender: TObject);
  1229. begin
  1230. dummyBoatHeel.RotationAngle.Z := tbHeel.Value; // boat heel
  1231. LabHeel.Text := Format('%5.1f', [tbHeel.Value]);
  1232. end;
  1233. procedure TFormSailboatDemo.tbJibRotTracking(Sender: TObject);
  1234. begin
  1235. dummyJib.RotationAngle.Y := tbJibRot.Value;
  1236. // JibSail.CamberRight := (tbJibRot.Value>0);
  1237. labJibRot.Text := Format('%5.1f', [tbJibRot.Value]);
  1238. end;
  1239. procedure TFormSailboatDemo.tbMainRotTracking(Sender: TObject);
  1240. begin
  1241. {$IFDEF OPYC}
  1242. // for OPYC, main rotation is controlled by simu
  1243. {$ELSE}
  1244. dummyMain.RotationAngle.Y := tbMainRot.Value;
  1245. MainSail.CamberRight := (tbMainRot.Value < 0);
  1246. labMainRot.Text := Format('%5.1f', [tbMainRot.Value]);
  1247. {$ENDIF OPYC}
  1248. end;
  1249. function TFormSailboatDemo.getSelectedWave: Integer; // 0, 1 or 2
  1250. begin
  1251. if comboWave.ItemIndex = -1 then
  1252. Result := 0
  1253. else
  1254. Result := comboWave.ItemIndex;
  1255. end;
  1256. // demo automation ( used by OPYC)
  1257. procedure TFormSailboatDemo.SetBoatState(const aCap, aHeel, aSpeed, aBoomAngle,
  1258. aRudderAngle, aWindDir, aWindSpeed: Single);
  1259. var
  1260. aSc: Single;
  1261. begin
  1262. // dummyBoatCap.RotationAngle.y := aCap;
  1263. // dummyBoatHeel.RotationAngle.z := aHeel;
  1264. tbCap.Value := aCap; // this calls trackbar events that set boat vars
  1265. tbHeel.Value := aHeel;
  1266. tbBoatSpeed.Value := aSpeed;
  1267. dummyBoom.RotationAngle.Y := aBoomAngle;
  1268. dummyRudder.RotationAngle.Y := aRudderAngle;
  1269. if dummyWindArrow.Visible then
  1270. begin
  1271. dummyWindArrow.RotationAngle.Y := 90 + aWindDir; // + Random(2)-1;
  1272. aSc := System.Math.Max(aWindSpeed / 12, 0.3);
  1273. dummyWindArrow.Scale.Point := Point3D(aSc, aSc, aSc);
  1274. // scale arrow according to WindSpeed
  1275. end;
  1276. end;
  1277. procedure TFormSailboatDemo.setBowSail(const Value: Integer);
  1278. var
  1279. ax, ay, az: Single;
  1280. bVisible: Boolean;
  1281. begin
  1282. if (fBowSail <> Value) then // changed sail
  1283. begin
  1284. fBowSail := Value;
  1285. bVisible := true;
  1286. case fBowSail of
  1287. 0:
  1288. begin
  1289. JibSail.MaterialSource := Self.texJibSail;
  1290. az := -0.62;
  1291. // sail position numbers found by adjusting obj pos at runtime
  1292. ay := -1.91;
  1293. end;
  1294. 1:
  1295. begin
  1296. JibSail.MaterialSource := Self.texCodeZero; // genoa = code zero
  1297. az := -0.52;
  1298. ay := -1.86;
  1299. end;
  1300. 2:
  1301. begin
  1302. JibSail.MaterialSource := Self.texSpinaker;
  1303. az := -0.32;
  1304. ay := -1.91;
  1305. end;
  1306. 3:
  1307. begin // 3=main sail only
  1308. bVisible := false;
  1309. // dont care about pos
  1310. end;
  1311. else
  1312. end;
  1313. JibSail.Visible := bVisible;
  1314. if bVisible then
  1315. begin
  1316. ax := JibSail.Position.X; // keep x
  1317. JibSail.Position.Point := Point3D(ax, ay, az);
  1318. end;
  1319. end;
  1320. end;
  1321. procedure TFormSailboatDemo.lbTexCoordXTracking(Sender: TObject);
  1322. // X and Y actually
  1323. begin
  1324. // P := '';
  1325. // TC:= '';
  1326. // OceanSurface.GetPointsTexCoordinates(P, TC);
  1327. // OceanSurface.MoveTextureBy(u,v);
  1328. // labDataTexCoordinates.Text := P;
  1329. // labDataPoints.Text := TC;
  1330. // OceanSurface.SetTextureCoordinates(u,v);
  1331. end;
  1332. Procedure TFormSailboatDemo.LoadTerrain;
  1333. var
  1334. stream: TMemoryStream;
  1335. begin
  1336. stream := TMemoryStream.Create;
  1337. ImageTerrain.Bitmap.SaveToStream(stream);
  1338. heightmapTerrain.loadHeightmapFromStream(stream);
  1339. stream.Free;
  1340. dummyTerrain.Position.Point := Point3D(0, 0, 0);
  1341. // loaded new terrain in the center. Bring terrain back
  1342. end;
  1343. procedure TFormSailboatDemo.InitClouds;
  1344. begin
  1345. GBEClouds1.addTextureCloud(materialCloud1);
  1346. GBEClouds1.addTextureCloud(materialCloud2);
  1347. GBEClouds1.addTextureCloud(materialCloud3);
  1348. GBEClouds1.NbClouds := 15;
  1349. GBEClouds1.WindSpeed := 0.01;
  1350. GBEClouds1.Limits := 100;
  1351. GBEClouds1.ActiveWind := true;
  1352. // FloatAnimation1.Start;
  1353. end;
  1354. function TFormSailboatDemo.getSelected3DObject: TControl3d;
  1355. begin
  1356. case comboSelObj.ItemIndex of
  1357. 0:
  1358. Result := modelBoat; // Hull
  1359. 1:
  1360. Result := MainSail; // Main
  1361. 2:
  1362. Result := JibSail; // Jib
  1363. 3:
  1364. Result := dummyMain; // dummyMain
  1365. 4:
  1366. Result := dummyJib; // dummyJib
  1367. 5:
  1368. Result := cylinderBoom; // Boom
  1369. 6:
  1370. Result := dummyBoom; // dummyBoom
  1371. 7:
  1372. Result := dummyBoatCap; // dummyBoat
  1373. 8:
  1374. Result := cubeJibStay; // cubeJibStay
  1375. 9:
  1376. Result := heightmapTerrain;
  1377. 10:
  1378. Result := GBEClouds1;
  1379. 11:
  1380. Result := dummyCrew;
  1381. 12:
  1382. Result := dummyRudder;
  1383. else
  1384. Result := modelBoat; // ??
  1385. end;
  1386. end;
  1387. procedure TFormSailboatDemo.tbSelObjXTracking(Sender: TObject);
  1388. var
  1389. v: Single;
  1390. aObj: TControl3d;
  1391. begin
  1392. aObj := getSelected3DObject;
  1393. v := tbSelObjX.Value;
  1394. labSelObjX.Text := Format('%5.2f', [v]);
  1395. aObj.Position.X := v;
  1396. end;
  1397. procedure TFormSailboatDemo.tbSelObjYTracking(Sender: TObject);
  1398. var
  1399. v: Single;
  1400. aObj: TControl3d;
  1401. begin
  1402. aObj := getSelected3DObject;
  1403. v := tbSelObjY.Value;
  1404. labSelObjY.Text := Format('%5.2f', [v]);
  1405. aObj.Position.Y := v;
  1406. end;
  1407. procedure TFormSailboatDemo.tbSelObjZTracking(Sender: TObject);
  1408. var
  1409. v: Single;
  1410. aObj: TControl3d;
  1411. begin
  1412. aObj := getSelected3DObject;
  1413. v := tbSelObjZ.Value;
  1414. labSelObjZ.Text := Format('%5.2f', [v]);
  1415. aObj.Position.Z := v;
  1416. end;
  1417. procedure TFormSailboatDemo.ScaleSailsForDemo;
  1418. // ad hoc object positioning for sailboat demo
  1419. begin
  1420. // scale jib and main
  1421. JibSail.Width := JibSail.Width / 1.8;
  1422. JibSail.Depth := JibSail.Depth / 1.8;
  1423. MainSail.Width := MainSail.Width / 1.8;
  1424. MainSail.Depth := MainSail.Depth / 1.8;
  1425. MainSail.Position.Point := Point3D(0.17, -2.4, -0.49);
  1426. // ad hoc positioning obtained from the app itself
  1427. JibSail.Position.Point := Point3D(0.29, -1.95, -0.24);
  1428. tbHeel.Value := 12; // some heel and some sail sheet
  1429. tbJibRot.Value := -10;
  1430. tbMainRot.Value := -8;
  1431. tbBoatSpeed.Value := 5;
  1432. end;
  1433. end.