소스 검색

Add env test

Miloslav Ciz 3 년 전
부모
커밋
6e2bbf64d4
6개의 변경된 파일193개의 추가작업 그리고 30개의 파일을 삭제
  1. 8 5
      TODO.txt
  2. 8 8
      programs/helper.h
  3. 1 1
      programs/make.sh
  4. 17 12
      programs/stack.c
  5. 45 0
      programs/test.c
  6. 114 4
      tinyphysicsengine.h

+ 8 - 5
TODO.txt

@@ -1,19 +1,19 @@
 TODO:
 TODO:
 - demo: angry-birds-like game
 - demo: angry-birds-like game
-- elasticity doesn't really work in cases when there is an opposing joint to the
-  colliding joint, the speeds always cancel out -- leave as is or somehow fix?
-- function that tests a validity of an environemnt function, i.e. if it behaves
+- function that tests validity of an environemnt function, i.e. if it behaves
   mathematically correct + test built in env functions with it
   mathematically correct + test built in env functions with it
-- zero weight joints should behave how?
-- test env functions with a single distinct point near camera
 - env function: heightmap
 - env function: heightmap
+- BUG: envBox function doesn't pass the env function test!
 - bounding box/sphere test functions/macros for optimization of environment
 - bounding box/sphere test functions/macros for optimization of environment
   building, plus a demo that tests if it actually accelerates it
   building, plus a demo that tests if it actually accelerates it
 - test ray casting (e.g. the hit of an outside ray should always be outside)
 - test ray casting (e.g. the hit of an outside ray should always be outside)
+- try to make better car physics
 
 
 DONE:
 DONE:
 - demo: car
 - demo: car
+- zero weight joints should behave how? <-- disallowed 0 mass
 - demo: testing different frictions on skewed plane, also different elasticities
 - demo: testing different frictions on skewed plane, also different elasticities
+- test env functions with a single distinct point near camera
 - bug? bodies stuck inside each other resist falling down by gravity (stack.c)
 - bug? bodies stuck inside each other resist falling down by gravity (stack.c)
   ^ Seems to be okay now?
   ^ Seems to be okay now?
 - test different tick lengths (demo) <-- seems OK
 - test different tick lengths (demo) <-- seems OK
@@ -22,6 +22,9 @@ DONE:
 - check if using fastBSphere vs normal BSphere doesn't affect the simulation
 - check if using fastBSphere vs normal BSphere doesn't affect the simulation
   result (it shouldn't) <-- on stacks.c gave the same world hash
   result (it shouldn't) <-- on stacks.c gave the same world hash
 - fine tune the number of reshapes needed for nice behavior
 - fine tune the number of reshapes needed for nice behavior
+- elasticity doesn't really work in cases when there is an opposing joint to the
+  colliding joint, the speeds always cancel out -- leave as is or somehow fix?
+  ^ let's just ignore it
 - body being pushed (e.g. by gravity) onto a sharp edge will likely not resist
 - body being pushed (e.g. by gravity) onto a sharp edge will likely not resist
   (due to only linear forces in connections) and will very easily be split very
   (due to only linear forces in connections) and will very easily be split very
   wide -- TRY AND FIX! Fix could be e.g. in a special function that checks
   wide -- TRY AND FIX! Fix could be e.g. in a special function that checks

+ 8 - 8
programs/helper.h

@@ -620,7 +620,7 @@ void s3l_drawPixel(S3L_PixelInfo *p)
   sdl_drawPixel(p->x,p->y,s3l_rr,s3l_gg,s3l_bb);
   sdl_drawPixel(p->x,p->y,s3l_rr,s3l_gg,s3l_bb);
 }
 }
 
 
-void helper_set3dColor(uint8_t r, uint8_t g, uint8_t b)
+void helper_set3DColor(uint8_t r, uint8_t g, uint8_t b)
 {
 {
   s3l_r = r;
   s3l_r = r;
   s3l_g = g;
   s3l_g = g;
@@ -679,7 +679,7 @@ void helper_drawModel(S3L_Model3D *model, TPE_Vec3 pos, TPE_Vec3 scale,
 #endif
 #endif
 }
 }
 
 
-void helper_draw3dTriangle(TPE_Vec3 v1, TPE_Vec3 v2, TPE_Vec3 v3)
+void helper_draw3DTriangle(TPE_Vec3 v1, TPE_Vec3 v2, TPE_Vec3 v3)
 {
 {
   triangleVertices[0] = v1.x; 
   triangleVertices[0] = v1.x; 
   triangleVertices[1] = v1.y; 
   triangleVertices[1] = v1.y; 
@@ -696,35 +696,35 @@ void helper_draw3dTriangle(TPE_Vec3 v1, TPE_Vec3 v2, TPE_Vec3 v3)
     TPE_vec3(0,0,0)); 
     TPE_vec3(0,0,0)); 
 }
 }
 
 
