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

Fixes properties caching optimization issue in SceneLoader.
Fixes memory leaks in Bundle and Texture.
Fixes compilation warning in Matrix.

Chris Culy 13 лет назад
Родитель
Сommit
9736fa587d

+ 15 - 2
gameplay/src/Bundle.cpp

@@ -598,10 +598,14 @@ Node* Bundle::loadNode(const char* id, Scene* sceneContext, Node* nodeContext)
     if (sceneContext)
     {
         node = sceneContext->findNode(id, true);
+        if (node)
+            node->addRef();
     }
     else if (nodeContext)
     {
         node = nodeContext->findNode(id, true);
+        if (node)
+            node->addRef();
     }
 
     if (node == NULL)
@@ -704,7 +708,7 @@ Node* Bundle::readNode(Scene* sceneContext, Node* nodeContext)
             if (fseek(_file, sizeof(float) * 16, SEEK_CUR) != 0)
             {
                 GP_ERROR("Failed to skip over node transform for node '%s'.", id);
-                return false;
+                return NULL;
             }
             readString(_file);
 
@@ -724,6 +728,7 @@ Node* Bundle::readNode(Scene* sceneContext, Node* nodeContext)
                 }
             }
 
+            iter->second->addRef();
             return iter->second;
         }
         else
@@ -1108,6 +1113,7 @@ void Bundle::resolveJointReferences(Scene* sceneContext, Node* nodeContext)
                     Joint* joint = static_cast<Joint*>(n);
                     joint->setInverseBindPose(skinData->inverseBindPoseMatrices[j]);
                     skinData->skin->setJoint(joint, j);
+                    SAFE_RELEASE(joint);
                 }
             }
         }
@@ -1120,6 +1126,7 @@ void Bundle::resolveJointReferences(Scene* sceneContext, Node* nodeContext)
             GP_ASSERT(node);
             Node* parent = node->getParent();
             
+            std::vector<Node*> loadedNodes;
             while (true)
             {
                 if (parent)
@@ -1165,13 +1172,19 @@ void Bundle::resolveJointReferences(Scene* sceneContext, Node* nodeContext)
                     }
 
                     if (nodeID != rootJoint->getId())
-                        loadNode(nodeID.c_str(), sceneContext, nodeContext);
+                        loadedNodes.push_back(loadNode(nodeID.c_str(), sceneContext, nodeContext));
 
                     break;
                 }
             }
 
             skinData->skin->setRootJoint(rootJoint);
+
+            // Release all the nodes that we loaded since the nodes are now owned by the mesh skin.
+            for (unsigned int i = 0; i < loadedNodes.size(); i++)
+            {
+                SAFE_RELEASE(loadedNodes[i]);
+            }
         }
 
         // Remove the joint hierarchy from the scene since it is owned by the mesh skin.

+ 2 - 0
gameplay/src/Matrix.cpp

@@ -3,7 +3,9 @@
 #include "Quaternion.h"
 #include "MathUtil.h"
 
+#ifndef MATRIX_SIZE
 #define MATRIX_SIZE     ( sizeof(float) * 16 )
+#endif
 
 namespace gameplay
 {

+ 87 - 59
gameplay/src/Properties.cpp

@@ -6,6 +6,10 @@
 namespace gameplay
 {
 
+// Utility functions (shared with SceneLoader).
+void calculateNamespacePath(const std::string& urlString, std::string& fileString, std::vector<std::string>& namespacePath);
+Properties* getPropertiesFromNamespacePath(Properties* properties, const std::vector<std::string>& namespacePath);
+
 Properties::Properties()
 {
 }
@@ -55,28 +59,11 @@ Properties* Properties::create(const char* url)
         return NULL;
     }
 
+    // Calculate the file and full namespace path from the specified url.
     std::string urlString = url;
     std::string fileString;
     std::vector<std::string> namespacePath;
-
-    // If the url references a specific namespace within the file,
-    // calculate the full namespace path to the final namespace.
-    unsigned int loc = urlString.rfind("#");
-    if (loc != urlString.npos)
-    {
-        fileString = urlString.substr(0, loc);
-        std::string namespacePathString = urlString.substr(loc + 1);
-        while ((loc = namespacePathString.find("/")) != namespacePathString.npos)
-        {
-            namespacePath.push_back(namespacePathString.substr(0, loc));
-            namespacePathString = namespacePathString.substr(loc + 1);
-        }
-        namespacePath.push_back(namespacePathString);
-    }
-    else
-    {
-        fileString = url;
-    }
+    calculateNamespacePath(urlString, fileString, namespacePath);
 
     FILE* file = FileSystem::openFile(fileString.c_str(), "rb");
     if (!file)
@@ -86,52 +73,26 @@ Properties* Properties::create(const char* url)
     }
 
     Properties* properties = new Properties(file);
