GLS.Navigator.pas 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952
  1. //
  2. // The graphics engine GLScene https://github.com/glscene
  3. //
  4. unit GLS.Navigator;
  5. (* Unit for navigating GLBaseObjects and GLSceneViewer. *)
  6. interface
  7. {$I GLScene.Defines.inc}
  8. uses
  9. Winapi.Windows,
  10. System.Types,
  11. System.Classes,
  12. System.SysUtils,
  13. System.Math,
  14. Vcl.Controls,
  15. Vcl.Graphics,
  16. Vcl.Forms,
  17. GLS.Scene,
  18. GLS.SceneViewer,
  19. GLS.Objects,
  20. GLS.GeomObjects,
  21. GLS.Context,
  22. GLScene.BaseClasses,
  23. GLScene.PersistentClasses,
  24. GLScene.VectorTypes,
  25. GLScene.VectorGeometry,
  26. GLS.Keyboard,
  27. GLS.HudObjects,
  28. GLScene.Coordinates,
  29. GLS.Screen,
  30. GLS.Material,
  31. GLS.Texture,
  32. GLScene.TextureFormat,
  33. GLS.RenderContextInfo;
  34. type
  35. (* TGLNavigator is the component for moving a TGLBaseSceneObject, and all Classes based on it,
  36. this includes all the objects from the Scene Editor.
  37. The four calls to get you started is
  38. TurnHorisontal : it turns left and right.
  39. TurnVertical : it turns up and down.
  40. MoveForward : moves back and forth.
  41. FlyForward : moves back and forth in the movingobject's direction
  42. The three properties to get you started is
  43. MovingObject : The Object that you are moving.
  44. UseVirtualUp : When UseVirtualUp is set you navigate Quake style. If it isn't more like Descent.
  45. AngleLock : Allows you to block the Vertical angles.
  46. Should only be used in conjunction with UseVirtualUp.
  47. MoveUpWhenMovingForward : Changes movement from Quake to Arcade Airplane...(no tilt and flying)
  48. InvertHorizontalSteeringWhenUpsideDown : When using virtual up, and vertically
  49. rotating beyond 90 degrees, will make steering seem inverted, so we "invert" back to normal *)
  50. TGLNavigator = class(TComponent)
  51. private
  52. FObject: TGLBaseSceneObject;
  53. FVirtualRight: TGLVector;
  54. FVirtualUp: TGCoordinates;
  55. FUseVirtualUp: boolean;
  56. FAutoUpdateObject: boolean;
  57. FMaxAngle: single;
  58. FMinAngle: single;
  59. FCurrentVAngle: single;
  60. FCurrentHAngle: single;
  61. FAngleLock: boolean;
  62. FMoveUpWhenMovingForward: boolean;
  63. FInvertHorizontalSteeringWhenUpsideDown: boolean;
  64. protected
  65. procedure Notification(AComponent: TComponent;
  66. Operation: TOperation); override;
  67. procedure SetObject(NewObject: TGLBaseSceneObject); virtual;
  68. procedure SetUseVirtualUp(UseIt: boolean);
  69. procedure SetVirtualUp(Up: TGCoordinates);
  70. function CalcRight: TGLVector;
  71. public
  72. constructor Create(AOwner: TComponent); override;
  73. destructor Destroy; override;
  74. procedure TurnHorizontal(Angle: single);
  75. procedure TurnVertical(Angle: single);
  76. procedure MoveForward(Distance: single);
  77. procedure StrafeHorizontal(Distance: single);
  78. procedure StrafeVertical(Distance: single);
  79. procedure Straighten;
  80. procedure FlyForward(Distance: single);
  81. procedure LoadState(Stream: TStream);
  82. procedure SaveState(Stream: TStream);
  83. property CurrentVAngle: single read FCurrentVAngle;
  84. property CurrentHAngle: single read FCurrentHAngle;
  85. published
  86. property MoveUpWhenMovingForward: boolean read FMoveUpWhenMovingForward
  87. write FMoveUpWhenMovingForward default False;
  88. property InvertHorizontalSteeringWhenUpsideDown: boolean
  89. read FInvertHorizontalSteeringWhenUpsideDown
  90. write FInvertHorizontalSteeringWhenUpsideDown default False;
  91. property VirtualUp: TGCoordinates read FVirtualUp write SetVirtualUp;
  92. property MovingObject: TGLBaseSceneObject read FObject write SetObject;
  93. property UseVirtualUp: boolean read FUseVirtualUp write SetUseVirtualUp
  94. default False;
  95. property AutoUpdateObject: boolean read FAutoUpdateObject
  96. write FAutoUpdateObject default False;
  97. property MaxAngle: single read FMaxAngle write FMaxAngle;
  98. property MinAngle: single read FMinAngle write FMinAngle;
  99. property AngleLock: boolean read FAngleLock write FAngleLock default False;
  100. end;
  101. (* TGLUserInterface is the component which reads the user input and transform it into action.
  102. The four calls to get you started is
  103. MouseLookActivate : set us up the bomb.
  104. MouseLookDeActivate : defuses it.
  105. Mouselook(deltaTime: double) : handles mouse look... Should be called in the Cadencer event. (Though it works every where!)
  106. MouseUpdate : Resets mouse position so that you don't notice that the mouse is limited to the screen should be called after Mouselook.
  107. The four properties to get you started are:
  108. InvertMouse : Inverts the mouse Y axis.
  109. MouseSpeed : Also known as mouse sensitivity.
  110. GLNavigator : The Navigator which receives the user movement.
  111. GLVertNavigator : The Navigator which if set receives the vertical user movement. Used mostly for cameras.... *)
  112. TGLUserInterface = class(TComponent)
  113. private
  114. FPrevPoint: TPoint;
  115. midScreenX, midScreenY: integer;
  116. FMouseActive: boolean;
  117. FMouseSpeed: single;
  118. FGLNavigator: TGLNavigator;
  119. FGLVertNavigator: TGLNavigator;
  120. FInvertMouse: boolean;
  121. procedure MouseInitialize;
  122. procedure SetMouseLookActive(const val: boolean);
  123. procedure setNavigator(val: TGLNavigator);
  124. procedure setVertNavigator(val: TGLNavigator);
  125. protected
  126. procedure Notification(AComponent: TComponent;
  127. Operation: TOperation); override;
  128. public
  129. constructor Create(AOwner: TComponent); override;
  130. destructor Destroy; override;
  131. procedure MouseUpdate;
  132. function MouseLook: boolean;
  133. procedure MouseLookActiveToggle;
  134. procedure MouseLookActivate;
  135. procedure MouseLookDeactivate;
  136. function IsMouseLookOn: boolean;
  137. procedure TurnHorizontal(Angle: Double);
  138. procedure TurnVertical(Angle: Double);
  139. property MouseLookActive: boolean read FMouseActive
  140. write SetMouseLookActive;
  141. published
  142. property InvertMouse: boolean read FInvertMouse write FInvertMouse
  143. default False;
  144. property MouseSpeed: single read FMouseSpeed write FMouseSpeed;
  145. property GLNavigator: TGLNavigator read FGLNavigator write setNavigator;
  146. property GLVertNavigator: TGLNavigator read FGLVertNavigator
  147. write setVertNavigator;
  148. end;
  149. TGLNaviCube = class(TGLBaseSceneObject)
  150. private
  151. FDelta, FFps, FTimer, FInactiveTime: single;
  152. FCube: TGLDummyCube;
  153. FSel: integer;
  154. FSelPos: TGLVector;
  155. FCam, FNaviCam: TGLCamera;
  156. FHud: TGLHUDSprite;
  157. FMem: TGLMemoryViewer;
  158. FViewer: TGLSceneViewer;
  159. FReady, FMouse: boolean;
  160. FMouseRotation: boolean;
  161. FMousePos: TPoint;
  162. FPosAnimationStart: TGLVector;
  163. FPosAnimationEnd: TGLVector;
  164. public
  165. constructor CreateAsChild(aParentOwner: TGLBaseSceneObject); reintroduce;
  166. procedure DoProgress(const pt: TGProgressTimes); override;
  167. procedure DoRender(var ARci: TGLRenderContextInfo;
  168. ARenderSelf, ARenderChildren: boolean); override;
  169. property SceneViewer: TGLSceneViewer read FViewer write FViewer;
  170. property Camera: TGLCamera read FCam write FCam;
  171. property FPS: single read FFps write FFps;
  172. property ActiveMouse: boolean read FMouse write FMouse;
  173. property InactiveTime: single read FInactiveTime write FInactiveTime;
  174. end;
  175. var
  176. sW2, sH2: integer;
  177. // -------------------------------------------------------------
  178. implementation
  179. // -------------------------------------------------------------
  180. constructor TGLNavigator.Create(AOwner: TComponent);
  181. begin
  182. inherited;
  183. FVirtualUp := TGCoordinates.CreateInitialized(Self, ZHmgVector, csPoint);
  184. FCurrentVAngle := 0;
  185. FCurrentHAngle := 0;
  186. end;
  187. destructor TGLNavigator.Destroy;
  188. begin
  189. FVirtualUp.Free;
  190. inherited;
  191. end;
  192. procedure TGLNavigator.SetObject(NewObject: TGLBaseSceneObject);
  193. begin
  194. If FObject <> NewObject then
  195. begin
  196. If Assigned(FObject) then
  197. FObject.RemoveFreeNotification(Self);
  198. FObject := NewObject;
  199. If Assigned(FObject) then
  200. begin
  201. if csdesigning in componentstate then
  202. begin
  203. If VectorLength(FVirtualUp.AsVector) = 0 then
  204. begin
  205. FVirtualUp.AsVector := FObject.Up.AsVector;
  206. end;
  207. Exit;
  208. end;
  209. If FUseVirtualUp Then
  210. FVirtualRight := CalcRight;
  211. FObject.FreeNotification(Self);
  212. end;
  213. end;
  214. end;
  215. procedure TGLNavigator.Notification(AComponent: TComponent;
  216. Operation: TOperation);
  217. begin
  218. If Operation = opRemove then
  219. If AComponent = FObject then
  220. MovingObject := Nil;
  221. inherited;
  222. end;
  223. Function TGLNavigator.CalcRight: TGLVector;
  224. begin
  225. If Assigned(FObject) then
  226. If FUseVirtualUp Then
  227. begin
  228. VectorCrossProduct(FObject.Direction.AsVector,
  229. FVirtualUp.AsVector, Result);
  230. ScaleVector(Result, 1 / VectorLength(Result));
  231. End
  232. else
  233. VectorCrossProduct(FObject.Direction.AsVector, FObject.Up.AsVector,
  234. Result); { automaticly length(1), if not this is a bug }
  235. end;
  236. procedure TGLNavigator.TurnHorizontal(Angle: single);
  237. Var
  238. T: TGLVector;
  239. U: TAffineVector;
  240. TempVal: single;
  241. begin
  242. If InvertHorizontalSteeringWhenUpsideDown and
  243. ((CurrentVAngle < -90) or (CurrentVAngle > 90)) then
  244. Angle := -Angle;
  245. FCurrentHAngle := (FCurrentHAngle - Angle);
  246. If (FCurrentHAngle < 0) or (FCurrentHAngle > 360) then
  247. begin
  248. TempVal := (FCurrentHAngle) / 360;
  249. FCurrentHAngle := (TempVal - Floor(TempVal)) * 360;
  250. end;
  251. Angle := DegToRadian(Angle); { make it ready for Cos and Sin }
  252. If FUseVirtualUp Then
  253. begin
  254. SetVector(U, VirtualUp.AsVector);
  255. T := FObject.Up.AsVector;
  256. RotateVector(T, U, Angle);
  257. FObject.Up.AsVector := T;
  258. T := FObject.Direction.AsVector;
  259. RotateVector(T, U, Angle);
  260. FObject.Direction.AsVector := T;
  261. End
  262. else
  263. FObject.Direction.AsVector := VectorCombine(FObject.Direction.AsVector,
  264. CalcRight, Cos(Angle), Sin(Angle));
  265. end;
  266. procedure TGLNavigator.TurnVertical(Angle: single);
  267. Var
  268. ExpectedAngle: single;
  269. CosAngle, SinAngle: single;
  270. TempVal: single;
  271. Direction: TGLVector;
  272. begin
  273. ExpectedAngle := FCurrentVAngle + Angle;
  274. If FAngleLock then
  275. begin
  276. If ExpectedAngle > FMaxAngle then
  277. begin
  278. If FCurrentVAngle = FMaxAngle then
  279. Exit;
  280. Angle := FMaxAngle - FCurrentVAngle;
  281. ExpectedAngle := FMaxAngle;
  282. End
  283. else
  284. begin
  285. If ExpectedAngle < FMinAngle then
  286. begin
  287. If FCurrentVAngle = FMinAngle then
  288. Exit;
  289. Angle := FMinAngle - FCurrentVAngle;
  290. ExpectedAngle := FMinAngle;
  291. end;
  292. end;
  293. end;
  294. FCurrentVAngle := ExpectedAngle;
  295. If (FCurrentVAngle < -180) or (FCurrentVAngle > 180) then
  296. begin
  297. TempVal := (FCurrentVAngle + 180) / 360;
  298. FCurrentVAngle := (TempVal - Floor(TempVal)) * 360 - 180;
  299. end;
  300. Angle := DegToRadian(Angle); { make it ready for Cos and Sin }
  301. SinCosine(Angle, SinAngle, CosAngle);
  302. Direction := VectorCombine(MovingObject.Direction.AsVector,
  303. MovingObject.Up.AsVector, CosAngle, SinAngle);
  304. MovingObject.Up.AsVector := VectorCombine(MovingObject.Direction.AsVector,
  305. MovingObject.Up.AsVector, SinAngle, CosAngle);
  306. MovingObject.Direction.AsVector := Direction;
  307. end;
  308. procedure TGLNavigator.MoveForward(Distance: single);
  309. begin
  310. If (FUseVirtualUp and (not MoveUpWhenMovingForward)) Then
  311. begin
  312. FObject.Position.AsVector := VectorCombine(FObject.Position.AsVector,
  313. VectorCrossProduct(FVirtualUp.AsVector, CalcRight), 1, Distance);
  314. End
  315. else
  316. FObject.Position.AsVector := VectorCombine(FObject.Position.AsVector,
  317. FObject.Direction.AsVector, 1, Distance);
  318. end;
  319. procedure TGLNavigator.StrafeHorizontal(Distance: single);
  320. begin
  321. FObject.Position.AsVector := VectorCombine(FObject.Position.AsVector,
  322. CalcRight, 1, Distance);
  323. end;
  324. procedure TGLNavigator.StrafeVertical(Distance: single);
  325. begin
  326. If UseVirtualUp Then
  327. begin
  328. FObject.Position.AsVector := VectorCombine(FObject.Position.AsVector,
  329. FVirtualUp.AsVector, 1, Distance);
  330. End
  331. else
  332. FObject.Position.AsVector := VectorCombine(FObject.Position.AsVector,
  333. FObject.Up.AsVector, 1, Distance);
  334. end;
  335. procedure TGLNavigator.FlyForward(Distance: single);
  336. begin
  337. FObject.Position.AsVector := VectorCombine(FObject.Position.AsVector,
  338. FObject.Direction.AsVector, 1, Distance);
  339. end;
  340. procedure TGLNavigator.Straighten;
  341. Var
  342. R: TGLVector;
  343. D: TGLVector;
  344. A: single;
  345. begin
  346. FCurrentVAngle := 0;
  347. FCurrentHAngle := 0;
  348. R := CalcRight;
  349. A := VectorAngleCosine(AffineVectorMake(MovingObject.Up.AsVector),
  350. AffineVectorMake(VirtualUp.AsVector));
  351. MovingObject.Up.AsVector := VirtualUp.AsVector;
  352. VectorCrossProduct(R, FVirtualUp.AsVector, D);
  353. If A >= 0 then
  354. ScaleVector(D, -1 / VectorLength(D))
  355. else
  356. ScaleVector(D, 1 / VectorLength(D));
  357. MovingObject.Direction.AsVector := D;
  358. end;
  359. procedure TGLNavigator.SetUseVirtualUp(UseIt: boolean);
  360. begin
  361. FUseVirtualUp := UseIt;
  362. if csdesigning in componentstate then
  363. Exit;
  364. If FUseVirtualUp then
  365. FVirtualRight := CalcRight;
  366. end;
  367. procedure TGLNavigator.SetVirtualUp(Up: TGCoordinates);
  368. begin
  369. FVirtualUp.Assign(Up);
  370. if csdesigning in componentstate then
  371. Exit;
  372. If FUseVirtualUp then
  373. FVirtualRight := CalcRight;
  374. end;
  375. procedure TGLNavigator.LoadState(Stream: TStream);
  376. Var
  377. Vector: TAffineVector;
  378. B: ByteBool;
  379. S: single;
  380. begin
  381. Stream.Read(Vector, SizeOf(TAffineVector));
  382. FObject.Position.AsAffineVector := Vector;
  383. Stream.Read(Vector, SizeOf(TAffineVector));
  384. FObject.Direction.AsAffineVector := Vector;
  385. Stream.Read(Vector, SizeOf(TAffineVector));
  386. FObject.Up.AsAffineVector := Vector;
  387. Stream.Read(B, SizeOf(ByteBool));
  388. UseVirtualUp := B;
  389. Stream.Read(B, SizeOf(ByteBool));
  390. FAngleLock := B;
  391. Stream.Read(S, SizeOf(single));
  392. FMaxAngle := S;
  393. Stream.Read(S, SizeOf(single));
  394. FMinAngle := S;
  395. Stream.Read(S, SizeOf(single));
  396. FCurrentVAngle := S;
  397. Stream.Read(S, SizeOf(single));
  398. FCurrentHAngle := S;
  399. end;
  400. procedure TGLNavigator.SaveState(Stream: TStream);
  401. Var
  402. Vector: TAffineVector;
  403. B: ByteBool;
  404. S: single;
  405. begin
  406. Vector := FObject.Position.AsAffineVector;
  407. Stream.Write(Vector, SizeOf(TAffineVector));
  408. Vector := FObject.Direction.AsAffineVector;
  409. Stream.Write(Vector, SizeOf(TAffineVector));
  410. Vector := FObject.Up.AsAffineVector;
  411. Stream.Write(Vector, SizeOf(TAffineVector));
  412. B := UseVirtualUp;
  413. Stream.Write(B, SizeOf(ByteBool));
  414. B := FAngleLock;
  415. Stream.Write(B, SizeOf(ByteBool));
  416. S := FMaxAngle;
  417. Stream.Write(S, SizeOf(single));
  418. S := FMinAngle;
  419. Stream.Write(S, SizeOf(single));
  420. S := FCurrentVAngle;
  421. Stream.Write(S, SizeOf(single));
  422. S := FCurrentHAngle;
  423. Stream.Write(S, SizeOf(single));
  424. end;
  425. function TGLUserInterface.IsMouseLookOn: boolean;
  426. begin
  427. Result := FMouseActive;
  428. end;
  429. procedure TGLUserInterface.TurnHorizontal(Angle: Double);
  430. begin
  431. GLNavigator.TurnHorizontal(Angle);
  432. end;
  433. procedure TGLUserInterface.TurnVertical(Angle: Double);
  434. begin
  435. If Assigned(GLVertNavigator) then
  436. GLVertNavigator.TurnVertical(Angle)
  437. else
  438. GLNavigator.TurnVertical(Angle);
  439. end;
  440. procedure TGLUserInterface.MouseLookActiveToggle;
  441. begin
  442. if FMouseActive then
  443. MouseLookDeactivate
  444. else
  445. MouseLookActivate;
  446. end;
  447. procedure TGLUserInterface.MouseLookActivate;
  448. begin
  449. if not FMouseActive then
  450. begin
  451. FMouseActive := True;
  452. MouseInitialize;
  453. GLShowCursor(False);
  454. end;
  455. end;
  456. procedure TGLUserInterface.MouseLookDeactivate;
  457. begin
  458. if FMouseActive then
  459. begin
  460. FMouseActive := False;
  461. GLShowCursor(True);
  462. end;
  463. end;
  464. procedure TGLUserInterface.MouseInitialize;
  465. begin
  466. midScreenX := GLGetScreenWidth div 2;
  467. midScreenY := GLGetScreenHeight div 2;
  468. FPrevPoint.x := midScreenX;
  469. FPrevPoint.Y := midScreenY;
  470. GLSetCursorPos(midScreenX, midScreenY);
  471. end;
  472. procedure TGLUserInterface.SetMouseLookActive(const val: boolean);
  473. begin
  474. if val <> FMouseActive then
  475. if val then
  476. MouseLookActivate
  477. else
  478. MouseLookDeactivate;
  479. end;
  480. procedure TGLUserInterface.MouseUpdate;
  481. begin
  482. if FMouseActive then
  483. GLGetCursorPos(FPrevPoint);
  484. end;
  485. function TGLUserInterface.MouseLook: boolean;
  486. var
  487. deltaX, deltaY: single;
  488. begin
  489. Result := False;
  490. if not FMouseActive then
  491. Exit;
  492. deltaX := (FPrevPoint.x - midScreenX) * MouseSpeed;
  493. deltaY := -(FPrevPoint.Y - midScreenY) * MouseSpeed;
  494. If InvertMouse then
  495. deltaY := -deltaY;
  496. if deltaX <> 0 then
  497. begin
  498. TurnHorizontal(deltaX * 0.01);
  499. Result := True;
  500. end;
  501. if deltaY <> 0 then
  502. begin
  503. TurnVertical(deltaY * 0.01);
  504. Result := True;
  505. end;
  506. if (FPrevPoint.x <> midScreenX) or (FPrevPoint.Y <> midScreenY) then
  507. GLSetCursorPos(midScreenX, midScreenY);
  508. end;
  509. constructor TGLUserInterface.Create(AOwner: TComponent);
  510. begin
  511. inherited;
  512. FMouseSpeed := 0;
  513. FMouseActive := False;
  514. midScreenX := GLGetScreenWidth div 2;
  515. midScreenY := GLGetScreenHeight div 2;
  516. FPrevPoint.x := midScreenX;
  517. FPrevPoint.Y := midScreenY;
  518. end;
  519. destructor TGLUserInterface.Destroy;
  520. begin
  521. if FMouseActive then
  522. MouseLookDeactivate; // added by JAJ
  523. inherited;
  524. end;
  525. procedure TGLUserInterface.Notification(AComponent: TComponent;
  526. Operation: TOperation);
  527. begin
  528. if Operation = opRemove then
  529. begin
  530. if AComponent = FGLNavigator then
  531. setNavigator(nil);
  532. if AComponent = FGLVertNavigator then
  533. setVertNavigator(nil);
  534. end;
  535. inherited;
  536. end;
  537. procedure TGLUserInterface.setNavigator(val: TGLNavigator);
  538. begin
  539. if Assigned(FGLNavigator) then
  540. FGLNavigator.RemoveFreeNotification(Self);
  541. FGLNavigator := val;
  542. if Assigned(val) then
  543. val.FreeNotification(Self);
  544. end;
  545. procedure TGLUserInterface.setVertNavigator(val: TGLNavigator);
  546. begin
  547. if Assigned(FGLVertNavigator) then
  548. FGLVertNavigator.RemoveFreeNotification(Self);
  549. FGLVertNavigator := val;
  550. if Assigned(val) then
  551. val.FreeNotification(Self);
  552. end;
  553. constructor TGLNaviCube.CreateAsChild(aParentOwner: TGLBaseSceneObject);
  554. procedure genTex(S: string; mat: TGLMaterial);
  555. var
  556. bmp: TBitmap;
  557. begin
  558. bmp := TBitmap.Create;
  559. bmp.Width := 64;
  560. bmp.Height := 64;
  561. with bmp.Canvas do
  562. begin
  563. Font.Name := 'Verdana';
  564. Font.Size := 10;
  565. TextOut(32 - TextWidth(S) div 2, 24, S);
  566. end;
  567. mat.FrontProperties.Diffuse.SetColor(1, 1, 1);
  568. mat.Texture.Image.Assign(bmp);
  569. mat.Texture.Disabled := False;
  570. mat.Texture.FilteringQuality := tfAnisotropic;
  571. mat.Texture.TextureMode := tmModulate;
  572. bmp.Free;
  573. end;
  574. procedure SetColor(m: TGLMaterial; c: single);
  575. begin
  576. m.FrontProperties.Diffuse.SetColor(c, c, 1);
  577. end;
  578. procedure addPlane(T: integer; ttl: string; c, x, Y, z, dx, dy, dz: single);
  579. begin
  580. with TGLPlane.CreateAsChild(FCube) do
  581. begin
  582. tag := T;
  583. tagfloat := c;
  584. Position.SetPoint(x, Y, z);
  585. Direction.SetVector(dx, dy, dz);
  586. genTex(ttl, Material);
  587. end;
  588. end;
  589. procedure addCube(T: integer; c, x, Y, z, sx, sy, sz: single);
  590. begin
  591. with TGLCube.CreateAsChild(FCube) do
  592. begin
  593. tag := T;
  594. tagfloat := c;
  595. Position.SetPoint(x, Y, z);
  596. Scale.SetVector(sx, sy, sz);
  597. SetColor(Material, c);
  598. end;
  599. end;
  600. begin
  601. inherited CreateAsChild(aParentOwner);
  602. FDelta := 2;
  603. FFps := 30;
  604. FTimer := 10;
  605. FMouse := True;
  606. FInactiveTime := 0;
  607. FHud := TGLHUDSprite.CreateAsChild(Self);
  608. FHud.Width := 128;
  609. FHud.Height := 128;
  610. FHud.Material.BlendingMode := bmTransparency;
  611. with FHud.Material.Texture do
  612. begin
  613. Disabled := False;
  614. ImageClassName := 'TGLBlankImage';
  615. MinFilter := miNearest;
  616. TGLBlankImage(Image).Width := 128;
  617. TGLBlankImage(Image).Height := 128;
  618. TextureMode := tmReplace;
  619. end;
  620. FHud.Position.SetPoint(-200, 50, 0);
  621. FNaviCam := TGLCamera.CreateAsChild(aParentOwner);
  622. FNaviCam.FocalLength := 55;
  623. FNaviCam.TargetObject := Self;
  624. FMem := TGLMemoryViewer.Create(aParentOwner);
  625. FMem.Width := 128;
  626. FMem.Height := 128;
  627. FMem.Camera := FNaviCam;
  628. with FMem.Buffer do
  629. begin
  630. BackgroundAlpha := 0;
  631. Antialiasing := aa6x;
  632. ContextOptions := [roDestinationAlpha];
  633. Lighting := False;
  634. end;
  635. FCube := TGLDummyCube.CreateAsChild(Self);
  636. FCube.Visible := False;
  637. with TGLDisk.CreateAsChild(FCube) do
  638. begin
  639. Position.SetPoint(0, -0.805, 0);
  640. Direction.SetVector(0, 1, 0);
  641. InnerRadius := 0.9;
  642. OuterRadius := 1.3;
  643. Slices := 60;
  644. Loops := 1;
  645. SetColor(Material, 0.6);
  646. end;
  647. with TGLDisk.CreateAsChild(FCube) do
  648. begin
  649. Position.SetPoint(0, -0.8, 0);
  650. Direction.SetVector(0, 1, 0);
  651. InnerRadius := 0.95;
  652. OuterRadius := 1.25;
  653. Slices := 60;
  654. Loops := 1;
  655. SetColor(Material, 1);
  656. end;
  657. addPlane(0, 'FRONT', 1, 0, 0, 0.7, 0, 0, 1);
  658. addPlane(1, 'RIGHT', 1, 0.7, 0, 0, 1, 0, 0);
  659. addPlane(2, 'LEFT', 1, -0.7, 0, 0, -1, 0, 0);
  660. addPlane(3, 'BACK', 1, 0, 0, -0.7, 0, 0, -1);
  661. addPlane(4, 'TOP', 1, 0, 0.7, 0, 0, 1, 0);
  662. addPlane(5, 'BOTTOM', 1, 0, -0.7, 0, 0, -1, 0);
  663. addCube(6, 0.9, 0, 0.6, 0.6, 1, 0.2, 0.2);
  664. addCube(7, 0.9, 0, 0.6, -0.6, 1, 0.2, 0.2);
  665. addCube(8, 0.9, 0, -0.6, 0.6, 1, 0.2, 0.2);
  666. addCube(9, 0.9, 0, -0.6, -0.6, 1, 0.2, 0.2);
  667. addCube(10, 0.9, 0.6, 0.6, 0, 0.2, 0.2, 1);
  668. addCube(11, 0.9, 0.6, -0.6, 0, 0.2, 0.2, 1);
  669. addCube(12, 0.9, -0.6, 0.6, 0, 0.2, 0.2, 1);
  670. addCube(13, 0.9, -0.6, -0.6, 0, 0.2, 0.2, 1);
  671. addCube(14, 0.9, 0.6, 0, 0.6, 0.2, 1, 0.2);
  672. addCube(15, 0.9, 0.6, 0, -0.6, 0.2, 1, 0.2);
  673. addCube(16, 0.9, -0.6, 0, 0.6, 0.2, 1, 0.2);
  674. addCube(17, 0.9, -0.6, 0, -0.6, 0.2, 1, 0.2);
  675. addCube(18, 0.8, 0.6, 0.6, 0.6, 0.2, 0.2, 0.2);
  676. addCube(19, 0.8, 0.6, 0.6, -0.6, 0.2, 0.2, 0.2);
  677. addCube(20, 0.8, 0.6, -0.6, 0.6, 0.2, 0.2, 0.2);
  678. addCube(21, 0.8, -0.6, 0.6, 0.6, 0.2, 0.2, 0.2);
  679. addCube(22, 0.8, 0.6, -0.6, -0.6, 0.2, 0.2, 0.2);
  680. addCube(23, 0.8, -0.6, -0.6, 0.6, 0.2, 0.2, 0.2);
  681. addCube(24, 0.8, -0.6, 0.6, -0.6, 0.2, 0.2, 0.2);
  682. addCube(25, 0.8, -0.6, -0.6, -0.6, 0.2, 0.2, 0.2);
  683. end;
  684. procedure TGLNaviCube.DoProgress(const pt: TGProgressTimes);
  685. const
  686. tb: array [0 .. 1] of array [0 .. 3] of TGLVector = (((x: 0; Y: 20; z: 1;
  687. W: 0), (x: 1; Y: 20; z: 0; W: 0), (x: 0; Y: 20; z: - 1; W: 0), (x: - 1;
  688. Y: 20; z: 0; W: 0)), ((x: 0; Y: - 20; z: 1; W: 0), (x: 1; Y: - 20; z: 0;
  689. W: 0), (x: 0; Y: - 20; z: - 1; W: 0), (x: - 1; Y: - 20; z: 0; W: 0)));
  690. var
  691. mp: TPoint;
  692. mover: boolean;
  693. i: integer;
  694. v0, v1, v2, v: TGLVector;
  695. obj: TGLBaseSceneObject;
  696. procedure moveTo(trgv: TGLVector);
  697. begin
  698. FPosAnimationStart := FCam.Position.AsVector;
  699. FPosAnimationEnd := FCam.TargetObject.AbsoluteToLocal
  700. (VectorScale(VectorNormalize(trgv), FCam.DistanceToTarget));
  701. FDelta := 0;
  702. end;
  703. begin
  704. mp := FViewer.ScreenToClient(Mouse.CursorPos);
  705. mover := (mp.x > FHud.Position.x - 64) and (mp.x < FHud.Position.x + 64) and
  706. (mp.Y > FHud.Position.Y - 64) and (mp.Y < FHud.Position.Y + 64);
  707. // mouse Down/Up
  708. if FDelta > 1 then
  709. begin
  710. if IsKeyDown(VK_LBUTTON) and (not FMouseRotation) then
  711. begin
  712. // selection > start auto rotation
  713. if mover and (FSel >= 0) then
  714. begin
  715. v := FCam.AbsoluteVectorToTarget;
  716. v.Y := 0;
  717. if v.x < 0 then
  718. i := -1
  719. else
  720. i := 1;
  721. i := round((ArcCosine(VectorAngleCosine(v, ZHmgPoint)) * i + PI) / PI
  722. * 2) mod 4;
  723. if (FSel = 4) or (FSel = 5) then
  724. moveTo(tb[FSel - 4][i])
  725. else
  726. moveTo(FSelPos);
  727. FInactiveTime := 0;
  728. end // start manual rotation
  729. else if FMouse then
  730. begin
  731. FMouseRotation := True;
  732. FMousePos := Mouse.CursorPos;
  733. ShowCursor(False);
  734. Mouse.CursorPos := point(sW2, sH2);
  735. FInactiveTime := 0;
  736. end;
  737. end;
  738. // stop rotation, restore cursor
  739. if (not IsKeyDown(VK_LBUTTON)) and FMouseRotation and FMouse then
  740. begin
  741. ShowCursor(True);
  742. FMouseRotation := False;
  743. Mouse.CursorPos := FMousePos;
  744. FInactiveTime := 0;
  745. end;
  746. end
  747. // auto rotation progress
  748. else
  749. begin
  750. FDelta := FDelta + pt.deltaTime * 2;
  751. v := VectorLerp(FPosAnimationStart, FPosAnimationEnd,
  752. FDelta * FDelta * (3 - 2 * FDelta));
  753. v := VectorScale(VectorNormalize(v), VectorLength(FPosAnimationStart));
  754. if FDelta < 1 then
  755. FCam.Position.SetPoint(v)
  756. else
  757. FCam.Position.SetPoint(FPosAnimationEnd);
  758. v := VectorScale(VectorNormalize(v), 10);
  759. if FDelta < 1 then
  760. v := VectorScale(VectorNormalize(v), 10)
  761. else
  762. v := VectorScale(VectorNormalize(FPosAnimationEnd), 10);
  763. FNaviCam.Position.SetPoint(v);
  764. for i := 2 to FCube.Count - 1 do
  765. with TGLSceneObject(FCube.Children[i]) do
  766. Material.FrontProperties.Diffuse.SetColor(tagfloat, tagfloat, 1);
  767. FInactiveTime := 0;
  768. end;
  769. FSel := -1;
  770. // manual rotation progress
  771. if FMouseRotation and FMouse then
  772. begin
  773. mp := Mouse.CursorPos;
  774. if FCam <> nil then
  775. FCam.MoveAroundTarget((sH2 - mp.Y) * 0.2, (sW2 - mp.x) * 0.2);
  776. FNaviCam.MoveAroundTarget((sH2 - mp.Y) * 0.2, (sW2 - mp.x) * 0.2);
  777. Mouse.CursorPos := point(sW2, sH2);
  778. FInactiveTime := 0;
  779. end
  780. else if FReady then
  781. begin
  782. // selection
  783. if mover and (FDelta > 1) then
  784. begin
  785. v0 := FNaviCam.AbsolutePosition;
  786. v1 := FMem.Buffer.ScreenToVector(mp.x - round(FHud.Position.x) + 64,
  787. round(FHud.Position.Y) - mp.Y + 64);
  788. SetVector(v2, 99999, 99999, 99999);
  789. obj := nil;
  790. for i := 2 to FCube.Count - 1 do
  791. with TGLSceneObject(FCube.Children[i]) do
  792. begin
  793. Material.FrontProperties.Diffuse.SetColor(tagfloat, tagfloat, 1);
  794. if RayCastIntersect(v0, v1, @v) then
  795. if VectorDistance2(v2, v0) > VectorDistance2(v, v0) then
  796. begin
  797. SetVector(v2, v);
  798. FSel := FCube.Children[i].tag;
  799. FSelPos := FCube.Children[i].Position.AsVector;
  800. obj := FCube.Children[i];
  801. end;
  802. end;
  803. if FSel >= 0 then
  804. begin
  805. FViewer.cursor := -21;
  806. TGLSceneObject(obj).Material.FrontProperties.Diffuse.SetColor
  807. (1, 0.6, 0);
  808. end
  809. else
  810. FViewer.cursor := 0;
  811. end;
  812. v := VectorScale(VectorNormalize(FCam.AbsoluteVectorToTarget), 10);
  813. FNaviCam.Position.SetPoint(VectorNegate(v));
  814. FInactiveTime := FInactiveTime + pt.deltaTime;
  815. end;
  816. // rendering
  817. FTimer := FTimer + pt.deltaTime;
  818. if FTimer > 1 / FFps then
  819. begin
  820. FTimer := FTimer - Floor(FTimer * FFps) / FFps;
  821. FMem.Render(FCube);
  822. FMem.CopyToTexture(FHud.Material.Texture);
  823. FReady := True;
  824. end;
  825. end;
  826. procedure TGLNaviCube.DoRender(var ARci: TGLRenderContextInfo;
  827. ARenderSelf, ARenderChildren: boolean);
  828. begin
  829. inherited;
  830. if (FCam = nil) and (Scene.CurrentGLCamera <> nil) then
  831. begin
  832. FCam := Scene.CurrentGLCamera;
  833. FNaviCam.Position.SetPoint
  834. (VectorScale(VectorNormalize(FCam.Position.AsVector), 10));
  835. end;
  836. if FViewer <> nil then
  837. FHud.Position.SetPoint(FViewer.Width - 80, 50, 0);
  838. end;
  839. // ------------------------------------------------
  840. initialization
  841. // ------------------------------------------------
  842. sW2 := Screen.Width div 2;
  843. sH2 := Screen.Height div 2;
  844. end.