-void helper_draw3dBox(TPE_Vec3 pos, TPE_Vec3 scale, TPE_Vec3 rot)
+void helper_draw3DBox(TPE_Vec3 pos, TPE_Vec3 scale, TPE_Vec3 rot)
 {
 {
   cubeModel.config.backfaceCulling = 2;
   cubeModel.config.backfaceCulling = 2;
   helper_drawModel(&cubeModel,pos,scale,rot);
   helper_drawModel(&cubeModel,pos,scale,rot);
 }
 }
 
 
-void helper_draw3dCylinder(TPE_Vec3 pos, TPE_Vec3 scale, TPE_Vec3 rot)
+void helper_draw3DCylinder(TPE_Vec3 pos, TPE_Vec3 scale, TPE_Vec3 rot)
 {
 {
   helper_drawModel(&cylinderModel,pos,scale,rot);
   helper_drawModel(&cylinderModel,pos,scale,rot);
 }
 }
 
 
-void helper_draw3dBoxInside(TPE_Vec3 pos, TPE_Vec3 scale, TPE_Vec3 rot)
+void helper_draw3DBoxInside(TPE_Vec3 pos, TPE_Vec3 scale, TPE_Vec3 rot)
 {
 {
   cubeModel.config.backfaceCulling = 1;
   cubeModel.config.backfaceCulling = 1;
   helper_drawModel(&cubeModel,pos,scale,rot);
   helper_drawModel(&cubeModel,pos,scale,rot);
 }
 }
 
 
-void helper_draw3dPlane(TPE_Vec3 pos, TPE_Vec3 scale, TPE_Vec3 rot)
+void helper_draw3DPlane(TPE_Vec3 pos, TPE_Vec3 scale, TPE_Vec3 rot)
 {
 {
   helper_drawModel(&planeModel,pos,scale,rot);
   helper_drawModel(&planeModel,pos,scale,rot);
 }
 }
 
 
-void helper_draw3dSphere(TPE_Vec3 pos, TPE_Vec3 scale, TPE_Vec3 rot)
+void helper_draw3DSphere(TPE_Vec3 pos, TPE_Vec3 scale, TPE_Vec3 rot)
 {
 {
   sphereModel.config.backfaceCulling = 2;
   sphereModel.config.backfaceCulling = 2;
   helper_drawModel(&sphereModel,pos,scale,rot);
   helper_drawModel(&sphereModel,pos,scale,rot);
 }
 }
 
 