-
     properties->resolveInheritance();
-
     fclose(file);
 
-    // If the url references a specific namespace within the file,
-    // return the specified namespace or notify the user if it cannot be found.
-    Properties* originalProperties = properties;
-    if (namespacePath.size() > 0)
+    // Get the specified properties object.
+    Properties* p = getPropertiesFromNamespacePath(properties, namespacePath);
+    if (!p)
     {
-        unsigned int size = namespacePath.size();
-        Properties* iter = properties->getNextNamespace();
-        for (unsigned int i = 0; i < size;)
-        {
-            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)
-                    {
-                        properties = iter->getNextNamespace();
-                        iter = properties;
-                    }
-                    else
-                        properties = iter;
-
-                    i++;
-                    break;
-                }
-                
-                iter = properties->getNextNamespace();
-            }
-        }
+        GP_ERROR("Failed to load properties from url '%s'.", url);
+        return NULL;
+    }
 
-        properties = properties->clone();
-        SAFE_DELETE(originalProperties);
-        return properties;
+    // If the loaded properties object is not the root namespace,
+    // then we have to clone it and delete the root namespace
+    // so that we don't leak memory.
+    if (p != properties)
+    {
+        p = p->clone();
+        SAFE_DELETE(properties);
     }
-    else
-        return properties;
+    return p;
 }
 
 void Properties::readProperties(FILE* file)
@@ -1009,4 +970,71 @@ Properties* Properties::clone()
     return p;
 }
 
+void calculateNamespacePath(const std::string& urlString, std::string& fileString, std::vector<std::string>& namespacePath)
+{
+    // If the url references a specific namespace within the file,
+    // calculate the full namespace path to the final namespace.
+    unsigned int loc = urlString.rfind("#");
+    if (loc != urlString.npos)
+    {
+        fileString = urlString.substr(0, loc);
+        std::string namespacePathString = urlString.substr(loc + 1);
+        while ((loc = namespacePathString.find("/")) != namespacePathString.npos)
+        {
+            namespacePath.push_back(namespacePathString.substr(0, loc));
+            namespacePathString = namespacePathString.substr(loc + 1);
+        }
+        namespacePath.push_back(namespacePathString);
+    }
+    else
+    {
+        fileString = urlString;
+    }
+}
+
+Properties* getPropertiesFromNamespacePath(Properties* properties, const std::vector<std::string>& namespacePath)
+{
+    // If the url references a specific namespace within the file,
+    // return the specified namespace or notify the user if it cannot be found.
+    Properties* originalProperties = properties;
+    if (namespacePath.size() > 0)
+    {
+        unsigned int size = namespacePath.size();
+        const char* tmp = namespacePath[0].c_str();
+        properties->rewind();
+        Properties* iter = properties->getNextNamespace();
+        for (unsigned int i = 0; i < size;)
+        {
+            while (true)
+            {
+                if (iter == NULL)
+                {
+                    GP_ERROR("Failed to load properties object from url.");
+                    return NULL;
+                }
+
+                if (strcmp(iter->getId(), namespacePath[i].c_str()) == 0)
+                {
+                    if (i != size - 1)
+                    {
+                        properties = iter->getNextNamespace();
+                        iter = properties;
+                    }
+                    else
+                        properties = iter;
+
+                    i++;
+                    break;
+                }
+                
+                iter = properties->getNextNamespace();
+            }
+        }
+
+        return properties;
+    }
+    else
+        return properties;
+}
+
 }

+ 38 - 7
gameplay/src/SceneLoader.cpp

