fBoxedinD.pas 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. unit fBoxedinD;
  2. interface
  3. uses
  4. Winapi.Windows,
  5. Winapi.OpenGL,
  6. System.SysUtils,
  7. System.Classes,
  8. Vcl.Controls,
  9. Vcl.Forms,
  10. Vcl.ExtCtrls,
  11. Vcl.StdCtrls,
  12. Vcl.ComCtrls,
  13. GLS.Keyboard,
  14. GLS.VectorGeometry,
  15. GLS.Scene,
  16. GLS.VectorFileObjects,
  17. GLS.VectorTypes,
  18. GLS.Objects,
  19. GLS.SceneViewer,
  20. GLS.Cadencer,
  21. GLS.Navigator,
  22. GLS.GeomObjects,
  23. GLS.Coordinates,
  24. GLS.Utils,
  25. GLS.BaseClasses,
  26. GLS.File3DS;
  27. type
  28. TFormBoxedin = class(TForm)
  29. GLScene1: TGLScene;
  30. LightSource1: TGLLightSource;
  31. DummyCube1: TGLDummyCube;
  32. FreeForm1: TGLFreeForm;
  33. Sphere1: TGLSphere;
  34. ArrowLine1: TGLArrowLine;
  35. GLSceneViewer2: TGLSceneViewer;
  36. Camera: TGLCamera;
  37. GLCadencer1: TGLCadencer;
  38. Timer1: TTimer;
  39. DummyCube2: TGLDummyCube;
  40. Sphere2: TGLSphere;
  41. LightSource2: TGLLightSource;
  42. Panel1: TPanel;
  43. Label1: TLabel;
  44. Label2: TLabel;
  45. Label3: TLabel;
  46. Label4: TLabel;
  47. TrackBar1: TTrackBar;
  48. Button1: TButton;
  49. Lines1: TGLLines;
  50. LabelFPS: TLabel;
  51. procedure FormCreate(Sender: TObject);
  52. procedure GLCadencer1Progress(Sender: TObject;
  53. const deltaTime, newTime: Double);
  54. procedure Timer1Timer(Sender: TObject);
  55. procedure Button1Click(Sender: TObject);
  56. private
  57. colTotalTime: Single; // for timing collision detection
  58. colCount: Integer;
  59. procedure AddToTrail(const p: TGLVector);
  60. public
  61. mousex, mousey: Integer;
  62. end;
  63. var
  64. FormBoxedin: TFormBoxedin;
  65. implementation
  66. {$R *.dfm}
  67. procedure TFormBoxedin.FormCreate(Sender: TObject);
  68. begin
  69. var Path: TFileName := GetCurrentAssetPath();
  70. SetCurrentDir(Path + '\model');
  71. FreeForm1.LoadFromFile('BoxedIn.3ds');
  72. FreeForm1.BuildOctree;
  73. Label1.Caption := 'Octree Nodes : ' + inttostr(FreeForm1.Octree.NodeCount);
  74. Label2.Caption := 'Tri Count Octree: ' +
  75. inttostr(FreeForm1.Octree.TriCountOctree);
  76. Label3.Caption := 'Tri Count Mesh : ' +
  77. inttostr(FreeForm1.Octree.TriCountMesh);
  78. Lines1.AddNode(0, 0, 0);
  79. Lines1.ObjectStyle := Lines1.ObjectStyle + [osDirectDraw];
  80. end;
  81. procedure TFormBoxedin.GLCadencer1Progress(Sender: TObject;
  82. const deltaTime, newTime: Double);
  83. var
  84. rayStart, rayVector: TGLVector;
  85. velocity: Single;
  86. pPoint: TGLVector;
  87. pNormal: TGLVector;
  88. t: Int64;
  89. begin
  90. if IsKeyDown(VK_ESCAPE) then
  91. close;
  92. velocity := TrackBar1.Position * deltaTime * 50;
  93. t := StartPrecisionTimer;
  94. with FreeForm1 do
  95. begin
  96. SetVector(rayStart, Sphere2.AbsolutePosition);
  97. SetVector(rayVector, Sphere2.AbsoluteDirection);
  98. NormalizeVector(rayVector);
  99. // Note: since collision may be performed on multiple meshes, we might need to know which hit
  100. // is closest (ie: d:=raystart - pPoint).
  101. if OctreeSphereSweepIntersect(rayStart, rayVector, velocity, Sphere2.Radius,
  102. @pPoint, @pNormal) then
  103. begin
  104. // Show the polygon intersection point
  105. NormalizeVector(pNormal);
  106. Sphere1.Position.AsVector := pPoint;
  107. Sphere1.Direction.AsVector := pNormal;
  108. // Make it rebound...
  109. with Sphere2.Direction do
  110. AsAffineVector := VectorReflect(AsAffineVector,
  111. AffineVectorMake(pNormal));
  112. // Add some "english"...
  113. with Sphere2.Direction do
  114. begin
  115. X := X + random / 10;
  116. Y := Y + random / 10;
  117. Z := Z + random / 10;
  118. end;
  119. // Add intersect point to trail
  120. AddToTrail(pPoint);
  121. end
  122. else
  123. begin
  124. Sphere2.Move(velocity); // No collision, so just move the ball.
  125. end;
  126. end;
  127. // Last trail point is always the sphere's current position
  128. Lines1.Nodes.Last.AsVector := Sphere2.Position.AsVector;
  129. colTotalTime := colTotalTime + StopPrecisionTimer(t);
  130. Inc(colCount);
  131. end;
  132. procedure TFormBoxedin.AddToTrail(const p: TGLVector);
  133. var
  134. i, k: Integer;
  135. begin
  136. Lines1.Nodes.Last.AsVector := p;
  137. Lines1.AddNode(0, 0, 0);
  138. if Lines1.Nodes.Count > 5 then // limit trail to 20 points
  139. Lines1.Nodes[0].Free;
  140. for i := 0 to 4 do // count to 19
  141. begin
  142. k := Lines1.Nodes.Count - i - 1;
  143. if k >= 0 then
  144. TGLLinesNode(Lines1.Nodes[k]).Color.Alpha := 0.95 - i * 0.05;
  145. end;
  146. end;
  147. procedure TFormBoxedin.Timer1Timer(Sender: TObject);
  148. var
  149. t: Single;
  150. begin
  151. if colCount > 0 then
  152. t := colTotalTime * 1000 / colCount
  153. else
  154. t := 0;
  155. LabelFPS.Caption := Format('%.2f FPS - %.3f ms for collisions/frame',
  156. [GLSceneViewer2.FramesPerSecond, t]);
  157. GLSceneViewer2.ResetPerformanceMonitor;
  158. colTotalTime := 0;
  159. colCount := 0;
  160. end;
  161. procedure TFormBoxedin.Button1Click(Sender: TObject);
  162. begin
  163. // If the ball gets stuck in a pattern, hit the reset button.
  164. with Sphere2.Position do
  165. begin
  166. X := random;
  167. Y := random;
  168. Z := random;
  169. end;
  170. with Sphere2.Direction do
  171. begin
  172. X := random;
  173. if random > 0.5 then
  174. X := -X;
  175. Y := random;
  176. if random > 0.5 then
  177. Y := -Y;
  178. Z := random;
  179. if random > 0.5 then
  180. Z := -Z;
  181. end;
  182. end;
  183. end.