Advertisement
Guest User

Untitled

a guest
Jan 22nd, 2017
126
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 50.26 KB | None | 0 0
  1. /*----------------------------------------------------------------------------
  2.  
  3. 2D Physics Test Program - a cheesy test harness for 2D physics
  4.  
  5. by Chris Hecker for my Game Developer Magazine articles. See my homepage
  6. for more information.
  7.  
  8. NOTE: This is a hacked test program, not a nice example of Windows programming.
  9. physics.cpp the only part of this you should look at!!!
  10.  
  11. This material is Copyright 1997 Chris Hecker, All Rights Reserved.
  12. It's for you to read and learn from, not to put in your own articles
  13. or books or on your website, etc. Thank you.
  14.  
  15. Chris Hecker
  16. checker@d6.com
  17. http://www.d6.com/users/checker
  18.  
  19. */
  20.  
  21. /*----------------------------------------------------------------------------
  22.  
  23. Interface functions between physics code and the dumb OS interface.
  24.  
  25. */
  26.  
  27. // physics -> app
  28.  
  29. void Line( int X0, int Y0, int X1, int Y1 );
  30. float GetTime( void );
  31.  
  32. extern int WorldWidth, WorldHeight;
  33.  
  34. // app -> physics
  35.  
  36. void Run( void );
  37.  
  38. void ToggleWorldSpring( void );
  39. void ToggleBodySpring( void );
  40. void ToggleGravity( void );
  41. void ToggleDamping( void );
  42.  
  43. NAME=physics
  44.  
  45. CC = cl -c -W4 -Zi -O2ab1gityp- -G5s -QIfdiv- -DSTRICT -DWIN32 -D_WIN32
  46. ASM = ml -c -D_WIN32=1 -Zi -Zf -coff
  47. LINK= link -map -pdb:none -debug:full -debugtype:cv -out:$(NAME).exe -subsystem:windows
  48. DEF =-DDEBUG -DSTRICT
  49. RC = rc
  50.  
  51. OBJ = $(NAME).obj win32.obj
  52.  
  53. LIBS = gdi32.lib user32.lib comdlg32.lib winmm.lib
  54.  
  55. .cpp.obj:
  56. $(CC) /Fo$*.obj /Fl$*.lst $<
  57.  
  58. .asm.obj:
  59. $(ASM) /Fo$*.obj /Fl $<
  60.  
  61. goal: $(NAME).exe
  62.  
  63. $(NAME).exe: $(OBJ) $(NAME).res makefile
  64. $(LINK) $(OBJ) $(LIBS) $(NAME).res
  65.  
  66. $(NAME).res: $(NAME).rc $(NAME).ico
  67. $(RC) -r $(NAME).rc
  68.  
  69. clean:
  70. del $(NAME).exe
  71. del *.lst
  72. del *.res
  73. del *.err
  74. del *.obj
  75. del *.map
  76. del *.sym
  77. del *.cod
  78. del *.pdb
  79.  
  80. /*----------------------------------------------------------------------------
  81.  
  82. 2D Physics Test Program - a cheesy test harness for 2D physics
  83.  
  84. by Chris Hecker for my Game Developer Magazine articles. See my homepage
  85. for more information.
  86.  
  87. NOTE: This is a hacked test program, not a nice example of Windows programming.
  88. physics.cpp the only part of this you should look at!!!
  89.  
  90. This material is Copyright 1997 Chris Hecker, All Rights Reserved.
  91. It's for you to read and learn from, not to put in your own articles
  92. or books or on your website, etc. Thank you.
  93.  
  94. Chris Hecker
  95. checker@d6.com
  96. http://www.d6.com/users/checker
  97.  
  98. */
  99.  
  100. /*----------------------------------------------------------------------------
  101.  
  102. math2d.h - The simple math library for the 2D physics demo.
  103.  
  104. 10/13/96 - checker
  105.  
  106. */
  107.  
  108. #if !defined(MATH2D_H)
  109. #define MATH2D_H
  110.  
  111. // explicit dependencies
  112. #include <math.h> // for sqrt
  113. #include <float.h>
  114.  
  115. /*----------------------------------------------------------------------------
  116.  
  117. Type and constant declarations.
  118.  
  119. */
  120.  
  121. typedef float real;
  122. typedef real r; // for constants, ie. r(1), not for declaration use
  123.  
  124. real const REAL_MAX = FLT_MAX;
  125. real const REAL_MIN = FLT_MIN;
  126.  
  127. real const PI = r(3.14159265358979323846);
  128. real const Epsilon = r(0.00001);
  129.  
  130. struct vector_2
  131. {
  132. real X, Y;
  133.  
  134. inline vector_2( void );
  135. inline vector_2( real X, real Y );
  136.  
  137. inline vector_2 &operator+=( vector_2 const &A );
  138. inline vector_2 &operator-=( vector_2 const &A );
  139. };
  140.  
  141. struct matrix_2x2
  142. {
  143. real aElements[2][2];
  144.  
  145. inline matrix_2x2( void );
  146. inline matrix_2x2( real RotateByThisManyRadians );
  147. };
  148.  
  149.  
  150.  
  151. /*----------------------------------------------------------------------------
  152.  
  153. Functions.
  154.  
  155. */
  156.  
  157. inline real RadiansFrom( real Degrees );
  158. inline real DegreesFrom( real Radians );
  159.  
  160. inline vector_2 operator-( vector_2 const &A, vector_2 const &B );
  161. inline vector_2 operator+( vector_2 const &A, vector_2 const &B );
  162. inline vector_2 operator*( real A, vector_2 const &B );
  163. inline vector_2 operator*( vector_2 const &A, real B );
  164. inline vector_2 operator/( vector_2 const &A, real B );
  165.  
  166. inline real DotProduct( vector_2 const &A, vector_2 const &B );
  167.  
  168. // A-perp dot B
  169. inline real PerpDotProduct( vector_2 const &A, vector_2 const &B );
  170.  
  171. inline vector_2 GetPerpendicular( vector_2 const &A );
  172. inline real GetLength( vector_2 const &A );
  173. inline vector_2 GetNormal( vector_2 const &A ); // @todo need this?
  174.  
  175. inline vector_2 operator*( matrix_2x2 const &A, vector_2 const &B );
  176.  
  177. /*----------------------------------------------------------------------------
  178.  
  179. Inline function definitions.
  180.  
  181. */
  182.  
  183. inline real RadiansFrom( real Degrees )
  184. {
  185. return (Degrees * PI) / r(180);
  186. }
  187.  
  188. inline real DegreesFrom( real Radians )
  189. {
  190. return (Radians * r(180)) / PI;
  191. }
  192.  
  193. inline vector_2 operator-( vector_2 const &A, vector_2 const &B )
  194. {
  195. return vector_2(A.X-B.X,A.Y-B.Y);
  196. }
  197.  
  198. inline vector_2 operator+( vector_2 const &A, vector_2 const &B )
  199. {
  200. return vector_2(A.X+B.X,A.Y+B.Y);
  201. }
  202.  
  203. inline vector_2 operator*( real A, vector_2 const &B )
  204. {
  205. return vector_2(A*B.X,A*B.Y);
  206. }
  207.  
  208. inline vector_2 operator*( vector_2 const &A, real B )
  209. {
  210. return vector_2(B*A.X,B*A.Y);
  211. }
  212.  
  213. inline vector_2 operator/( vector_2 const &A, real B )
  214. {
  215. return vector_2(A.X/B,A.Y/B);
  216. }
  217.  
  218. inline real DotProduct( vector_2 const &A, vector_2 const &B )
  219. {
  220. return A.X*B.X + A.Y*B.Y;
  221. }
  222.  
  223. inline real PerpDotProduct( vector_2 const &A, vector_2 const &B )
  224. {
  225. return A.X*B.Y - A.Y*B.X;
  226. }
  227.  
  228. inline vector_2 GetPerpendicular( vector_2 const &A )
  229. {
  230. return vector_2(-A.Y,A.X);
  231. }
  232.  
  233. inline real GetLength( vector_2 const &A )
  234. {
  235. return r(sqrt(A.X*A.X + A.Y*A.Y));
  236. }
  237.  
  238. inline vector_2 GetNormal( vector_2 const &A )
  239. {
  240. real OneOverLength = r(1)/GetLength(A);
  241. return vector_2(OneOverLength*A.X,OneOverLength*A.Y);
  242. }
  243.  
  244. inline vector_2::vector_2( void ) : X(r(0)), Y(r(0))
  245. {
  246. }
  247.  
  248. inline vector_2::vector_2( real X_, real Y_ ) : X(X_), Y(Y_)
  249. {
  250. }
  251.  
  252. inline vector_2 &vector_2::operator+=( vector_2 const &A )
  253. {
  254. X += A.X;
  255. Y += A.Y;
  256. return *this;
  257. }
  258. inline vector_2 &vector_2::operator-=( vector_2 const &A )
  259. {
  260. X -= A.X;
  261. Y -= A.Y;
  262. return *this;
  263. }
  264.  
  265. inline vector_2 operator*( matrix_2x2 const &A, vector_2 const &B )
  266. {
  267. return vector_2(A.aElements[0][0]*B.X + A.aElements[0][1]*B.Y,
  268. A.aElements[1][0]*B.X + A.aElements[1][1]*B.Y);
  269. }
  270.  
  271. inline matrix_2x2::matrix_2x2( void )
  272. {
  273. aElements[0][0] = aElements[0][1] = aElements[1][0] = aElements[1][1] =r(0);
  274. }
  275.  
  276. inline matrix_2x2::matrix_2x2( real Radians )
  277. {
  278. real const CosAngle = (real)cos(Radians);
  279. real const SinAngle = (real)sin(Radians);
  280.  
  281. aElements[0][0] = CosAngle; aElements[0][1] = -SinAngle;
  282. aElements[1][0] = SinAngle; aElements[1][1] = CosAngle;
  283. }
  284.  
  285. #endif
  286.  
  287. /*----------------------------------------------------------------------------
  288.  
  289. 2D Physics Test Program - a cheesy test harness for 2D physics
  290.  
  291. by Chris Hecker for my Game Developer Magazine articles. See my homepage
  292. for more information.
  293.  
  294. NOTE: This is a hacked test program, not a nice example of Windows programming.
  295. physics.cpp the only part of this you should look at!!!
  296.  
  297. This material is Copyright 1997 Chris Hecker, All Rights Reserved.
  298. It's for you to read and learn from, not to put in your own articles
  299. or books or on your website, etc. Thank you.
  300.  
  301. Chris Hecker
  302. checker@d6.com
  303. http://www.d6.com/users/checker
  304.  
  305. */
  306.  
  307. /*----------------------------------------------------------------------------
  308.  
  309. physics.cpp - This file implements the 2D physics simulator.
  310.  
  311. 10/15/96 - checker
  312.  
  313. */
  314.  
  315. #include <assert.h>
  316.  
  317. #include "physics.h"
  318. #include "iface.h"
  319.  
  320. /*----------------------------------------------------------------------------
  321.  
  322. Globals
  323.  
  324. */
  325.  
  326. // weird CodeWarrior bug with global initialization forces me to do this
  327. #define WIDTH 400
  328. #define HEIGHT 400
  329.  
  330. int WorldWidth = WIDTH;
  331. int WorldHeight = HEIGHT;
  332.  
  333. simulation_world World(r(WIDTH),r(HEIGHT));
  334.  
  335. /*----------------------------------------------------------------------------
  336.  
  337. various forces you can add to the system
  338.  
  339. @todo need to figure out units here so these numbers mean something
  340.  
  341. */
  342.  
  343. int WorldSpringActive = 0; // spring goes from body 0: vertex 0 to origin
  344. real const Kws = r(30); // Hooke's spring constant
  345. real const Kwd = r(5); // damping constant
  346. vector_2 WorldSpringAnchor(r(0),r(0));
  347.  
  348. int BodySpringActive = 0; // spring goes from body 0 to body 1
  349. real const Kbs = r(10); // Hooke's spring constant
  350. real const Kbd = r(5); // damping constant
  351. int Body0SpringVertexIndex = 2;
  352. int Body1SpringVertexIndex = 0;
  353.  
  354. int GravityActive = 0;
  355. vector_2 Gravity(r(0),r(-100));
  356.  
  357. int DampingActive = 0;
  358. real const Kdl = r(2.5); // linear damping factor
  359. real const Kda = r(1400); // angular damping factor
  360.  
  361. /*----------------------------------------------------------------------------
  362.  
  363. Run
  364.  
  365. */
  366.  
  367. void Run( void )
  368. {
  369. static real LastTime = GetTime();
  370.  
  371. // use a fixed timestep until we implement a better integrator
  372. // real Time = GetTime();
  373. real Time = LastTime + r(0.02);
  374.  
  375. World.Simulate(Time - LastTime);
  376.  
  377. World.Render();
  378.  
  379. LastTime = Time;
  380. }
  381.  
  382. /*----------------------------------------------------------------------------
  383.  
  384. Toggles
  385.  
  386. */
  387.  
  388. void ToggleWorldSpring( void )
  389. {
  390. WorldSpringActive = WorldSpringActive ? 0 : 1;
  391. }
  392.  
  393. void ToggleBodySpring( void )
  394. {
  395. BodySpringActive = BodySpringActive ? 0 : 1;
  396. }
  397.  
  398. void ToggleGravity( void )
  399. {
  400. GravityActive = GravityActive ? 0 : 1;
  401. }
  402.  
  403. void ToggleDamping( void )
  404. {
  405. DampingActive = DampingActive ? 0 : 1;
  406. }
  407.  
  408. /*----------------------------------------------------------------------------
  409.  
  410. utilities
  411.  
  412. */
  413.  
  414. void InitializeBody( rigid_body &Body, real Density, real Width, real Height,
  415. real CoefficientOfRestitution )
  416. {
  417. real const Mass = Density * Width * Height;
  418.  
  419. Body.CoefficientOfRestitution = CoefficientOfRestitution;
  420.  
  421. Body.Width = Width;
  422. Body.Height = Height;
  423.  
  424. Body.OneOverMass = r(1) / Mass;
  425.  
  426. // integrate over the body to find the moment of inertia
  427.  
  428. Body.OneOverCMMomentOfInertia = r(1) / ((Mass / r(12)) *
  429. (Width * Width + Height * Height));
  430.  
  431. // 0-out non-vector quantities
  432. Body.aConfigurations[0].Orientation = r(0);
  433. Body.aConfigurations[0].AngularVelocity = r(0);
  434. Body.aConfigurations[0].Torque = r(0);
  435. }
  436.  
  437. /*----------------------------------------------------------------------------
  438.  
  439. simulation_world ctor
  440.  
  441. */
  442.  
  443. simulation_world::simulation_world( real WorldWidth_, real WorldHeight_ ) :
  444. WorldWidth(WorldWidth_), WorldHeight(WorldHeight_),
  445. SourceConfigurationIndex(0), TargetConfigurationIndex(1)
  446. {
  447. // initialize bodies
  448. real const Density = r(0.01);
  449. InitializeBody(aBodies[0],Density,r(40),r(20),r(1));
  450. InitializeBody(aBodies[1],Density,r(50),r(10),r(1));
  451.  
  452. aBodies[0].aConfigurations[0].CMVelocity = vector_2(r(40),r(10));
  453. aBodies[0].aConfigurations[0].AngularVelocity = r(PI);
  454.  
  455. // initialize walls
  456. aWalls[0].Normal = vector_2(r(0),r(-1));
  457. aWalls[0].c = r(WorldHeight/2 - 3);
  458.  
  459. aWalls[1].Normal = vector_2(r(0),r(1));
  460. aWalls[1].c = r(WorldHeight/2 - 3);
  461.  
  462. aWalls[2].Normal = vector_2(r(-1),r(0));
  463. aWalls[2].c = r(WorldWidth/2 - 3);
  464.  
  465. aWalls[3].Normal = vector_2(r(1),r(0));
  466. aWalls[3].c = r(WorldWidth/2 - 3);
  467.  
  468. aWalls[4].Normal = GetNormal(vector_2(r(0.5),r(1)));
  469. aWalls[4].c = r(WorldWidth/2);
  470.  
  471. // generate the wall lines
  472. for(int Counter = 0;Counter < NumberOfWalls;Counter++)
  473. {
  474. wall &Wall = aWalls[Counter];
  475.  
  476. // make a big line in the direction of the wall
  477.  
  478. vector_2 PointOnWall = -Wall.c * Wall.Normal;
  479. vector_2 v = GetPerpendicular(Wall.Normal);
  480. real t0 = -REAL_MAX;
  481. real t1 = REAL_MAX;
  482.  
  483. // now clip the line to the walls
  484.  
  485. for(int WallIndex = 0;WallIndex < NumberOfWalls;WallIndex++)
  486. {
  487. if(WallIndex != Counter)
  488. {
  489. wall &ClipWall = aWalls[WallIndex];
  490.  
  491. real Denominator = DotProduct(v,ClipWall.Normal);
  492.  
  493. if(fabs(Denominator) > Epsilon)
  494. {
  495. // not coplanar
  496.  
  497. real t = - (ClipWall.c +
  498. DotProduct(PointOnWall,ClipWall.Normal)) /
  499. Denominator;
  500.  
  501. if(Denominator > r(0))
  502. {
  503. // the clip wall's clipping the t0 side of line
  504. if(t > t0)
  505. {
  506. t0 = t;
  507. }
  508. }
  509. else
  510. {
  511. // it's clipping the t1 side
  512. if(t < t1)
  513. {
  514. t1 = t;
  515. }
  516. }
  517. }
  518. }
  519. }
  520.  
  521. // make sure we got clipped
  522. assert((t0 != -REAL_MAX) && (t1 != REAL_MAX));
  523. // but not completely clipped
  524. assert(t0 < t1);
  525.  
  526. Wall.StartPoint = PointOnWall + t0 * v;
  527. Wall.EndPoint = PointOnWall + t1 * v;
  528. }
  529.  
  530. // calculate initial box positions
  531. CalculateVertices(0);
  532. }
  533.  
  534. /*----------------------------------------------------------------------------
  535.  
  536. simulation_world dtor
  537.  
  538. */
  539.  
  540. simulation_world::~simulation_world( void )
  541. {
  542.  
  543. }
  544.  
  545. /*----------------------------------------------------------------------------
  546.  
  547. Render - render the source configurations
  548.  
  549. */
  550.  
  551. #pragma warning(disable:4244) // float -> int
  552. void simulation_world::Render( void )
  553. {
  554. int Counter;
  555.  
  556. // draw walls
  557.  
  558. for(Counter = 0;Counter < NumberOfWalls;Counter++)
  559. {
  560. wall &Wall = aWalls[Counter];
  561.  
  562. Line(Wall.StartPoint.X,Wall.StartPoint.Y,
  563. Wall.EndPoint.X,Wall.EndPoint.Y);
  564. }
  565.  
  566. // draw bodies
  567.  
  568. for(Counter = 0;Counter < NumberOfBodies;Counter++)
  569. {
  570. rigid_body::configuration::bounding_box &Box =
  571. aBodies[Counter].aConfigurations[SourceConfigurationIndex].
  572. BoundingBox;
  573.  
  574. for(int Edge = 0;Edge < 4;Edge++)
  575. {
  576. int Start = Edge;
  577. int End = (Edge + 1) % 4;
  578.  
  579. Line(Box.aVertices[Start].X,Box.aVertices[Start].Y,
  580. Box.aVertices[End].X,Box.aVertices[End].Y);
  581. }
  582. }
  583.  
  584. // draw springs
  585.  
  586. if(WorldSpringActive)
  587. {
  588. rigid_body::configuration::bounding_box &Box =
  589. aBodies[0].aConfigurations[SourceConfigurationIndex].BoundingBox;
  590.  
  591. Line(Box.aVertices[0].X,Box.aVertices[0].Y,
  592. WorldSpringAnchor.X,WorldSpringAnchor.Y);
  593. }
  594.  
  595. if(BodySpringActive)
  596. {
  597. rigid_body::configuration::bounding_box &Box0 =
  598. aBodies[0].aConfigurations[SourceConfigurationIndex].BoundingBox;
  599. rigid_body::configuration::bounding_box &Box1 =
  600. aBodies[1].aConfigurations[SourceConfigurationIndex].BoundingBox;
  601.  
  602. assert(NumberOfBodies >= 2);
  603. vector_2 P0 = Box0.aVertices[Body0SpringVertexIndex];
  604. vector_2 P1 = Box1.aVertices[Body1SpringVertexIndex];
  605. Line(P0.X,P0.Y,P1.X,P1.Y);
  606. }
  607.  
  608. // draw gravity vector
  609.  
  610. if(GravityActive)
  611. {
  612. Line(0,0,0,-30);
  613. Line(0,-30,5,-25);
  614. Line(0,-30,-5,-25);
  615. }
  616.  
  617. // draw damping symbol
  618.  
  619. if(DampingActive)
  620. {
  621. Line(-5,0,5,0);
  622. Line(0,-5,0,5);
  623. }
  624. }
  625. #pragma warning(default:4244) // float -> int
  626.  
  627. /*----------------------------------------------------------------------------
  628.  
  629. Simulate - Integrate forward DeltaTime seconds.
  630.  
  631. @todo do I need to store the last simulation time?
  632.  
  633. */
  634.  
  635. void simulation_world::Simulate( real DeltaTime )
  636. {
  637. real CurrentTime = r(0);
  638. real TargetTime = DeltaTime;
  639.  
  640. while(CurrentTime < DeltaTime)
  641. {
  642. ComputeForces(SourceConfigurationIndex);
  643.  
  644. Integrate(TargetTime-CurrentTime);
  645.  
  646. CalculateVertices(TargetConfigurationIndex);
  647.  
  648. CheckForCollisions(TargetConfigurationIndex);
  649.  
  650. if(CollisionState == Penetrating)
  651. {
  652. // we simulated too far, so subdivide time and try again
  653. TargetTime = (CurrentTime + TargetTime) / r(2);
  654.  
  655. // blow up if we aren't moving forward each step, which is
  656. // probably caused by interpenetration at the frame start
  657.  
  658. assert(fabs(TargetTime - CurrentTime) > Epsilon);
  659. }
  660. else
  661. {
  662. // either colliding or clear
  663.  
  664. if(CollisionState == Colliding)
  665. {
  666. // @todo handle multiple simultaneous collisions
  667.  
  668. int Counter = 0;
  669. do
  670. {
  671. ResolveCollisions(TargetConfigurationIndex);
  672. Counter++;
  673. } while((CheckForCollisions(TargetConfigurationIndex) ==
  674. Colliding) && (Counter < 100));
  675.  
  676. assert(Counter < 100);
  677. }
  678.  
  679. // we made a successful step, so swap configurations
  680. // to "save" the data for the next step
  681.  
  682. CurrentTime = TargetTime;
  683. TargetTime = DeltaTime;
  684.  
  685. SourceConfigurationIndex = SourceConfigurationIndex ? 0 : 1;
  686. TargetConfigurationIndex = TargetConfigurationIndex ? 0 : 1;
  687. }
  688. }
  689. }
  690.  
  691. /*----------------------------------------------------------------------------
  692.  
  693. ComputeForces - compute forces for gravity, spring, etc.
  694.  
  695. */
  696.  
  697. void simulation_world::ComputeForces( int ConfigurationIndex )
  698. {
  699. int Counter;
  700.  
  701. for(Counter = 0;Counter < NumberOfBodies;Counter++)
  702. {
  703. rigid_body &Body = aBodies[Counter];
  704. rigid_body::configuration &Configuration =
  705. Body.aConfigurations[ConfigurationIndex];
  706.  
  707. // clear forces
  708.  
  709. Configuration.Torque = r(0);
  710. Configuration.CMForce = vector_2(r(0),r(0));
  711.  
  712. if(GravityActive)
  713. {
  714. Configuration.CMForce += Gravity / Body.OneOverMass;
  715. }
  716.  
  717. if(DampingActive)
  718. {
  719. Configuration.CMForce += -Kdl * Configuration.CMVelocity;
  720. Configuration.Torque += -Kda * Configuration.AngularVelocity;
  721. }
  722. }
  723.  
  724. if(BodySpringActive)
  725. {
  726. rigid_body &Body0 = aBodies[0];
  727. rigid_body::configuration &Configuration0 =
  728. Body0.aConfigurations[ConfigurationIndex];
  729. rigid_body::configuration::bounding_box &Box0 =
  730. Configuration0.BoundingBox;
  731. vector_2 Position0 = Box0.aVertices[Body0SpringVertexIndex];
  732. vector_2 U0 = Position0 - Configuration0.CMPosition;
  733. vector_2 VU0 = Configuration0.CMVelocity +
  734. Configuration0.AngularVelocity * GetPerpendicular(U0);
  735.  
  736. rigid_body &Body1 = aBodies[1];
  737. rigid_body::configuration &Configuration1 =
  738. Body1.aConfigurations[ConfigurationIndex];
  739. rigid_body::configuration::bounding_box &Box1 =
  740. Configuration1.BoundingBox;
  741. vector_2 Position1 = Box1.aVertices[Body1SpringVertexIndex];
  742. vector_2 U1 = Position1 - Configuration1.CMPosition;
  743. vector_2 VU1 = Configuration1.CMVelocity +
  744. Configuration1.AngularVelocity * GetPerpendicular(U1);
  745.  
  746. // spring goes from 0 to 1
  747.  
  748. vector_2 SpringVector = Position1 - Position0;
  749. vector_2 Spring = -Kbs * SpringVector;
  750.  
  751. vector_2 RelativeVelocity = VU1 - VU0;
  752. // project velocity onto spring to get damping vector
  753. // this is basically a Gram-Schmidt projection
  754. vector_2 DampingForce =
  755. -Kbd * (DotProduct(RelativeVelocity,SpringVector)/
  756. DotProduct(SpringVector,SpringVector)) * SpringVector;
  757.  
  758. Spring += DampingForce;
  759.  
  760. Configuration0.CMForce -= Spring;
  761. Configuration0.Torque -= PerpDotProduct(U0,Spring);
  762.  
  763. Configuration1.CMForce += Spring;
  764. Configuration1.Torque += PerpDotProduct(U1,Spring);
  765. }
  766.  
  767. if(WorldSpringActive)
  768. {
  769. // apply spring to body 0's vertex 0 to anchor
  770.  
  771. rigid_body &Body = aBodies[0];
  772. rigid_body::configuration &Configuration =
  773. Body.aConfigurations[ConfigurationIndex];
  774. rigid_body::configuration::bounding_box &Box =
  775. Configuration.BoundingBox;
  776.  
  777. vector_2 Position = Box.aVertices[0];
  778.  
  779. vector_2 U = Position - Configuration.CMPosition;
  780. vector_2 VU = Configuration.CMVelocity +
  781. Configuration.AngularVelocity * GetPerpendicular(U);
  782.  
  783. vector_2 Spring = -Kws * (Position - WorldSpringAnchor);
  784. // project velocity onto spring to get damping vector
  785. // this is basically a Gram-Schmidt projection
  786. vector_2 DampingForce =
  787. -Kwd * (DotProduct(VU,Spring)/DotProduct(Spring,Spring)) * Spring;
  788.  
  789. Spring += DampingForce;
  790.  
  791. Configuration.CMForce += Spring;
  792. Configuration.Torque += PerpDotProduct(U,Spring);
  793. }
  794. }
  795.  
  796.  
  797. /*----------------------------------------------------------------------------
  798.  
  799. CalculateVertices - figure out the body vertices from the configuration
  800.  
  801. @todo should't this be in the body?
  802.  
  803. */
  804.  
  805. void simulation_world::CalculateVertices( int ConfigurationIndex )
  806. {
  807. int Counter;
  808.  
  809. for(Counter = 0;Counter < NumberOfBodies;Counter++)
  810. {
  811. matrix_2x2 const Rotation(
  812. aBodies[Counter].aConfigurations[ConfigurationIndex].
  813. Orientation);
  814.  
  815. vector_2 const Position =
  816. aBodies[Counter].aConfigurations[ConfigurationIndex].
  817. CMPosition;
  818.  
  819. rigid_body::configuration::bounding_box &Box =
  820. aBodies[Counter].aConfigurations[ConfigurationIndex].BoundingBox;
  821.  
  822. real const Width = aBodies[Counter].Width / 2.0f;
  823. real const Height = aBodies[Counter].Height / 2.0f;
  824.  
  825. Box.aVertices[0] = Position + Rotation * vector_2( Width, Height);
  826. Box.aVertices[1] = Position + Rotation * vector_2( Width,-Height);
  827. Box.aVertices[2] = Position + Rotation * vector_2(-Width,-Height);
  828. Box.aVertices[3] = Position + Rotation * vector_2(-Width, Height);
  829. }
  830. }
  831.  
  832. /*----------------------------------------------------------------------------
  833.  
  834. Integrate - integrate the rigid body configurations forward in time from
  835. source config to target config
  836.  
  837. @todo calculate initial derivatives _once_
  838. @todo use something better than Euler's method
  839.  
  840. */
  841.  
  842. void simulation_world::Integrate( real DeltaTime )
  843. {
  844. int Counter;
  845.  
  846. for(Counter = 0;Counter < NumberOfBodies;Counter++)
  847. {
  848. rigid_body::configuration &Source =
  849. aBodies[Counter].aConfigurations[SourceConfigurationIndex];
  850. rigid_body::configuration &Target =
  851. aBodies[Counter].aConfigurations[TargetConfigurationIndex];
  852.  
  853. Target.CMPosition = Source.CMPosition +
  854. DeltaTime * Source.CMVelocity;
  855.  
  856. Target.Orientation = Source.Orientation +
  857. DeltaTime * Source.AngularVelocity;
  858.  
  859. Target.CMVelocity = Source.CMVelocity +
  860. (DeltaTime * aBodies[Counter].OneOverMass) * Source.CMForce;
  861.  
  862. Target.AngularVelocity = Source.AngularVelocity +
  863. (DeltaTime * aBodies[Counter].OneOverCMMomentOfInertia) *
  864. Source.Torque;
  865. }
  866. }
  867.  
  868.  
  869. /*----------------------------------------------------------------------------
  870.  
  871. CheckForCollisions - test the current configuration for collisions
  872.  
  873. @todo handle multiple simultaneous collisions
  874.  
  875. */
  876.  
  877. simulation_world::collision_state
  878. simulation_world::CheckForCollisions( int ConfigurationIndex )
  879. {
  880. // be optimistic!
  881. CollisionState = Clear;
  882. float const DepthEpsilon = 1.0f;
  883.  
  884. real const HalfWidth = WorldWidth / 2.0f;
  885. real const HalfHeight = WorldHeight / 2.0f;
  886.  
  887. for(int Body = 0;(Body < NumberOfBodies) &&
  888. (CollisionState != Penetrating);Body++)
  889. {
  890. // @todo active configuration number?!?!?
  891. rigid_body::configuration &Configuration =
  892. aBodies[Body].aConfigurations[ConfigurationIndex];
  893.  
  894. rigid_body::configuration::bounding_box &Box =
  895. Configuration.BoundingBox;
  896.  
  897. for(int Counter = 0;(Counter < 4) &&
  898. (CollisionState != Penetrating);Counter++)
  899. {
  900. vector_2 Position = Box.aVertices[Counter];
  901.  
  902. vector_2 CMToCornerPerp =
  903. GetPerpendicular(Position - Configuration.CMPosition);
  904.  
  905. vector_2 Velocity = Configuration.CMVelocity +
  906. Configuration.AngularVelocity * CMToCornerPerp;
  907.  
  908. for(int WallIndex = 0;(WallIndex < NumberOfWalls) &&
  909. (CollisionState != Penetrating);WallIndex++)
  910. {
  911. wall &Wall = aWalls[WallIndex];
  912.  
  913. real axbyc = DotProduct(Position,Wall.Normal) + Wall.c;
  914.  
  915. if(axbyc < -DepthEpsilon)
  916. {
  917. CollisionState = Penetrating;
  918. }
  919. else
  920. if(axbyc < DepthEpsilon)
  921. {
  922. real RelativeVelocity = DotProduct(Wall.Normal,Velocity);
  923.  
  924. if(RelativeVelocity < r(0))
  925. {
  926. CollisionState = Colliding;
  927. CollisionNormal = Wall.Normal;
  928. CollidingCornerIndex = Counter;
  929. CollidingBodyIndex = Body;
  930. }
  931. }
  932. }
  933. }
  934. }
  935.  
  936. return CollisionState;
  937. }
  938.  
  939.  
  940. /*----------------------------------------------------------------------------
  941.  
  942. ResolveCollisions - calculate collision impulses
  943.  
  944. @todo handle multiple simultaneous collisions
  945.  
  946. */
  947.  
  948. void simulation_world::ResolveCollisions( int ConfigurationIndex )
  949. {
  950. rigid_body &Body = aBodies[CollidingBodyIndex];
  951. rigid_body::configuration &Configuration =
  952. Body.aConfigurations[ConfigurationIndex];
  953.  
  954. vector_2 Position =
  955. Configuration.BoundingBox.aVertices[CollidingCornerIndex];
  956.  
  957. vector_2 CMToCornerPerp = GetPerpendicular(Position -
  958. Configuration.CMPosition);
  959.  
  960. vector_2 Velocity = Configuration.CMVelocity +
  961. Configuration.AngularVelocity * CMToCornerPerp;
  962.  
  963. real ImpulseNumerator = -(r(1) + Body.CoefficientOfRestitution) *
  964. DotProduct(Velocity,CollisionNormal);
  965.  
  966. float PerpDot = DotProduct(CMToCornerPerp,CollisionNormal);
  967.  
  968. real ImpulseDenominator = Body.OneOverMass +
  969. Body.OneOverCMMomentOfInertia * PerpDot * PerpDot;
  970.  
  971. real Impulse = ImpulseNumerator / ImpulseDenominator;
  972.  
  973. Configuration.CMVelocity += Impulse * Body.OneOverMass * CollisionNormal;
  974.  
  975. Configuration.AngularVelocity +=
  976. Impulse * Body.OneOverCMMomentOfInertia * PerpDot;
  977. }
  978.  
  979. /*----------------------------------------------------------------------------
  980.  
  981. 2D Physics Test Program - a cheesy test harness for 2D physics
  982.  
  983. by Chris Hecker for my Game Developer Magazine articles. See my homepage
  984. for more information.
  985.  
  986. NOTE: This is a hacked test program, not a nice example of Windows programming.
  987. physics.cpp the only part of this you should look at!!!
  988.  
  989. This material is Copyright 1997 Chris Hecker, All Rights Reserved.
  990. It's for you to read and learn from, not to put in your own articles
  991. or books or on your website, etc. Thank you.
  992.  
  993. Chris Hecker
  994. checker@d6.com
  995. http://www.d6.com/users/checker
  996.  
  997. */
  998.  
  999. /*----------------------------------------------------------------------------
  1000.  
  1001. physics.h - The header for the physics demo.
  1002.  
  1003. 10/15/96 - checker
  1004.  
  1005. */
  1006.  
  1007. #if !defined(PHYSICS_H)
  1008. #define PHYSICS_H
  1009.  
  1010. // explicit dependencies
  1011. #include "math2d.h"
  1012.  
  1013.  
  1014.  
  1015. /*----------------------------------------------------------------------------
  1016.  
  1017. Declarations for physics code.
  1018.  
  1019. */
  1020.  
  1021. struct rigid_body
  1022. {
  1023. real Width, Height;
  1024. real OneOverMass, OneOverCMMomentOfInertia;
  1025. real CoefficientOfRestitution;
  1026.  
  1027. enum { NumberOfConfigurations = 2 };
  1028.  
  1029. struct configuration
  1030. {
  1031. vector_2 CMPosition;
  1032. real Orientation;
  1033.  
  1034. vector_2 CMVelocity;
  1035. real AngularVelocity;
  1036.  
  1037. vector_2 CMForce;
  1038. real Torque;
  1039.  
  1040. struct bounding_box
  1041. {
  1042. vector_2 aVertices[4];
  1043.  
  1044. } BoundingBox;
  1045.  
  1046. } aConfigurations[NumberOfConfigurations];
  1047. };
  1048.  
  1049. class simulation_world
  1050. {
  1051. public:
  1052.  
  1053. simulation_world( real WorldWidth, real WorldHeight );
  1054.  
  1055. void Simulate( real DeltaTime );
  1056. void Render( void );
  1057.  
  1058. ~simulation_world( void );
  1059.  
  1060. private:
  1061.  
  1062. enum collision_state
  1063. {
  1064. Penetrating,
  1065. Colliding,
  1066. Clear
  1067. } CollisionState;
  1068.  
  1069. vector_2 CollisionNormal;
  1070. int CollidingBodyIndex;
  1071. int CollidingCornerIndex;
  1072.  
  1073. int SourceConfigurationIndex;
  1074. int TargetConfigurationIndex;
  1075.  
  1076. void ComputeForces( int ConfigurationIndex );
  1077. void Integrate( real DeltaTime );
  1078. collision_state CheckForCollisions( int ConfigurationIndex );
  1079. void ResolveCollisions( int ConfigurationIndex );
  1080. void CalculateVertices( int ConfigurationIndex );
  1081.  
  1082. real WorldWidth, WorldHeight;
  1083.  
  1084. enum { NumberOfWalls = 5 };
  1085. struct wall
  1086. {
  1087. // define wall by plane equation
  1088. vector_2 Normal; // inward pointing
  1089. real c; // ax + by + c = 0
  1090.  
  1091. // points for drawing wall
  1092. vector_2 StartPoint;
  1093. vector_2 EndPoint;
  1094. } aWalls[NumberOfWalls];
  1095.  
  1096. enum { NumberOfBodies = 2 };
  1097. rigid_body aBodies[NumberOfBodies];
  1098. };
  1099.  
  1100. #endif
  1101.  
  1102. /*----------------------------------------------------------------------------
  1103.  
  1104. 2D Physics Test Program - a cheesy test harness for 2D physics
  1105.  
  1106. by Chris Hecker for my Game Developer Magazine articles. See my homepage
  1107. for more information.
  1108.  
  1109. NOTE: This is a hacked test program, not a nice example of Windows programming.
  1110. physics.cpp the only part of this you should look at!!!
  1111.  
  1112. This material is Copyright 1997 Chris Hecker, All Rights Reserved.
  1113. It's for you to read and learn from, not to put in your own articles
  1114. or books or on your website, etc. Thank you.
  1115.  
  1116. Chris Hecker
  1117. checker@d6.com
  1118. http://www.d6.com/users/checker
  1119.  
  1120. */
  1121.  
  1122. #include "windows.h"
  1123. #include "win32.h"
  1124.  
  1125. AppIcon ICON physics.ico
  1126.  
  1127. AppAbout DIALOG DISCARDABLE 0, 0, 255, 86
  1128. STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
  1129. CAPTION "About the Cheesy Physics App"
  1130. FONT 8, "MS Sans Serif"
  1131. BEGIN
  1132. DEFPUSHBUTTON "OK",IDOK,5,65,50,14
  1133. LTEXT "Cheesy 2D Physics Test App for my Game Developer Magazine articles",
  1134. -1,5,5,250,8
  1135. LTEXT "by Chris Hecker (checker@netcom.com)",-1,5,15,150,8
  1136. LTEXT "http://ourworld.compuserve.com/homepages/checker",-1,5,25,250,8
  1137. ICON "AppIcon",-1,225,30,0,0
  1138. END
  1139.  
  1140. AppMenu menu
  1141. begin
  1142. POPUP "&File"
  1143. BEGIN
  1144. MENUITEM "&About", MENU_ABOUT
  1145. END
  1146. POPUP "&Toggles"
  1147. BEGIN
  1148. MENUITEM "&WorldSpringaW", MENU_WORLDSPRING
  1149. MENUITEM "&BodySpringaB", MENU_BODYSPRING
  1150. MENUITEM "&DampingaD", MENU_DAMPING
  1151. MENUITEM "&GravityaG", MENU_GRAVITY
  1152. END
  1153. end
  1154.  
  1155. /* strstream.h -- class strstream declarations
  1156.  
  1157. */
  1158.  
  1159. /*
  1160. * C/C++ Run Time Library - Version 6.5
  1161. *
  1162. * Copyright (c) 1990, 1994 by Borland International
  1163. * All Rights Reserved.
  1164. *
  1165. */
  1166.  
  1167. #ifndef __cplusplus
  1168. #error Must use C++ for the type strstream.
  1169. #endif
  1170.  
  1171. #ifndef __STRSTREAM_H
  1172. #define __STRSTREAM_H
  1173.  
  1174. #if !defined(___DEFS_H)
  1175. #include <_defs.h>
  1176. #endif
  1177.  
  1178. #if !defined(__IOSTREAM_H)
  1179. #include <iostream.h>
  1180. #endif
  1181.  
  1182.  
  1183. #if !defined(RC_INVOKED)
  1184.  
  1185. #pragma option -a-
  1186.  
  1187. #if defined(__BCOPT__)
  1188. #if !defined(_RTL_ALLOW_po) && !defined(__FLAT__)
  1189. #pragma option -po- // disable Object data calling convention
  1190. #endif
  1191. #endif
  1192.  
  1193. #if !defined(__TINY__)
  1194. #pragma option -RT
  1195. #endif
  1196.  
  1197. #pragma option -Vo-
  1198.  
  1199. #if defined(__STDC__)
  1200. #pragma warn -nak
  1201. #endif
  1202.  
  1203. #endif /* !RC_INVOKED */
  1204.  
  1205.  
  1206. _CLASSDEF(strstreambuf)
  1207. _CLASSDEF(strstreambase)
  1208. _CLASSDEF(istrstream)
  1209. _CLASSDEF(ostrstream)
  1210. _CLASSDEF(strstream)
  1211.  
  1212. class _EXPCLASS strstreambuf : public streambuf {
  1213. public:
  1214. _RTLENTRY strstreambuf();
  1215. _RTLENTRY strstreambuf(int n);
  1216. _RTLENTRY strstreambuf(void _FAR * (*a)(long), void (*f)(void _FAR *));
  1217. _RTLENTRY strstreambuf( char _FAR * _s, int,
  1218. char _FAR * _strt=0);
  1219. _RTLENTRY strstreambuf(signed char _FAR * _s, int,
  1220. signed char _FAR * _strt=0);
  1221. _RTLENTRY strstreambuf(unsigned char _FAR * _s, int,
  1222. unsigned char _FAR * _strt=0);
  1223. _RTLENTRY ~strstreambuf();
  1224.  
  1225. void _RTLENTRY freeze(int = 1);
  1226. char _FAR * _RTLENTRY str();
  1227. virtual int _RTLENTRY doallocate();
  1228. virtual int _RTLENTRY overflow(int);
  1229. virtual int _RTLENTRY underflow();
  1230. virtual int _RTLENTRY sync();
  1231. virtual streambuf _FAR * _RTLENTRY setbuf(char _FAR *, int);
  1232. virtual streampos _RTLENTRY seekoff(streamoff, ios::seek_dir, int);
  1233.  
  1234. private:
  1235. void _FAR * _RTLENTRY (*allocf)(long);
  1236. void _RTLENTRY (*freef)(void _FAR *);
  1237. short ssbflags;
  1238. enum { dynamic = 1, frozen = 2, unlimited = 4 };
  1239. int next_alloc;
  1240.  
  1241. void _RTLENTRY init(char _FAR *, int, char _FAR *);
  1242. };
  1243.  
  1244.  
  1245. class _EXPCLASS strstreambase : public virtual ios {
  1246. public:
  1247. strstreambuf _FAR * _RTLENTRY rdbuf();
  1248.  
  1249. protected:
  1250. _RTLENTRY strstreambase(char _FAR *, int, char _FAR *);
  1251. _RTLENTRY strstreambase();
  1252. _RTLENTRY ~strstreambase();
  1253. private:
  1254. strstreambuf buf;
  1255. };
  1256. inline strstreambuf _FAR * _RTLENTRY strstreambase::rdbuf()
  1257. { return &this->buf; }
  1258.  
  1259.  
  1260. class _EXPCLASS istrstream : public strstreambase, public istream {
  1261. public:
  1262. _RTLENTRY istrstream( char _FAR *);
  1263. _RTLENTRY istrstream(signed char _FAR *);
  1264. _RTLENTRY istrstream(unsigned char _FAR *);
  1265. _RTLENTRY istrstream( char _FAR *, int);
  1266. _RTLENTRY istrstream(signed char _FAR *, int);
  1267. _RTLENTRY istrstream(unsigned char _FAR *, int);
  1268. _RTLENTRY ~istrstream();
  1269. };
  1270.  
  1271.  
  1272. class _EXPCLASS ostrstream : public strstreambase, public ostream {
  1273. public:
  1274. _RTLENTRY ostrstream( char _FAR *, int, int = ios::out);
  1275. _RTLENTRY ostrstream(signed char _FAR *, int, int = ios::out);
  1276. _RTLENTRY ostrstream(unsigned char _FAR *, int, int = ios::out);
  1277. _RTLENTRY ostrstream();
  1278. _RTLENTRY ~ostrstream();
  1279.  
  1280. char _FAR * _RTLENTRY str();
  1281. int _RTLENTRY pcount();
  1282. };
  1283. inline char _FAR * _RTLENTRY ostrstream::str()
  1284. { return strstreambase::rdbuf()->str(); }
  1285. inline int _RTLENTRY ostrstream::pcount()
  1286. { return strstreambase::rdbuf()->out_waiting(); }
  1287.  
  1288.  
  1289. class _EXPCLASS strstream : public strstreambase, public iostream {
  1290. public:
  1291. _RTLENTRY strstream();
  1292. _RTLENTRY strstream( char _FAR *, int _sz, int _m);
  1293. _RTLENTRY strstream(signed char _FAR *, int _sz, int _m);
  1294. _RTLENTRY strstream(unsigned char _FAR *, int _sz, int _m);
  1295. _RTLENTRY ~strstream();
  1296.  
  1297. char _FAR * _RTLENTRY str();
  1298. };
  1299. inline char _FAR * _RTLENTRY strstream::str()
  1300. { return strstreambase::rdbuf()->str(); }
  1301.  
  1302.  
  1303. #if !defined(RC_INVOKED)
  1304.  
  1305. #if defined(__STDC__)
  1306. #pragma warn .nak
  1307. #endif
  1308.  
  1309. #pragma option -Vo.
  1310.  
  1311. #if !defined(__TINY__)
  1312. #pragma option -RT.
  1313. #endif
  1314.  
  1315. #if defined(__BCOPT__)
  1316. #if !defined(_RTL_ALLOW_po) && !defined(__FLAT__)
  1317. #pragma option -po. // restore Object data calling convention
  1318. #endif
  1319. #endif
  1320.  
  1321. #pragma option -a. /* restore default packing */
  1322.  
  1323. #endif /* !RC_INVOKED */
  1324.  
  1325.  
  1326. #endif /* __STRSTREAM_H */
  1327.  
  1328. /*----------------------------------------------------------------------------
  1329.  
  1330. 2D Physics Test Program - a cheesy test harness for 2D physics
  1331.  
  1332. by Chris Hecker for my Game Developer Magazine articles. See my homepage
  1333. for more information.
  1334.  
  1335. NOTE: This is a hacked test program, not a nice example of Windows programming.
  1336. physics.cpp the only part of this you should look at!!!
  1337.  
  1338. This material is Copyright 1997 Chris Hecker, All Rights Reserved.
  1339. It's for you to read and learn from, not to put in your own articles
  1340. or books or on your website, etc. Thank you.
  1341.  
  1342. Chris Hecker
  1343. checker@d6.com
  1344. http://www.d6.com/users/checker
  1345.  
  1346. */
  1347.  
  1348. #define WIN32_LEAN_AND_MEAN
  1349. #define WIN32_EXTRA_LEAN
  1350. #include <windows.h>
  1351. #include <windowsx.h>
  1352. #include <mmsystem.h>
  1353. #include <commdlg.h>
  1354. #include <stdlib.h>
  1355. #include <math.h>
  1356. #include <assert.h>
  1357.  
  1358. #include "win32.h"
  1359. #include "iface.h"
  1360.  
  1361. #pragma warning (disable:4244) // conversion from float to int
  1362.  
  1363. /*----------------------------------------------------------------------------
  1364.  
  1365. Globals and declarations
  1366.  
  1367. */
  1368.  
  1369. char szAppName[200] = "Cheesy 2D Physics App";
  1370.  
  1371. HINSTANCE hInstApp;
  1372. HWND hwndApp;
  1373. HPALETTE hpalApp;
  1374. BOOL fAppActive;
  1375.  
  1376. LONG FAR PASCAL AppWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam);
  1377. LONG AppCommand (HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam);
  1378. int AppPaint (HWND hwnd, HDC hdc);
  1379.  
  1380. void AppExit(void);
  1381. BOOL AppIdle(void);
  1382.  
  1383. HBITMAP OldBitmap;
  1384. HDC BufferDC;
  1385. HBITMAP BufferBitmap;
  1386.  
  1387. /*----------------------------------------------------------------------------*
  1388. | AppAbout( hDlg, uiMessage, wParam, lParam ) |
  1389. | |
  1390. | Description: |
  1391. | This function handles messages belonging to the "About" dialog box. |
  1392. | The only message that it looks for is WM_COMMAND, indicating the use |
  1393. | has pressed the "OK" button. When this happens, it takes down |
  1394. | the dialog box. |
  1395. | |
  1396. | Arguments: |
  1397. | hDlg window handle of about dialog window |
  1398. | uiMessage message number |
  1399. | wParam message-dependent |
  1400. | lParam message-dependent |
  1401. | |
  1402. | Returns: |
  1403. | TRUE if message has been processed, else FALSE |
  1404. | |
  1405. *----------------------------------------------------------------------------*/
  1406. BOOL FAR PASCAL AppAbout(HWND hwnd,UINT msg,WPARAM wParam,
  1407. LPARAM /* lParam */ )
  1408. {
  1409. switch (msg)
  1410. {
  1411. case WM_COMMAND:
  1412. if (LOWORD(wParam) == IDOK)
  1413. {
  1414. EndDialog(hwnd,TRUE);
  1415. }
  1416. break;
  1417.  
  1418. case WM_INITDIALOG:
  1419. return TRUE;
  1420. }
  1421. return FALSE;
  1422. }
  1423.  
  1424. /*----------------------------------------------------------------------------*
  1425. | AppInit( hInst, hPrev) |
  1426. | |
  1427. | Description: |
  1428. | This is called when the application is first loaded into |
  1429. | memory. It performs all initialization that doesn't need to be done |
  1430. | once per instance. |
  1431. | |
  1432. | Arguments: |
  1433. | hInstance instance handle of current instance |
  1434. | hPrev instance handle of previous instance |
  1435. | |
  1436. | Returns: |
  1437. | TRUE if successful, FALSE if not |
  1438. | |
  1439. *----------------------------------------------------------------------------*/
  1440. BOOL AppInit(HINSTANCE hInst,HINSTANCE hPrev,int sw,LPSTR szCmdLine)
  1441. {
  1442. WNDCLASS cls;
  1443.  
  1444. /* Save instance handle for DialogBoxs */
  1445. hInstApp = hInst;
  1446.  
  1447. if (!hPrev)
  1448. {
  1449. /*
  1450. * Register a class for the main application window
  1451. */
  1452. cls.hCursor = LoadCursor(NULL,IDC_ARROW);
  1453. cls.hIcon = LoadIcon(hInst,"AppIcon");
  1454. cls.lpszMenuName = "AppMenu";
  1455. cls.lpszClassName = szAppName;
  1456. cls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  1457. cls.hInstance = hInst;
  1458. cls.style = CS_BYTEALIGNCLIENT | CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
  1459. cls.lpfnWndProc = (WNDPROC)AppWndProc;
  1460. cls.cbWndExtra = 0;
  1461. cls.cbClsExtra = 0;
  1462.  
  1463. if (!RegisterClass(&cls))
  1464. return FALSE;
  1465. }
  1466.  
  1467. DWORD Style = WS_OVERLAPPEDWINDOW;
  1468. RECT WindowRect = { 0, 0 };
  1469. WindowRect.right = WorldWidth;
  1470. WindowRect.bottom = WorldHeight;
  1471.  
  1472. AdjustWindowRect(&WindowRect,Style,TRUE);
  1473.  
  1474. hwndApp = CreateWindow(szAppName,szAppName,Style,
  1475. CW_USEDEFAULT,0,
  1476. WindowRect.right-WindowRect.left,
  1477. WindowRect.bottom-WindowRect.top,
  1478. 0,0,hInst,0);
  1479.  
  1480.  
  1481.  
  1482. // create buffer bitmap
  1483.  
  1484. HDC Screen = GetDC(0);
  1485. BufferDC = CreateCompatibleDC(0);
  1486. BufferBitmap = CreateCompatibleBitmap(Screen,WorldWidth,WorldHeight);
  1487. OldBitmap = SelectBitmap(BufferDC,BufferBitmap);
  1488. ReleaseDC(0,Screen);
  1489.  
  1490. ShowWindow(hwndApp,sw);
  1491.  
  1492. return TRUE;
  1493. }
  1494.  
  1495.  
  1496. /*----------------------------------------------------------------------------*
  1497. | AppExit() |
  1498. | |
  1499. | Description: |
  1500. | app is just about to exit, cleanup |
  1501. | |
  1502. *----------------------------------------------------------------------------*/
  1503. void AppExit()
  1504. {
  1505. SelectObject(BufferDC,OldBitmap);
  1506. DeleteObject(BufferBitmap);
  1507. DeleteDC(BufferDC);
  1508. }
  1509.  
  1510. BOOL AppIdle()
  1511. {
  1512. if (fAppActive)
  1513. {
  1514. HDC WindowDC = GetDC(hwndApp);
  1515. AppPaint(hwndApp,WindowDC);
  1516. ReleaseDC(hwndApp,WindowDC);
  1517.  
  1518. return FALSE;
  1519. }
  1520. else
  1521. {
  1522. //
  1523. // we are a background app.
  1524. //
  1525. return TRUE; // nothing to do.
  1526. }
  1527. }
  1528.  
  1529. /*----------------------------------------------------------------------------*
  1530. | WinMain( hInst, hPrev, lpszCmdLine, cmdShow ) |
  1531. | |
  1532. | Description: |
  1533. | The main procedure for the App. After initializing, it just goes |
  1534. | into a message-processing loop until it gets a WM_QUIT message |
  1535. | (meaning the app was closed). |
  1536. | |
  1537. | Arguments: |
  1538. | hInst instance handle of this instance of the app |
  1539. | hPrev instance handle of previous instance, NULL if first |
  1540. | szCmdLine ->null-terminated command line |
  1541. | cmdShow specifies how the window is initially displayed |
  1542. | |
  1543. | Returns: |
  1544. | The exit code as specified in the WM_QUIT message. |
  1545. | |
  1546. *----------------------------------------------------------------------------*/
  1547. int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
  1548. {
  1549. MSG msg;
  1550.  
  1551. /* Call initialization procedure */
  1552. if (!AppInit(hInst,hPrev,sw,szCmdLine))
  1553. return FALSE;
  1554.  
  1555. /*
  1556. * Polling messages from event queue
  1557. */
  1558. for (;;)
  1559. {
  1560. if (PeekMessage(&msg, NULL, 0, 0,PM_REMOVE))
  1561. {
  1562. if (msg.message == WM_QUIT)
  1563. break;
  1564.  
  1565. TranslateMessage(&msg);
  1566. DispatchMessage(&msg);
  1567. }
  1568. else
  1569. {
  1570. if (AppIdle())
  1571. WaitMessage();
  1572. }
  1573. }
  1574.  
  1575.  
  1576. AppExit();
  1577. return msg.wParam;
  1578. }
  1579.  
  1580. /*----------------------------------------------------------------------------*
  1581. | AppPaint(hwnd, hdc) |
  1582. | |
  1583. | Description: |
  1584. | The paint function. Right now this does nothing. |
  1585. | |
  1586. | Arguments: |
  1587. | hwnd window painting into |
  1588. | hdc display context to paint to |
  1589. | |
  1590. | Returns: |
  1591. | nothing |
  1592. | |
  1593. *----------------------------------------------------------------------------*/
  1594. int AppPaint (HWND hwnd, HDC hdc)
  1595. {
  1596. RECT rc;
  1597. GetClientRect(hwnd, &rc);
  1598.  
  1599. PatBlt(BufferDC,0,0,WorldWidth,WorldHeight,WHITENESS);
  1600.  
  1601. Run(); // run the physics
  1602.  
  1603. BitBlt(hdc,0,0,rc.right,rc.bottom,BufferDC,0,0,SRCCOPY);
  1604.  
  1605. return TRUE;
  1606. }
  1607.  
  1608. /*----------------------------------------------------------------------------*
  1609. | AppWndProc( hwnd, uiMessage, wParam, lParam ) |
  1610. | |
  1611. | Description: |
  1612. | The window proc for the app's main (tiled) window. This processes all |
  1613. | of the parent window's messages. |
  1614. | |
  1615. *----------------------------------------------------------------------------*/
  1616. LONG FAR PASCAL AppWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
  1617. {
  1618. PAINTSTRUCT ps;
  1619. HDC hdc;
  1620.  
  1621. switch (msg)
  1622. {
  1623. case WM_CREATE:
  1624. break;
  1625.  
  1626. case WM_ACTIVATEAPP:
  1627. fAppActive = (BOOL)wParam;
  1628. break;
  1629.  
  1630. case WM_KEYDOWN:
  1631. {
  1632. switch(wParam)
  1633. {
  1634. case 'W':
  1635. {
  1636. SendMessage(hwnd,WM_COMMAND,MENU_WORLDSPRING,0);
  1637. break;
  1638. }
  1639. case 'B':
  1640. {
  1641. SendMessage(hwnd,WM_COMMAND,MENU_BODYSPRING,0);
  1642. break;
  1643. }
  1644. case 'D':
  1645. {
  1646. SendMessage(hwnd,WM_COMMAND,MENU_DAMPING,0);
  1647. break;
  1648. }
  1649. case 'G':
  1650. {
  1651. SendMessage(hwnd,WM_COMMAND,MENU_GRAVITY,0);
  1652. break;
  1653. }
  1654. break;
  1655. }
  1656. }
  1657.  
  1658. case WM_LBUTTONDOWN:
  1659. {
  1660. break;
  1661. }
  1662.  
  1663. case WM_MOUSEMOVE:
  1664. {
  1665. break;
  1666. }
  1667.  
  1668. case WM_LBUTTONUP:
  1669. {
  1670. break;
  1671. }
  1672.  
  1673. case WM_ERASEBKGND:
  1674. break;
  1675.  
  1676. case WM_INITMENU:
  1677. break;
  1678.  
  1679. case WM_COMMAND:
  1680. return AppCommand(hwnd,msg,wParam,lParam);
  1681.  
  1682. case WM_DESTROY:
  1683. PostQuitMessage(0);
  1684. break;
  1685.  
  1686. case WM_CLOSE:
  1687. break;
  1688.  
  1689. case WM_PAINT:
  1690. hdc = BeginPaint(hwnd,&ps);
  1691. AppPaint (hwnd,hdc);
  1692. EndPaint(hwnd,&ps);
  1693. return 0L;
  1694.  
  1695. case WM_SIZE:
  1696. break;
  1697. }
  1698. return DefWindowProc(hwnd,msg,wParam,lParam);
  1699. }
  1700.  
  1701. /*----------------------------------------------------------------------------*
  1702. | AppCommand(hwnd, msg, wParam, lParam ) |
  1703. | |
  1704. | Description: |
  1705. | handles WM_COMMAND messages for the main window (hwndApp) |
  1706. | of the parent window's messages. |
  1707. | |
  1708. *----------------------------------------------------------------------------*/
  1709. LONG AppCommand (HWND hwnd,UINT /* msg */,WPARAM wParam,LPARAM /* lParam */)
  1710. {
  1711. switch(wParam)
  1712. {
  1713. case MENU_ABOUT:
  1714. DialogBox(hInstApp,"AppAbout",hwnd,AppAbout);
  1715. break;
  1716.  
  1717. case MENU_WORLDSPRING:
  1718. ToggleWorldSpring();
  1719. break;
  1720. case MENU_BODYSPRING:
  1721. ToggleBodySpring();
  1722. break;
  1723. case MENU_DAMPING:
  1724. ToggleDamping();
  1725. break;
  1726. case MENU_GRAVITY:
  1727. ToggleGravity();
  1728. break;
  1729.  
  1730. case MENU_EXIT:
  1731. PostMessage(hwnd,WM_CLOSE,0,0L);
  1732. break;
  1733. }
  1734. return 0L;
  1735. }
  1736.  
  1737. extern "C" void __cdecl _assert( void *pExpression, void *pFile,
  1738. unsigned LineNumber )
  1739. {
  1740. char aBuffer[500];
  1741. wsprintf(aBuffer,"Assertion: %snFile: %s, Line: %dn"
  1742. "Hit Abort to exit, Retry to debug, Ignore to continue",
  1743. pExpression,pFile,LineNumber);
  1744.  
  1745. int Hit = MessageBox(hwndApp,aBuffer,"Assert!",MB_ABORTRETRYIGNORE |
  1746. MB_ICONHAND);
  1747.  
  1748. if(Hit == IDABORT)
  1749. {
  1750. exit(0);
  1751. }
  1752. else
  1753. if(Hit == IDRETRY)
  1754. {
  1755. DebugBreak();
  1756. }
  1757. }
  1758.  
  1759. /*----------------------------------------------------------------------------
  1760.  
  1761. iface.h functions
  1762.  
  1763. */
  1764.  
  1765. void Line( int X0, int Y0, int X1, int Y1 )
  1766. {
  1767. MoveToEx(BufferDC,(WorldWidth/2)+X0,(WorldHeight/2)-Y0,0);
  1768. LineTo(BufferDC,(WorldWidth/2)+X1,(WorldHeight/2)-Y1);
  1769. }
  1770.  
  1771. float GetTime( void )
  1772. {
  1773. static DWORD StartMilliseconds;
  1774. if(!StartMilliseconds)
  1775. {
  1776. // yes, the first time through will be a 0 timestep
  1777. StartMilliseconds = timeGetTime();
  1778. }
  1779.  
  1780. DWORD CurrentMilliseconds = timeGetTime();
  1781. return float(CurrentMilliseconds - StartMilliseconds) / 1000.0f;
  1782. }
  1783.  
  1784. /*----------------------------------------------------------------------------
  1785.  
  1786. 2D Physics Test Program - a cheesy test harness for 2D physics
  1787.  
  1788. by Chris Hecker for my Game Developer Magazine articles. See my homepage
  1789. for more information.
  1790.  
  1791. NOTE: This is a hacked test program, not a nice example of Windows programming.
  1792. physics.cpp the only part of this you should look at!!!
  1793.  
  1794. This material is Copyright 1997 Chris Hecker, All Rights Reserved.
  1795. It's for you to read and learn from, not to put in your own articles
  1796. or books or on your website, etc. Thank you.
  1797.  
  1798. Chris Hecker
  1799. checker@d6.com
  1800. http://www.d6.com/users/checker
  1801.  
  1802. */
  1803.  
  1804. /* Menu Items */
  1805. #define MENU_ABOUT 0
  1806. #define MENU_EXIT 1
  1807. #define MENU_WORLDSPRING 2
  1808. #define MENU_BODYSPRING 3
  1809. #define MENU_DAMPING 4
  1810. #define MENU_GRAVITY 5
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement