GLNavigator.pas 27 KB

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