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

Merge pull request #455 from blackberry-gaming/next-dgough

Next dgough
Sean Paul Taylor 13 лет назад
Родитель
Сommit
78f6fdacd4

+ 7 - 7
gameplay-encoder/README.md

@@ -21,13 +21,13 @@ You must then rebuild gameplay-encoder with the follow platform/tooling instruct
 - Edit the project properties of "gameplay-encoder"
 - Add Preprocessor Definition "USE_FBX" (C++/Preprocessor)
 - Add the FBX SDK include directory to Additional Include Directories (C++/General)
-  * Example: C:/Program Files/Autodesk/FBX/FbxSdk/2012.2/include
+  * Example: C:/Program Files/Autodesk/FBX/FbxSdk/2013.1/include
 - Add the FBX lib directory to the Additional Library Directories (Linker/General)
-  * Example: C:/Program Files/Autodesk/FBX/FbxSdk/2012.2/lib/vs2010/x86
-- Add "fbxsdk-2012.2-mdd.lib" and "wininet.lib" to the Additional Dependencies (Linker/Input)
-  * Example: fbxsdk-2012.2-mdd.lib;wininet.lib
+  * Example: C:/Program Files/Autodesk/FBX/FbxSdk/2013.1/lib/vs2010/x86
+- Add "fbxsdk-2013.1-mdd.lib" and "wininet.lib" to the Additional Dependencies (Linker/Input)
+  * Example: fbxsdk-2013.1-mdd.lib;wininet.lib
 - Add a post build event to copy the DLL (Build Events/Post-Build Event)
-  * Example: copy /Y "C:\Program Files\Autodesk\FBX\FbxSdk\2012.2\lib\vs2010\x86\fbxsdk-2012.2d.dll" "$(TargetDir)"
+  * Example: copy /Y "C:\Program Files\Autodesk\FBX\FbxSdk\2013.1\lib\vs2010\x86\fbxsdk-2013.1d.dll" "$(TargetDir)"
 - Build gameplay-encoder
 
 ### Building FBX Support on Mac OS X using XCode 4.3.2+
@@ -35,9 +35,9 @@ You must then rebuild gameplay-encoder with the follow platform/tooling instruct
 - Edit the project properties of target "gameplay-encoder".
 - Add Preprocessor Macro "USE_FBX" to both Debug/Release sections. (Build Settings)
 - Add the FBX include directory to Header Search Paths: (Build Settings)
-  * Example: /Applications/Autodesk/FBXSDK20122/include
+  * Example: /Applications/Autodesk/FBXSDK20131/include
 - Add the FBX library and dependency Library/Frameworks: (Build Phases -> Link Binary with Libraries)
-  * Example: /Applications/Autodesk/FBXSDK20122/lib/gcc4/ub/libfbxsdk-2012.2-static.a  (Add Other)
+  * Example: /Applications/Autodesk/FBXSDK20131/lib/gcc4/ub/libfbxsdk-2013.1-static.a  (Add Other)
   * Example: libiconv.dylib, Cocoa.framework, SystemConfiguration.framework
 - Build gameplay-encoder
 

+ 21 - 17
gameplay-encoder/src/DAESceneEncoder.cpp

@@ -54,7 +54,7 @@ void DAESceneEncoder::optimizeCOLLADA(const EncoderArguments& arguments, domCOLL
     {
         if (!_collada->writeTo(arguments.getFilePath(), arguments.getDAEOutputPath()))
         {
-            fprintf(stderr,"Error: COLLADA failed to write the dom for file:%s\n", arguments.getDAEOutputPath().c_str());
+            fprintf(stderr,"Error: COLLADA failed to write the dom for file: %s\n", arguments.getDAEOutputPath().c_str());
         }
     }
 }
