fBoxedinD.pas 4.8 KB

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