Ver Fonte

Fixed the encoder so that it can read DAE_FBX files from Maya.

Darryl Gough há 13 anos atrás
pai
commit
cd13d03178

+ 130 - 73
gameplay-encoder/src/DAESceneEncoder.cpp

@@ -366,89 +366,114 @@ void DAESceneEncoder::loadAnimations(const domCOLLADA* dom)
     }
 }
 
-void DAESceneEncoder::loadAnimation(const domAnimationRef animationRef)
+void DAESceneEncoder::loadAnimation(const domAnimationRef animationRef, const char* altId)
 {
-    // <channel> points to one <sampler>
-    // <sampler> points to multiple <input> elements
-
-    Animation* animation = new Animation();
-    const char* str = animationRef->getId();
-    if (str)
+    // Animations can contain other animations.
+    const domAnimation_Array& animationArray = animationRef->getAnimation_array();
+    unsigned int animationCount = animationArray.getCount();
+    
+    if (animationCount == 1)
     {
-        animation->setId(str);
+        // DAE_FBX nests 1 animation within another animation for some reason.
+        loadAnimation(animationArray.get(0), animationRef->getId());
     }
+    else if ( animationCount > 1)
+    {
+        loadAnimation(animationArray.get(0));
+    }
+
+    // <channel> points to one <sampler>
+    // <sampler> points to multiple <input> elements
 
     // <channel>
     const domChannel_Array& channelArray = animationRef->getChannel_array();
     size_t channelArrayCount = channelArray.getCount();
-    for (size_t i = 0; i < channelArrayCount; ++i)
+    if (channelArrayCount > 0)
     {
-        AnimationChannel* animationChannel = new AnimationChannel();
-
-        const domChannelRef& channelRef = channelArray.get(i);
-
-        // <sampler>
-        const domSamplerRef sampler = getSampler(channelRef);
-        assert(sampler);
+        Animation* animation = new Animation();
+        const char* str = animationRef->getId();
+        if (str)
+        {
+            animation->setId(str);
+        }
+        else if (altId)
+        {
+            animation->setId(altId);
+        }
 
-        // <input>
-        const domInputLocal_Array& inputArray = sampler->getInput_array();
-        size_t inputArrayCount = inputArray.getCount();
-        for (size_t j = 0; j < inputArrayCount; ++j)
+        for (size_t i = 0; i < channelArrayCount; ++i)
         {
-            const domInputLocalRef& inputLocal = inputArray.get(j);
+            AnimationChannel* animationChannel = new AnimationChannel();
 
-            // <source>
-            const domSourceRef source = getSource(inputLocal, animationRef);
+            const domChannelRef& channelRef = channelArray.get(i);
 
-            std::string semantic = inputLocal->getSemantic();
-            if (equals(semantic, "INTERPOLATION"))
-            {
-                // Interpolation source is a list of strings
-                loadInterpolation(source, animationChannel);
-            }
-            else
+            // <sampler>
+            const domSamplerRef sampler = getSampler(channelRef);
+            assert(sampler);
+
+            // <input>
+            const domInputLocal_Array& inputArray = sampler->getInput_array();
+            size_t inputArrayCount = inputArray.getCount();
+            for (size_t j = 0; j < inputArrayCount; ++j)
             {
-                // The other sources are lists of floats.
-                std::vector<float> floats;
-                copyFloats(source->getFloat_array(), &floats);
-                if (equals(semantic, "INPUT"))
-                {
-                    // TODO: Ensure param name is TIME?
-                    for (std::vector<float>::iterator k = floats.begin(); k != floats.end(); ++k)
-                    {
-                        // Convert seconds to milliseconds
-                        *k = *k * 1000.0f;
-                    }
-                    animationChannel->setKeyTimes(floats);
-                }
-                else if (equals(semantic, "OUTPUT"))
+                const domInputLocalRef& inputLocal = inputArray.get(j);
+
+                // <source>
+                const domSourceRef source = getSource(inputLocal, animationRef);
+
+                std::string semantic = inputLocal->getSemantic();
+                if (equals(semantic, "INTERPOLATION"))
                 {
-                    animationChannel->setKeyValues(floats);
+                    // Interpolation source is a list of strings
+                    loadInterpolation(source, animationChannel);
                 }
-                else if (equals(semantic, "IN_TANGENT"))
+                else
                 {
-                    animationChannel->setTangentsIn(floats);
+                    // The other sources are lists of floats.
+                    std::vector<float> floats;
+                    copyFloats(source->getFloat_array(), &floats);
+                    if (equals(semantic, "INPUT"))
+                    {
+                        // TODO: Ensure param name is TIME?
+                        for (std::vector<float>::iterator k = floats.begin(); k != floats.end(); ++k)
+                        {
+                            // Convert seconds to milliseconds
+                            *k = *k * 1000.0f;
+                        }
+                        animationChannel->setKeyTimes(floats);
+                    }
+                    else if (equals(semantic, "OUTPUT"))
+                    {
+                        animationChannel->setKeyValues(floats);
+                    }
+                    else if (equals(semantic, "IN_TANGENT"))
+                    {
+                        animationChannel->setTangentsIn(floats);
+                    }
+                    else if (equals(semantic, "OUT_TANGENT"))
+                    {
+                        animationChannel->setTangentsOut(floats);
+                    }
                 }
-                else if (equals(semantic, "OUT_TANGENT"))
+            }
+            
+            // get target attribute enum value
+            if (loadTarget(channelRef, animationChannel))
+            {
+                if (animationChannel->getKeyTimes().size() > 0)
                 {
-                    animationChannel->setTangentsOut(floats);
+                    animation->add(animationChannel);
                 }
             }
         }
-        // get target attribute enum value
-        if (loadTarget(channelRef, animationChannel))
+        if (animation->getAnimationChannelCount() > 0)
         {
-            animation->add(animationChannel);
+            _gamePlayFile.addAnimation(animation);
+        }
+        else
+        {
+            delete animation;
         }
-    }
-    if (animation->getAnimationChannelCount() > 0)
-    {
-        _gamePlayFile.addAnimation(animation);
-    }
-    else
-    {
-        delete animation;
     }
 }
 