@@ -227,10 +227,6 @@ void DAESceneEncoder::write(const std::string& filepath, const EncoderArguments&
 {
     _begin = clock();
     const char* nodeId = arguments.getNodeId();
-    bool text = arguments.textOutputEnabled();
-
-    std::string filenameOnly = getFilenameFromFilePath(filepath);
-    std::string dstPath = filepath.substr(0, filepath.find_last_of('/'));
     
     // Load the collada document
     _collada = new DAE();
@@ -239,7 +235,7 @@ void DAESceneEncoder::write(const std::string& filepath, const EncoderArguments&
     end("Open file");
     if (!_dom)
     {
-        fprintf(stderr,"Error: COLLADA failed to open file:%s\n", filepath.c_str());
+        fprintf(stderr,"Error: COLLADA failed to open file: %s\n", filepath.c_str());
         if (_collada)
         {
             delete _collada;
@@ -309,24 +305,32 @@ void DAESceneEncoder::write(const std::string& filepath, const EncoderArguments&
     loadAnimations(_dom);
     end("loadAnimations");
 
-    std::string dstFilename = dstPath;
-    dstFilename.append(1, '/');
-    dstFilename.append(getFilenameNoExt(filenameOnly));
-
     _gamePlayFile.adjust();
 
-    if (text)
+    // Write the output file
+    std::string outputFilePath = arguments.getOutputFilePath();
+    if (arguments.textOutputEnabled())
     {
-        std::string outFile = dstFilename + ".xml";
-        fprintf(stderr, "Saving debug file: %s\n", outFile.c_str());
-        _gamePlayFile.saveText(outFile);
+        int pos = outputFilePath.find_last_of('.');
+        if (pos > 2)
+        {
+            std::string path = outputFilePath.substr(0, pos);
+            path.append(".xml");
+            fprintf(stderr, "Saving debug file: %s\n", path.c_str());
+            if (!_gamePlayFile.saveText(path))
+            {
+                fprintf(stderr,"Error writing text file: %s\n", path.c_str());
+            }
+        }
     }
     else
     {
-        std::string outFile = dstFilename + ".gpb";
-        fprintf(stderr, "Saving binary file: %s\n", outFile.c_str());
+        fprintf(stderr, "Saving binary file: %s\n", outputFilePath.c_str());
         begin();
-        _gamePlayFile.saveBinary(outFile);
+        if (!_gamePlayFile.saveBinary(outputFilePath))
+        {
+            fprintf(stderr,"Error writing binary file: %s\n", outputFilePath.c_str());
+        }
         end("save binary");
     }
     

+ 4 - 1
gameplay-encoder/src/DAEUtil.cpp

@@ -412,7 +412,10 @@ domVisual_scene* getVisualScene(const domCOLLADA::domSceneRef& domScene)
         for (size_t j = 0; j < visualSceneCount; ++j)
         {
             domVisual_sceneRef visualScene = visualScenes.get(j);
-            return visualScene.cast();
+            if (domVisual_scene* v = visualScene.cast())
+            {
+                return v;
+            }
         }
     }
     return NULL;

+ 165 - 17
gameplay-encoder/src/EncoderArguments.cpp

@@ -24,26 +24,30 @@ EncoderArguments::EncoderArguments(size_t argc, const char** argv) :
 
     if (argc > 1)
     {
-        size_t filePathIndex = argc - 1;
-        if (argv[filePathIndex])
-        {
-            _filePath.assign(getRealPath(argv[filePathIndex]));
-        }
-        
         // read the options
-        std::vector<std::string> options;
-        for (size_t i = 1; i < filePathIndex; ++i)
+        std::vector<std::string> arguments;
+        for (size_t i = 1; i < argc; ++i)
         {
-            options.push_back(argv[i]);
+            arguments.push_back(argv[i]);
         }
-        
-        for (size_t i = 0; i < options.size(); ++i)
+        size_t index = 0;
+        for (size_t i = 0; i < arguments.size(); ++i)
         {
-            if (options[i][0] == '-')
+            if (arguments[i][0] == '-')
             {
-                readOption(options, &i);
+                readOption(arguments, &i);
+                index = i + 1;
             }
         }
+        if (arguments.size() - index == 2)
+        {
+            setInputfilePath(arguments[index]);
+            setOutputfilePath(arguments[index + 1]);
+        }
+        else if (arguments.size() - index == 1)
+        {
+            setInputfilePath(arguments[index]);
+        }
     }
     else
     {
@@ -70,10 +74,42 @@ const char* EncoderArguments::getFilePathPointer() const
     return _filePath.c_str();
 }
 
-std::string EncoderArguments::getOutputPath() const
+std::string EncoderArguments::getOutputDirPath() const
 {
-    int pos = _filePath.find_last_of('/');
-    return (pos == -1 ? _filePath : _filePath.substr(0, pos));
+    if (_fileOutputPath.size() > 0)
+    {
+        int pos = _fileOutputPath.find_last_of('/');
+        return (pos == -1 ? _fileOutputPath : _fileOutputPath.substr(0, pos));
+    }
+    else
+    {
+        int pos = _filePath.find_last_of('/');
+        return (pos == -1 ? _filePath : _filePath.substr(0, pos));
+    }
+}
+
+std::string EncoderArguments::getOutputFilePath() const
+{
+    if (_fileOutputPath.size() > 0)
+    {
+        return _fileOutputPath;
+    }
+    else
+    {
+        int pos = _filePath.find_last_of('.');
+        if (pos > 0)
+        {
+            std::string outputFilePath(_filePath.substr(0, pos));
+            outputFilePath.append(".gpb");
+            return outputFilePath;
+        }
+        else
+        {
+            std::string outputFilePath(_filePath);
+            outputFilePath.append(".gpb");
+            return outputFilePath;
+        }
+    }
 }
 
 const std::string& EncoderArguments::getDAEOutputPath() const
@@ -134,7 +170,7 @@ bool EncoderArguments::fileExists() const
 
 void EncoderArguments::printUsage() const
 {
-    fprintf(stderr,"Usage: gameplay-encoder [options] <filepath>\n\n");
+    fprintf(stderr,"Usage: gameplay-encoder [options] <input filepath> <output filepath>\n\n");
     fprintf(stderr,"Supported file extensions:\n");
     fprintf(stderr,"  .dae\t(COLLADA)\n");
     fprintf(stderr,"  .fbx\t(FBX)\n");
@@ -343,6 +379,43 @@ void EncoderArguments::readOption(const std::vector<std::string>& options, size_
     }
 }
 
+void EncoderArguments::setInputfilePath(const std::string& inputPath)
+{
+    _filePath.assign(getRealPath(inputPath));
+}
+
+void EncoderArguments::setOutputfilePath(const std::string& outputPath)
+{
+    if (outputPath.size() > 0 && outputPath[0] != '\0')
+    {
+        std::string realPath = getRealPath(outputPath);
+        if (endsWith(realPath.c_str(), ".gpb"))
+        {
+            _fileOutputPath.assign(realPath);
+        }
+        else if (endsWith(outputPath.c_str(), "/"))
+        {
+            std::string filenameNoExt = getFilenameNoExt(getFilenameFromFilePath(_filePath));
+
+            _fileOutputPath.assign(outputPath);
+            _fileOutputPath.append(filenameNoExt);
+            _fileOutputPath.append(".gpb");
+        }
+        else
+        {
+            std::string filenameNoExt = getFilenameNoExt(getFilenameFromFilePath(realPath));
+            int pos = realPath.find_last_of("/");
+            if (pos)
+            {
+                _fileOutputPath = realPath.substr(0, pos);
+                _fileOutputPath.append("/");
+                _fileOutputPath.append(filenameNoExt);
+                _fileOutputPath.append(".gpb");
+            }
+        }
+    }
+}
+
 std::string EncoderArguments::getRealPath(const std::string& filepath)
 {
     char path[PATH_MAX + 1]; /* not sure about the "+ 1" */
@@ -362,4 +435,79 @@ void EncoderArguments::replace_char(char* str, char oldChar, char newChar)
     }
 }
 
+std::string concat(const std::string& a, const char* b)
+{
+    std::string str(a);
+    str.append(b);
+    return str;
+}
+
+
+void unittestsEncoderArguments()
+{
+    std::string dir = EncoderArguments::getRealPath(".");
+    std::string exePath = EncoderArguments::getRealPath(".");
+    exePath.append("/gameplay-encoder.exe");
+    const char* exe = exePath.c_str();
+    {
+        const char* argv[] = {exe, "-groupAnimations", "root", "movements", "C:\\Git\\gaming\\GamePlay\\gameplay-encoder\\res\\seymour.dae"};
+        EncoderArguments args(sizeof(argv) / sizeof(char*), (const char**)argv);
+        assert(equals(args.getAnimationId("root"), ("movements")));
+        assert(equals(args.getGroupAnimationNodeId()[0], ("root")));
+        assert(equals(args.getOutputFilePath(), "C:/Git/gaming/GamePlay/gameplay-encoder/res/seymour.gpb"));
+    }
+    {
+        // Test with only input file name (relative)
+        const char* argv[] = {exe, "input.dae"};
+        EncoderArguments args(sizeof(argv) / sizeof(char*), (const char**)argv);
+        assert(equals(args.getFilePath(), concat(dir, "/input.dae")));
+        assert(equals(args.getOutputFilePath(), concat(dir, "/input.gpb")));
+        equals(args.getOutputDirPath(), dir);
+    }
+    {
+        // Test specifying a relative output path
+        const char* argv[] = {exe, "input.dae", "output.gpb"};
+        EncoderArguments args(sizeof(argv) / sizeof(char*), (const char**)argv);
+        assert(equals(args.getFilePath(), concat(dir, "/input.dae")));
+        assert(equals(args.getOutputFilePath(), concat(dir, "/output.gpb")));
+    }
+    {
+        // Test specifying a relative output path
+        const char* argv[] = {exe, "input.fbx", "output.gpb"};
+        EncoderArguments args(sizeof(argv) / sizeof(char*), (const char**)argv);
+        assert(equals(args.getFilePath(), concat(dir, "/input.fbx")));
+        assert(equals(args.getOutputFilePath(), concat(dir, "/output.gpb")));
+    }
+    {
+        // Test specifying a relative output path to a directory
+        const char* argv[] = {exe, "input.dae", "stuff/output.gpb"};
+        EncoderArguments args(sizeof(argv) / sizeof(char*), (const char**)argv);
+        assert(equals(args.getFilePath(), concat(dir, "/input.dae")));
+        assert(equals(args.getOutputFilePath(), concat(dir, "/stuff/output.gpb")));
+    }
+    {
+        // Test parsing some arguments
+        const char* argv[] = {exe, "-dae", "collada.dae", "-t", "input.dae", "output.gpb"};
+        EncoderArguments args(sizeof(argv) / sizeof(char*), (const char**)argv);
+        assert(equals(args.getFilePath(), concat(dir, "/input.dae")));
+        assert(equals(args.getOutputFilePath(), concat(dir, "/output.gpb")));
+        assert(args.textOutputEnabled());
+        //assert(equals(args.getDAEOutputPath(), concat(dir, "/collada.dae")));
+    }
+    {
+        // Test output file with no file extension
+        const char* argv[] = {exe, "input.dae", "output"};
+        EncoderArguments args(sizeof(argv) / sizeof(char*), (const char**)argv);
+        assert(equals(args.getFilePath(), concat(dir, "/input.dae")));
+        assert(equals(args.getOutputFilePath(), concat(dir, "/output.gpb")));
+    }
+    {
+        // Test output file with wrong file extension
+        const char* argv[] = {exe, "input.dae", "output.dae"};
+        EncoderArguments args(sizeof(argv) / sizeof(char*), (const char**)argv);
+        assert(equals(args.getFilePath(), concat(dir, "/input.dae")));
+        assert(equals(args.getOutputFilePath(), concat(dir, "/output.gpb")));
+    }
+}
+
 }

+ 21 - 2
gameplay-encoder/src/EncoderArguments.h

@@ -57,8 +57,15 @@ public:
 
     /**
      * Returns the output path/folder.
+     * Example: "C:/dir"
      */
-    std::string getOutputPath() const;
+    std::string getOutputDirPath() const;
+
+    /**
+     * Returns the output file path.
+     * Example: "C:/dir/scene.gpb"
+     */
+    std::string getOutputFilePath() const;
 
     const std::vector<std::string>& getGroupAnimationNodeId() const;
     const std::vector<std::string>& getGroupAnimationAnimationId() const;
@@ -92,6 +99,9 @@ public:
     const char* getNodeId() const;
     unsigned int getFontSize() const;
 
+
+    static std::string getRealPath(const std::string& filepath);
+
 private:
 
     /**
@@ -103,7 +113,13 @@ private:
      */
     void readOption(const std::vector<std::string>& options, size_t *index);
 
-    static std::string getRealPath(const std::string& filepath);
+    void setInputfilePath(const std::string& inputPath);
+
+    /**
+     * Sets the output file path that the encoder will write to.
+     */
+    void setOutputfilePath(const std::string& outputPath);
+    
 
     /**
      * Replaces all instance of oldChar with newChar in str.
@@ -113,6 +129,7 @@ private:
 private:
     
     std::string _filePath;
+    std::string _fileOutputPath;
     std::string _nodeId;
     std::string _daeOutputPath;
 
@@ -129,6 +146,8 @@ private:
 
 };
 
+void unittestsEncoderArguments();
+
 }
 
 #endif

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


+ 18 - 16
gameplay-encoder/src/FBXSceneEncoder.h

@@ -3,6 +3,8 @@
 
 #ifdef USE_FBX
 
+#define FBXSDK_NEW_API
+
 #include <iostream>
 #include <list>
 #include <vector>
@@ -65,7 +67,7 @@ private:
      * 
      * @param fbxScene The FBX scene to load.
      */
-    void loadScene(KFbxScene* fbxScene);
+    void loadScene(FbxScene* fbxScene);
 
     /**
      * Loads all of the animatiosn from the given FBX scene.
@@ -73,7 +75,7 @@ private:
      * @param fbxScene The scene to load animations from.
      * @param arguments The command line arguments passed to the encoder.
      */
-    void loadAnimations(KFbxScene* fbxScene, const EncoderArguments& arguments);
+    void loadAnimations(FbxScene* fbxScene, const EncoderArguments& arguments);
 
     /**
      * Loads the animations from the given FBX animation layer recursively starting from fbxNode.
@@ -82,7 +84,7 @@ private:
      * @param fbxNode The node to start loading animations from.
      * @param arguments The command line arguments passed to the encoder.
      */
-    void loadAnimationLayer(KFbxAnimLayer* fbxAnimLayer, KFbxNode* fbxNode, const EncoderArguments& arguments);
+    void loadAnimationLayer(FbxAnimLayer* fbxAnimLayer, FbxNode* fbxNode, const EncoderArguments& arguments);
 
     /**
      * Loads animation channels from the given node and adds the channels to the given animation.
@@ -91,14 +93,14 @@ private:
      * @param fbxNode The node to load animation channels from.
      * @param animation The animation to add the channels to.
      */
-    void loadAnimationChannels(KFbxAnimLayer* pAnimLayer, KFbxNode* fbxNode, Animation* animation);
+    void loadAnimationChannels(FbxAnimLayer* pAnimLayer, FbxNode* fbxNode, Animation* animation);
 
     /**
      * Loads the bind shape for all mesh skins that have be loaded so far.
      * 
      * @param fbxScene The FBX scene to read the bind shapes from.
      */
-    void loadBindShapes(KFbxScene* fbxScene);
+    void loadBindShapes(FbxScene* fbxScene);
 
     /**
      * Loads the camera from the given FBX node and adds to it to the given GamePlay node.
@@ -106,7 +108,7 @@ private:
      * @param fbxNode The FBX node to load from.
      * @param node The GamePlay node to add to.
      */
-    void loadCamera(KFbxNode* fbxNode, Node* node);
+    void loadCamera(FbxNode* fbxNode, Node* node);
 
     /**
      * Loads the light from the given FBX node and adds to it to the given GamePlay node.
@@ -114,7 +116,7 @@ private:
      * @param fbxNode The FBX node to load from.
      * @param node The GamePlay node to add to.
      */
-    void loadLight(KFbxNode* fbxNode, Node* node);
+    void loadLight(FbxNode* fbxNode, Node* node);
     
     /**
      * Loads the model from the given FBX node and adds to it to the given GamePlay node.
@@ -122,7 +124,7 @@ private:
      * @param fbxNode The FBX node to load from.
      * @param node The GamePlay node to add to.
      */
-    void loadModel(KFbxNode* fbxNode, Node* node);
+    void loadModel(FbxNode* fbxNode, Node* node);
 
     /**
      * Loads the mesh skin from the given FBX mesh and adds it to the given GamePlay model.
@@ -130,7 +132,7 @@ private:
      * @param fbxMesh The FBX mesh to load the skin from.
      * @param model The model to add the skin to.
      */
-    void loadSkin(KFbxMesh* fbxMesh, Model* model);
+    void loadSkin(FbxMesh* fbxMesh, Model* model);
     
     /**
      * Loads the FBX Node and creates a GamePlay Node.
@@ -139,7 +141,7 @@ private:
      * 
      * @return The newly created Node or NULL if the node could not be loaded.
      */
-    Node* loadNode(KFbxNode* fbxNode);
+    Node* loadNode(FbxNode* fbxNode);
     
     /**
      * Loads the FbxMesh and returns a GamePlay mesh.
@@ -149,7 +151,7 @@ private:
      * 
      * @return The GamePlay mesh that was loaded from the FBX Mesh.
      */
-    Mesh* loadMesh(KFbxMesh* fbxMesh);
+    Mesh* loadMesh(FbxMesh* fbxMesh);
 
     /**
      * Gets the Mesh that was saved with the given ID. Returns NULL if a match is not found.
@@ -158,7 +160,7 @@ private:
      * 
      * @return The mesh that was saved with the ID or NULL if none was found.
      */
-    Mesh* getMesh(size_t meshId);
+    Mesh* getMesh(FbxUInt64 meshId);
 
     /**
      * Saves the Mesh with the given id.
@@ -166,7 +168,7 @@ private:
      * @param meshId The ID of the FbxMesh to use as a key.
      * @param mesh The mesh to save.
      */
-    void saveMesh(size_t meshId, Mesh* mesh);
+    void saveMesh(FbxUInt64 meshId, Mesh* mesh);
     
     /**
      * Prints a message.
@@ -181,14 +183,14 @@ private:
      * @param fbxNode The FBX node to get the transfrom data from
      * @param node The GamePlay Node to copy the transform to.
      */
-    void transformNode(KFbxNode* fbxNode, Node* node);
+    void transformNode(FbxNode* fbxNode, Node* node);
 
     /**
      * Recursively triangules the meshes starting from the given node.
      * 
      * @param fbxNode The node to start triangulating from.
      */
-    static void triangulateRecursive(KFbxNode* fbxNode);
+    static void triangulateRecursive(FbxNode* fbxNode);
 
     /**
      * Prints a warning message.
@@ -210,7 +212,7 @@ private:
     /**
      * The collection of meshes for the purpose of making sure that the same model is not loaded twice. (Mesh instancing)
      */
-    std::map<size_t, Mesh*> _meshes;
+    std::map<FbxUInt64, Mesh*> _meshes;
 
     /**
      * The animation that channels should be added to it the user is using the -groupAnimation command line argument. May be NULL.

+ 34 - 5
gameplay-encoder/src/GPBFile.cpp

@@ -29,16 +29,33 @@ GPBFile* GPBFile::getInstance()
     return __instance;
 }
 
-void GPBFile::saveBinary(const std::string& filepath)
+bool GPBFile::saveBinary(const std::string& filepath)
 {
     _file = fopen(filepath.c_str(), "w+b");
+    if (!_file)
+    {
+        return false;
+    }
+    size_t n = 0;
 
     // identifier
     char identifier[] = { '«', 'G', 'P', 'B', '»', '\r', '\n', '\x1A', '\n' };
-    fwrite(identifier, 1, sizeof(identifier), _file);
+    n = fwrite(identifier, 1, sizeof(identifier), _file);
+    if (n != sizeof(identifier))
+    {
+        fclose(_file);
+        return false;
+    }
 
     // version
-    fwrite(GPB_VERSION, 1, sizeof(GPB_VERSION), _file);
+    n = fwrite(GPB_VERSION, 1, sizeof(GPB_VERSION), _file);
+    if (n != sizeof(GPB_VERSION))
+    {
+        fclose(_file);
+        return false;
+    }
+
+    // TODO: Check for errors on all file writing.
 
     // write refs
     _refTable.writeBinary(_file);
@@ -60,13 +77,24 @@ void GPBFile::saveBinary(const std::string& filepath)
     _refTable.updateOffsets(_file);
     
     fclose(_file);
+    return true;
 }
 
-void GPBFile::saveText(const std::string& filepath)
+bool GPBFile::saveText(const std::string& filepath)
 {
     _file = fopen(filepath.c_str(), "w");
+    if (!_file)
+    {
+        return false;
+    }
+
+    if (fprintf(_file, "<root>\n") <= 0)
+    {
+        fclose(_file);
+        return false;
+    }
 
-    fprintf(_file, "<root>\n");
+    // TODO: Check for errors on all file writing.
 
     // write refs
     _refTable.writeText(_file);
@@ -86,6 +114,7 @@ void GPBFile::saveText(const std::string& filepath)
     fprintf(_file, "</root>");
 
     fclose(_file);
+    return true;
 }
 
 void GPBFile::add(Object* obj)

+ 6 - 2
gameplay-encoder/src/GPBFile.h

@@ -49,15 +49,19 @@ public:
      * Saves the GPBFile as a binary file at filepath.
      *
      * @param filepath The file name and path to save to.
+     * 
+     * @return True if successful, false if error.
      */
-    void saveBinary(const std::string& filepath);
+    bool saveBinary(const std::string& filepath);
 
     /**
      * Saves the GPBFile as a text file at filepath. Useful for debugging.
      *
      * @param filepath The file name and path to save to.
+     * 
+     * @return True if successful, false if error.
      */
-    void saveText(const std::string& filepath);
+    bool saveText(const std::string& filepath);
     
     void add(Object* obj);
     void addScene(Scene* scene);

+ 1 - 1
gameplay-encoder/src/Node.cpp

@@ -132,7 +132,7 @@ void Node::generateHeightmap()
         {
             DEBUGPRINT_VARG("> Generating heightmap for node: %s\n", getId().c_str());
 
-            std::string heightmapFilename(EncoderArguments::getInstance()->getOutputPath());
+            std::string heightmapFilename(EncoderArguments::getInstance()->getOutputDirPath());
             heightmapFilename += "/heightmap_";
             heightmapFilename += getId();
             heightmapFilename += ".png";

+ 11 - 1
gameplay-encoder/src/StringUtil.cpp

@@ -77,11 +77,21 @@ bool endsWith(const char* str, const char* suffix, bool ignoreCase)
     return true;
 }
 
+bool endsWith(const std::string& str, const char* suffix, bool ignoreCase)
+{
+    return endsWith(str.c_str(), suffix, ignoreCase);
+}
+
 bool equals(const std::string& a, const char* b)
 {
     return (a.compare(b) == 0);
 }
 
+bool equals(const std::string& a, const std::string& b)
+{
+    return (a.compare(b) == 0);
+}
+
 bool equalsIgnoreCase(const std::string& a, const char* b)
 {
     size_t bLength = strlen(b);
@@ -103,7 +113,7 @@ std::string getFilenameFromFilePath(const std::string& filepath)
 {
     if (filepath.find_last_of("/") != std::string::npos)
     {
-        return filepath.substr(filepath.find_last_of("/")+1);
+        return filepath.substr(filepath.find_last_of("/") + 1);
     }
     return "";
 }

+ 12 - 0
gameplay-encoder/src/StringUtil.h

@@ -4,19 +4,31 @@
 namespace gameplay
 {
 
+/**
+ * Returns true if the given string starts with the prefix.
+ */
 bool startsWith(const char* str, const char* prefix, bool ignoreCase = true);
+
+/**
+ * Returns true if the given string ends with the suffix.
+ */
 bool endsWith(const char* str, const char* suffix, bool ignoreCase = true);
+bool endsWith(const std::string& str, const char* suffix, bool ignoreCase = true);
 
 /**
  * Return true if the strings are equal. Case sensitive.
  */
 bool equals(const std::string& a, const char* b);
+bool equals(const std::string& a, const std::string& b);
 
 /**
  * Returns true if the strings are equal. Case insensitive.
  */
 bool equalsIgnoreCase(const std::string& a, const char* b);
 
+/**
+ * Returns the filename from the given real path.
+ */
 std::string getFilenameFromFilePath(const std::string& filepath);
 
 std::string getFilenameNoExt(const std::string& filename);

+ 1 - 1
gameplay/src/Curve.cpp

@@ -119,7 +119,7 @@ void Curve::setPoint(unsigned int index, float time, float* value, Interpolation
 
 void Curve::setPoint(unsigned int index, float time, float* value, InterpolationType type, float* inValue, float* outValue)
 {
-    assert(index < _pointCount && time >= 0.0f && time <= 1.0f && !(index == 0 && time != 0.0f) && !(_pointCount != 1 && index == _pointCount - 1 && time != 1.0f));
+    assert(index < _pointCount && time >= 0.0f && time <= 1.0f && !(_pointCount > 1 && index == 0 && time != 0.0f) && !(_pointCount != 1 && index == _pointCount - 1 && time != 1.0f));
 
     _points[index].time = time;
     _points[index].type = type;

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