Просмотр исходного кода

Merge branch 'next' of https://github.com/blackberry-gaming/GamePlay into next-ablake

Conflicts:
	gameplay-samples/sample04-particles/bar-descriptor.xml
	gameplay-samples/sample04-particles/res/editor.theme
	gameplay-samples/sample04-particles/sample04-particles.vcxproj
	gameplay-samples/sample04-particles/sample04-particles.vcxproj.filters
Adam Blake 13 лет назад
Родитель
Сommit
31ba03f9ba

+ 5 - 5
gameplay/src/AnimationTarget.cpp

@@ -123,7 +123,7 @@ Animation* AnimationTarget::createAnimation(const char* id, Properties* animatio
     const char* propertyIdStr = animationProperties->getString("property");
     if (propertyIdStr == NULL)
     {
-        GP_ERROR("Attribute \'property\' must be specified for an animation.");
+        GP_ERROR("Attribute 'property' must be specified for an animation.");
         return NULL;
     }
     
@@ -138,28 +138,28 @@ Animation* AnimationTarget::createAnimation(const char* id, Properties* animatio
     unsigned int keyCount = animationProperties->getInt("keyCount");
     if (keyCount == 0)
     {
-        GP_ERROR("Attribute \'keyCount\' must be specified for an animation.");
+        GP_ERROR("Attribute 'keyCount' must be specified for an animation.");
         return NULL;
     }
 
     const char* keyTimesStr = animationProperties->getString("keyTimes");
     if (keyTimesStr == NULL)
     {
-        GP_ERROR("Attribute \'keyTimes\' must be specified for an animation.");
+        GP_ERROR("Attribute 'keyTimes' must be specified for an animation.");
         return NULL;
     }
     
     const char* keyValuesStr = animationProperties->getString("keyValues");
     if (keyValuesStr == NULL)
     {
-        GP_ERROR("Attribute \'keyValues\' must be specified for an animation.");
+        GP_ERROR("Attribute 'keyValues' must be specified for an animation.");
         return NULL;
     }
     
     const char* curveStr = animationProperties->getString("curve");
     if (curveStr == NULL)
     {
-        GP_ERROR("Attribute \'curve\' must be specified for an animation.");
+        GP_ERROR("Attribute 'curve' must be specified for an animation.");
         return NULL;
     }
     

+ 1 - 1
gameplay/src/AudioSource.cpp

@@ -75,7 +75,7 @@ AudioSource* AudioSource::create(Properties* properties)
     GP_ASSERT(properties);
     if (!properties || !(strcmp(properties->getNamespace(), "audio") == 0))
     {
-        GP_ERROR("Failed to load audio source from properties object: must be non-null object and have namespace equal to \'audio\'.");
+        GP_ERROR("Failed to load audio source from properties object: must be non-null object and have namespace equal to 'audio'.");
         return NULL;
     }
 

+ 1 - 1
gameplay/src/Base.h

@@ -62,7 +62,7 @@ extern void printError(const char* format, ...);
 #define GP_ASSERT(expression) do { \
     if (!(expression)) \
     { \
-        printError("%s -- Assertion \'" #expression "\' failed.\n", __FUNCTION__); \
+        printError("%s -- Assertion '" #expression "' failed.\n", __FUNCTION__); \
         GP_FORCE_ASSERTION_FAILURE; \
     } } while (0)
 #else

+ 6 - 4
gameplay/src/BoundingBox.cpp

@@ -64,6 +64,8 @@ Vector3 BoundingBox::getCenter() const
 
 void BoundingBox::getCenter(Vector3* dst) const
 {
+    GP_ASSERT(dst);
+
     dst->set(min, max);
     dst->scale(0.5f);
     dst->add(min);
@@ -247,6 +249,10 @@ void BoundingBox::set(const Vector3& min, const Vector3& max)
 
 void updateMinMax(Vector3* point, Vector3* min, Vector3* max)
 {
+    GP_ASSERT(point);
+    GP_ASSERT(min);
+    GP_ASSERT(max);
+
     // Leftmost point.
     if (point->x < min->x)
     {
@@ -292,10 +298,6 @@ void BoundingBox::set(const BoundingBox& box)
 
 void BoundingBox::set(const BoundingSphere& sphere)
 {
-    std::vector<int> v;
-    v.push_back(0);
-    std::vector<int> v2 = v;
-
     const Vector3& center = sphere.center;
     float radius = sphere.radius;
 

+ 8 - 0
gameplay/src/BoundingSphere.cpp

@@ -158,6 +158,9 @@ bool BoundingSphere::isEmpty() const
 
 void BoundingSphere::merge(const BoundingSphere& sphere)
 {
+    if (sphere.isEmpty())
+        return;
+
     // Calculate the distance between the two centers.
     float vx = center.x - sphere.center.x;
     float vy = center.y - sphere.center.y;
@@ -177,6 +180,7 @@ void BoundingSphere::merge(const BoundingSphere& sphere)
     }
 
     // Calculate the unit vector between the two centers.
+    GP_ASSERT(d != 0.0f);
     float dI = 1.0f / d;
     vx *= dI;
     vy *= dI;
@@ -200,6 +204,9 @@ void BoundingSphere::merge(const BoundingSphere& sphere)
 
 void BoundingSphere::merge(const BoundingBox& box)
 {
+    if (box.isEmpty())
+        return;
+
     const Vector3& min = box.min;
     const Vector3& max = box.max;
 
@@ -240,6 +247,7 @@ void BoundingSphere::merge(const BoundingBox& box)
     }
 
     // Calculate the unit vector between the center and the farthest point.
+    GP_ASSERT(distance != 0.0f);
     float dI = 1.0f / distance;
     v1x *= dI;
     v1y *= dI;

Разница между файлами не показана из-за своего большого размера
+ 225 - 107
gameplay/src/Bundle.cpp


+ 10 - 17
gameplay/src/Camera.cpp

@@ -245,23 +245,21 @@ const Frustum& Camera::getFrustum() const
 
 void Camera::project(const Rectangle& viewport, const Vector3& position, float* x, float* y, float* depth)
 {
-    // Determine viewport coords to use.
-    float vpx = viewport.x;
-    float vpy = viewport.y;
-    float vpw = viewport.width;
-    float vph = viewport.height;
+    GP_ASSERT(x);
+    GP_ASSERT(y);
 
     // Transform the point to clip-space.
     Vector4 clipPos;
     getViewProjectionMatrix().transformVector(Vector4(position.x, position.y, position.z, 1.0f), &clipPos);
 
     // Compute normalized device coordinates.
+    GP_ASSERT(clipPos.w != 0.0f);
     float ndcX = clipPos.x / clipPos.w;
     float ndcY = clipPos.y / clipPos.w;
 
     // Compute screen coordinates by applying our viewport transformation.
-    *x = vpx + (ndcX + 1.0f) * 0.5f * vpw;
-    *y = vpy + (1.0f - (ndcY + 1.0f) * 0.5f) * vph;
+    *x = viewport.x + (ndcX + 1.0f) * 0.5f * viewport.width;
+    *y = viewport.y + (1.0f - (ndcY + 1.0f) * 0.5f) * viewport.height;
     if (depth)
     {
         float ndcZ = clipPos.z / clipPos.w;
@@ -271,18 +269,11 @@ void Camera::project(const Rectangle& viewport, const Vector3& position, float*
 
 void Camera::unproject(const Rectangle& viewport, float x, float y, float depth, Vector3* dst)
 {
-    // Determine viewport coords to use.
-    float vpx = viewport.x;
-    float vpy = viewport.y;
-    float vpw = viewport.width;
-    float vph = viewport.height;
+    GP_ASSERT(dst);
     
     // Create our screen space position in NDC.
-    Vector4 screen(
-        ((float)x - (float)vpx) / (float)vpw,
-        ((float)(vph - y) - (float)vpy) / (float)vph,
-        depth,
-        1.0f );
+    GP_ASSERT(viewport.width != 0.0f && viewport.height != 0.0f);
+    Vector4 screen((x - viewport.x) / viewport.width, ((viewport.height - y) - viewport.y) / viewport.height, depth, 1.0f);
 
     // Map to range -1 to 1.
     screen.x = screen.x * 2.0f - 1.0f;
@@ -305,6 +296,8 @@ void Camera::unproject(const Rectangle& viewport, float x, float y, float depth,
 
 void Camera::pickRay(const Rectangle& viewport, float x, float y, Ray* dst)
 {
+    GP_ASSERT(dst);
+
     // Get the world-space position at the near clip plane.
     Vector3 nearPoint;
     unproject(viewport, x, y, 0.0f, &nearPoint);

+ 1 - 1
gameplay/src/Container.cpp

@@ -121,7 +121,7 @@ void Container::addControls(Theme* theme, Properties* properties)
         }
         else
         {
-            GP_ERROR("Failed to create control; unrecognized control name \'%s\'.", controlName.c_str());
+            GP_ERROR("Failed to create control; unrecognized control name '%s'.", controlName.c_str());
         }
 
         // Add the new control to the form.

+ 1 - 1
gameplay/src/Control.cpp

@@ -1273,7 +1273,7 @@ Control::Alignment Control::getAlignment(const char* alignment)
     }
     else
     {
-        GP_ERROR("Failed to get corresponding control alignment for unsupported value \'%s\'.", alignment);
+        GP_ERROR("Failed to get corresponding control alignment for unsupported value '%s'.", alignment);
     }
 
     // Default.

+ 38 - 10
gameplay/src/FileSystem.cpp

@@ -50,7 +50,7 @@ void makepath(std::string path, int mode)
             // Directory does not exist.
             if (mkdir(dirPath.c_str(), 0777) != 0)
             {
-                GP_WARN("Failed to create directory: '%s'", dirPath.c_str());
+                GP_ERROR("Failed to create directory: '%s'", dirPath.c_str());
                 return;
             }
         }
@@ -151,6 +151,8 @@ bool FileSystem::listFiles(const char* dirPath, std::vector<std::string>& files)
 
 FILE* FileSystem::openFile(const char* path, const char* mode)
 {
+    GP_ASSERT(path);
+
     std::string fullPath(__resourcePath);
     fullPath += path;
     
@@ -168,10 +170,25 @@ FILE* FileSystem::openFile(const char* path, const char* mode)
             const void* data = AAsset_getBuffer(asset);
             int length = AAsset_getLength(asset);
             FILE* file = fopen(fullPath.c_str(), "wb");
-        
-            int ret = fwrite(data, sizeof(unsigned char), length, file);
-            GP_ASSERT(ret == length);
-            fclose(file);
+            if (file != NULL)
+            {
+                int ret = fwrite(data, sizeof(unsigned char), length, file);
+                if (fclose(file) != 0)
+                {
+                    GP_ERROR("Failed to close file on file system created from APK asset.");
+                    return NULL;
+                }
+                if (ret != length)
+                {
+                    GP_ERROR("Failed to write all data from APK asset to file on file system.");
+                    return NULL;
+                }
+            }
+            else
+            {
+                GP_ERROR("Failed to create file on file system from APK asset.");
+                return NULL;
+            }
         }
     }
 #endif
@@ -204,17 +221,24 @@ char* FileSystem::readAll(const char* filePath, int* fileSize)
     }
 
     // Obtain file length.
-    fseek(file, 0, SEEK_END);
+    if (fseek(file, 0, SEEK_END) != 0)
+    {
+        GP_ERROR("Failed to seek to the end of the file '%s' to obtain the file length.", filePath);
+        return NULL;
+    }
     int size = (int)ftell(file);
-     fseek(file, 0, SEEK_SET);
+    if (fseek(file, 0, SEEK_SET) != 0)
+    {
+        GP_ERROR("Failed to seek to beginning of the file '%s' to begin reading in the entire file.", filePath);
+        return NULL;
+    }
 
     // Read entire file contents.
     char* buffer = new char[size + 1];
     int read = (int)fread(buffer, 1, size, file);
-    GP_ASSERT(read == size);
     if (read != size)
     {
-        GP_ERROR("Read error for file: %s (%d < %d)", filePath, (int)read, (int)size);
+        GP_ERROR("Failed to read complete contents of file '%s' (amount read vs. file size: %d < %d).", filePath, (int)read, (int)size);
         SAFE_DELETE_ARRAY(buffer);
         return NULL;
     }
@@ -223,7 +247,11 @@ char* FileSystem::readAll(const char* filePath, int* fileSize)
     buffer[size] = '\0';
 
     // Close file and return.
-    fclose(file);
+    if (fclose(file) != 0)
+    {
+        GP_ERROR("Failed to close file '%s'.", filePath);
+    }
+
     if (fileSize)
     {
         *fileSize = size; 

+ 11 - 17
gameplay/src/Font.cpp

@@ -242,9 +242,7 @@ Font::Text* Font::createText(const char* text, const Rectangle& area, const Vect
         }
 
         // Wrap if necessary.
-        if (wrap &&
-            xPos + (int)tokenWidth > area.x + area.width ||
-            (rightToLeft && currentLineLength > lineLength))
+        if (wrap && (xPos + (int)tokenWidth > area.x + area.width || (rightToLeft && currentLineLength > lineLength)))
         {
             yPos += (int)size;
             currentLineLength = tokenLength;
@@ -303,11 +301,11 @@ Font::Text* Font::createText(const char* text, const Rectangle& area, const Vect
                         if (batch->_vertexCount == 0)
                         {
                             // Simply copy values directly into the start of the index array
-                            //memcpy(_indicesPtr, indices, indexCount * sizeof(unsigned short));
-                            batch->_indices[batch->_vertexCount] = batch->_vertexCount++;
-                            batch->_indices[batch->_vertexCount] = batch->_vertexCount++;
-                            batch->_indices[batch->_vertexCount] = batch->_vertexCount++;
-                            batch->_indices[batch->_vertexCount] = batch->_vertexCount++;
+                            batch->_indices[batch->_vertexCount] = batch->_vertexCount;
+                            batch->_indices[batch->_vertexCount] = batch->_vertexCount + 1;
+                            batch->_indices[batch->_vertexCount] = batch->_vertexCount + 2;
+                            batch->_indices[batch->_vertexCount] = batch->_vertexCount + 3;
+                            batch->_vertexCount += 4;
                             batch->_indexCount += 4;
                         }
                         else
@@ -506,6 +504,7 @@ void Font::drawText(const char* text, int x, int y, const Vector4& color, unsign
                     xPos += floor(g.width * scale + (float)(size >> 3));
                     break;
                 }
+                break;
             }
         }
 
@@ -586,9 +585,7 @@ void Font::drawText(const char* text, const Rectangle& area, const Vector4& colo
         }
 
         // Wrap if necessary.
-        if (wrap &&
-            xPos + (int)tokenWidth > area.x + area.width ||
-            (rightToLeft && currentLineLength > lineLength))
+        if (wrap && (xPos + (int)tokenWidth > area.x + area.width || (rightToLeft && currentLineLength > lineLength)))
         {
             yPos += (int)size;
             currentLineLength = tokenLength;
@@ -1353,9 +1350,7 @@ int Font::getIndexOrLocation(const char* text, const Rectangle& area, unsigned i
         }
 
         // Wrap if necessary.
-        if (wrap &&
-            xPos + (int)tokenWidth > area.x + area.width ||
-            (rightToLeft && currentLineLength > lineLength))
+        if (wrap && (xPos + (int)tokenWidth > area.x + area.width || (rightToLeft && currentLineLength > lineLength)))
         {
             yPos += size;
             currentLineLength = tokenLength;
@@ -1707,16 +1702,15 @@ Font::Justify Font::getJustify(const char* justify)
     }
     else
     {
-        GP_ERROR("Failed to get corresponding font justification for unsupported value \'%s\'.", justify);
+        GP_ERROR("Failed to get corresponding font justification for unsupported value '%s'.", justify);
     }
 
     // Default.
     return Font::ALIGN_TOP_LEFT;
 }
 
-Font::Text::Text(const char* text) : _vertexCount(0), _indexCount(0)
+Font::Text::Text(const char* text) : _text(text), _vertexCount(0), _vertices(NULL), _indexCount(0), _indices(NULL)
 {
-    _text = text;
     const int length = strlen(text);
     _vertices = new SpriteBatch::SpriteVertex[length * 4];
     _indices = new unsigned short[((length - 1) * 6) + 4];

+ 2 - 2
gameplay/src/Font.h

@@ -103,10 +103,10 @@ public:
 
     private:
         std::string _text;
-        SpriteBatch::SpriteVertex* _vertices;
-        unsigned short* _indices;
         unsigned int _vertexCount;
+        SpriteBatch::SpriteVertex* _vertices;
         unsigned int _indexCount;
+        unsigned short* _indices;
         Vector4 _color;
     };
 

+ 1 - 1
gameplay/src/Form.cpp

@@ -80,7 +80,7 @@ Form* Form::create(const char* url)
         layout = ScrollLayout::create();
         break;
     default:
-        GP_ERROR("Unsupported layout type \'%d\'.", getLayoutType(layoutString));
+        GP_ERROR("Unsupported layout type '%d'.", getLayoutType(layoutString));
     }
 
     Theme* theme = Theme::create(themeFile);

+ 2 - 0
gameplay/src/Joint.cpp

@@ -22,6 +22,7 @@ Joint* Joint::create(const char* id)
 Node* Joint::cloneSingleNode(NodeCloneContext &context) const
 {
     Joint* copy = Joint::create(getId());
+    GP_ASSERT(copy);
     context.registerClonedNode(this, copy);
     copy->_bindPose = _bindPose;
     copy->_skinCount = _skinCount;
@@ -54,6 +55,7 @@ void Joint::updateJointMatrix(const Matrix& bindShape, Vector4* matrixPalette)
         Matrix::multiply(Node::getWorldMatrix(), getInverseBindPose(), &t);
         Matrix::multiply(t, bindShape, &t);
 
+        GP_ASSERT(matrixPalette);
         matrixPalette[0].set(t.m[0], t.m[4], t.m[8], t.m[12]);
         matrixPalette[1].set(t.m[1], t.m[5], t.m[9], t.m[13]);
         matrixPalette[2].set(t.m[2], t.m[6], t.m[10], t.m[14]);

+ 24 - 20
gameplay/src/Node.cpp

@@ -402,11 +402,9 @@ const Matrix& Node::getWorldMatrix() const
 
         // Our world matrix was just updated, so call getWorldMatrix() on all child nodes
         // to force their resolved world matrices to be updated.
-        Node* node = getFirstChild();
-        while (node)
+        for (Node* child = getFirstChild(); child != NULL; child = child->getNextSibling())
         {
-            node->getWorldMatrix();
-            node = node->getNextSibling();
+            child->getWorldMatrix();
         }
     }
 
@@ -546,8 +544,6 @@ Vector3 Node::getForwardVectorView() const
     Vector3 vector;
     getWorldMatrix().getForwardVector(&vector);
     getViewMatrix().transformVector(&vector);
-    //getForwardVector(&vector);
-    //getWorldViewMatrix().transformVector(&vector);
     return vector;
 }
 
@@ -601,8 +597,7 @@ void Node::transformChanged()
     _dirtyBits |= NODE_DIRTY_WORLD | NODE_DIRTY_BOUNDS;
 
     // Notify our children that their transform has also changed (since transforms are inherited).
-    Node* n = getFirstChild();
-    while (n)
+    for (Node* n = getFirstChild(); n != NULL; n = n->getNextSibling())
     {
         if (Transform::isTransformChangedSuspended())
         {
@@ -617,7 +612,6 @@ void Node::transformChanged()
         {
             n->transformChanged();
         }
-        n = n->getNextSibling();
     }
 
     Transform::transformChanged();
@@ -647,10 +641,10 @@ Animation* Node::getAnimation(const char* id) const
         MeshSkin* skin = model->getSkin();
         if (skin)
         {
-            Joint* rootJoint = skin->getRootJoint();
-            if (rootJoint)
+            Node* rootNode = skin->_rootNode;
+            if (rootNode)
             {
-                animation = rootJoint->getAnimation(id);
+                animation = rootNode->getAnimation(id);
                 if (animation)
                     return animation;
             }
@@ -665,6 +659,7 @@ Animation* Node::getAnimation(const char* id) const
             std::vector<MaterialParameter*>::iterator itr = material->_parameters.begin();
             for (; itr != material->_parameters.end(); itr++)
             {
+                GP_ASSERT(*itr);
                 animation = ((MaterialParameter*)(*itr))->getAnimation(id);
                 if (animation)
                     return animation;
@@ -682,15 +677,11 @@ Animation* Node::getAnimation(const char* id) const
     }
 
     // Look through this node's children for an animation with the specified ID.
-    unsigned int childCount = this->getChildCount();
-    Node* child = this->getFirstChild();
-    for (unsigned int i = 0; i < childCount; i++)
+    for (Node* child = getFirstChild(); child != NULL; child = child->getNextSibling())
     {
         animation = child->getAnimation(id);
         if (animation)
             return animation;
-
-        child = child->getNextSibling();
     }
     
     return NULL;
@@ -833,6 +824,7 @@ const BoundingSphere& Node::getBoundingSphere() const
                 // since joint parent nodes that are not in the matrix pallette do not need to
                 // be considered as directly transforming vertices on the GPU (they can instead
                 // be applied directly to the bounding volume transformation below).
+                GP_ASSERT(_model->getSkin()->getRootJoint());
                 Node* jointParent = _model->getSkin()->getRootJoint()->getParent();
                 if (jointParent)
                 {
@@ -890,6 +882,7 @@ Node* Node::cloneSingleNode(NodeCloneContext &context) const
 Node* Node::cloneRecursive(NodeCloneContext &context) const
 {
     Node* copy = cloneSingleNode(context);
+    GP_ASSERT(copy);
 
     Node* lastChild = NULL;
     for (Node* child = getFirstChild(); child != NULL; child = child->getNextSibling())
@@ -900,6 +893,7 @@ Node* Node::cloneRecursive(NodeCloneContext &context) const
     for (Node* child = lastChild; child != NULL; child = child->getPreviousSibling())
     {
         Node* childCopy = child->cloneRecursive(context);
+        GP_ASSERT(childCopy);
         copy->addChild(childCopy);
         childCopy->release();
     }
@@ -908,6 +902,7 @@ Node* Node::cloneRecursive(NodeCloneContext &context) const
 
 void Node::cloneInto(Node* node, NodeCloneContext &context) const
 {
+    GP_ASSERT(node);
     Transform::cloneInto(node, context);
 
     // TODO: Clone the rest of the node data.
@@ -1027,10 +1022,9 @@ PhysicsCollisionObject* Node::setCollisionObject(const char* url)
 {
     // Load the collision object properties from file.
     Properties* properties = Properties::create(url);
-    GP_ASSERT(properties);
     if (properties == NULL)
     {
-        GP_WARN("Failed to load collision object file: %s", url);
+        GP_ERROR("Failed to load collision object file: %s", url);
         return NULL;
     }
 
@@ -1050,7 +1044,7 @@ PhysicsCollisionObject* Node::setCollisionObject(Properties* properties)
         strcmp(properties->getNamespace(), "ghostObject") == 0 || 
         strcmp(properties->getNamespace(), "rigidBody") == 0))
     {
-        GP_WARN("Failed to load collision object from properties object: must be non-null object and have namespace equal to \'character\', \'ghostObject\', or \'rigidBody\'.");
+        GP_ERROR("Failed to load collision object from properties object: must be non-null object and have namespace equal to 'character', 'ghostObject', or 'rigidBody'.");
         return NULL;
     }
 
@@ -1081,23 +1075,33 @@ NodeCloneContext::~NodeCloneContext()
 
 Animation* NodeCloneContext::findClonedAnimation(const Animation* animation)
 {
+    GP_ASSERT(animation);
+
     AnimationMap::iterator it = _clonedAnimations.find(animation);
     return it != _clonedAnimations.end() ? it->second : NULL;
 }
 
 void NodeCloneContext::registerClonedAnimation(const Animation* original, Animation* clone)
 {
+    GP_ASSERT(original);
+    GP_ASSERT(clone);
+
     _clonedAnimations[original] = clone;
 }
 
 Node* NodeCloneContext::findClonedNode(const Node* node)
 {
+    GP_ASSERT(node);
+
     NodeMap::iterator it = _clonedNodes.find(node);
     return it != _clonedNodes.end() ? it->second : NULL;
 }
 
 void NodeCloneContext::registerClonedNode(const Node* original, Node* clone)
 {
+    GP_ASSERT(original);
+    GP_ASSERT(clone);
+
     _clonedNodes[original] = clone;
 }
 

+ 1 - 1
gameplay/src/PhysicsCharacter.cpp

@@ -90,7 +90,7 @@ PhysicsCharacter* PhysicsCharacter::create(Node* node, Properties* properties)
     GP_ASSERT(properties);
     if (!properties || !(strcmp(properties->getNamespace(), "character") == 0))
     {
-        GP_WARN("Failed to load physics character from properties object: must be non-null object and have namespace equal to \'character\'.");
+        GP_WARN("Failed to load physics character from properties object: must be non-null object and have namespace equal to 'character'.");
         return NULL;
     }
 

+ 1 - 1
gameplay/src/PhysicsCollisionShape.cpp

@@ -124,7 +124,7 @@ PhysicsCollisionShape::Definition* PhysicsCollisionShape::Definition::create(Nod
         strcmp(properties->getNamespace(), "ghostObject") == 0 || 
         strcmp(properties->getNamespace(), "rigidBody") == 0))
     {
-        GP_WARN("Failed to load physics collision shape from properties object: must be non-null object and have namespace equal to \'character\', \'ghostObject\', or \'rigidBody\'.");
+        GP_WARN("Failed to load physics collision shape from properties object: must be non-null object and have namespace equal to 'character', 'ghostObject', or 'rigidBody'.");
         return NULL;
     }
 

+ 1 - 1
gameplay/src/PhysicsConstraint.cpp

@@ -145,7 +145,7 @@ Vector3 PhysicsConstraint::getWorldCenterOfMass(const Model* model)
         else
         {
             // Warn the user that the model has no bounding volume.
-            GP_WARN("Model \'%s\' has no bounding volume - center of mass is defaulting to local coordinate origin.", model->getNode()->getId());
+            GP_WARN("Model '%s' has no bounding volume - center of mass is defaulting to local coordinate origin.", model->getNode()->getId());
             model->getNode()->getWorldMatrix().transformPoint(&center);
         }
     }

+ 1 - 1
gameplay/src/PhysicsGhostObject.cpp

@@ -45,7 +45,7 @@ PhysicsGhostObject* PhysicsGhostObject::create(Node* node, Properties* propertie
     GP_ASSERT(properties);
     if (!properties || !(strcmp(properties->getNamespace(), "ghostObject") == 0))
     {
-        GP_WARN("Failed to load ghost object from properties object: must be non-null object and have namespace equal to \'ghost\'.");
+        GP_WARN("Failed to load ghost object from properties object: must be non-null object and have namespace equal to 'ghost'.");
         return NULL;
     }
 

+ 1 - 1
gameplay/src/PhysicsRigidBody.cpp

@@ -147,7 +147,7 @@ PhysicsRigidBody* PhysicsRigidBody::create(Node* node, Properties* properties)
     GP_ASSERT(properties);
     if (!properties || !(strcmp(properties->getNamespace(), "rigidBody") == 0))
     {
-        GP_WARN("Failed to load rigid body from properties object: must be non-null object and have namespace equal to \'rigidBody\'.");
+        GP_WARN("Failed to load rigid body from properties object: must be non-null object and have namespace equal to 'rigidBody'.");
         return NULL;
     }
 

+ 55 - 26
gameplay/src/Properties.cpp

@@ -21,6 +21,7 @@ Properties::Properties(const Properties& copy)
     std::vector<Properties*>::const_iterator it;
     for (it = copy._namespaces.begin(); it < copy._namespaces.end(); it++)
     {
+        GP_ASSERT(*it);
         _namespaces.push_back(new Properties(**it));
     }
     rewind();
@@ -48,11 +49,9 @@ Properties::Properties(FILE* file, const char* name, const char* id, const char*
 
 Properties* Properties::create(const char* url)
 {
-    GP_ASSERT(url);
-
     if (!url || strlen(url) == 0)
     {
-        GP_WARN("Attempting to create a Properties object from an empty URL!");
+        GP_ERROR("Attempting to create a Properties object from an empty URL!");
         return NULL;
     }
 
@@ -82,6 +81,7 @@ Properties* Properties::create(const char* url)
     FILE* file = FileSystem::openFile(fileString.c_str(), "rb");
     if (!file)
     {
+        GP_ERROR("Failed to open file '%s'.", fileString.c_str());
         return NULL;
     }
 
@@ -102,6 +102,12 @@ Properties* Properties::create(const char* url)
         {
             while (true)
             {
+                if (iter == NULL)
+                {
+                    GP_ERROR("Failed to load Properties object from URL '%s'.", url);
+                    return NULL;
+                }
+
                 if (strcmp(iter->getId(), namespacePath[i].c_str()) == 0)
                 {
                     if (i != size - 1)
@@ -117,11 +123,6 @@ Properties* Properties::create(const char* url)
                 }
                 
                 iter = properties->getNextNamespace();
-                if (iter == NULL)
-                {
-                    GP_WARN("Failed to load Properties object from URL '%s'.", url);
-                    return NULL;
-                }
             }
         }
 
@@ -135,6 +136,8 @@ Properties* Properties::create(const char* url)
 
 void Properties::readProperties(FILE* file)
 {
+    GP_ASSERT(file);
+
     char line[2048];
     int c;
     char* name;
@@ -155,6 +158,7 @@ void Properties::readProperties(FILE* file)
         rc = fgets(line, 2048, file);
         if (rc == NULL)
         {
+            GP_ERROR("Error reading line from file.");
             return;
         }
 
@@ -173,7 +177,7 @@ void Properties::readProperties(FILE* file)
                 name = strtok(line, " =\t");
                 if (name == NULL)
                 {
-                    GP_ERROR("Error parsing properties file: value without name.");
+                    GP_ERROR("Error parsing properties file: attribute without name.");
                     return;
                 }
 
@@ -181,7 +185,8 @@ void Properties::readProperties(FILE* file)
                 value = strtok(NULL, "=");
                 if (value == NULL)
                 {
-                    GP_ERROR("Error parsing properties file: name without value.");
+                    GP_ERROR("Error parsing properties file: attribute with name ('%s') but no value.", name);
+                    return;
                 }
 
                 // Remove white-space from value.
@@ -214,7 +219,8 @@ void Properties::readProperties(FILE* file)
                 name = trimWhiteSpace(name);
                 if (name == NULL)
                 {
-                    GP_ERROR("Error parsing properties file: unknown error.");
+                    GP_ERROR("Error parsing properties file: failed to determine a valid token for line '%s'.", line);
+                    return;
                 }
                 else if (name[0] == '}')
                 {
@@ -260,7 +266,8 @@ void Properties::readProperties(FILE* file)
                         else
                         {
                             // Back up from fgetc()
-                            fseek(file, -1, SEEK_CUR);
+                            if (fseek(file, -1, SEEK_CUR) != 0)
+                                GP_ERROR("Failed to seek backwards a single character after testing if the next line starts with '{'.");
 
                             // Store "name value" as a name/value pair, or even just "name".
                             if (value != NULL)
@@ -300,7 +307,12 @@ void Properties::skipWhiteSpace(FILE* file)
     // If we are not at the end of the file, then since we found a
     // non-whitespace character, we put the cursor back in front of it.
     if (c != EOF)
-        fseek(file, -1, SEEK_CUR);
+    {
+        if (fseek(file, -1, SEEK_CUR) != 0)
+        {
+            GP_ERROR("Failed to seek backwards one character after skipping whitespace.");
+        }
+    }
 }
 
 char* Properties::trimWhiteSpace(char *str)
@@ -375,6 +387,7 @@ void Properties::resolveInheritance(const char* id)
                 std::vector<Properties*>::const_iterator itt;
                 for (itt = parent->_namespaces.begin(); itt < parent->_namespaces.end(); itt++)
                 {
+                    GP_ASSERT(*itt);
                     derived->_namespaces.push_back(new Properties(**itt));
                 }
                 derived->rewind();
@@ -404,6 +417,8 @@ void Properties::resolveInheritance(const char* id)
 
 void Properties::mergeWith(Properties* overrides)
 {
+    GP_ASSERT(overrides);
+
     // Overwrite or add each property found in child.
     char* value = new char[255];
     overrides->rewind();
@@ -507,6 +522,8 @@ void Properties::rewind()
 
 Properties* Properties::getNamespace(const char* id) const
 {
+    GP_ASSERT(id);
+
     Properties* ret = NULL;
     std::vector<Properties*>::const_iterator it;
     
@@ -547,6 +564,8 @@ bool Properties::exists(const char* name) const
 
 const bool isStringNumeric(const char* str)
 {
+    GP_ASSERT(str);
+
     // The first character may be '-'
     if (*str == '-')
         str++;
@@ -587,7 +606,6 @@ Properties::Type Properties::getType(const char* name) const
 
     // Parse the value to determine the format
     unsigned int commaCount = 0;
-    //unsigned int length = strlen(value);
     char* valuePtr = const_cast<char*>(value);
     while (valuePtr = strchr(valuePtr, ','))
     {
@@ -654,7 +672,7 @@ int Properties::getInt(const char* name) const
         scanned = sscanf(valueString, "%d", &value);
         if (scanned != 1)
         {
-            GP_ERROR("Error parsing property: %s", name);
+            GP_ERROR("Error attempting to parse property '%s' as an integer.", name);
             return 0;
         }
         return value;
@@ -673,7 +691,7 @@ float Properties::getFloat(const char* name) const
         scanned = sscanf(valueString, "%f", &value);
         if (scanned != 1)
         {
-            GP_ERROR("Error parsing property: %s", name);
+            GP_ERROR("Error attempting to parse property '%s' as a float.", name);
             return 0.0f;
         }
         return value;
@@ -692,7 +710,7 @@ long Properties::getLong(const char* name) const
         scanned = sscanf(valueString, "%ld", &value);
         if (scanned != 1)
         {
-            GP_ERROR("Error parsing property: %s", name);
+            GP_ERROR("Error attempting to parse property '%s' as a long integer.", name);
             return 0L;
         }
         return value;
@@ -716,7 +734,7 @@ bool Properties::getMatrix(const char* name, Matrix* out) const
 
         if (scanned != 16)
         {
-            GP_ERROR("Error parsing property: %s", name);
+            GP_ERROR("Error attempting to parse property '%s' as a matrix.", name);
             out->setIdentity();
             return false;
         }
@@ -741,7 +759,7 @@ bool Properties::getVector2(const char* name, Vector2* out) const
         scanned = sscanf(valueString, "%f,%f", &x, &y);
         if (scanned != 2)
         {
-            GP_ERROR("Error parsing property: %s", name);
+            GP_ERROR("Error attempting to parse property '%s' as a two-dimensional vector.", name);
             out->set(0.0f, 0.0f);
             return false;
         }
@@ -766,7 +784,7 @@ bool Properties::getVector3(const char* name, Vector3* out) const
         scanned = sscanf(valueString, "%f,%f,%f", &x, &y, &z);
         if (scanned != 3)
         {
-            GP_ERROR("Error parsing property: %s", name);
+            GP_ERROR("Error attempting to parse property '%s' as a three-dimensional vector.", name);
             out->set(0.0f, 0.0f, 0.0f);
             return false;
         }
@@ -791,7 +809,7 @@ bool Properties::getVector4(const char* name, Vector4* out) const
         scanned = sscanf(valueString, "%f,%f,%f,%f", &x, &y, &z, &w);
         if (scanned != 4)
         {
-            GP_ERROR("Error parsing property: %s", name);
+            GP_ERROR("Error attempting to parse property '%s' as a four-dimensional vector.", name);
             out->set(0.0f, 0.0f, 0.0f, 0.0f);
             return false;
         }
@@ -816,7 +834,7 @@ bool Properties::getQuaternionFromAxisAngle(const char* name, Quaternion* out) c
         scanned = sscanf(valueString, "%f,%f,%f,%f", &x, &y, &z, &theta);
         if (scanned != 4)
         {
-            GP_ERROR("Error parsing property: %s", name);
+            GP_ERROR("Error attempting to parse property '%s' as an axis-angle rotation.", name);
             out->set(0.0f, 0.0f, 0.0f, 1.0f);
             return false;
         }
@@ -840,14 +858,19 @@ bool Properties::getColor(const char* name, Vector3* out) const
             valueString[0] != '#')
         {
             // Not a color string.
-            GP_ERROR("Error parsing property: %s", name);
+            GP_ERROR("Error attempting to parse property '%s' as an RGB color (not specified as a color string).", name);
             out->set(0.0f, 0.0f, 0.0f);
             return false;
         }
 
         // Read the string into an int as hex.
         unsigned int color;
-        sscanf(valueString+1, "%x", &color);
+        if (sscanf(valueString+1, "%x", &color) != 1)
+        {
+            GP_ERROR("Error attempting to parse property '%s' as an RGB color.", name);
+            out->set(0.0f, 0.0f, 0.0f);
+            return false;
+        }
 
         out->set(Vector3::fromColor(color));
         return true;
@@ -868,14 +891,19 @@ bool Properties::getColor(const char* name, Vector4* out) const
             valueString[0] != '#')
         {
             // Not a color string.
-            GP_ERROR("Error parsing property: %s", name);
+            GP_ERROR("Error attempting to parse property '%s' as an RGBA color (not specified as a color string).", name);
             out->set(0.0f, 0.0f, 0.0f, 0.0f);
             return false;
         }
 
         // Read the string into an int as hex.
         unsigned int color;
-        sscanf(valueString+1, "%x", &color);
+        if (sscanf(valueString+1, "%x", &color) != 1)
+        {
+            GP_ERROR("Error attempting to parse property '%s' as an RGBA color.", name);
+            out->set(0.0f, 0.0f, 0.0f, 0.0f);
+            return false;
+        }
 
         out->set(Vector4::fromColor(color));
         return true;
@@ -898,6 +926,7 @@ Properties* Properties::clone()
     unsigned int count = _namespaces.size();
     for (unsigned int i = 0; i < count; i++)
     {
+        GP_ASSERT(_namespaces[i]);
         p->_namespaces.push_back(_namespaces[i]->clone());
     }
     p->_namespacesItr = p->_namespaces.end();

+ 16 - 9
gameplay/src/Scene.cpp

@@ -119,6 +119,7 @@ unsigned int Scene::findNodes(const char* id, std::vector<Node*>& nodes, bool re
 Node* Scene::addNode(const char* id)
 {
     Node* node = Node::create(id);
+    GP_ASSERT(node);
     addNode(node);
 
     // Call release to decrement the ref count to 1 before returning.
@@ -237,7 +238,7 @@ void Scene::setActiveCamera(Camera* camera)
             // Unbind the active camera from the audio listener
             if (audioListener && (audioListener->getCamera() == _activeCamera))
             {
-                AudioListener::getInstance()->setCamera(NULL);
+                audioListener->setCamera(NULL);
             }
 
             SAFE_RELEASE(_activeCamera);
@@ -251,7 +252,7 @@ void Scene::setActiveCamera(Camera* camera)
 
             if (audioListener && _bindAudioListenerToCamera)
             {
-                AudioListener::getInstance()->setCamera(_activeCamera);
+                audioListener->setCamera(_activeCamera);
             }
         }
     }
@@ -309,6 +310,7 @@ Material* createDebugMaterial()
 
     Effect* effect = Effect::createFromSource(vs_str, fs_str);
     Material* material = Material::create(effect);
+    GP_ASSERT(material && material->getStateBlock());
     material->getStateBlock()->setDepthTest(true);
 
     SAFE_RELEASE(effect);
@@ -359,6 +361,8 @@ struct DebugVertex
 
 void drawDebugLine(MeshBatch* batch, const Vector3& point1, const Vector3& point2, const Vector3& color)
 {
+    GP_ASSERT(batch);
+
     static DebugVertex verts[2];
 
     verts[0].x = point1.x;
@@ -457,12 +461,15 @@ void drawDebugSphere(MeshBatch* batch, const BoundingSphere& sphere)
 
 void drawDebugNode(MeshBatch* batch, Node* node, unsigned int debugFlags)
 {
+    GP_ASSERT(node);
     Model* model = node->getModel();
 
     if ((debugFlags & Scene::DEBUG_BOXES) && model)
     {
+        GP_ASSERT(model->getMesh());
+
         MeshSkin* skin = model->getSkin();
-        if (skin && skin->getRootJoint()->getParent())
+        if (skin && skin->getRootJoint() && skin->getRootJoint()->getParent())
         {
             // For skinned meshes that have a parent node to the skin's root joint,
             // we need to transform the bounding volume by that parent node's transform
@@ -480,11 +487,9 @@ void drawDebugNode(MeshBatch* batch, Node* node, unsigned int debugFlags)
         drawDebugSphere(batch, node->getBoundingSphere());
     }
 
-    Node* child = node->getFirstChild();
-    while (child)
+    for (Node* child = node->getFirstChild(); child != NULL; child = child->getNextSibling())
     {
         drawDebugNode(batch, child, debugFlags);
-        child = child->getNextSibling();
     }
 }
 
@@ -507,17 +512,19 @@ void Scene::drawDebug(unsigned int debugFlags)
 
     _debugBatch->begin();
 
-    Node* node = _firstNode;
-    while (node)
+    for (Node* node = _firstNode; node != NULL; node = node->_nextSibling)
     {
         drawDebugNode(_debugBatch, node, debugFlags);
-        node = node->_nextSibling;
     }
 
     _debugBatch->end();
 
     if (_activeCamera)
+    {
+        GP_ASSERT(_debugBatch->getMaterial());
+        GP_ASSERT(_debugBatch->getMaterial()->getParameter("u_viewProjectionMatrix"));
         _debugBatch->getMaterial()->getParameter("u_viewProjectionMatrix")->setValue(_activeCamera->getViewProjectionMatrix());
+    }
 
     _debugBatch->draw();
 }

+ 125 - 59
gameplay/src/SceneLoader.cpp

@@ -13,23 +13,19 @@ std::string SceneLoader::_path;
 
 Scene* SceneLoader::load(const char* url)
 {
-    GP_ASSERT(url);
-
     // Load the scene properties from file.
     Properties* properties = Properties::create(url);
-    GP_ASSERT(properties);
     if (properties == NULL)
     {
-        GP_WARN("Failed to load scene file: %s", url);
+        GP_ERROR("Failed to load scene file '%s'.", url);
         return NULL;
     }
 
     // Check if the properties object is valid and has a valid namespace.
     Properties* sceneProperties = (strlen(properties->getNamespace()) > 0) ? properties : properties->getNextNamespace();
-    GP_ASSERT(sceneProperties);
     if (!sceneProperties || !(strcmp(sceneProperties->getNamespace(), "scene") == 0))
     {
-        GP_WARN("Failed to load scene from properties object: must be non-null object and have namespace equal to 'scene'.");
+        GP_ERROR("Failed to load scene from properties object: must be non-null object and have namespace equal to 'scene'.");
         SAFE_DELETE(properties);
         return NULL;
     }
@@ -45,6 +41,7 @@ Scene* SceneLoader::load(const char* url)
     Scene* scene = loadMainSceneData(sceneProperties);
     if (!scene)
     {
+        GP_ERROR("Failed to load main scene from bundle.");
         SAFE_DELETE(properties);
         return NULL;
     }
@@ -152,14 +149,15 @@ void SceneLoader::applyNodeProperties(const Scene* scene, const Properties* scen
     for (unsigned int i = 0, ncount = _sceneNodes.size(); i < ncount; ++i)
     {
         SceneNode& sceneNode = _sceneNodes[i];
+        GP_ASSERT(sceneNode._nodeID);
 
         if (sceneNode._exactMatch)
         {
-            // Find the node matching the specified ID exactly
+            // Find the node matching the specified ID exactly.
             Node* node = scene->findNode(sceneNode._nodeID);
             if (!node)
             {
-                GP_WARN("Attempting to set a property for node '%s', which does not exist in the scene.", sceneNode._nodeID);
+                GP_ERROR("Failed to set property for node '%s', which does not exist in the scene.", sceneNode._nodeID);
                 continue;
             }
 
@@ -172,11 +170,14 @@ void SceneLoader::applyNodeProperties(const Scene* scene, const Properties* scen
         }
         else
         {
-            // Find all nodes matching the specified ID
+            // Find all nodes matching the specified ID.
             std::vector<Node*> nodes;
             unsigned int nodeCount = scene->findNodes(sceneNode._nodeID, nodes, true, false);
             if (nodeCount == 0)
+            {
+                GP_ERROR("Failed to set property for nodes with id matching '%s'; no such nodes exist in the scene.", sceneNode._nodeID);
                 continue;
+            }
             
             for (unsigned int j = 0, pcount = sceneNode._properties.size(); j < pcount; ++j)
             {
@@ -204,7 +205,7 @@ void SceneLoader::applyNodeProperty(SceneNode& sceneNode, Node* node, const Prop
         Properties* p = _propertiesFromFile[snp._file];
         if (!p)
         {
-            GP_WARN("The referenced node data in file '%s' failed to load.", snp._file.c_str());
+            GP_ERROR("The referenced node data in file '%s' failed to load.", snp._file.c_str());
             return;
         }
 
@@ -214,7 +215,7 @@ void SceneLoader::applyNodeProperty(SceneNode& sceneNode, Node* node, const Prop
             p = p->getNamespace(snp._id.c_str());
             if (!p)
             {
-                GP_WARN("The referenced node data at '%s#%s' failed to load.", snp._file.c_str(), snp._id.c_str());
+                GP_ERROR("The referenced node data at '%s#%s' failed to load.", snp._file.c_str(), snp._id.c_str());
                 return;
             }
         }
@@ -236,7 +237,10 @@ void SceneLoader::applyNodeProperty(SceneNode& sceneNode, Node* node, const Prop
         }
         case SceneNodeProperty::MATERIAL:
             if (!node->getModel())
-                GP_WARN("Attempting to set a material on node '%s', which has no model.", sceneNode._nodeID);
+            {
+                GP_ERROR("Attempting to set a material on node '%s', which has no model.", sceneNode._nodeID);
+                return;
+            }
             else
             {
                 Material* material = Material::create(p);
@@ -259,7 +263,7 @@ void SceneLoader::applyNodeProperty(SceneNode& sceneNode, Node* node, const Prop
             Properties* p = _propertiesFromFile[snp._file];
             if (!p)
             {
-                GP_WARN("The referenced node data in file '%s' failed to load.", snp._file.c_str());
+                GP_ERROR("The referenced node data in file '%s' failed to load.", snp._file.c_str());
                 return;
             }
 
@@ -269,7 +273,7 @@ void SceneLoader::applyNodeProperty(SceneNode& sceneNode, Node* node, const Prop
                 p = p->getNamespace(snp._id.c_str());
                 if (!p)
                 {
-                    GP_WARN("The referenced node data at '%s#%s' failed to load.", snp._file.c_str(), snp._id.c_str());
+                    GP_ERROR("The referenced node data at '%s#%s' failed to load.", snp._file.c_str(), snp._id.c_str());
                     return;
                 }
             }
@@ -283,15 +287,18 @@ void SceneLoader::applyNodeProperty(SceneNode& sceneNode, Node* node, const Prop
             // Check to make sure the type of the namespace used to load the physics collision object is correct.
             if (snp._type == SceneNodeProperty::CHARACTER && strcmp(p->getNamespace(), "character") != 0)
             {
-                GP_WARN("Attempting to set a 'character' (physics collision object attribute) on a node using a '%s' definition.", p->getNamespace());
+                GP_ERROR("Attempting to set a 'character' (physics collision object attribute) on a node using a '%s' definition.", p->getNamespace());
+                return;
             }
             else if (snp._type == SceneNodeProperty::GHOSTOBJECT && strcmp(p->getNamespace(), "ghostObject") != 0)
             {
-                GP_WARN("Attempting to set a 'ghostObject' (physics collision object attribute) on a node using a '%s' definition.", p->getNamespace());
+                GP_ERROR("Attempting to set a 'ghostObject' (physics collision object attribute) on a node using a '%s' definition.", p->getNamespace());
+                return;
             }
             else if (snp._type == SceneNodeProperty::RIGIDBODY && strcmp(p->getNamespace(), "rigidBody") != 0)
             {
-                GP_WARN("Attempting to set a 'rigidBody' (physics collision object attribute) on a node using a '%s' definition.", p->getNamespace());
+                GP_ERROR("Attempting to set a 'rigidBody' (physics collision object attribute) on a node using a '%s' definition.", p->getNamespace());
+                return;
             }
             else
             {
@@ -300,13 +307,19 @@ void SceneLoader::applyNodeProperty(SceneNode& sceneNode, Node* node, const Prop
                 const char* name = NULL;
                 if (np && (name = np->getString("rigidBodyModel")))
                 {
+                    GP_ASSERT(scene);
                     Node* modelNode = scene->findNode(name);
                     if (!modelNode)
-                        GP_WARN("Node '%s' does not exist; attempting to use its model for collision object creation.", name);
+                    {
+                        GP_ERROR("Node '%s' does not exist; attempting to use its model for collision object creation.", name);
+                        return;
+                    }
                     else
                     {
                         if (!modelNode->getModel())
-                            GP_WARN("Node '%s' does not have a model; attempting to use its model for collision object creation.", name);
+                        {
+                            GP_ERROR("Node '%s' does not have a model; attempting to use its model for collision object creation.", name);
+                        }
                         else
                         {
                             // Temporarily set rigidBody model on model so it's used during collision object creation.
@@ -335,13 +348,13 @@ void SceneLoader::applyNodeProperty(SceneNode& sceneNode, Node* node, const Prop
             break;
         }
         default:
-            // This cannot happen.
+            GP_ERROR("Unsupported node property type (%d).", snp._type);
             break;
         }
     }
     else
     {
-        // Handle Scale, Rotate and Translate
+        // Handle scale, rotate and translate.
         Properties* np = sceneProperties->getNamespace(sceneNode._nodeID);
         const char* name = NULL;
 
@@ -379,7 +392,7 @@ void SceneLoader::applyNodeProperty(SceneNode& sceneNode, Node* node, const Prop
             break;
         }
         default:
-            GP_WARN("Unsupported node property type: %d.", snp._type);
+            GP_ERROR("Unsupported node property type (%d).", snp._type);
             break;
         }
     }
@@ -387,6 +400,8 @@ void SceneLoader::applyNodeProperty(SceneNode& sceneNode, Node* node, const Prop
 
 void SceneLoader::applyNodeUrls(Scene* scene)
 {
+    GP_ASSERT(scene);
+
     // Apply all URL node properties so that when we go to apply
     // the other node properties, the node is in the scene.
     for (unsigned int i = 0, ncount = _sceneNodes.size(); i < ncount; ++i)
@@ -416,7 +431,7 @@ void SceneLoader::applyNodeUrls(Scene* scene)
                     }
                     else
                     {
-                        GP_WARN("Could not find node '%s' in main scene GPB file.", snp._id.c_str());
+                        GP_ERROR("Could not find node '%s' in main scene GPB file.", snp._id.c_str());
                     }
                 }
                 else
@@ -427,10 +442,13 @@ void SceneLoader::applyNodeUrls(Scene* scene)
                     unsigned int nodeCount = scene->findNodes(snp._id.c_str(), nodes, true, false);
                     if (nodeCount > 0)
                     {
+                        GP_ASSERT(sceneNode._nodeID);
+
                         for (unsigned int k = 0; k < nodeCount; ++k)
                         {
                             // Construct a new node ID using _nodeID plus the remainder of the partial match.
                             Node* node = nodes[k];
+                            GP_ASSERT(node);
                             std::string newID(sceneNode._nodeID);
                             newID += (node->getId() + snp._id.length());
                             node->setId(newID.c_str());
@@ -438,7 +456,7 @@ void SceneLoader::applyNodeUrls(Scene* scene)
                     }
                     else
                     {
-                        GP_WARN("Could not find any nodes matching '%s' in main scene GPB file.", snp._id.c_str());
+                        GP_ERROR("Could not find any nodes matching '%s' in main scene GPB file.", snp._id.c_str());
                     }
                 }
             }
@@ -463,7 +481,7 @@ void SceneLoader::applyNodeUrls(Scene* scene)
                         }
                         else
                         {
-                            GP_WARN("Could not load node '%s' in GPB file '%s'.", snp._id.c_str(), snp._file.c_str());
+                            GP_ERROR("Could not load node '%s' from GPB file '%s'.", snp._id.c_str(), snp._file.c_str());
                         }
                     }
                     else
@@ -494,7 +512,7 @@ void SceneLoader::applyNodeUrls(Scene* scene)
                         }
                         if (matchCount == 0)
                         {
-                            GP_WARN("Could not find any nodes matching '%s' in GPB file '%s'.", snp._id.c_str(), snp._file.c_str());
+                            GP_ERROR("Could not find any nodes matching '%s' in GPB file '%s'.", snp._id.c_str(), snp._file.c_str());
                         }
                     }
 
@@ -502,7 +520,7 @@ void SceneLoader::applyNodeUrls(Scene* scene)
                 }
                 else
                 {
-                    GP_WARN("Failed to load GPB file '%s' for node stitching.", snp._file.c_str());
+                    GP_ERROR("Failed to load GPB file '%s' for node stitching.", snp._file.c_str());
                 }
             }
 
@@ -523,11 +541,11 @@ void SceneLoader::buildReferenceTables(Properties* sceneProperties)
         {
             if (strlen(ns->getId()) == 0)
             {
-                GP_WARN("Nodes must have an ID; skipping the current node.");
+                GP_ERROR("Attempting to load a node without an ID.");
                 continue;
             }
 
-            // Add a SceneNode to the end of the list
+            // Add a SceneNode to the end of the list.
             _sceneNodes.resize(_sceneNodes.size() + 1);
             SceneNode& sceneNode = _sceneNodes[_sceneNodes.size()-1];
             sceneNode._nodeID = ns->getId();
@@ -596,7 +614,7 @@ void SceneLoader::buildReferenceTables(Properties* sceneProperties)
                 }
                 else
                 {
-                    GP_WARN("Unsupported node property: %s = %s", name, ns->getString());
+                    GP_ERROR("Unsupported node property: %s = %s", name, ns->getString());
                 }
             }
         }
@@ -611,20 +629,20 @@ void SceneLoader::buildReferenceTables(Properties* sceneProperties)
                     const char* animationID = animation->getId();
                     if (strlen(animationID) == 0)
                     {
-                        GP_WARN("Animations must have an ID; skipping the current animation.");
+                        GP_ERROR("Attempting to load an animation without an ID.");
                         continue;
                     }
 
                     const char* url = animation->getString("url");
                     if (!url)
                     {
-                        GP_WARN("Animations must have a URL; skipping animation '%s'.", animationID);
+                        GP_ERROR("Attempting to load animation '%s' without a URL.", animationID);
                         continue;
                     }
                     const char* targetID = animation->getString("target");
                     if (!targetID)
                     {
-                        GP_WARN("Animations must have a target; skipping animation '%s'.", animationID);
+                        GP_ERROR("Attempting to load animation '%s' without a target.", animationID);
                         continue;
                     }
 
@@ -632,7 +650,7 @@ void SceneLoader::buildReferenceTables(Properties* sceneProperties)
                 }
                 else
                 {
-                    GP_WARN("Unsupported child namespace (of 'animations'): %s", ns->getNamespace());
+                    GP_ERROR("Unsupported child namespace (of 'animations'): %s", ns->getNamespace());
                 }
             }
         }
@@ -644,7 +662,7 @@ void SceneLoader::buildReferenceTables(Properties* sceneProperties)
         else
         {
             // TODO: Should we ignore these items? They could be used for generic properties file inheritance.
-            GP_WARN("Unsupported child namespace (of 'scene'): %s", ns->getNamespace());
+            GP_ERROR("Unsupported child namespace (of 'scene'): %s", ns->getNamespace());
         }
     }
 }
@@ -659,7 +677,7 @@ void SceneLoader::createAnimations(const Scene* scene)
         Node* node = scene->findNode(_animations[i]._targetID);
         if (!node)
         {
-            GP_WARN("Attempting to create an animation targeting node '%s', which does not exist in the scene.", _animations[i]._targetID);
+            GP_ERROR("Attempting to create an animation targeting node '%s', which does not exist in the scene.", _animations[i]._targetID);
             continue;
         }
 
@@ -667,7 +685,7 @@ void SceneLoader::createAnimations(const Scene* scene)
         Properties* p = _propertiesFromFile[_animations[i]._file];
         if (!p)
         {
-            GP_WARN("The referenced animation data in file '%s' failed to load.", _animations[i]._file.c_str());
+            GP_ERROR("The referenced animation data in file '%s' failed to load.", _animations[i]._file.c_str());
             continue;
         }
         if (_animations[i]._id.size() > 0)
@@ -675,7 +693,7 @@ void SceneLoader::createAnimations(const Scene* scene)
             p = p->getNamespace(_animations[i]._id.c_str());
             if (!p)
             {
-                GP_WARN("The referenced animation data at '%s#%s' failed to load.", _animations[i]._file.c_str(), _animations[i]._id.c_str());
+                GP_ERROR("The referenced animation data at '%s#%s' failed to load.", _animations[i]._file.c_str(), _animations[i]._id.c_str());
                 continue;
             }
         }
@@ -686,7 +704,10 @@ void SceneLoader::createAnimations(const Scene* scene)
 
 PhysicsConstraint* SceneLoader::loadGenericConstraint(const Properties* constraint, PhysicsRigidBody* rbA, PhysicsRigidBody* rbB)
 {
-    PhysicsGenericConstraint* physicsConstraint;
+    GP_ASSERT(rbA);
+    GP_ASSERT(constraint);
+    GP_ASSERT(Game::getInstance()->getPhysicsController());
+    PhysicsGenericConstraint* physicsConstraint = NULL;
 
     // Create the constraint from the specified properties.
     Quaternion roA;
@@ -714,6 +735,7 @@ PhysicsConstraint* SceneLoader::loadGenericConstraint(const Properties* constrai
     {
         physicsConstraint = Game::getInstance()->getPhysicsController()->createGenericConstraint(rbA, rbB);
     }
+    GP_ASSERT(physicsConstraint);
 
     // Set the optional parameters that were specified.
     Vector3 v;
@@ -731,6 +753,9 @@ PhysicsConstraint* SceneLoader::loadGenericConstraint(const Properties* constrai
 
 PhysicsConstraint* SceneLoader::loadHingeConstraint(const Properties* constraint, PhysicsRigidBody* rbA, PhysicsRigidBody* rbB)
 {
+    GP_ASSERT(rbA);
+    GP_ASSERT(constraint);
+    GP_ASSERT(Game::getInstance()->getPhysicsController());
     PhysicsHingeConstraint* physicsConstraint = NULL;
 
     // Create the constraint from the specified properties.
@@ -752,25 +777,44 @@ PhysicsConstraint* SceneLoader::loadHingeConstraint(const Properties* constraint
         physicsConstraint = Game::getInstance()->getPhysicsController()->createHingeConstraint(rbA, roA, toA);
     }
 
-    // Attempt to load the hinge limits first as a Vector3 and if that doesn't work, try loading as a Vector2.
-    // We do this because the user can specify just the min and max angle, or both angle along with bounciness.
-    Vector3 fullLimits;
-    Vector2 angleLimits;
-    if (constraint->getVector3("limits", &fullLimits))
-        physicsConstraint->setLimits(MATH_DEG_TO_RAD(fullLimits.x), MATH_DEG_TO_RAD(fullLimits.y), fullLimits.z);
-    else if (constraint->getVector2("limits", &angleLimits))
-        physicsConstraint->setLimits(angleLimits.x, angleLimits.y);
+    // Load the hinge angle limits (lower and upper) and the hinge bounciness (if specified).
+    const char* limitsString = constraint->getString("limits");
+    if (limitsString)
+    {
+        float lowerLimit, upperLimit;
+        int scanned;
+        scanned = sscanf(limitsString, "%f,%f", &lowerLimit, &upperLimit);
+        if (scanned == 2)
+        {
+            physicsConstraint->setLimits(MATH_DEG_TO_RAD(lowerLimit), MATH_DEG_TO_RAD(upperLimit));
+        }
+        else
+        {
+            float bounciness;
+            scanned = sscanf(limitsString, "%f,%f,%f", &lowerLimit, &upperLimit, &bounciness);
+            if (scanned == 3)
+            {
+                physicsConstraint->setLimits(MATH_DEG_TO_RAD(lowerLimit), MATH_DEG_TO_RAD(upperLimit), bounciness);
+            }
+            else
+            {
+                GP_ERROR("Failed to parse 'limits' attribute for hinge constraint '%s'.", constraint->getId());
+            }
+        }
+    }
 
     return physicsConstraint;
 }
 
 Scene* SceneLoader::loadMainSceneData(const Properties* sceneProperties)
 {
+    GP_ASSERT(sceneProperties);
+
     // Load the main scene from the specified path.
     Bundle* bundle = Bundle::create(_path.c_str());
     if (!bundle)
     {
-        GP_WARN("Failed to load scene GPB file '%s'.", _path.c_str());
+        GP_ERROR("Failed to load scene GPB file '%s'.", _path.c_str());
         return NULL;
     }
 
@@ -778,7 +822,7 @@ Scene* SceneLoader::loadMainSceneData(const Properties* sceneProperties)
     Scene* scene = bundle->loadScene(NULL);
     if (!scene)
     {
-        GP_WARN("Failed to load scene from '%s'.", _path.c_str());
+        GP_ERROR("Failed to load scene from '%s'.", _path.c_str());
         SAFE_RELEASE(bundle);
         return NULL;
     }
@@ -798,6 +842,10 @@ Scene* SceneLoader::loadMainSceneData(const Properties* sceneProperties)
 
 void SceneLoader::loadPhysics(Properties* physics, Scene* scene)
 {
+    GP_ASSERT(physics);
+    GP_ASSERT(scene);
+    GP_ASSERT(Game::getInstance()->getPhysicsController());
+
     // Go through the supported global physics properties and apply them.
     Vector3 gravity;
     if (physics->getVector3("gravity", &gravity))
@@ -817,18 +865,18 @@ void SceneLoader::loadPhysics(Properties* physics, Scene* scene)
             name = constraint->getString("rigidBodyA");
             if (!name)
             {
-                GP_WARN("Missing property 'rigidBodyA' for constraint %s", constraint->getId());
+                GP_ERROR("Missing property 'rigidBodyA' for constraint '%s'.", constraint->getId());
                 continue;
             }
             Node* rbANode = scene->findNode(name);
             if (!rbANode)
             {
-                GP_WARN("Node '%s' to be used as 'rigidBodyA' for constraint %s cannot be found.", name, constraint->getId());
+                GP_ERROR("Node '%s' to be used as 'rigidBodyA' for constraint '%s' cannot be found.", name, constraint->getId());
                 continue;
             }
             if (!rbANode->getCollisionObject() || rbANode->getCollisionObject()->getType() != PhysicsCollisionObject::RIGID_BODY)
             {
-                GP_WARN("Node '%s' to be used as 'rigidBodyA' does not have a rigid body.", name);
+                GP_ERROR("Node '%s' to be used as 'rigidBodyA' does not have a rigid body.", name);
                 continue;
             }
             PhysicsRigidBody* rbA = static_cast<PhysicsRigidBody*>(rbANode->getCollisionObject());
@@ -844,12 +892,12 @@ void SceneLoader::loadPhysics(Properties* physics, Scene* scene)
                 Node* rbBNode = scene->findNode(name);
                 if (!rbBNode)
                 {
-                    GP_WARN("Node '%s' to be used as 'rigidBodyB' for constraint %s cannot be found.", name, constraint->getId());
+                    GP_ERROR("Node '%s' to be used as 'rigidBodyB' for constraint '%s' cannot be found.", name, constraint->getId());
                     continue;
                 }
                 if (!rbBNode->getCollisionObject() || rbBNode->getCollisionObject()->getType() != PhysicsCollisionObject::RIGID_BODY)
                 {
-                    GP_WARN("Node '%s' to be used as 'rigidBodyB' does not have a rigid body.", name);
+                    GP_ERROR("Node '%s' to be used as 'rigidBodyB' does not have a rigid body.", name);
                     continue;
                 }
                 rbB = static_cast<PhysicsRigidBody*>(rbBNode->getCollisionObject());
@@ -878,18 +926,25 @@ void SceneLoader::loadPhysics(Properties* physics, Scene* scene)
             {
                 physicsConstraint = loadSpringConstraint(constraint, rbA, rbB);
             }
+            else
+            {
+                GP_ERROR("Unsupported physics constraint type '%s'.", type.c_str());
+            }
             
             // If the constraint failed to load, continue on to the next one.
             if (!physicsConstraint)
+            {
+                GP_ERROR("Failed to create physics constraint.");
                 continue;
+            }
 
             // If the breaking impulse was specified, apply it to the constraint.
-            if (constraint->getString("breakingImpulse"))
+            if (constraint->exists("breakingImpulse"))
                 physicsConstraint->setBreakingImpulse(constraint->getFloat("breakingImpulse"));
         }
         else
         {
-            GP_WARN("Unsupported child namespace (of 'physics'): %s", physics->getNamespace());
+            GP_ERROR("Unsupported 'physics' child namespace '%s'.", physics->getNamespace());
         }
     }
 }
@@ -901,9 +956,8 @@ void SceneLoader::loadReferencedFiles()
     for (; iter != _propertiesFromFile.end(); iter++)
     {
         Properties* p = Properties::create(iter->first.c_str());
-        GP_ASSERT(p);
         if (p == NULL)
-            GP_WARN("Failed to load referenced file: %s", iter->first.c_str());
+            GP_ERROR("Failed to load referenced file '%s'.", iter->first.c_str());
 
         iter->second = p;
     }
@@ -911,6 +965,10 @@ void SceneLoader::loadReferencedFiles()
 
 PhysicsConstraint* SceneLoader::loadSocketConstraint(const Properties* constraint, PhysicsRigidBody* rbA, PhysicsRigidBody* rbB)
 {
+    GP_ASSERT(rbA);
+    GP_ASSERT(constraint);
+    GP_ASSERT(Game::getInstance()->getPhysicsController());
+
     PhysicsSocketConstraint* physicsConstraint = NULL;
     Vector3 toA;
     bool offsetSpecified = constraint->getVector3("translationOffsetA", &toA);
@@ -939,9 +997,13 @@ PhysicsConstraint* SceneLoader::loadSocketConstraint(const Properties* constrain
 
 PhysicsConstraint* SceneLoader::loadSpringConstraint(const Properties* constraint, PhysicsRigidBody* rbA, PhysicsRigidBody* rbB)
 {
+    GP_ASSERT(rbA);
+    GP_ASSERT(constraint);
+    GP_ASSERT(Game::getInstance()->getPhysicsController());
+
     if (!rbB)
     {
-        GP_WARN("Spring constraints require two rigid bodies.");
+        GP_ERROR("Spring constraints require two rigid bodies.");
         return NULL;
     }
 
@@ -963,6 +1025,7 @@ PhysicsConstraint* SceneLoader::loadSpringConstraint(const Properties* constrain
     {
         physicsConstraint = Game::getInstance()->getPhysicsController()->createSpringConstraint(rbA, rbB);
     }
+    GP_ASSERT(physicsConstraint);
 
     // Set the optional parameters that were specified.
     Vector3 v;
@@ -1005,7 +1068,10 @@ PhysicsConstraint* SceneLoader::loadSpringConstraint(const Properties* constrain
 void SceneLoader::splitURL(const char* url, std::string* file, std::string* id)
 {
     if (!url)
+    {
+        // This is allowed since many scene node properties do not use the URL.
         return;
+    }
 
     std::string urlString = url;
 

Некоторые файлы не были показаны из-за большого количества измененных файлов