@@ -685,6 +710,11 @@ void DAESceneEncoder::loadScene(const domVisual_scene* visualScene)
 
     const domNode_Array& nodes = visualScene->getNode_array();
     scene->setId(visualScene->getId());
+    if (scene->getId().length() == 0)
+    {
+        scene->setId("__SCENE__");
+    }
+
     size_t childCount = nodes.getCount();
     for (size_t i = 0; i < childCount; ++i)
     {
@@ -989,16 +1019,21 @@ void DAESceneEncoder::loadControllerInstance(const domNode* n, Node* node)
                     domInstance_controller::domSkeleton_Array& skeletons = instanceControllerRef->getSkeleton_array();
                     if (skeletons.getCount() == 0)
                     {
-                        warning("No skeletons found for instance controller: ");
-                        delete model;
-                        continue;
+                        domNode* rootJoint = getRootJointNode(skinElement);
+                        if (rootJoint)
+                        {
+                            loadSkeleton(rootJoint, model->getSkin());
+                            node->setModel(model);
+                        }
+                    }
+                    else
+                    {
+                        // Load the skeleton for this skin
+                        domInstance_controller::domSkeletonRef skeleton = getSkeleton(instanceControllerRef);
+                        assert(skeleton);
+                        loadSkeleton(skeleton, model->getSkin());
+                        node->setModel(model);
                     }
-                    // Load the skeleton for this skin
-                    domInstance_controller::domSkeletonRef skeleton = getSkeleton(instanceControllerRef);
-                    assert(skeleton);
-                    loadSkeleton(skeleton, model->getSkin());
-
-                    node->setModel(model);
                 }
             }
         }
@@ -1182,21 +1217,33 @@ Light* DAESceneEncoder::loadLight(const domLight* lightRef)
             {
                 light->setQuadraticAttenuation((float)quadAtt->getValue());
             }
+
+            // When Maya exports DAE_FBX, the ambient lights are converted into point lights but with not attenuation elements.
+            // If this point light has no attenuation then assume it is ambient.
+            if (!(constAtt.cast() && linearAtt.cast() && quadAtt.cast()))
+            {
+                light->setAmbientLight();
+            }
         }
     }
     _gamePlayFile.addLight(light);
     return light;
 }
 
