fOdeFurballD.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. unit fOdeFurballD;
  2. interface
  3. uses
  4. Winapi.Windows,
  5. System.SysUtils,
  6. System.Classes,
  7. System.Math,
  8. Vcl.Graphics,
  9. Vcl.Controls,
  10. Vcl.Forms,
  11. Vcl.Dialogs,
  12. Vcl.StdCtrls,
  13. Vcl.ExtCtrls,
  14. Vcl.ComCtrls,
  15. Vcl.Imaging.Jpeg,
  16. Stage.VectorTypes,
  17. Stage.Keyboard,
  18. Stage.VectorGeometry,
  19. GLS.SceneViewer,
  20. GLS.Scene,
  21. GLS.Objects,
  22. GLS.Cadencer,
  23. GLS.Texture,
  24. GLS.Extrusion,
  25. ODE.Import,
  26. GLS.ODEUtils,
  27. GLS.ShadowPlane,
  28. GLS.Navigator,
  29. GLS.VerletTypes,
  30. GLS.XCollection,
  31. GLS.Color,
  32. GLS.Coordinates,
  33. GLS.BaseClasses;
  34. const
  35. cMaxWindMag = 8;
  36. type
  37. TFormFurball = class(TForm)
  38. GLCadencer1: TGLCadencer;
  39. GLScene1: TGLScene;
  40. DC_LightHolder: TGLDummyCube;
  41. GLCamera1: TGLCamera;
  42. GLLightSource1: TGLLightSource;
  43. GLSceneViewer1: TGLSceneViewer;
  44. GLShadowPlane_Floor: TGLShadowPlane;
  45. GLShadowPlane_Wall: TGLShadowPlane;
  46. Sphere1: TGLSphere;
  47. DCShadowCaster: TGLDummyCube;
  48. FurBall: TGLSphere;
  49. GLShadowPlane_Floor2: TGLShadowPlane;
  50. GLLines1: TGLLines;
  51. GLShadowPlane_Wall2: TGLShadowPlane;
  52. GLShadowPlane_Wall3: TGLShadowPlane;
  53. Label_FPS: TLabel;
  54. Timer1: TTimer;
  55. Panel1: TPanel;
  56. CheckBox_LockBall: TCheckBox;
  57. CheckBox_Inertia: TCheckBox;
  58. CheckBox_FurGravity: TCheckBox;
  59. CheckBox_WindResistence: TCheckBox;
  60. TrackBar_WindForce: TTrackBar;
  61. CheckBox_Bald: TCheckBox;
  62. Label1: TLabel;
  63. CheckBox_Shadows: TCheckBox;
  64. procedure FormCreate(Sender: TObject);
  65. procedure FormClose(Sender: TObject; var Action: TCloseAction);
  66. procedure GLCadencer1Progress(Sender: TObject; const deltaTime,
  67. newTime: Double);
  68. procedure DC_LightHolderProgress(Sender: TObject; const deltaTime,
  69. newTime: Double);
  70. procedure GLSceneViewer1MouseMove(Sender: TObject; Shift: TShiftState;
  71. X, Y: Integer);
  72. procedure FormMouseWheel(Sender: TObject; Shift: TShiftState;
  73. WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
  74. procedure CheckBox_FurGravityClick(Sender: TObject);
  75. procedure CheckBox_WindResistenceClick(Sender: TObject);
  76. procedure CheckBox_BaldClick(Sender: TObject);
  77. procedure Timer1Timer(Sender: TObject);
  78. procedure CheckBox_ShadowsClick(Sender: TObject);
  79. procedure CheckBox_InertiaClick(Sender: TObject);
  80. procedure TrackBar_WindForceChange(Sender: TObject);
  81. public
  82. odeFurBallBody : PdxBody;
  83. odeFurBallGeom : PdxGeom;
  84. world : PdxWorld;
  85. space : PdxSpace;
  86. contactgroup : TdJointGroupID;
  87. VerletWorld : TGLVerletWorld;
  88. HairList : TList;
  89. VCSphere : TGLVerletFrictionSphere;
  90. PhysicsTime : single;
  91. Gravity : TGLVerletGravity;
  92. AirResistance : TGLVerletAirResistance;
  93. procedure CreateBall;
  94. procedure CreateFur;
  95. end;
  96. var
  97. FormFurball: TFormFurball;
  98. //-----------------------------------------
  99. implementation
  100. //-----------------------------------------
  101. {$R *.dfm}
  102. procedure nearCallback (data : pointer; o1, o2 : PdxGeom); cdecl;
  103. const
  104. cCOL_MAX = 1;
  105. var
  106. i, numc : integer;
  107. b1,b2 : PdxBody;
  108. contact : array[0..cCOL_MAX-1] of TdContact;
  109. c : TdJointID;
  110. begin
  111. // exit without doing anything if the two bodies are connected by a joint
  112. b1 := dGeomGetBody(o1);
  113. b2 := dGeomGetBody(o2);
  114. if (Assigned(b1) and Assigned(b2) and (dAreConnected (b1,b2)<>0)) then
  115. exit;
  116. for i :=0 to cCOL_MAX-1 do
  117. begin
  118. contact[i].surface.mode := dContactBounce;
  119. // This determines friction, play around with it!
  120. contact[i].surface.mu := 3;//10e9; //dInfinity; SHOULD BE INFINITY!
  121. contact[i].surface.mu2 := 0;
  122. contact[i].surface.bounce := 0.5;//0.5;
  123. contact[i].surface.bounce_vel := 0.1;
  124. end;
  125. numc := dCollide (o1,o2,cCOL_MAX,contact[0].geom,sizeof(TdContact));
  126. if (numc>0) then
  127. begin
  128. for i := 0 to numc-1 do
  129. begin
  130. c := dJointCreateContact (FormFurBall.world,FormFurBall.contactgroup, @contact[i]);
  131. dJointAttach (c,b1,b2);
  132. end;
  133. end;
  134. end;
  135. const
  136. cOffset = 0.03;
  137. procedure TFormFurball.FormCreate(Sender: TObject);
  138. begin
  139. Show;
  140. Randomize;
  141. world := dWorldCreate();
  142. space := dHashSpaceCreate(nil);
  143. contactgroup := dJointGroupCreate (1000000);
  144. dWorldSetGravity (world,0,0,-9.81);
  145. CreateODEPlaneFromGLPlane(GLShadowPlane_Floor, space);
  146. CreateODEPlaneFromGLPlane(GLShadowPlane_Floor2, space);
  147. CreateODEPlaneFromGLPlane(GLShadowPlane_Wall, space);
  148. CreateODEPlaneFromGLPlane(GLShadowPlane_Wall2, space);
  149. CreateODEPlaneFromGLPlane(GLShadowPlane_Wall3, space);
  150. // dCreatePlane (space,0,0,1,0);
  151. VerletWorld := TGLVerletWorld.Create;
  152. VerletWorld.Iterations := 2;
  153. VerletWorld.VerletNodeClass := TGLVerletNode;
  154. CheckBox_FurGravityClick(Sender);
  155. CheckBox_WindResistenceClick(Sender);
  156. CreateVerletPlaneFromGLPlane(GLShadowPlane_Floor, VerletWorld, cOffset);
  157. CreateVerletPlaneFromGLPlane(GLShadowPlane_Floor2, VerletWorld, cOffset);
  158. CreateVerletPlaneFromGLPlane(GLShadowPlane_Wall, VerletWorld, cOffset);
  159. CreateVerletPlaneFromGLPlane(GLShadowPlane_Wall2, VerletWorld, cOffset);
  160. CreateVerletPlaneFromGLPlane(GLShadowPlane_Wall3, VerletWorld, cOffset);
  161. HairList := TList.Create;
  162. CreateBall;
  163. end;
  164. procedure TFormFurball.FormClose(Sender: TObject; var Action: TCloseAction);
  165. begin
  166. GLCadencer1.Enabled := false;
  167. dJointGroupDestroy (contactgroup);
  168. dSpaceDestroy (space);
  169. dWorldDestroy (world);
  170. end;
  171. var
  172. angle : double=0;
  173. procedure TFormFurball.GLCadencer1Progress(Sender: TObject; const deltaTime,
  174. newTime: Double);
  175. const
  176. cTIME_STEP = 0.01;
  177. var
  178. i,j : integer;
  179. Delta : single;
  180. Hair : TGLVerletHair;
  181. GLLines : TGLLines;
  182. begin
  183. Delta := deltaTime;
  184. angle := angle + Delta*3;
  185. while PhysicsTime<newTime do
  186. begin
  187. PhysicsTime := PhysicsTime + cTIME_STEP;
  188. if not CheckBox_LockBall.Checked then
  189. begin
  190. dSpaceCollide (space,nil,nearCallback);
  191. dWorldStep (world, cTIME_STEP);//}
  192. // remove all contact joints
  193. dJointGroupEmpty (contactgroup);
  194. if IsKeyDown(VK_UP) then
  195. dBodyAddForce(odeFurBallBody, 0,0,2.5)
  196. else if IsKeyDown(VK_DOWN) then
  197. dBodyAddForce(odeFurBallBody, 0,0,-2.5);
  198. if IsKeyDown('A') then
  199. dBodyAddForce(odeFurBallBody, 0,-1,0)
  200. else if IsKeyDown('D') then
  201. dBodyAddForce(odeFurBallBody, 0,1,0);
  202. if IsKeyDown('W') then
  203. dBodyAddForce(odeFurBallBody, -1,0,0)
  204. else if IsKeyDown('S') then
  205. dBodyAddForce(odeFurBallBody, 1,0,0);
  206. end;
  207. PositionSceneObject(FurBall, odeFurBallGeom);
  208. VCSphere.Location := FurBall.Position.AsAffineVector;
  209. VerletWorld.Progress(cTIME_STEP, PhysicsTime);
  210. end;
  211. for i := 0 to HairList.Count -1 do
  212. begin
  213. Hair := TGLVerletHair(HairList[i]);
  214. GLLines := TGLLines(Hair.Data);
  215. for j := 1 to Hair.NodeList.Count-1 do
  216. GLLines.Nodes[j-1].AsAffineVector := Hair.NodeList[j].Location;
  217. end;
  218. end;
  219. procedure TFormFurball.DC_LightHolderProgress(Sender: TObject; const deltaTime,
  220. newTime: Double);
  221. begin
  222. // DC_LightHolder.Roll(deltaTime*pi*2*8);
  223. end;
  224. var
  225. FoldMouseX : integer;
  226. FoldMouseY : integer;
  227. procedure TFormFurball.GLSceneViewer1MouseMove(Sender: TObject;
  228. Shift: TShiftState; X, Y: Integer);
  229. begin
  230. if ssLeft in Shift then
  231. GLCamera1.MoveAroundTarget(FoldMouseY-Y, FoldMouseX-X);
  232. FoldMouseX := X;
  233. FoldMouseY := Y;
  234. end;
  235. procedure TFormFurball.CreateBall;
  236. var
  237. m : TdMass;
  238. begin
  239. dMassSetSphere (m,1,FurBall.Radius);
  240. odeFurBallGeom := dCreateSphere (space,FurBall.Radius);
  241. odeFurBallBody := dBodyCreate(World);
  242. dGeomSetBody (odeFurBallGeom,odeFurBallBody);
  243. dBodySetMass (odeFurBallBody, @m);
  244. dBodySetLinearVel(odeFurBallBody, 0, 14, 0);
  245. dBodyAddTorque(odeFurBallBody, 0.1,0.1,0.1);
  246. // Add the GLScene object
  247. odeFurBallGeom.Data:=FurBall;
  248. CopyPosFromGeomToGL(odeFurBallGeom, FurBall);
  249. VCSphere := TGLVerletFrictionSphere.Create(VerletWorld);
  250. VCSphere.Radius := FurBall.Radius * 1.1;
  251. VCSphere.Location := AffineVectorMake(FurBall.AbsolutePosition);
  252. CreateFur;
  253. end;
  254. const
  255. cRadiusMultiplier = 5;
  256. cSegmentCount = 4;
  257. cHairCount = 200;
  258. cRootDepth = 4;
  259. procedure TFormFurball.CreateFur;
  260. // Much, MUCH easier that uniform distribution, and it looks fun.
  261. procedure CreateRandomHair;
  262. var
  263. i : integer;
  264. Dir : TAffineVector;
  265. Hair : TGLVerletHair;
  266. GLLines : TGLLines;
  267. begin
  268. Dir := AffineVectorMake(random-0.5,random-0.5,random-0.5);
  269. NormalizeVector(Dir);
  270. Hair := TGLVerletHair.Create(VerletWorld, FurBall.Radius * cRootDepth,
  271. FurBall.Radius*cRadiusMultiplier, cSegmentCount,
  272. VectorAdd(AffineVectorMake(FurBall.AbsolutePosition), VectorScale(Dir, FurBall.Radius)),
  273. Dir, [vhsSkip1Node]);
  274. //GLLines := TGLLines(GLScene1.Objects.AddNewChild(TGLLines));
  275. GLLines := TGLLines(DCShadowCaster.AddNewChild(TGLLines));
  276. GLLines.NodesAspect := lnaInvisible;
  277. GLLines.LineWidth := 2;
  278. GLLines.LineColor.Color := clrBlack;
  279. for i := 0 to Hair.NodeList.Count-1 do
  280. TGLVerletNode(Hair.NodeList[i]).GLBaseSceneObject := FurBall;
  281. for i := 1 to Hair.NodeList.Count-1 do
  282. GLLines.AddNode(Hair.NodeList[i].Location);
  283. for i := 0 to GLLines.Nodes.Count-1 do
  284. TGLLinesNode(GLLines.Nodes[i]).Color.Color := clrBlack;
  285. GLLines.ObjectStyle:=GLLines.ObjectStyle+[osDirectDraw];
  286. GLLines.SplineMode := lsmCubicSpline;
  287. Hair.Data := GLLines;
  288. HairList.Add(Hair);
  289. end;
  290. var
  291. Hair : TGLVerletHair;
  292. i : integer;
  293. begin
  294. for i := 0 to HairList.Count-1 do
  295. begin
  296. Hair := TGLVerletHair(HairList[i]);
  297. TGLLines(Hair.Data).Free;
  298. Hair.Free;
  299. end;
  300. HairList.Clear;
  301. for i := 0 to cHairCount-1 do
  302. CreateRandomHair;
  303. end;
  304. procedure TFormFurball.FormMouseWheel(Sender: TObject; Shift: TShiftState;
  305. WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
  306. begin
  307. GLCamera1.AdjustDistanceToTarget(Power(1.1, WheelDelta/120));
  308. end;
  309. procedure TFormFurball.CheckBox_FurGravityClick(Sender: TObject);
  310. begin
  311. if not CheckBox_FurGravity.Checked then
  312. FreeAndNil(Gravity)
  313. else
  314. begin
  315. Gravity := TGLVerletGravity.Create(VerletWorld);
  316. Gravity.Gravity := AffineVectorMake(0,0,-9.81);
  317. end;
  318. end;
  319. procedure TFormFurball.CheckBox_WindResistenceClick(Sender: TObject);
  320. begin
  321. if not CheckBox_WindResistence.Checked then
  322. FreeAndNil(AirResistance)
  323. else
  324. begin
  325. AirResistance := TGLVerletAirResistance.Create(VerletWorld);
  326. AirResistance.DragCoeff := 0.01;
  327. AirResistance.WindDirection := AffineVectorMake(1,0,0);
  328. AirResistance.WindMagnitude := TrackBar_WindForce.Position/100 * cMaxWindMag;
  329. AirResistance.WindChaos := 0.4;
  330. end;
  331. TrackBar_WindForce.Enabled := CheckBox_WindResistence.Checked;
  332. end;
  333. procedure TFormFurball.TrackBar_WindForceChange(Sender: TObject);
  334. begin
  335. if Assigned(AirResistance) then
  336. AirResistance.WindMagnitude := TrackBar_WindForce.Position/100 * cMaxWindMag;
  337. end;
  338. procedure TFormFurball.CheckBox_BaldClick(Sender: TObject);
  339. var
  340. i : integer;
  341. begin
  342. for i := 0 to HairList.Count -1 do
  343. begin
  344. with TGLVerletHair(HairList[i]) do
  345. begin
  346. Anchor.NailedDown := not CheckBox_Bald.Checked;
  347. Anchor.OldLocation := Anchor.Location;
  348. Root.NailedDown := not CheckBox_Bald.Checked;
  349. Root.OldLocation := Root.Location;
  350. end;
  351. end;
  352. if not CheckBox_Bald.Checked then
  353. VerletWorld.PauseInertia(5);
  354. end;
  355. procedure TFormFurball.Timer1Timer(Sender: TObject);
  356. begin
  357. Label_FPS.Caption := GLSceneViewer1.FramesPerSecondText;
  358. GLSceneViewer1.ResetPerformanceMonitor;
  359. end;
  360. procedure TFormFurball.CheckBox_ShadowsClick(Sender: TObject);
  361. var
  362. light : TGLLightSource;
  363. begin
  364. if CheckBox_Shadows.Checked then
  365. light := GLLightSource1
  366. else
  367. light := nil;
  368. GLShadowPlane_Floor.ShadowedLight := light;
  369. GLShadowPlane_Floor2.ShadowedLight := light;
  370. GLShadowPlane_Wall.ShadowedLight := light;
  371. GLShadowPlane_Wall2.ShadowedLight := light;
  372. GLShadowPlane_Wall3.ShadowedLight := light;
  373. end;
  374. procedure TFormFurball.CheckBox_InertiaClick(Sender: TObject);
  375. begin
  376. VerletWorld.Inertia := CheckBox_Inertia.Checked;
  377. end;
  378. end.