fOdeFurballD.pas 12 KB

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