@@ -6,6 +6,11 @@
 namespace gameplay
 {
 
+// Utility functions (shared with Properties).
+extern void calculateNamespacePath(const std::string& urlString, std::string& fileString, std::vector<std::string>& namespacePath);
+extern Properties* getPropertiesFromNamespacePath(Properties* properties, const std::vector<std::string>& namespacePath);
+    
+std::map<std::string, Properties*> SceneLoader::_propertiesFromFile;
 std::map<std::string, Properties*> SceneLoader::_properties;
 std::vector<SceneLoader::SceneAnimation> SceneLoader::_animations;
 std::vector<SceneLoader::SceneNode> SceneLoader::_sceneNodes;
@@ -89,11 +94,11 @@ Scene* SceneLoader::load(const char* url)
         loadPhysics(physics, scene);
 
     // Clean up all loaded properties objects.
-    std::map<std::string, Properties*>::iterator iter = _properties.begin();
-    for (; iter != _properties.end(); iter++)
+    _properties.clear();
+    std::map<std::string, Properties*>::iterator iter = _propertiesFromFile.begin();
+    for (; iter != _propertiesFromFile.end(); iter++)
     {
-        if (iter->first.find(_path) == iter->first.npos)
-            SAFE_DELETE(iter->second);
+        SAFE_DELETE(iter->second);
     }
 
     // Clean up the .scene file's properties object.
@@ -827,10 +832,36 @@ void SceneLoader::loadReferencedFiles()
     {
         if (iter->second == NULL)
         {
-            Properties* p = Properties::create(iter->first.c_str());
-            if (p == NULL)
-                GP_ERROR("Failed to load referenced file '%s'.", iter->first.c_str());
+            std::string fileString;
+            std::vector<std::string> namespacePath;
+            calculateNamespacePath(iter->first, fileString, namespacePath);
+
+            // Check if the referenced properties file has already been loaded.
+            Properties* properties = NULL;
+            std::map<std::string, Properties*>::iterator pffIter = _propertiesFromFile.find(fileString);
+            if (pffIter != _propertiesFromFile.end())
+            {
+                properties = pffIter->second;
+            }
+            else
+            {
+                properties = Properties::create(fileString.c_str());
+                if (properties == NULL)
+                {
+                    GP_ERROR("Failed to load referenced properties file '%s'.", fileString);
+                    continue;
+                }
+
+                // Add the properties object to the cache.
+                _propertiesFromFile.insert(std::make_pair(fileString, properties));
+            }
 
+            Properties* p = getPropertiesFromNamespacePath(properties, namespacePath);
+            if (!p)
+            {
+                GP_ERROR("Failed to load referenced properties from url '%s'.", iter->first.c_str());
+                continue;
+            }
             iter->second = p;
         }
     }

+ 1 - 0
gameplay/src/SceneLoader.h

@@ -105,6 +105,7 @@ private:
     static void splitURL(const std::string& url, std::string* file, std::string* id);
     
     
+    static std::map<std::string, Properties*> _propertiesFromFile;      // Holds the properties object for a given file.
     static std::map<std::string, Properties*> _properties;              // Holds the properties object for a given URL.
     static std::vector<SceneAnimation> _animations;                     // Holds the animations declared in the .scene file.
     static std::vector<SceneNode> _sceneNodes;                          // Holds all the nodes+properties declared in the .scene file.

+ 11 - 0
gameplay/src/Texture.cpp

@@ -637,6 +637,7 @@ Texture* Texture::createCompressedDDS(const char* path)
             {
                 GP_ERROR("Failed to close file '%s'.", path);
             }
+            SAFE_DELETE_ARRAY(mipLevels);
             return NULL;
         }
 
@@ -676,6 +677,7 @@ Texture* Texture::createCompressedDDS(const char* path)
         {
             GP_ERROR("Failed to close file '%s'.", path);
         }
+        SAFE_DELETE_ARRAY(mipLevels);
         return NULL;
     }
     else if (header.ddspf.dwFlags == 0x41/*DDPF_RGB|DDPF_ALPHAPIXELS*/)
@@ -687,6 +689,7 @@ Texture* Texture::createCompressedDDS(const char* path)
         {
             GP_ERROR("Failed to close file '%s'.", path);
         }
+        SAFE_DELETE_ARRAY(mipLevels);
         return NULL;
     }
     else
@@ -697,6 +700,7 @@ Texture* Texture::createCompressedDDS(const char* path)
         {
             GP_ERROR("Failed to close file '%s'.", path);
         }
+        SAFE_DELETE_ARRAY(mipLevels);
         return NULL;
     }
     
@@ -731,8 +735,15 @@ Texture* Texture::createCompressedDDS(const char* path)
         {
             GL_ASSERT( glTexImage2D(GL_TEXTURE_2D, i, internalFormat, mipLevels[i].width, mipLevels[i].height, 0, format, GL_UNSIGNED_INT, mipLevels[i].data) );
         }
+        
+        // Clean up the texture data.
+        SAFE_DELETE_ARRAY(mipLevels[i].data);
     }
     
+
+    // Clean up mip levels structure.
+    SAFE_DELETE_ARRAY(mipLevels);
+
     return texture;
 }