Browse Source

Merge pull request #555 from blackberry-gaming/next-kwhatmough

Change heightmap format from grayscale to packed RGB. Maintain compatibi...
Sean Paul Taylor 13 years ago
parent
commit
69cda31f64

+ 7 - 3
gameplay-encoder/src/Mesh.cpp

@@ -225,10 +225,14 @@ void Mesh::generateHeightmap(const char* filename)
             // Write height value normalized between 0-255 (between min and max height)
             float h = heights[y*width + x];
             float nh = (h - minHeight) / maxHeight;
-            png_byte b = (png_byte)(nh * 255.0f);
-            
+            int bits = (int)(nh * 16777215.0f); // 2^24-1
+
             int pos = x*3;
-            row[pos] = row[pos+1] = row[pos+2] = b;
+            row[pos+2] = (png_byte)(bits & 0xff);
+            bits >>= 8;
+            row[pos+1] = (png_byte)(bits & 0xff);
+            bits >>= 8;
+            row[pos] = (png_byte)(bits & 0xff);
         }
         png_write_row(png_ptr, row);
     }

+ 25 - 3
gameplay/src/PhysicsController.cpp

@@ -1057,9 +1057,21 @@ PhysicsCollisionShape* PhysicsController::createHeightfield(Node* node, Image* i
     {
         for (unsigned int y = 0, h = image->getHeight(); y < h; ++y)
         {
-            heights[x + y * w] = ((((float)data[(x + y * h) * pixelSize + 0]) +
-                ((float)data[(x + y * h) * pixelSize + 1]) +
-                ((float)data[(x + y * h) * pixelSize + 2])) / 768.0f) * (maxHeight - minHeight) + minHeight;
+            //
+            // Orignially in GamePlay this was normalizedHeightGrayscale which generally yielded
+            // only 8-bit precision. This has been replaced by normalizedHeightPacked (with a
+            // corresponding change in gameplay-encoder).
+            //
+            // BACKWARD COMPATIBILITY
+            // In grayscale images where r=g=b this will maintain some degree of compatibility,
+            // to within 0.4%. This can be seen by setting r=g=b=x and comparing the grayscale
+            // height expression to the packed height expression: the error is 2^-8 + 2^-16
+            // which is just under 0.4%.
+            //
+            heights[x + y * w] = normalizedHeightPacked(
+                data[(x + y * h) * pixelSize + 0],
+                data[(x + y * h) * pixelSize + 1],
+                data[(x + y * h) * pixelSize + 2]) * (maxHeight - minHeight) + minHeight;
         }
     }
 
@@ -1382,6 +1394,16 @@ float PhysicsController::calculateHeight(float* data, unsigned int width, unsign
     }
 }
 
+float PhysicsController::normalizedHeightGrayscale(float r, float g, float b)
+{
+    return (r + g + b) / 768.0f;
+}
+
+float PhysicsController::normalizedHeightPacked(float r, float g, float b)
+{
+    return (256.0f*r + g + 0.00390625f*b) / 65536.0f;
+}
+
 void PhysicsController::addConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b, PhysicsConstraint* constraint)
 {
     GP_ASSERT(a);

+ 6 - 0
gameplay/src/PhysicsController.h

@@ -457,6 +457,12 @@ private:
     static float calculateHeight(float* data, unsigned int width, unsigned int height, float x, float y,
         const Matrix* worldMatrix = NULL, Vector3* normalData = NULL, Vector3* normalResult = NULL);
 
+    // Legacy method for grayscale heightmaps: r + g + b, normalized.
+    static float normalizedHeightGrayscale(float r, float g, float b);
+
+    // Higher precision method for heightmaps: 65536*r + 256*g + b, normalized.
+    static float normalizedHeightPacked(float r, float g, float b);
+
     // Sets up the given constraint for the given two rigid bodies.
     void addConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b, PhysicsConstraint* constraint);