Quellcode durchsuchen

Merge branch 'master' into patch-1

ihsinme vor 4 Jahren
Ursprung
Commit
6a78ef5652
3 geänderte Dateien mit 90 neuen und 7 gelöschten Zeilen
  1. 72 5
      code/AssetLib/FBX/FBXExporter.cpp
  2. 2 0
      code/AssetLib/FBX/FBXExporter.h
  3. 16 2
      code/Common/SceneCombiner.cpp

+ 72 - 5
code/AssetLib/FBX/FBXExporter.cpp

@@ -2203,7 +2203,65 @@ void FBXExporter::WriteObjects ()
         bpnode.Dump(outstream, binary, indent);
     }*/
 
-    // TODO: cameras, lights
+    // lights
+    indent = 1;
+    lights_uids.clear();
+    for (size_t li = 0; li < mScene->mNumLights; ++li) {
+        aiLight* l = mScene->mLights[li];
+
+        int64_t uid = generate_uid();
+        const std::string lightNodeAttributeName = l->mName.C_Str() + FBX::SEPARATOR + "NodeAttribute";
+
+        FBX::Node lna("NodeAttribute");
+        lna.AddProperties(uid, lightNodeAttributeName, "Light");
+        FBX::Node lnap("Properties70");
+
+        // Light color.
+        lnap.AddP70colorA("Color", l->mColorDiffuse.r, l->mColorDiffuse.g, l->mColorDiffuse.b);
+
+        // TODO Assimp light description is quite concise and do not handle light intensity.
+        // Default value to 1000W.
+        lnap.AddP70numberA("Intensity", 1000);
+
+        // FBXLight::EType conversion
+        switch (l->mType) {
+        case aiLightSource_POINT:
+            lnap.AddP70enum("LightType", 0);
+            break;
+        case aiLightSource_DIRECTIONAL:
+            lnap.AddP70enum("LightType", 1);
+            break;
+        case aiLightSource_SPOT:
+            lnap.AddP70enum("LightType", 2);
+            lnap.AddP70numberA("InnerAngle", AI_RAD_TO_DEG(l->mAngleInnerCone));
+            lnap.AddP70numberA("OuterAngle", AI_RAD_TO_DEG(l->mAngleOuterCone));
+            break;
+        // TODO Assimp do not handle 'area' nor 'volume' lights, but FBX does.
+        /*case aiLightSource_AREA:
+            lnap.AddP70enum("LightType", 3);
+            lnap.AddP70enum("AreaLightShape", 0); // 0=Rectangle, 1=Sphere
+            break;
+        case aiLightSource_VOLUME:
+            lnap.AddP70enum("LightType", 4);
+            break;*/
+        default:
+            break;
+        }
+
+        // Did not understood how to configure the decay so disabling attenuation.
+        lnap.AddP70enum("DecayType", 0);
+
+        // Dump to FBX stream
+        lna.AddChild(lnap);
+        lna.AddChild("TypeFlags", FBX::FBXExportProperty("Light"));
+        lna.AddChild("GeometryVersion", FBX::FBXExportProperty(int32_t(124)));
+        lna.Dump(outstream, binary, indent);
+
+        // Store name and uid (will be used later when parsing scene nodes)
+        lights_uids[l->mName.C_Str()] = uid;
+    }
+
+    // TODO: cameras
 
     // write nodes (i.e. model hierarchy)
     // start at root node
@@ -2607,10 +2665,19 @@ void FBXExporter::WriteModelNodes(
         // and connect them
         connections.emplace_back("C", "OO", node_attribute_uid, node_uid);
     } else {
-        // generate a null node so we can add children to it
-        WriteModelNode(
-            outstream, binary, node, node_uid, "Null", transform_chain
-        );
+        const auto& lightIt = lights_uids.find(node->mName.C_Str());
+        if(lightIt != lights_uids.end()) {
+            // Node has a light connected to it.
+            WriteModelNode(
+                outstream, binary, node, node_uid, "Light", transform_chain
+            );
+            connections.emplace_back("C", "OO", lightIt->second, node_uid);
+        } else {
+            // generate a null node so we can add children to it
+            WriteModelNode(
+                outstream, binary, node, node_uid, "Null", transform_chain
+            );
+        }
     }
 
     // if more than one child mesh, make nodes for each mesh

+ 2 - 0
code/AssetLib/FBX/FBXExporter.h

@@ -63,6 +63,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 struct aiScene;
 struct aiNode;
+struct aiLight;
 //struct aiMaterial;
 
 namespace Assimp
@@ -95,6 +96,7 @@ namespace Assimp
         std::vector<int64_t> mesh_uids;
         std::vector<int64_t> material_uids;
         std::map<const aiNode*,int64_t> node_uids;
+        std::map<std::string,int64_t> lights_uids;
 
         // this crude unique-ID system is actually fine
         int64_t last_uid = 999999;

+ 16 - 2
code/Common/SceneCombiner.cpp

@@ -406,11 +406,25 @@ void SceneCombiner::MergeScenes(aiScene **_dest, aiScene *master, std::vector<At
                             // Check whether this texture is an embedded texture.
                             // In this case the property looks like this: *<n>,
                             // where n is the index of the texture.
-                            aiString &s = *((aiString *)prop->mData);
+                            // Copy here because we overwrite the string data in-place and the buffer inside of aiString
+                            // will be a lie if we just reinterpret from prop->mData. The size of mData is not guaranteed to be
+                            // MAXLEN in size.
+                            aiString s(*(aiString *)prop->mData);
                             if ('*' == s.data[0]) {
                                 // Offset the index and write it back ..
                                 const unsigned int idx = strtoul10(&s.data[1]) + offset[n];
-                                ASSIMP_itoa10(&s.data[1], sizeof(s.data) - 1, idx);
+                                const unsigned int oldLen = s.length;
+
+                                s.length = 1 + ASSIMP_itoa10(&s.data[1], sizeof(s.data) - 1, idx);
+
+                                // The string changed in size so we need to reallocate the buffer for the property.
+                                if (oldLen < s.length) {
+                                    prop->mDataLength += s.length - oldLen;
+                                    delete[] prop->mData;
+                                    prop->mData = new char[prop->mDataLength];
+                                }
+
+                                memcpy(prop->mData, static_cast<void*>(&s), prop->mDataLength);
                             }
                         }