+
 void DAESceneEncoder::loadSkeleton(domInstance_controller::domSkeleton* skeletonElement, MeshSkin* skin)
 {
     xsAnyURI skeletonUri = skeletonElement->getValue();
     daeString skeletonId = skeletonUri.getID();
     daeSIDResolver resolver(skeletonUri.getElement(), skeletonId);
     domNode* rootNode = daeSafeCast<domNode>(resolver.getElement());
-    
+    loadSkeleton(rootNode, skin);
+}
+
+void DAESceneEncoder::loadSkeleton(domNode* rootNode, MeshSkin* skin)
+{
     // Get the lookup scene id (sid) and joint index.
-    std::string id = std::string(skeletonId);
+    std::string id = std::string(rootNode->getId());
 
     // Has the skeleton (root joint) been loaded yet?
     Node* skeleton = (Node*)_gamePlayFile.getFromRefTable(id);
@@ -1674,6 +1721,7 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
             {
                 maxOffset = offset;
             }
+            int polyIndexInt = (int) polyInts.get(poly + offset);
             unsigned int polyIndex = (unsigned int) polyInts.get(poly + offset);
 
             switch (polygonInputs[k]->type)
@@ -1774,8 +1822,17 @@ Mesh* DAESceneEncoder::loadMesh(const domMesh* meshElement, const std::string& g
                 {
                     // TODO: This assumes (s, t) are first
                     unsigned int stride = (unsigned int)polygonInputs[k]->accessor->getStride();
-                    vertex.texCoord.x = (float)source.get(polyIndex * stride);
-                    vertex.texCoord.y = (float)source.get(polyIndex * stride + 1);
+                    if (polyIndexInt < 0)
+                    {
+                        unsigned int i = (unsigned int)((int)polygonInputs[k]->accessor->getCount()) + polyIndexInt;
+                        vertex.texCoord.x = (float)source.get(i * stride);
+                        vertex.texCoord.y = (float)source.get(i * stride + 1);
+                    }
+                    else
+                    {
+                        vertex.texCoord.x = (float)source.get(polyIndex * stride);
+                        vertex.texCoord.y = (float)source.get(polyIndex * stride + 1);
+                    }
                 }
                 else
                 {

+ 3 - 1
gameplay-encoder/src/DAESceneEncoder.h

@@ -111,14 +111,16 @@ private:
      * Loads a COLLADA animation element.
      * 
      * @param animationRef The animation dom element to load from.
+     * @param altId   The id string to use if the animation doesn't have an id.
      */
-    void loadAnimation(const domAnimationRef animationRef);
+    void loadAnimation(const domAnimationRef animationRef, const char* altId = NULL);
 
     Camera* loadCamera(const domCamera* cameraRef);
     Light* loadLight(const domLight* lightRef);
     Model* loadSkin(const domSkin* skinElement);
     Model* loadGeometry(const domGeometry* geometry, const domBind_materialRef bindMaterial);
 
+    void loadSkeleton(domNode* rootNode, MeshSkin* skin);
     void loadSkeleton(domInstance_controller::domSkeleton* skeletonElement, MeshSkin* skin);
     
     /**

+ 50 - 14
gameplay-encoder/src/DAEUtil.cpp

@@ -13,7 +13,16 @@ namespace gameplay
  * 
  * @return The index in skeletonArray or -1 if not found.
  */
-int getIndex(const domInstance_controller::domSkeleton_Array& skeletonArray, const domNodeRef& node);
+static int getIndex(const domInstance_controller::domSkeleton_Array& skeletonArray, const domNodeRef& node);
+
+/**
+ * Gets all of the animation channels that target the given node and appends them to the list.
+ * 
+ * @param animationRef The animation to search in.
+ * @param nodeIdSlash The node's id with a forward slash appended to it.
+ * @param channels The list of channels to append to.
+ */
+static void getAnimationChannels(const domAnimationRef& animationRef, const std::string& nodeIdSlash, std::list<domChannelRef>& channels);
 
 void getAnimationChannels(const domNodeRef& node, std::list<domChannelRef>& channels)
 {
@@ -33,19 +42,7 @@ void getAnimationChannels(const domNodeRef& node, std::list<domChannelRef>& chan
         for (size_t j = 0; j < animationCount; ++j)
         {
             domAnimationRef& animationRef = animationArray.get(j);
-            domChannel_Array& channelArray = animationRef->getChannel_array();
-            size_t channelArrayCount = channelArray.getCount();
-            for (size_t k = 0; k < channelArrayCount; ++k)
-            {
-                domChannelRef& channel = channelArray.get(k);
-                const char* target = channel->getTarget();
-
-                // TODO: Assumes only one target per channel?
-                if (startsWith(target, nodeIdSlash.c_str()))
-                {
-                    channels.push_back(channel);
-                }
-            }
+            getAnimationChannels(animationRef, nodeIdSlash, channels);
         }
     }
 
@@ -262,6 +259,20 @@ const domInstance_controller::domSkeletonRef getSkeleton(const domInstance_contr
     return NULL;
 }
 
+domNode* getRootJointNode(const domSkin* skin)
+{
+    std::vector<std::string> names;
+    getJointNames(skin, names);
+    daeSIDResolver resolver(const_cast<domSkin*>(skin)->getDocument()->getDomRoot(), names[0].c_str());
+    daeElement* element = resolver.getElement();
+    if (element && element->getElementType() == COLLADA_TYPE::NODE)
+    {
+        domNode* node = daeSafeCast<domNode>(resolver.getElement());
+        return node;
+    }
+    return NULL;
+}
+
 bool equalKeyTimes(const domSource* s1, const domSource* s2)
 {
     // TODO: shouldn't assume that the source has a float array.
@@ -355,4 +366,29 @@ int getIndex(const domInstance_controller::domSkeleton_Array& skeletonArray, con
     return -1;
 }
 
+void getAnimationChannels(const domAnimationRef& animationRef, const std::string& nodeIdSlash, std::list<domChannelRef>& channels)
+{
+    domChannel_Array& channelArray = animationRef->getChannel_array();
+    size_t channelArrayCount = channelArray.getCount();
+    for (size_t k = 0; k < channelArrayCount; ++k)
+    {
+        domChannelRef& channel = channelArray.get(k);
+        const char* target = channel->getTarget();
+
+        // TODO: Assumes only one target per channel?
+        if (startsWith(target, nodeIdSlash.c_str()))
+        {
+            channels.push_back(channel);
+        }
+    }
+
+    // This animation could have child animations.
+    const domAnimation_Array& animationArray = animationRef->getAnimation_array();
+    unsigned int animationCount = animationArray.getCount();
+    for (size_t i = 0; i < animationCount; ++i)
+    {
+        getAnimationChannels(animationArray[i], nodeIdSlash, channels);
+    }
+}
+
 }

+ 9 - 0
gameplay-encoder/src/DAEUtil.h

@@ -77,6 +77,15 @@ const domName_arrayRef getSourceNameArray(const domSourceRef& source);
  */
 const domInstance_controller::domSkeletonRef getSkeleton(const domInstance_controllerRef& instanceController);
 
+/**
+ * Returns the root joint node of the given skin.
+ * 
+ * @param skin The COLLADA skin to get the root joint for.
+ * 
+ * @return The COLLADA node or NULL if not found.
+ */
+domNode* getRootJointNode(const domSkin* skin);
+
 /**
  * Returns true if the two given animation channels have equal key time input source.
  * 

+ 1 - 0
gameplay-encoder/src/Scene.cpp

@@ -9,6 +9,7 @@ Scene::Scene(void) : _cameraNode(NULL)
     _ambientColor[0] = 0.0f;
     _ambientColor[1] = 0.0f;
     _ambientColor[2] = 0.0f;
+    setId("scene");
 }
 
 Scene::~Scene(void)

+ 4 - 5
gameplay-encoder/src/TTFFontEncoder.cpp

@@ -5,7 +5,7 @@
 namespace gameplay
 {
 
-void drawBitmap(unsigned char* dstBitmap, int x, int y, int dstWidth, unsigned char* srcBitmap, int srcWidth, int srcHeight)
+static void drawBitmap(unsigned char* dstBitmap, int x, int y, int dstWidth, unsigned char* srcBitmap, int srcWidth, int srcHeight)
 {
     // offset dst bitmap by x,y.
     dstBitmap +=  (x + (y * dstWidth));
@@ -18,17 +18,17 @@ void drawBitmap(unsigned char* dstBitmap, int x, int y, int dstWidth, unsigned c
     }
 }
 
-void writeUint(FILE* fp, unsigned int i)
+static void writeUint(FILE* fp, unsigned int i)
 {
     fwrite(&i, sizeof(unsigned int), 1, fp);
 }
 
-void writeFloat(FILE* fp, float f)
+static void writeFloat(FILE* fp, float f)
 {
     fwrite(&f, sizeof(float), 1, fp);
 }
 
-void writeString(FILE* fp, const char* str)
+static void writeString(FILE* fp, const char* str)
 {
     unsigned int len = strlen(str);
     fwrite(&len, sizeof(unsigned int), 1, fp);
@@ -40,7 +40,6 @@ void writeString(FILE* fp, const char* str)
 
 int writeFont(const char* filename, unsigned int fontSize, const char* id, bool fontpreview = false)
 {
- 
     Glyph glyphArray[END_INDEX - START_INDEX];
     
     // Initialize freetype library.

+ 0 - 8
gameplay-encoder/src/TTFFontEncoder.h

@@ -18,14 +18,6 @@ public:
     float uvCoords[4];
 };
 
-void drawBitmap(unsigned char* dstBitmap, int x, int y, int dstWidth, unsigned char* srcBitmap, int srcWidth, int srcHeight);
-
-void writeUint(FILE* fp, unsigned int i);
-
-void writeFloat(FILE* fp, float f);
-
-void writeString(FILE* fp, const char* str);
-
 int writeFont(const char* filename, unsigned int fontSize, const char* id, bool fontpreview);
 
 }

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

@@ -7,7 +7,7 @@
 
 using namespace gameplay;
 
-std::string getFileName(const std::string& filepath)
+static std::string getFileName(const std::string& filepath)
 {
     size_t index1 = filepath.find_last_of('\\');
     size_t index2 = filepath.find_last_of('/');

+ 1 - 1
gameplay/src/Bundle.cpp

@@ -1210,7 +1210,7 @@ Animation* Bundle::readAnimationChannelData(Animation* animation, const char* id
 
 Mesh* Bundle::loadMesh(const char* id)
 {
-    return loadMesh(id, false);
+    return loadMesh(id, NULL);
 }
 
 Mesh* Bundle::loadMesh(const char* id, const char* nodeId)