-void helper_draw3dSphereInside(TPE_Vec3 pos, TPE_Vec3 scale, TPE_Vec3 rot)
+void helper_draw3DSphereInside(TPE_Vec3 pos, TPE_Vec3 scale, TPE_Vec3 rot)
 {
 {
   sphereModel.config.backfaceCulling = 1;
   sphereModel.config.backfaceCulling = 1;
   helper_drawModel(&sphereModel,pos,scale,rot);
   helper_drawModel(&sphereModel,pos,scale,rot);

+ 1 - 1
programs/make.sh

@@ -1,5 +1,5 @@
 #!/bin/bash
 #!/bin/bash
 
 
-PROGRAM=water # change this to name of a program you want to compile :)
+PROGRAM=test # change this to name of a program you want to compile :)
 
 
 clear; clear; g++ -x c -g -fmax-errors=5 -pedantic -O3 -Wall -Wextra -Wstrict-prototypes -Wold-style-definition -Wno-unused-parameter -Wno-missing-field-initializers -o $PROGRAM $PROGRAM.c -lm -lSDL2 && ./$PROGRAM
 clear; clear; g++ -x c -g -fmax-errors=5 -pedantic -O3 -Wall -Wextra -Wstrict-prototypes -Wold-style-definition -Wno-unused-parameter -Wno-missing-field-initializers -o $PROGRAM $PROGRAM.c -lm -lSDL2 && ./$PROGRAM

+ 17 - 12
programs/stack.c

@@ -69,6 +69,11 @@ int main(void)
 
 
     timeMeasure += helper_getMicroSecs() - t1;
     timeMeasure += helper_getMicroSecs() - t1;
 
 
+
+
+
+
+
 if (helper_frame == 200)
 if (helper_frame == 200)
   printf("hash: %lu\n",TPE_worldHash(&tpe_world));
   printf("hash: %lu\n",TPE_worldHash(&tpe_world));
 
 
@@ -94,7 +99,7 @@ if (helper_frame == 200)
 
 
       TPE_Vec3 orient = TPE_rotationFromVecs(forw,right);
       TPE_Vec3 orient = TPE_rotationFromVecs(forw,right);
     
     
-      helper_set3dColor(100 + i * 5,16 - i,100 - i * 5); 
+      helper_set3DColor(100 + i * 5,16 - i,100 - i * 5); 
 
 
 bodyPositions[i] =
 bodyPositions[i] =
 TPE_vec3KeepWithinBox(
 TPE_vec3KeepWithinBox(
@@ -117,21 +122,21 @@ bodyOrientations[i].z =
 
 
       switch (i % 5)
       switch (i % 5)
       {
       {
-        case 0: helper_draw3dBox(bodyPositions[i],TPE_vec3(1200,1200,1200),bodyOrientations[i]); break;
-        case 1: helper_draw3dTriangle(bodyPositions[i],joints[1].position,joints[2].position); break;
-        case 2: helper_draw3dSphere(bodyPositions[i],TPE_vec3(500,500,500),bodyOrientations[i]); break;
-        case 3: helper_draw3dBox(bodyPositions[i],TPE_vec3(1200,400,1200),bodyOrientations[i]); break; 
-        case 4: helper_draw3dBox(bodyPositions[i],TPE_vec3(200,200,1200),bodyOrientations[i]); break;
+        case 0: helper_draw3DBox(bodyPositions[i],TPE_vec3(1200,1200,1200),bodyOrientations[i]); break;
+        case 1: helper_draw3DTriangle(bodyPositions[i],joints[1].position,joints[2].position); break;
+        case 2: helper_draw3DSphere(bodyPositions[i],TPE_vec3(500,500,500),bodyOrientations[i]); break;
+        case 3: helper_draw3DBox(bodyPositions[i],TPE_vec3(1200,400,1200),bodyOrientations[i]); break; 
+        case 4: helper_draw3DBox(bodyPositions[i],TPE_vec3(200,200,1200),bodyOrientations[i]); break;
         default: break;
         default: break;
       }
       }
     }
     }
 
 
-    helper_set3dColor(100,100,100); 
-    helper_draw3dTriangle(TPE_vec3(0,0,0),TPE_vec3(-5000,5000,-10000),TPE_vec3(-5000,5000,10000));
-    helper_set3dColor(140,140,140);
-    helper_draw3dTriangle(TPE_vec3(0,0,0),TPE_vec3(-5000,5000,10000),TPE_vec3(5000,5000,0));
-    helper_set3dColor(80,80,80);
-    helper_draw3dTriangle(TPE_vec3(0,0,0),TPE_vec3(-5000,5000,-10000),TPE_vec3(5000,5000,0));
+    helper_set3DColor(100,100,100); 
+    helper_draw3DTriangle(TPE_vec3(0,0,0),TPE_vec3(-5000,5000,-10000),TPE_vec3(-5000,5000,10000));
+    helper_set3DColor(140,140,140);
+    helper_draw3DTriangle(TPE_vec3(0,0,0),TPE_vec3(-5000,5000,10000),TPE_vec3(5000,5000,0));
+    helper_set3DColor(80,80,80);
+    helper_draw3DTriangle(TPE_vec3(0,0,0),TPE_vec3(-5000,5000,-10000),TPE_vec3(5000,5000,0));
 
 
     if (helper_debugDrawOn)
     if (helper_debugDrawOn)
       helper_debugDraw(1);
       helper_debugDraw(1);

+ 45 - 0
programs/test.c

@@ -5,6 +5,37 @@
 
 
 #define ass(cond,text) { printf(text ": "); if (!(cond)) { puts("ERROR"); return 1; } else puts("OK"); }
 #define ass(cond,text) { printf(text ": "); if (!(cond)) { puts("ERROR"); return 1; } else puts("OK"); }
 
 
+TPE_Unit rampPoits[6] =
+{
+  0,0,
+  -2400,1400,
+  -2400,0
+};
+
+TPE_Vec3 envFunc(TPE_Vec3 p, TPE_Unit maxD)
+{
+  TPE_ENV_START( TPE_envAABoxInside(p,TPE_vec3(0,1000,0),TPE_vec3(3000,2500,3000)),p )
+  TPE_ENV_NEXT( TPE_envAATriPrism(p,TPE_vec3(100,200,-10),rampPoits,3000,2),p)
+//TPE_ENV_NEXT( TPE_envBox(p,TPE_vec3(-100,300,200),TPE_vec3(500,600,700),TPE_vec3(10,30,50)), p)
+  TPE_ENV_NEXT( TPE_envAABox(p,TPE_vec3(-100,300,200),TPE_vec3(500,600,700)), p)
+
+  TPE_ENV_END
+}
+
+TPE_Vec3 envFuncBad(TPE_Vec3 p, TPE_Unit maxD)
+{
+  p.x += 200;
+  return p;
+}
+
+TPE_Vec3 envFuncBad2(TPE_Vec3 p, TPE_Unit maxD)
+{
+  if (p.y > p.x)
+    p.x = p.y;
+
+  return p;
+}
+
 int main(void)
 int main(void)
 {
 {
   puts("== testing tinyphysicsengine ==");
   puts("== testing tinyphysicsengine ==");
@@ -88,6 +119,20 @@ int main(void)
       for (int j = i + 1; j < 4; ++j)
       for (int j = i + 1; j < 4; ++j)
         ass(wHashes[i] != wHashes[j],"world hash");
         ass(wHashes[i] != wHashes[j],"world hash");
   }
   }
+ 
+  {
+    puts("-- environment functions --");
+
+    ass(TPE_testClosestPointFunction(envFunc,TPE_vec3(-3000,-3000,-3000),
+      TPE_vec3(3000,3000,3000),32,10,0),"env function");
+
+    ass(!TPE_testClosestPointFunction(envFuncBad,TPE_vec3(-1000,-1000,-1000),
+      TPE_vec3(2000,3000,100),32,10,0),"env function bad");
+
+    ass(!TPE_testClosestPointFunction(envFuncBad2,TPE_vec3(-1000,-2000,-200),
+      TPE_vec3(1000,1000,2000),32,10,0),"env function bad");
+
+  }
 
 
 
 
   return 0;
   return 0;

+ 114 - 4
tinyphysicsengine.h

@@ -189,6 +189,7 @@ typedef struct
                                           to keep the body's shape. */
                                           to keep the body's shape. */
 
 
 static inline TPE_Unit TPE_abs(TPE_Unit x);
 static inline TPE_Unit TPE_abs(TPE_Unit x);
+static inline TPE_Unit TPE_max(TPE_Unit a, TPE_Unit b);
 
 
 /** Function used for defining static environment, working similarly to an SDF
 /** Function used for defining static environment, working similarly to an SDF
   (signed distance function). The parameters are: 3D point P, max distance D.
   (signed distance function). The parameters are: 3D point P, max distance D.
@@ -236,6 +237,24 @@ typedef struct
   TPE_CollisionCallback collisionCallback;
   TPE_CollisionCallback collisionCallback;
 } TPE_World;
 } TPE_World;
 
 
+/** Tests the mathematical validity of given closest point function (function
+  representing the physics environment), i.e. whether for example approaching
+  some closest point in a straight line keeps approximately the same closest
+  point. Note that this function may take a long time to complete, especially
+  with higher gridResolution values and more complex environment functions. You
+  should use this function to test your environment function, especially if you
+  create functions for your own shapes etc. The cornerFrom and cornerTo points
+  are corners of an axis-aligned box within which testing will take place, 
+  gridResolution defines numbers of points (i.e. step length) along each
+  dimension to test (recommended e.g. 64), allowedError says error within which
+  points will be considered the same (recommended range approx. 10 to 200). If
+  testing is successful, 1 is returned, otherwise 0 is returned and the point
+  around which error was detected is returned in errorPoint (unless the pointer
+  is 0 in which case it is ignored). */
+uint8_t TPE_testClosestPointFunction(TPE_ClosestPointFunction f,
+  TPE_Vec3 cornerFrom, TPE_Vec3 cornerTo, uint8_t gridResolution,
+  TPE_UnitReduced allowedError, TPE_Vec3 *errorPoint);
+
 void TPE_bodyInit(TPE_Body *body, 
 void TPE_bodyInit(TPE_Body *body, 
   TPE_Joint *joints, uint8_t jointCount, 
   TPE_Joint *joints, uint8_t jointCount, 
   TPE_Connection *connections, uint8_t connectionCount,
   TPE_Connection *connections, uint8_t connectionCount,
@@ -705,10 +724,7 @@ void TPE_bodyInit(TPE_Body *body,
 
 
   body->flags = 0;
   body->flags = 0;
 
 
-  body->jointMass = mass / jointCount;
- 
-  if (body->jointMass == 0)
-    body->jointMass = 1;
+  body->jointMass = TPE_nonZero(mass / jointCount);
 
 
   for (uint32_t i = 0; i < connectionCount; ++i)
   for (uint32_t i = 0; i < connectionCount; ++i)
   {
   {
@@ -2716,6 +2732,11 @@ TPE_Unit TPE_abs(TPE_Unit x)
   return x >= 0 ? x : (-1 * x);
   return x >= 0 ? x : (-1 * x);
 }
 }
 
 
+TPE_Unit TPE_max(TPE_Unit a, TPE_Unit b)
+{
+  return (a > b) ? a : b;
+}
+
 TPE_Vec3 TPE_envAATriPrism(TPE_Vec3 point, TPE_Vec3 center,
 TPE_Vec3 TPE_envAATriPrism(TPE_Vec3 point, TPE_Vec3 center,
   const TPE_Unit sides[6], TPE_Unit depth, uint8_t direction)
   const TPE_Unit sides[6], TPE_Unit depth, uint8_t direction)
 {
 {
@@ -2868,4 +2889,93 @@ void TPE_bodyMoveTo(TPE_Body *body, TPE_Vec3 position)
     body->joints[i].position = TPE_vec3Plus(body->joints[i].position,position);
     body->joints[i].position = TPE_vec3Plus(body->joints[i].position,position);
 }
 }
 
 
+uint8_t TPE_testClosestPointFunction(TPE_ClosestPointFunction f,
+  TPE_Vec3 cornerFrom, TPE_Vec3 cornerTo, uint8_t gridResolution,
+  TPE_UnitReduced allowedError, TPE_Vec3 *errorPoint)
+{
+  TPE_Vec3 p;
+
+  cornerTo = TPE_vec3Minus(cornerTo,cornerFrom);
+
+  for (uint16_t z = 0; z < gridResolution; ++z)
+  {
+    p.z = cornerFrom.z + (z * cornerTo.z) / gridResolution;
+
+    for (uint16_t y = 0; y < gridResolution; ++y)
+    {
+      p.y = cornerFrom.y + (y * cornerTo.y) / gridResolution;
+
+      for (uint16_t x = 0; x < gridResolution; ++x)
+      {
+        p.x = cornerFrom.x + (x * cornerTo.x) / gridResolution;
+
+        TPE_Vec3 p2 = f(p,TPE_INFINITY);
+
+        if (p.x != p2.x || p.y != p2.y || p.z != p2.z) // only test outside
+        {
+          // 1st try to approach the closest point and see if it stays the same:
+
+          TPE_Vec3 p3 = p;
+
+          for (uint8_t i = 0; i < 3; ++i)
+          {
+            p3 =
+              TPE_vec3((p3.x + p2.x) / 2,(p3.y + p2.y) / 2,(p3.z + p2.z) / 2);
+
+            TPE_Vec3 p4 = f(p3,TPE_INFINITY);
+
+            if (TPE_abs(p4.x - p2.x) + TPE_abs(p4.y - p2.y) 
+              + TPE_abs(p4.z - p2.z) > allowedError) // taxicab dist. for speed
+            {
+              if (errorPoint != 0)
+                *errorPoint = p;
+
+              return 0;
+            }
+          }
+ 
+          // now test 8 points inside the sphere of radius:
+
+          TPE_Unit d = TPE_DISTANCE(p,p2);
+
+          p3.z = p.z - d / 2;
+         
+          for (uint8_t zz = 0; zz < 2; ++zz)
+          {
+            p3.y = p.y - d / 2;
+
+            for (uint8_t yy = 0; yy < 2; ++yy)
+            {
+              p3.x = p.x - d / 2;
+
+              for (uint8_t zz = 0; zz < 2; ++zz)
+              {
+                if (TPE_DISTANCE(p,f(p3,TPE_INFINITY)) + allowedError < d)
+                {
+                  /* In the sphere of distance radius to the original point's
+                     closest point we've gotten a closer point which should
+                     never happen. */
+
+                  if (errorPoint != 0)
+                    *errorPoint = p;
+
+                  return 0;
+                }
+
+                p3.x += d;
+              }
+
+              p3.y += d;
+            }
+ 
+            p3.z += d;
+          }
+        }
+      }
+    }
+  }
+
+  return 1;
+}
+
 #endif // guard
 #endif // guard