Update OpenFBX
Updated to commit 365f52c1edad6bd283c8a645f1d8d2347dbd1e35
This commit is contained in:
@@ -49,7 +49,7 @@ Quaternion ToQuaternion(const ofbx::Quat& v)
|
|||||||
return Quaternion((float)v.x, (float)v.y, (float)v.z, (float)v.w);
|
return Quaternion((float)v.x, (float)v.y, (float)v.z, (float)v.w);
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix ToMatrix(const ofbx::Matrix& mat)
|
Matrix ToMatrix(const ofbx::DMatrix& mat)
|
||||||
{
|
{
|
||||||
Matrix result;
|
Matrix result;
|
||||||
for (int32 i = 0; i < 16; i++)
|
for (int32 i = 0; i < 16; i++)
|
||||||
@@ -445,7 +445,7 @@ Matrix GetOffsetMatrix(OpenFbxImporterData& data, const ofbx::Mesh* mesh, const
|
|||||||
|
|
||||||
bool IsMeshInvalid(const ofbx::Mesh* aMesh)
|
bool IsMeshInvalid(const ofbx::Mesh* aMesh)
|
||||||
{
|
{
|
||||||
return aMesh->getGeometry()->getVertexCount() == 0;
|
return aMesh->getGeometry()->getGeometryData().getPositions().count == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImportBones(OpenFbxImporterData& data, String& errorMsg)
|
bool ImportBones(OpenFbxImporterData& data, String& errorMsg)
|
||||||
@@ -524,56 +524,56 @@ bool ImportBones(OpenFbxImporterData& data, String& errorMsg)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh* aMesh, MeshData& mesh, String& errorMsg, int32 triangleStart, int32 triangleEnd)
|
bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh* aMesh, MeshData& mesh, String& errorMsg, int partitionIndex)
|
||||||
{
|
{
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
mesh.Name = aMesh->name;
|
mesh.Name = aMesh->name;
|
||||||
ZoneText(*mesh.Name, mesh.Name.Length());
|
ZoneText(*mesh.Name, mesh.Name.Length());
|
||||||
const int32 firstVertexOffset = triangleStart * 3;
|
|
||||||
const int32 lastVertexOffset = triangleEnd * 3;
|
|
||||||
const ofbx::Geometry* aGeometry = aMesh->getGeometry();
|
const ofbx::Geometry* aGeometry = aMesh->getGeometry();
|
||||||
const int vertexCount = lastVertexOffset - firstVertexOffset + 3;
|
const ofbx::GeometryData& geometryData = aMesh->getGeometryData();
|
||||||
ASSERT(firstVertexOffset + vertexCount <= aGeometry->getVertexCount());
|
const ofbx::GeometryPartition& partition = geometryData.getPartition(partitionIndex);
|
||||||
const ofbx::Vec3* vertices = aGeometry->getVertices();
|
const int vertexCount = partition.triangles_count * 3;
|
||||||
const ofbx::Vec3* normals = aGeometry->getNormals();
|
const ofbx::Vec3Attributes& positions = geometryData.getPositions();
|
||||||
const ofbx::Vec3* tangents = aGeometry->getTangents();
|
const ofbx::Vec2Attributes& uvs = geometryData.getUVs();
|
||||||
const ofbx::Vec4* colors = aGeometry->getColors();
|
const ofbx::Vec3Attributes& normals = geometryData.getNormals();
|
||||||
const ofbx::Vec2* uvs = aGeometry->getUVs();
|
const ofbx::Vec3Attributes& tangents = geometryData.getTangents();
|
||||||
|
const ofbx::Vec4Attributes& colors = geometryData.getColors();
|
||||||
const ofbx::Skin* skin = aGeometry->getSkin();
|
const ofbx::Skin* skin = aGeometry->getSkin();
|
||||||
const ofbx::BlendShape* blendShape = aGeometry->getBlendShape();
|
const ofbx::BlendShape* blendShape = aGeometry->getBlendShape();
|
||||||
|
|
||||||
|
static Array<int> triangulatedIndices;
|
||||||
|
triangulatedIndices.Resize(vertexCount, false);
|
||||||
|
|
||||||
// Properties
|
// Properties
|
||||||
const ofbx::Material* aMaterial = nullptr;
|
const ofbx::Material* aMaterial = nullptr;
|
||||||
if (aMesh->getMaterialCount() > 0)
|
if (aMesh->getMaterialCount() > 0)
|
||||||
{
|
aMaterial = aMesh->getMaterial(partitionIndex);
|
||||||
if (aGeometry->getMaterials())
|
|
||||||
aMaterial = aMesh->getMaterial(aGeometry->getMaterials()[triangleStart]);
|
|
||||||
else
|
|
||||||
aMaterial = aMesh->getMaterial(0);
|
|
||||||
}
|
|
||||||
mesh.MaterialSlotIndex = data.AddMaterial(result, aMaterial);
|
mesh.MaterialSlotIndex = data.AddMaterial(result, aMaterial);
|
||||||
|
|
||||||
// Vertex positions
|
// Vertex positions
|
||||||
mesh.Positions.Resize(vertexCount, false);
|
mesh.Positions.Resize(vertexCount, false);
|
||||||
for (int i = 0; i < vertexCount; i++)
|
{
|
||||||
mesh.Positions.Get()[i] = ToFloat3(vertices[i + firstVertexOffset]);
|
int numVertsProcessed = 0;
|
||||||
|
for (int i = 0; i < partition.polygon_count; i++)
|
||||||
|
{
|
||||||
|
int numVerts = ofbx::triangulate(geometryData, partition.polygons[i], &triangulatedIndices[numVertsProcessed]);
|
||||||
|
for (int j = numVertsProcessed; j < numVertsProcessed + numVerts; j++)
|
||||||
|
mesh.Positions.Get()[j] = ToFloat3(positions.get(triangulatedIndices[j]));
|
||||||
|
numVertsProcessed += numVerts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Indices (dummy index buffer)
|
// Indices (dummy index buffer)
|
||||||
if (vertexCount % 3 != 0)
|
|
||||||
{
|
|
||||||
errorMsg = TEXT("Invalid vertex count. It must be multiple of 3.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
mesh.Indices.Resize(vertexCount, false);
|
mesh.Indices.Resize(vertexCount, false);
|
||||||
for (int i = 0; i < vertexCount; i++)
|
for (int i = 0; i < vertexCount; i++)
|
||||||
mesh.Indices.Get()[i] = i;
|
mesh.Indices.Get()[i] = i;
|
||||||
|
|
||||||
// Texture coordinates
|
// Texture coordinates
|
||||||
if (uvs)
|
if (uvs.values)
|
||||||
{
|
{
|
||||||
mesh.UVs.Resize(vertexCount, false);
|
mesh.UVs.Resize(vertexCount, false);
|
||||||
for (int i = 0; i < vertexCount; i++)
|
for (int i = 0; i < vertexCount; i++)
|
||||||
mesh.UVs.Get()[i] = ToFloat2(uvs[i + firstVertexOffset]);
|
mesh.UVs.Get()[i] = ToFloat2(uvs.get(triangulatedIndices[i]));
|
||||||
if (data.ConvertRH)
|
if (data.ConvertRH)
|
||||||
{
|
{
|
||||||
for (int32 v = 0; v < vertexCount; v++)
|
for (int32 v = 0; v < vertexCount; v++)
|
||||||
@@ -582,7 +582,7 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Normals
|
// Normals
|
||||||
if (data.Options.CalculateNormals || !normals)
|
if (data.Options.CalculateNormals || !normals.values)
|
||||||
{
|
{
|
||||||
if (mesh.GenerateNormals(data.Options.SmoothingNormalsAngle))
|
if (mesh.GenerateNormals(data.Options.SmoothingNormalsAngle))
|
||||||
{
|
{
|
||||||
@@ -590,11 +590,11 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (normals)
|
else if (normals.values)
|
||||||
{
|
{
|
||||||
mesh.Normals.Resize(vertexCount, false);
|
mesh.Normals.Resize(vertexCount, false);
|
||||||
for (int i = 0; i < vertexCount; i++)
|
for (int i = 0; i < vertexCount; i++)
|
||||||
mesh.Normals.Get()[i] = ToFloat3(normals[i + firstVertexOffset]);
|
mesh.Normals.Get()[i] = ToFloat3(normals.get(triangulatedIndices[i]));
|
||||||
if (data.ConvertRH)
|
if (data.ConvertRH)
|
||||||
{
|
{
|
||||||
// Mirror normals along the Z axis
|
// Mirror normals along the Z axis
|
||||||
@@ -604,15 +604,15 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Tangents
|
// Tangents
|
||||||
if ((data.Options.CalculateTangents || !tangents) && mesh.UVs.HasItems())
|
if ((data.Options.CalculateTangents || !tangents.values) && mesh.UVs.HasItems())
|
||||||
{
|
{
|
||||||
// Generated after full mesh data conversion
|
// Generated after full mesh data conversion
|
||||||
}
|
}
|
||||||
else if (tangents)
|
else if (tangents.values)
|
||||||
{
|
{
|
||||||
mesh.Tangents.Resize(vertexCount, false);
|
mesh.Tangents.Resize(vertexCount, false);
|
||||||
for (int i = 0; i < vertexCount; i++)
|
for (int i = 0; i < vertexCount; i++)
|
||||||
mesh.Tangents.Get()[i] = ToFloat3(tangents[i + firstVertexOffset]);
|
mesh.Tangents.Get()[i] = ToFloat3(tangents.get(triangulatedIndices[i]));
|
||||||
if (data.ConvertRH)
|
if (data.ConvertRH)
|
||||||
{
|
{
|
||||||
// Mirror tangents along the Z axis
|
// Mirror tangents along the Z axis
|
||||||
@@ -658,12 +658,12 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if has that channel texcoords
|
// Check if has that channel texcoords
|
||||||
const auto lightmapUVs = aGeometry->getUVs(inputChannelIndex);
|
const auto lightmapUVs = geometryData.getUVs(inputChannelIndex);
|
||||||
if (lightmapUVs)
|
if (lightmapUVs.values)
|
||||||
{
|
{
|
||||||
mesh.LightmapUVs.Resize(vertexCount, false);
|
mesh.LightmapUVs.Resize(vertexCount, false);
|
||||||
for (int i = 0; i < vertexCount; i++)
|
for (int i = 0; i < vertexCount; i++)
|
||||||
mesh.LightmapUVs.Get()[i] = ToFloat2(lightmapUVs[i + firstVertexOffset]);
|
mesh.LightmapUVs.Get()[i] = ToFloat2(lightmapUVs.get(triangulatedIndices[i]));
|
||||||
if (data.ConvertRH)
|
if (data.ConvertRH)
|
||||||
{
|
{
|
||||||
for (int32 v = 0; v < vertexCount; v++)
|
for (int32 v = 0; v < vertexCount; v++)
|
||||||
@@ -677,11 +677,11 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Vertex Colors
|
// Vertex Colors
|
||||||
if (data.Options.ImportVertexColors && colors)
|
if (data.Options.ImportVertexColors && colors.values)
|
||||||
{
|
{
|
||||||
mesh.Colors.Resize(vertexCount, false);
|
mesh.Colors.Resize(vertexCount, false);
|
||||||
for (int i = 0; i < vertexCount; i++)
|
for (int i = 0; i < vertexCount; i++)
|
||||||
mesh.Colors.Get()[i] = ToColor(colors[i + firstVertexOffset]);
|
mesh.Colors.Get()[i] = ToColor(colors.get(triangulatedIndices[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blend Indices and Blend Weights
|
// Blend Indices and Blend Weights
|
||||||
@@ -718,7 +718,7 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
|
|||||||
const double* clusterWeights = cluster->getWeights();
|
const double* clusterWeights = cluster->getWeights();
|
||||||
for (int j = 0; j < cluster->getIndicesCount(); j++)
|
for (int j = 0; j < cluster->getIndicesCount(); j++)
|
||||||
{
|
{
|
||||||
int vtxIndex = clusterIndices[j] - firstVertexOffset;
|
int vtxIndex = clusterIndices[j];
|
||||||
float vtxWeight = (float)clusterWeights[j];
|
float vtxWeight = (float)clusterWeights[j];
|
||||||
if (vtxWeight <= 0 || vtxIndex < 0 || vtxIndex >= vertexCount)
|
if (vtxWeight <= 0 || vtxIndex < 0 || vtxIndex >= vertexCount)
|
||||||
continue;
|
continue;
|
||||||
@@ -762,9 +762,9 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
|
|||||||
continue;
|
continue;
|
||||||
const ofbx::Shape* shape = channel->getShape(targetShapeCount - 1);
|
const ofbx::Shape* shape = channel->getShape(targetShapeCount - 1);
|
||||||
|
|
||||||
if (shape->getVertexCount() != aGeometry->getVertexCount())
|
if (shape->getVertexCount() != vertexCount)
|
||||||
{
|
{
|
||||||
LOG(Error, "Blend shape '{0}' in mesh '{1}' has different amount of vertices ({2}) than mesh ({3})", String(shape->name), mesh.Name, shape->getVertexCount(), aGeometry->getVertexCount());
|
LOG(Error, "Blend shape '{0}' in mesh '{1}' has different amount of vertices ({2}) than mesh ({3})", String(shape->name), mesh.Name, shape->getVertexCount(), vertexCount);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -779,14 +779,14 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
|
|||||||
auto shapeVertices = shape->getVertices();
|
auto shapeVertices = shape->getVertices();
|
||||||
for (int32 i = 0; i < blendShapeData.Vertices.Count(); i++)
|
for (int32 i = 0; i < blendShapeData.Vertices.Count(); i++)
|
||||||
{
|
{
|
||||||
auto delta = ToFloat3(shapeVertices[i + firstVertexOffset]) - mesh.Positions.Get()[i];
|
auto delta = ToFloat3(shapeVertices[i]) - mesh.Positions.Get()[i];
|
||||||
blendShapeData.Vertices.Get()[i].PositionDelta = delta;
|
blendShapeData.Vertices.Get()[i].PositionDelta = delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto shapeNormals = shape->getNormals();
|
auto shapeNormals = shape->getNormals();
|
||||||
for (int32 i = 0; i < blendShapeData.Vertices.Count(); i++)
|
for (int32 i = 0; i < blendShapeData.Vertices.Count(); i++)
|
||||||
{
|
{
|
||||||
auto delta = ToFloat3(shapeNormals[i + firstVertexOffset]);
|
auto delta = ToFloat3(shapeNormals[i]);
|
||||||
if (data.ConvertRH)
|
if (data.ConvertRH)
|
||||||
{
|
{
|
||||||
// Mirror normals along the Z axis
|
// Mirror normals along the Z axis
|
||||||
@@ -820,7 +820,7 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
|
|||||||
Swap(mesh.Indices.Get()[i], mesh.Indices.Get()[i + 2]);
|
Swap(mesh.Indices.Get()[i], mesh.Indices.Get()[i + 2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((data.Options.CalculateTangents || !tangents) && mesh.UVs.HasItems())
|
if ((data.Options.CalculateTangents || !tangents.values) && mesh.UVs.HasItems())
|
||||||
{
|
{
|
||||||
if (mesh.GenerateTangents(data.Options.SmoothingTangentsAngle))
|
if (mesh.GenerateTangents(data.Options.SmoothingTangentsAngle))
|
||||||
{
|
{
|
||||||
@@ -858,7 +858,7 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImportMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh* aMesh, String& errorMsg, int32 triangleStart, int32 triangleEnd)
|
bool ImportMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh* aMesh, String& errorMsg, int partitionIndex)
|
||||||
{
|
{
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
|
|
||||||
@@ -899,7 +899,7 @@ bool ImportMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
|
|||||||
|
|
||||||
// Import mesh data
|
// Import mesh data
|
||||||
MeshData* meshData = New<MeshData>();
|
MeshData* meshData = New<MeshData>();
|
||||||
if (ProcessMesh(result, data, aMesh, *meshData, errorMsg, triangleStart, triangleEnd))
|
if (ProcessMesh(result, data, aMesh, *meshData, errorMsg, partitionIndex))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Link mesh
|
// Link mesh
|
||||||
@@ -917,35 +917,17 @@ bool ImportMesh(int32 index, ModelData& result, OpenFbxImporterData& data, Strin
|
|||||||
{
|
{
|
||||||
const auto aMesh = data.Scene->getMesh(index);
|
const auto aMesh = data.Scene->getMesh(index);
|
||||||
const auto aGeometry = aMesh->getGeometry();
|
const auto aGeometry = aMesh->getGeometry();
|
||||||
const auto trianglesCount = aGeometry->getVertexCount() / 3;
|
|
||||||
if (IsMeshInvalid(aMesh))
|
if (IsMeshInvalid(aMesh))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (aMesh->getMaterialCount() < 2 || !aGeometry->getMaterials())
|
const auto& geomData = aMesh->getGeometryData();
|
||||||
|
for (int i = 0; i < geomData.getPartitionCount(); i++)
|
||||||
{
|
{
|
||||||
// Fast path if mesh is using single material for all triangles
|
const auto& partition = geomData.getPartition(i);
|
||||||
if (ImportMesh(result, data, aMesh, errorMsg, 0, trianglesCount - 1))
|
if (partition.polygon_count == 0)
|
||||||
return true;
|
continue;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Create mesh for each sequence of triangles that share the same material
|
|
||||||
const auto materials = aGeometry->getMaterials();
|
|
||||||
int32 rangeStart = 0;
|
|
||||||
int32 rangeStartVal = materials[rangeStart];
|
|
||||||
for (int32 triangleIndex = 1; triangleIndex < trianglesCount; triangleIndex++)
|
|
||||||
{
|
|
||||||
if (rangeStartVal != materials[triangleIndex])
|
|
||||||
{
|
|
||||||
if (ImportMesh(result, data, aMesh, errorMsg, rangeStart, triangleIndex - 1))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Start a new range
|
if (ImportMesh(result, data, aMesh, errorMsg, i))
|
||||||
rangeStart = triangleIndex;
|
|
||||||
rangeStartVal = materials[triangleIndex];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ImportMesh(result, data, aMesh, errorMsg, rangeStart, trianglesCount - 1))
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -962,24 +944,24 @@ struct AnimInfo
|
|||||||
|
|
||||||
struct Frame
|
struct Frame
|
||||||
{
|
{
|
||||||
ofbx::Vec3 Translation;
|
ofbx::DVec3 Translation;
|
||||||
ofbx::Vec3 Rotation;
|
ofbx::DVec3 Rotation;
|
||||||
ofbx::Vec3 Scaling;
|
ofbx::DVec3 Scaling;
|
||||||
};
|
};
|
||||||
|
|
||||||
void ExtractKeyframePosition(const ofbx::Object* bone, ofbx::Vec3& trans, const Frame& localFrame, Float3& keyframe)
|
void ExtractKeyframePosition(const ofbx::Object* bone, ofbx::DVec3& trans, const Frame& localFrame, Float3& keyframe)
|
||||||
{
|
{
|
||||||
const Matrix frameTrans = ToMatrix(bone->evalLocal(trans, localFrame.Rotation, localFrame.Scaling));
|
const Matrix frameTrans = ToMatrix(bone->evalLocal(trans, localFrame.Rotation, localFrame.Scaling));
|
||||||
keyframe = frameTrans.GetTranslation();
|
keyframe = frameTrans.GetTranslation();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExtractKeyframeRotation(const ofbx::Object* bone, ofbx::Vec3& trans, const Frame& localFrame, Quaternion& keyframe)
|
void ExtractKeyframeRotation(const ofbx::Object* bone, ofbx::DVec3& trans, const Frame& localFrame, Quaternion& keyframe)
|
||||||
{
|
{
|
||||||
const Matrix frameTrans = ToMatrix(bone->evalLocal(localFrame.Translation, trans, { 1.0, 1.0, 1.0 }));
|
const Matrix frameTrans = ToMatrix(bone->evalLocal(localFrame.Translation, trans, { 1.0, 1.0, 1.0 }));
|
||||||
Quaternion::RotationMatrix(frameTrans, keyframe);
|
Quaternion::RotationMatrix(frameTrans, keyframe);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExtractKeyframeScale(const ofbx::Object* bone, ofbx::Vec3& trans, const Frame& localFrame, Float3& keyframe)
|
void ExtractKeyframeScale(const ofbx::Object* bone, ofbx::DVec3& trans, const Frame& localFrame, Float3& keyframe)
|
||||||
{
|
{
|
||||||
// Fix empty scale case
|
// Fix empty scale case
|
||||||
if (Math::IsZero(trans.x) && Math::IsZero(trans.y) && Math::IsZero(trans.z))
|
if (Math::IsZero(trans.x) && Math::IsZero(trans.y) && Math::IsZero(trans.z))
|
||||||
@@ -990,7 +972,7 @@ void ExtractKeyframeScale(const ofbx::Object* bone, ofbx::Vec3& trans, const Fra
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void ImportCurve(const ofbx::AnimationCurveNode* curveNode, LinearCurve<T>& curve, AnimInfo& info, void (*ExtractKeyframe)(const ofbx::Object*, ofbx::Vec3&, const Frame&, T&))
|
void ImportCurve(const ofbx::AnimationCurveNode* curveNode, LinearCurve<T>& curve, AnimInfo& info, void (*ExtractKeyframe)(const ofbx::Object*, ofbx::DVec3&, const Frame&, T&))
|
||||||
{
|
{
|
||||||
if (curveNode == nullptr)
|
if (curveNode == nullptr)
|
||||||
return;
|
return;
|
||||||
@@ -1008,7 +990,7 @@ void ImportCurve(const ofbx::AnimationCurveNode* curveNode, LinearCurve<T>& curv
|
|||||||
|
|
||||||
key.Time = (float)i;
|
key.Time = (float)i;
|
||||||
|
|
||||||
ofbx::Vec3 trans = curveNode->getNodeLocalTransform(t);
|
ofbx::DVec3 trans = curveNode->getNodeLocalTransform(t);
|
||||||
ExtractKeyframe(bone, trans, localFrame, key.Value);
|
ExtractKeyframe(bone, trans, localFrame, key.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1125,10 +1107,9 @@ bool ModelTool::ImportDataOpenFBX(const String& path, ModelData& data, Options&
|
|||||||
errorMsg = TEXT("Cannot load file.");
|
errorMsg = TEXT("Cannot load file.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
ofbx::u64 loadFlags = 0;
|
ofbx::u16 loadFlags = 0;
|
||||||
if (EnumHasAnyFlags(options.ImportTypes, ImportDataTypes::Geometry))
|
if (EnumHasAnyFlags(options.ImportTypes, ImportDataTypes::Geometry))
|
||||||
{
|
{
|
||||||
loadFlags |= (ofbx::u64)ofbx::LoadFlags::TRIANGULATE;
|
|
||||||
if (!options.ImportBlendShapes)
|
if (!options.ImportBlendShapes)
|
||||||
loadFlags |= (ofbx::u64)ofbx::LoadFlags::IGNORE_BLEND_SHAPES;
|
loadFlags |= (ofbx::u64)ofbx::LoadFlags::IGNORE_BLEND_SHAPES;
|
||||||
}
|
}
|
||||||
|
|||||||
4193
Source/ThirdParty/OpenFBX/libdeflate.cpp
vendored
Normal file
4193
Source/ThirdParty/OpenFBX/libdeflate.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
411
Source/ThirdParty/OpenFBX/libdeflate.h
vendored
Normal file
411
Source/ThirdParty/OpenFBX/libdeflate.h
vendored
Normal file
@@ -0,0 +1,411 @@
|
|||||||
|
/*
|
||||||
|
* libdeflate.h - public header for libdeflate
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBDEFLATE_H
|
||||||
|
#define LIBDEFLATE_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define LIBDEFLATE_VERSION_MAJOR 1
|
||||||
|
#define LIBDEFLATE_VERSION_MINOR 18
|
||||||
|
#define LIBDEFLATE_VERSION_STRING "1.18"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Users of libdeflate.dll on Windows can define LIBDEFLATE_DLL to cause
|
||||||
|
* __declspec(dllimport) to be used. This should be done when it's easy to do.
|
||||||
|
* Otherwise it's fine to skip it, since it is a very minor performance
|
||||||
|
* optimization that is irrelevant for most use cases of libdeflate.
|
||||||
|
*/
|
||||||
|
#ifndef LIBDEFLATEAPI
|
||||||
|
# if defined(LIBDEFLATE_DLL) && (defined(_WIN32) || defined(__CYGWIN__))
|
||||||
|
# define LIBDEFLATEAPI __declspec(dllimport)
|
||||||
|
# else
|
||||||
|
# define LIBDEFLATEAPI
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ========================================================================== */
|
||||||
|
/* Compression */
|
||||||
|
/* ========================================================================== */
|
||||||
|
|
||||||
|
struct libdeflate_compressor;
|
||||||
|
struct libdeflate_options;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* libdeflate_alloc_compressor() allocates a new compressor that supports
|
||||||
|
* DEFLATE, zlib, and gzip compression. 'compression_level' is the compression
|
||||||
|
* level on a zlib-like scale but with a higher maximum value (1 = fastest, 6 =
|
||||||
|
* medium/default, 9 = slow, 12 = slowest). Level 0 is also supported and means
|
||||||
|
* "no compression", specifically "create a valid stream, but only emit
|
||||||
|
* uncompressed blocks" (this will expand the data slightly).
|
||||||
|
*
|
||||||
|
* The return value is a pointer to the new compressor, or NULL if out of memory
|
||||||
|
* or if the compression level is invalid (i.e. outside the range [0, 12]).
|
||||||
|
*
|
||||||
|
* Note: for compression, the sliding window size is defined at compilation time
|
||||||
|
* to 32768, the largest size permissible in the DEFLATE format. It cannot be
|
||||||
|
* changed at runtime.
|
||||||
|
*
|
||||||
|
* A single compressor is not safe to use by multiple threads concurrently.
|
||||||
|
* However, different threads may use different compressors concurrently.
|
||||||
|
*/
|
||||||
|
LIBDEFLATEAPI struct libdeflate_compressor *
|
||||||
|
libdeflate_alloc_compressor(int compression_level);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Like libdeflate_alloc_compressor(), but adds the 'options' argument.
|
||||||
|
*/
|
||||||
|
LIBDEFLATEAPI struct libdeflate_compressor *
|
||||||
|
libdeflate_alloc_compressor_ex(int compression_level,
|
||||||
|
const struct libdeflate_options *options);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* libdeflate_deflate_compress() performs raw DEFLATE compression on a buffer of
|
||||||
|
* data. It attempts to compress 'in_nbytes' bytes of data located at 'in' and
|
||||||
|
* write the result to 'out', which has space for 'out_nbytes_avail' bytes. The
|
||||||
|
* return value is the compressed size in bytes, or 0 if the data could not be
|
||||||
|
* compressed to 'out_nbytes_avail' bytes or fewer (but see note below).
|
||||||
|
*
|
||||||
|
* If compression is successful, then the output data is guaranteed to be a
|
||||||
|
* valid DEFLATE stream that decompresses to the input data. No other
|
||||||
|
* guarantees are made about the output data. Notably, different versions of
|
||||||
|
* libdeflate can produce different compressed data for the same uncompressed
|
||||||
|
* data, even at the same compression level. Do ***NOT*** do things like
|
||||||
|
* writing tests that compare compressed data to a golden output, as this can
|
||||||
|
* break when libdeflate is updated. (This property isn't specific to
|
||||||
|
* libdeflate; the same is true for zlib and other compression libraries too.)
|
||||||
|
*/
|
||||||
|
LIBDEFLATEAPI size_t
|
||||||
|
libdeflate_deflate_compress(struct libdeflate_compressor *compressor,
|
||||||
|
const void *in, size_t in_nbytes,
|
||||||
|
void *out, size_t out_nbytes_avail);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* libdeflate_deflate_compress_bound() returns a worst-case upper bound on the
|
||||||
|
* number of bytes of compressed data that may be produced by compressing any
|
||||||
|
* buffer of length less than or equal to 'in_nbytes' using
|
||||||
|
* libdeflate_deflate_compress() with the specified compressor. This bound will
|
||||||
|
* necessarily be a number greater than or equal to 'in_nbytes'. It may be an
|
||||||
|
* overestimate of the true upper bound. The return value is guaranteed to be
|
||||||
|
* the same for all invocations with the same compressor and same 'in_nbytes'.
|
||||||
|
*
|
||||||
|
* As a special case, 'compressor' may be NULL. This causes the bound to be
|
||||||
|
* taken across *any* libdeflate_compressor that could ever be allocated with
|
||||||
|
* this build of the library, with any options.
|
||||||
|
*
|
||||||
|
* Note that this function is not necessary in many applications. With
|
||||||
|
* block-based compression, it is usually preferable to separately store the
|
||||||
|
* uncompressed size of each block and to store any blocks that did not compress
|
||||||
|
* to less than their original size uncompressed. In that scenario, there is no
|
||||||
|
* need to know the worst-case compressed size, since the maximum number of
|
||||||
|
* bytes of compressed data that may be used would always be one less than the
|
||||||
|
* input length. You can just pass a buffer of that size to
|
||||||
|
* libdeflate_deflate_compress() and store the data uncompressed if
|
||||||
|
* libdeflate_deflate_compress() returns 0, indicating that the compressed data
|
||||||
|
* did not fit into the provided output buffer.
|
||||||
|
*/
|
||||||
|
LIBDEFLATEAPI size_t
|
||||||
|
libdeflate_deflate_compress_bound(struct libdeflate_compressor *compressor,
|
||||||
|
size_t in_nbytes);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Like libdeflate_deflate_compress(), but uses the zlib wrapper format instead
|
||||||
|
* of raw DEFLATE.
|
||||||
|
*/
|
||||||
|
LIBDEFLATEAPI size_t
|
||||||
|
libdeflate_zlib_compress(struct libdeflate_compressor *compressor,
|
||||||
|
const void *in, size_t in_nbytes,
|
||||||
|
void *out, size_t out_nbytes_avail);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Like libdeflate_deflate_compress_bound(), but assumes the data will be
|
||||||
|
* compressed with libdeflate_zlib_compress() rather than with
|
||||||
|
* libdeflate_deflate_compress().
|
||||||
|
*/
|
||||||
|
LIBDEFLATEAPI size_t
|
||||||
|
libdeflate_zlib_compress_bound(struct libdeflate_compressor *compressor,
|
||||||
|
size_t in_nbytes);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Like libdeflate_deflate_compress(), but uses the gzip wrapper format instead
|
||||||
|
* of raw DEFLATE.
|
||||||
|
*/
|
||||||
|
LIBDEFLATEAPI size_t
|
||||||
|
libdeflate_gzip_compress(struct libdeflate_compressor *compressor,
|
||||||
|
const void *in, size_t in_nbytes,
|
||||||
|
void *out, size_t out_nbytes_avail);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Like libdeflate_deflate_compress_bound(), but assumes the data will be
|
||||||
|
* compressed with libdeflate_gzip_compress() rather than with
|
||||||
|
* libdeflate_deflate_compress().
|
||||||
|
*/
|
||||||
|
LIBDEFLATEAPI size_t
|
||||||
|
libdeflate_gzip_compress_bound(struct libdeflate_compressor *compressor,
|
||||||
|
size_t in_nbytes);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* libdeflate_free_compressor() frees a compressor that was allocated with
|
||||||
|
* libdeflate_alloc_compressor(). If a NULL pointer is passed in, no action is
|
||||||
|
* taken.
|
||||||
|
*/
|
||||||
|
LIBDEFLATEAPI void
|
||||||
|
libdeflate_free_compressor(struct libdeflate_compressor *compressor);
|
||||||
|
|
||||||
|
/* ========================================================================== */
|
||||||
|
/* Decompression */
|
||||||
|
/* ========================================================================== */
|
||||||
|
|
||||||
|
struct libdeflate_decompressor;
|
||||||
|
struct libdeflate_options;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* libdeflate_alloc_decompressor() allocates a new decompressor that can be used
|
||||||
|
* for DEFLATE, zlib, and gzip decompression. The return value is a pointer to
|
||||||
|
* the new decompressor, or NULL if out of memory.
|
||||||
|
*
|
||||||
|
* This function takes no parameters, and the returned decompressor is valid for
|
||||||
|
* decompressing data that was compressed at any compression level and with any
|
||||||
|
* sliding window size.
|
||||||
|
*
|
||||||
|
* A single decompressor is not safe to use by multiple threads concurrently.
|
||||||
|
* However, different threads may use different decompressors concurrently.
|
||||||
|
*/
|
||||||
|
LIBDEFLATEAPI struct libdeflate_decompressor *
|
||||||
|
libdeflate_alloc_decompressor(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Like libdeflate_alloc_decompressor(), but adds the 'options' argument.
|
||||||
|
*/
|
||||||
|
LIBDEFLATEAPI struct libdeflate_decompressor *
|
||||||
|
libdeflate_alloc_decompressor_ex(const struct libdeflate_options *options);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Result of a call to libdeflate_deflate_decompress(),
|
||||||
|
* libdeflate_zlib_decompress(), or libdeflate_gzip_decompress().
|
||||||
|
*/
|
||||||
|
enum libdeflate_result {
|
||||||
|
/* Decompression was successful. */
|
||||||
|
LIBDEFLATE_SUCCESS = 0,
|
||||||
|
|
||||||
|
/* Decompression failed because the compressed data was invalid,
|
||||||
|
* corrupt, or otherwise unsupported. */
|
||||||
|
LIBDEFLATE_BAD_DATA = 1,
|
||||||
|
|
||||||
|
/* A NULL 'actual_out_nbytes_ret' was provided, but the data would have
|
||||||
|
* decompressed to fewer than 'out_nbytes_avail' bytes. */
|
||||||
|
LIBDEFLATE_SHORT_OUTPUT = 2,
|
||||||
|
|
||||||
|
/* The data would have decompressed to more than 'out_nbytes_avail'
|
||||||
|
* bytes. */
|
||||||
|
LIBDEFLATE_INSUFFICIENT_SPACE = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* libdeflate_deflate_decompress() decompresses a DEFLATE stream from the buffer
|
||||||
|
* 'in' with compressed size up to 'in_nbytes' bytes. The uncompressed data is
|
||||||
|
* written to 'out', a buffer with size 'out_nbytes_avail' bytes. If
|
||||||
|
* decompression succeeds, then 0 (LIBDEFLATE_SUCCESS) is returned. Otherwise,
|
||||||
|
* a nonzero result code such as LIBDEFLATE_BAD_DATA is returned, and the
|
||||||
|
* contents of the output buffer are undefined.
|
||||||
|
*
|
||||||
|
* Decompression stops at the end of the DEFLATE stream (as indicated by the
|
||||||
|
* BFINAL flag), even if it is actually shorter than 'in_nbytes' bytes.
|
||||||
|
*
|
||||||
|
* libdeflate_deflate_decompress() can be used in cases where the actual
|
||||||
|
* uncompressed size is known (recommended) or unknown (not recommended):
|
||||||
|
*
|
||||||
|
* - If the actual uncompressed size is known, then pass the actual
|
||||||
|
* uncompressed size as 'out_nbytes_avail' and pass NULL for
|
||||||
|
* 'actual_out_nbytes_ret'. This makes libdeflate_deflate_decompress() fail
|
||||||
|
* with LIBDEFLATE_SHORT_OUTPUT if the data decompressed to fewer than the
|
||||||
|
* specified number of bytes.
|
||||||
|
*
|
||||||
|
* - If the actual uncompressed size is unknown, then provide a non-NULL
|
||||||
|
* 'actual_out_nbytes_ret' and provide a buffer with some size
|
||||||
|
* 'out_nbytes_avail' that you think is large enough to hold all the
|
||||||
|
* uncompressed data. In this case, if the data decompresses to less than
|
||||||
|
* or equal to 'out_nbytes_avail' bytes, then
|
||||||
|
* libdeflate_deflate_decompress() will write the actual uncompressed size
|
||||||
|
* to *actual_out_nbytes_ret and return 0 (LIBDEFLATE_SUCCESS). Otherwise,
|
||||||
|
* it will return LIBDEFLATE_INSUFFICIENT_SPACE if the provided buffer was
|
||||||
|
* not large enough but no other problems were encountered, or another
|
||||||
|
* nonzero result code if decompression failed for another reason.
|
||||||
|
*/
|
||||||
|
LIBDEFLATEAPI enum libdeflate_result
|
||||||
|
libdeflate_deflate_decompress(struct libdeflate_decompressor *decompressor,
|
||||||
|
const void *in, size_t in_nbytes,
|
||||||
|
void *out, size_t out_nbytes_avail,
|
||||||
|
size_t *actual_out_nbytes_ret);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Like libdeflate_deflate_decompress(), but adds the 'actual_in_nbytes_ret'
|
||||||
|
* argument. If decompression succeeds and 'actual_in_nbytes_ret' is not NULL,
|
||||||
|
* then the actual compressed size of the DEFLATE stream (aligned to the next
|
||||||
|
* byte boundary) is written to *actual_in_nbytes_ret.
|
||||||
|
*/
|
||||||
|
LIBDEFLATEAPI enum libdeflate_result
|
||||||
|
libdeflate_deflate_decompress_ex(struct libdeflate_decompressor *decompressor,
|
||||||
|
const void *in, size_t in_nbytes,
|
||||||
|
void *out, size_t out_nbytes_avail,
|
||||||
|
size_t *actual_in_nbytes_ret,
|
||||||
|
size_t *actual_out_nbytes_ret);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Like libdeflate_deflate_decompress(), but assumes the zlib wrapper format
|
||||||
|
* instead of raw DEFLATE.
|
||||||
|
*
|
||||||
|
* Decompression will stop at the end of the zlib stream, even if it is shorter
|
||||||
|
* than 'in_nbytes'. If you need to know exactly where the zlib stream ended,
|
||||||
|
* use libdeflate_zlib_decompress_ex().
|
||||||
|
*/
|
||||||
|
LIBDEFLATEAPI enum libdeflate_result
|
||||||
|
libdeflate_zlib_decompress(struct libdeflate_decompressor *decompressor,
|
||||||
|
const void *in, size_t in_nbytes,
|
||||||
|
void *out, size_t out_nbytes_avail,
|
||||||
|
size_t *actual_out_nbytes_ret);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Like libdeflate_zlib_decompress(), but adds the 'actual_in_nbytes_ret'
|
||||||
|
* argument. If 'actual_in_nbytes_ret' is not NULL and the decompression
|
||||||
|
* succeeds (indicating that the first zlib-compressed stream in the input
|
||||||
|
* buffer was decompressed), then the actual number of input bytes consumed is
|
||||||
|
* written to *actual_in_nbytes_ret.
|
||||||
|
*/
|
||||||
|
LIBDEFLATEAPI enum libdeflate_result
|
||||||
|
libdeflate_zlib_decompress_ex(struct libdeflate_decompressor *decompressor,
|
||||||
|
const void *in, size_t in_nbytes,
|
||||||
|
void *out, size_t out_nbytes_avail,
|
||||||
|
size_t *actual_in_nbytes_ret,
|
||||||
|
size_t *actual_out_nbytes_ret);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Like libdeflate_deflate_decompress(), but assumes the gzip wrapper format
|
||||||
|
* instead of raw DEFLATE.
|
||||||
|
*
|
||||||
|
* If multiple gzip-compressed members are concatenated, then only the first
|
||||||
|
* will be decompressed. Use libdeflate_gzip_decompress_ex() if you need
|
||||||
|
* multi-member support.
|
||||||
|
*/
|
||||||
|
LIBDEFLATEAPI enum libdeflate_result
|
||||||
|
libdeflate_gzip_decompress(struct libdeflate_decompressor *decompressor,
|
||||||
|
const void *in, size_t in_nbytes,
|
||||||
|
void *out, size_t out_nbytes_avail,
|
||||||
|
size_t *actual_out_nbytes_ret);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Like libdeflate_gzip_decompress(), but adds the 'actual_in_nbytes_ret'
|
||||||
|
* argument. If 'actual_in_nbytes_ret' is not NULL and the decompression
|
||||||
|
* succeeds (indicating that the first gzip-compressed member in the input
|
||||||
|
* buffer was decompressed), then the actual number of input bytes consumed is
|
||||||
|
* written to *actual_in_nbytes_ret.
|
||||||
|
*/
|
||||||
|
LIBDEFLATEAPI enum libdeflate_result
|
||||||
|
libdeflate_gzip_decompress_ex(struct libdeflate_decompressor *decompressor,
|
||||||
|
const void *in, size_t in_nbytes,
|
||||||
|
void *out, size_t out_nbytes_avail,
|
||||||
|
size_t *actual_in_nbytes_ret,
|
||||||
|
size_t *actual_out_nbytes_ret);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* libdeflate_free_decompressor() frees a decompressor that was allocated with
|
||||||
|
* libdeflate_alloc_decompressor(). If a NULL pointer is passed in, no action
|
||||||
|
* is taken.
|
||||||
|
*/
|
||||||
|
LIBDEFLATEAPI void
|
||||||
|
libdeflate_free_decompressor(struct libdeflate_decompressor *decompressor);
|
||||||
|
|
||||||
|
/* ========================================================================== */
|
||||||
|
/* Checksums */
|
||||||
|
/* ========================================================================== */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* libdeflate_adler32() updates a running Adler-32 checksum with 'len' bytes of
|
||||||
|
* data and returns the updated checksum. When starting a new checksum, the
|
||||||
|
* required initial value for 'adler' is 1. This value is also returned when
|
||||||
|
* 'buffer' is specified as NULL.
|
||||||
|
*/
|
||||||
|
LIBDEFLATEAPI uint32_t
|
||||||
|
libdeflate_adler32(uint32_t adler, const void *buffer, size_t len);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* libdeflate_crc32() updates a running CRC-32 checksum with 'len' bytes of data
|
||||||
|
* and returns the updated checksum. When starting a new checksum, the required
|
||||||
|
* initial value for 'crc' is 0. This value is also returned when 'buffer' is
|
||||||
|
* specified as NULL.
|
||||||
|
*/
|
||||||
|
LIBDEFLATEAPI uint32_t
|
||||||
|
libdeflate_crc32(uint32_t crc, const void *buffer, size_t len);
|
||||||
|
|
||||||
|
/* ========================================================================== */
|
||||||
|
/* Custom memory allocator */
|
||||||
|
/* ========================================================================== */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Install a custom memory allocator which libdeflate will use for all memory
|
||||||
|
* allocations by default. 'malloc_func' is a function that must behave like
|
||||||
|
* malloc(), and 'free_func' is a function that must behave like free().
|
||||||
|
*
|
||||||
|
* The per-(de)compressor custom memory allocator that can be specified in
|
||||||
|
* 'struct libdeflate_options' takes priority over this.
|
||||||
|
*
|
||||||
|
* This doesn't affect the free() function that will be used to free
|
||||||
|
* (de)compressors that were already in existence when this is called.
|
||||||
|
*/
|
||||||
|
LIBDEFLATEAPI void
|
||||||
|
libdeflate_set_memory_allocator(void *(*malloc_func)(size_t),
|
||||||
|
void (*free_func)(void *));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Advanced options. This is the options structure that
|
||||||
|
* libdeflate_alloc_compressor_ex() and libdeflate_alloc_decompressor_ex()
|
||||||
|
* require. Most users won't need this and should just use the non-"_ex"
|
||||||
|
* functions instead. If you do need this, it should be initialized like this:
|
||||||
|
*
|
||||||
|
* struct libdeflate_options options;
|
||||||
|
*
|
||||||
|
* memset(&options, 0, sizeof(options));
|
||||||
|
* options.sizeof_options = sizeof(options);
|
||||||
|
* // Then set the fields that you need to override the defaults for.
|
||||||
|
*/
|
||||||
|
struct libdeflate_options {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This field must be set to the struct size. This field exists for
|
||||||
|
* extensibility, so that fields can be appended to this struct in
|
||||||
|
* future versions of libdeflate while still supporting old binaries.
|
||||||
|
*/
|
||||||
|
size_t sizeof_options;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An optional custom memory allocator to use for this (de)compressor.
|
||||||
|
* 'malloc_func' must be a function that behaves like malloc(), and
|
||||||
|
* 'free_func' must be a function that behaves like free().
|
||||||
|
*
|
||||||
|
* This is useful in cases where a process might have multiple users of
|
||||||
|
* libdeflate who want to use different memory allocators. For example,
|
||||||
|
* a library might want to use libdeflate with a custom memory allocator
|
||||||
|
* without interfering with user code that might use libdeflate too.
|
||||||
|
*
|
||||||
|
* This takes priority over the "global" memory allocator (which by
|
||||||
|
* default is malloc() and free(), but can be changed by
|
||||||
|
* libdeflate_set_memory_allocator()). Moreover, libdeflate will never
|
||||||
|
* call the "global" memory allocator if a per-(de)compressor custom
|
||||||
|
* allocator is always given.
|
||||||
|
*/
|
||||||
|
void *(*malloc_func)(size_t);
|
||||||
|
void (*free_func)(void *);
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* LIBDEFLATE_H */
|
||||||
2924
Source/ThirdParty/OpenFBX/ofbx.cpp
vendored
2924
Source/ThirdParty/OpenFBX/ofbx.cpp
vendored
File diff suppressed because it is too large
Load Diff
447
Source/ThirdParty/OpenFBX/ofbx.h
vendored
447
Source/ThirdParty/OpenFBX/ofbx.h
vendored
@@ -9,10 +9,10 @@ typedef unsigned char u8;
|
|||||||
typedef unsigned short u16;
|
typedef unsigned short u16;
|
||||||
typedef unsigned int u32;
|
typedef unsigned int u32;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
typedef long long i64;
|
typedef long long i64;
|
||||||
typedef unsigned long long u64;
|
typedef unsigned long long u64;
|
||||||
#else
|
#else
|
||||||
typedef long i64;
|
typedef long i64;
|
||||||
typedef unsigned long u64;
|
typedef unsigned long u64;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -21,46 +21,71 @@ static_assert(sizeof(u32) == 4, "u32 is not 4 bytes");
|
|||||||
static_assert(sizeof(u64) == 8, "u64 is not 8 bytes");
|
static_assert(sizeof(u64) == 8, "u64 is not 8 bytes");
|
||||||
static_assert(sizeof(i64) == 8, "i64 is not 8 bytes");
|
static_assert(sizeof(i64) == 8, "i64 is not 8 bytes");
|
||||||
|
|
||||||
|
typedef decltype(sizeof(0)) usize;
|
||||||
|
|
||||||
using JobFunction = void (*)(void*);
|
using JobFunction = void (*)(void*);
|
||||||
using JobProcessor = void (*)(JobFunction, void*, void*, u32, u32);
|
using JobProcessor = void (*)(JobFunction, void*, void*, u32, u32);
|
||||||
|
|
||||||
enum class LoadFlags : u64 {
|
// Ignoring certain nodes will only stop them from being processed not tokenised (i.e. they will still be in the tree)
|
||||||
TRIANGULATE = 1 << 0,
|
enum class LoadFlags : u16
|
||||||
|
{
|
||||||
|
NONE = 0,
|
||||||
|
UNUSED = 1 << 0, // can be reused
|
||||||
IGNORE_GEOMETRY = 1 << 1,
|
IGNORE_GEOMETRY = 1 << 1,
|
||||||
IGNORE_BLEND_SHAPES = 1 << 2,
|
IGNORE_BLEND_SHAPES = 1 << 2,
|
||||||
|
IGNORE_CAMERAS = 1 << 3,
|
||||||
|
IGNORE_LIGHTS = 1 << 4,
|
||||||
|
IGNORE_TEXTURES = 1 << 5,
|
||||||
|
IGNORE_SKIN = 1 << 6,
|
||||||
|
IGNORE_BONES = 1 << 7,
|
||||||
|
IGNORE_PIVOTS = 1 << 8,
|
||||||
|
IGNORE_ANIMATIONS = 1 << 9,
|
||||||
|
IGNORE_MATERIALS = 1 << 10,
|
||||||
|
IGNORE_POSES = 1 << 11,
|
||||||
|
IGNORE_VIDEOS = 1 << 12,
|
||||||
|
IGNORE_LIMBS = 1 << 13,
|
||||||
|
IGNORE_MESHES = 1 << 14,
|
||||||
|
IGNORE_MODELS = 1 << 15,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr LoadFlags operator|(LoadFlags lhs, LoadFlags rhs)
|
||||||
struct Vec2
|
|
||||||
{
|
{
|
||||||
double x, y;
|
return static_cast<LoadFlags>(static_cast<u16>(lhs) | static_cast<u16>(rhs));
|
||||||
};
|
}
|
||||||
|
|
||||||
|
inline LoadFlags& operator|=(LoadFlags& lhs, LoadFlags rhs)
|
||||||
struct Vec3
|
|
||||||
{
|
{
|
||||||
double x, y, z;
|
return lhs = lhs | rhs;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
struct DVec2 { double x, y; };
|
||||||
|
struct DVec3 { double x, y, z; };
|
||||||
|
struct DVec4 { double x, y, z, w; };
|
||||||
|
struct DMatrix { double m[16]; /* last 4 are translation */ };
|
||||||
|
struct DQuat{ double x, y, z, w; };
|
||||||
|
|
||||||
struct Vec4
|
struct FVec2 { float x, y; };
|
||||||
{
|
struct FVec3 { float x, y, z; };
|
||||||
double x, y, z, w;
|
struct FVec4 { float x, y, z, w; };
|
||||||
};
|
struct FMatrix { float m[16]; };
|
||||||
|
struct FQuat{ float x, y, z, w; };
|
||||||
|
|
||||||
struct Matrix
|
|
||||||
{
|
|
||||||
double m[16]; // last 4 are translation
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct Quat
|
|
||||||
{
|
|
||||||
double x, y, z, w;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
#define OFBX_SINGLE_PRECISION
|
||||||
|
#ifdef OFBX_SINGLE_PRECISION
|
||||||
|
// use floats for vertices, normals, uvs, ...
|
||||||
|
using Vec2 = FVec2;
|
||||||
|
using Vec3 = FVec3;
|
||||||
|
using Vec4 = FVec4;
|
||||||
|
using Matrix = FMatrix;
|
||||||
|
using Quat = FQuat;
|
||||||
|
#else
|
||||||
|
// use doubles for vertices, normals, uvs, ...
|
||||||
|
using Vec2 = DVec2;
|
||||||
|
using Vec3 = DVec3;
|
||||||
|
using Vec4 = DVec4;
|
||||||
|
using Matrix = DMatrix;
|
||||||
|
using Quat = DQuat;
|
||||||
|
#endif
|
||||||
|
|
||||||
struct Color
|
struct Color
|
||||||
{
|
{
|
||||||
@@ -81,9 +106,10 @@ struct DataView
|
|||||||
i64 toI64() const;
|
i64 toI64() const;
|
||||||
int toInt() const;
|
int toInt() const;
|
||||||
u32 toU32() const;
|
u32 toU32() const;
|
||||||
|
bool toBool() const;
|
||||||
double toDouble() const;
|
double toDouble() const;
|
||||||
float toFloat() const;
|
float toFloat() const;
|
||||||
|
|
||||||
template <int N>
|
template <int N>
|
||||||
void toString(char(&out)[N]) const
|
void toString(char(&out)[N]) const
|
||||||
{
|
{
|
||||||
@@ -113,7 +139,8 @@ struct IElementProperty
|
|||||||
ARRAY_INT = 'i',
|
ARRAY_INT = 'i',
|
||||||
ARRAY_LONG = 'l',
|
ARRAY_LONG = 'l',
|
||||||
ARRAY_FLOAT = 'f',
|
ARRAY_FLOAT = 'f',
|
||||||
BINARY = 'R'
|
BINARY = 'R',
|
||||||
|
NONE = ' '
|
||||||
};
|
};
|
||||||
virtual ~IElementProperty() {}
|
virtual ~IElementProperty() {}
|
||||||
virtual Type getType() const = 0;
|
virtual Type getType() const = 0;
|
||||||
@@ -168,6 +195,8 @@ struct Object
|
|||||||
TEXTURE,
|
TEXTURE,
|
||||||
LIMB_NODE,
|
LIMB_NODE,
|
||||||
NULL_NODE,
|
NULL_NODE,
|
||||||
|
CAMERA,
|
||||||
|
LIGHT,
|
||||||
NODE_ATTRIBUTE,
|
NODE_ATTRIBUTE,
|
||||||
CLUSTER,
|
CLUSTER,
|
||||||
SKIN,
|
SKIN,
|
||||||
@@ -189,22 +218,22 @@ struct Object
|
|||||||
Object* resolveObjectLink(int idx) const;
|
Object* resolveObjectLink(int idx) const;
|
||||||
Object* resolveObjectLink(Type type, const char* property, int idx) const;
|
Object* resolveObjectLink(Type type, const char* property, int idx) const;
|
||||||
Object* resolveObjectLinkReverse(Type type) const;
|
Object* resolveObjectLinkReverse(Type type) const;
|
||||||
Object* getParent() const;
|
Object* getParent() const { return parent; }
|
||||||
|
|
||||||
RotationOrder getRotationOrder() const;
|
RotationOrder getRotationOrder() const;
|
||||||
Vec3 getRotationOffset() const;
|
DVec3 getRotationOffset() const;
|
||||||
Vec3 getRotationPivot() const;
|
DVec3 getRotationPivot() const;
|
||||||
Vec3 getPostRotation() const;
|
DVec3 getPostRotation() const;
|
||||||
Vec3 getScalingOffset() const;
|
DVec3 getScalingOffset() const;
|
||||||
Vec3 getScalingPivot() const;
|
DVec3 getScalingPivot() const;
|
||||||
Vec3 getPreRotation() const;
|
DVec3 getPreRotation() const;
|
||||||
Vec3 getLocalTranslation() const;
|
DVec3 getLocalTranslation() const;
|
||||||
Vec3 getLocalRotation() const;
|
DVec3 getLocalRotation() const;
|
||||||
Vec3 getLocalScaling() const;
|
DVec3 getLocalScaling() const;
|
||||||
Matrix getGlobalTransform() const;
|
DMatrix getGlobalTransform() const;
|
||||||
Matrix getLocalTransform() const;
|
DMatrix getLocalTransform() const;
|
||||||
Matrix evalLocal(const Vec3& translation, const Vec3& rotation) const;
|
DMatrix evalLocal(const DVec3& translation, const DVec3& rotation) const;
|
||||||
Matrix evalLocal(const Vec3& translation, const Vec3& rotation, const Vec3& scaling) const;
|
DMatrix evalLocal(const DVec3& translation, const DVec3& rotation, const DVec3& scaling) const;
|
||||||
bool isNode() const { return is_node; }
|
bool isNode() const { return is_node; }
|
||||||
|
|
||||||
|
|
||||||
@@ -214,11 +243,14 @@ struct Object
|
|||||||
}
|
}
|
||||||
|
|
||||||
u64 id;
|
u64 id;
|
||||||
|
u32 depth = 0xffFFffFF;
|
||||||
|
Object* parent = nullptr;
|
||||||
char name[128];
|
char name[128];
|
||||||
const IElement& element;
|
const IElement& element;
|
||||||
const Object* node_attribute;
|
const Object* node_attribute;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
friend struct Scene;
|
||||||
bool is_node;
|
bool is_node;
|
||||||
const Scene& scene;
|
const Scene& scene;
|
||||||
};
|
};
|
||||||
@@ -228,7 +260,7 @@ struct Pose : Object {
|
|||||||
static const Type s_type = Type::POSE;
|
static const Type s_type = Type::POSE;
|
||||||
Pose(const Scene& _scene, const IElement& _element);
|
Pose(const Scene& _scene, const IElement& _element);
|
||||||
|
|
||||||
virtual Matrix getMatrix() const = 0;
|
virtual DMatrix getMatrix() const = 0;
|
||||||
virtual const Object* getNode() const = 0;
|
virtual const Object* getNode() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -255,6 +287,124 @@ struct Texture : Object
|
|||||||
virtual DataView getEmbeddedData() const = 0;
|
virtual DataView getEmbeddedData() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Light : Object
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class LightType
|
||||||
|
{
|
||||||
|
POINT,
|
||||||
|
DIRECTIONAL,
|
||||||
|
SPOT,
|
||||||
|
AREA,
|
||||||
|
VOLUME,
|
||||||
|
COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class DecayType
|
||||||
|
{
|
||||||
|
NO_DECAY,
|
||||||
|
LINEAR,
|
||||||
|
QUADRATIC,
|
||||||
|
CUBIC,
|
||||||
|
COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
Light(const Scene& _scene, const IElement& _element)
|
||||||
|
: Object(_scene, _element)
|
||||||
|
{
|
||||||
|
// Initialize the light properties here
|
||||||
|
}
|
||||||
|
|
||||||
|
// Light type
|
||||||
|
virtual LightType getLightType() const = 0;
|
||||||
|
|
||||||
|
// Light properties
|
||||||
|
virtual bool doesCastLight() const = 0;
|
||||||
|
virtual bool doesDrawVolumetricLight() const = 0;
|
||||||
|
virtual bool doesDrawGroundProjection() const = 0;
|
||||||
|
virtual bool doesDrawFrontFacingVolumetricLight() const = 0;
|
||||||
|
virtual Color getColor() const = 0;
|
||||||
|
virtual double getIntensity() const = 0;
|
||||||
|
virtual double getInnerAngle() const = 0;
|
||||||
|
virtual double getOuterAngle() const = 0;
|
||||||
|
virtual double getFog() const = 0;
|
||||||
|
virtual DecayType getDecayType() const = 0;
|
||||||
|
virtual double getDecayStart() const = 0;
|
||||||
|
|
||||||
|
// Near attenuation
|
||||||
|
virtual bool doesEnableNearAttenuation() const = 0;
|
||||||
|
virtual double getNearAttenuationStart() const = 0;
|
||||||
|
virtual double getNearAttenuationEnd() const = 0;
|
||||||
|
|
||||||
|
// Far attenuation
|
||||||
|
virtual bool doesEnableFarAttenuation() const = 0;
|
||||||
|
virtual double getFarAttenuationStart() const = 0;
|
||||||
|
virtual double getFarAttenuationEnd() const = 0;
|
||||||
|
|
||||||
|
// Shadows
|
||||||
|
virtual const Texture* getShadowTexture() const = 0;
|
||||||
|
virtual bool doesCastShadows() const = 0;
|
||||||
|
virtual Color getShadowColor() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Camera : Object
|
||||||
|
{
|
||||||
|
enum class ProjectionType
|
||||||
|
{
|
||||||
|
PERSPECTIVE,
|
||||||
|
ORTHOGRAPHIC,
|
||||||
|
COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class ApertureMode // Used to determine how to calculate the FOV
|
||||||
|
{
|
||||||
|
HORIZANDVERT,
|
||||||
|
HORIZONTAL,
|
||||||
|
VERTICAL,
|
||||||
|
FOCALLENGTH,
|
||||||
|
COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class GateFit
|
||||||
|
{
|
||||||
|
NONE,
|
||||||
|
VERTICAL,
|
||||||
|
HORIZONTAL,
|
||||||
|
FILL,
|
||||||
|
OVERSCAN,
|
||||||
|
STRETCH,
|
||||||
|
COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
static const Type s_type = Type::CAMERA;
|
||||||
|
|
||||||
|
Camera(const Scene& _scene, const IElement& _element)
|
||||||
|
: Object(_scene, _element)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Type getType() const { return Type::CAMERA; }
|
||||||
|
virtual ProjectionType getProjectionType() const = 0;
|
||||||
|
virtual ApertureMode getApertureMode() const = 0;
|
||||||
|
|
||||||
|
virtual double getFilmHeight() const = 0;
|
||||||
|
virtual double getFilmWidth() const = 0;
|
||||||
|
|
||||||
|
virtual double getAspectHeight() const = 0;
|
||||||
|
virtual double getAspectWidth() const = 0;
|
||||||
|
|
||||||
|
virtual double getNearPlane() const = 0;
|
||||||
|
virtual double getFarPlane() const = 0;
|
||||||
|
virtual bool doesAutoComputeClipPanes() const = 0;
|
||||||
|
|
||||||
|
virtual GateFit getGateFit() const = 0;
|
||||||
|
virtual double getFilmAspectRatio() const = 0;
|
||||||
|
virtual double getFocalLength() const = 0;
|
||||||
|
virtual double getFocusDistance() const = 0;
|
||||||
|
|
||||||
|
virtual DVec3 getBackgroundColor() const = 0;
|
||||||
|
virtual DVec3 getInterestPosition() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
struct Material : Object
|
struct Material : Object
|
||||||
{
|
{
|
||||||
@@ -291,8 +441,8 @@ struct Cluster : Object
|
|||||||
virtual int getIndicesCount() const = 0;
|
virtual int getIndicesCount() const = 0;
|
||||||
virtual const double* getWeights() const = 0;
|
virtual const double* getWeights() const = 0;
|
||||||
virtual int getWeightsCount() const = 0;
|
virtual int getWeightsCount() const = 0;
|
||||||
virtual Matrix getTransformMatrix() const = 0;
|
virtual DMatrix getTransformMatrix() const = 0;
|
||||||
virtual Matrix getTransformLinkMatrix() const = 0;
|
virtual DMatrix getTransformLinkMatrix() const = 0;
|
||||||
virtual const Object* getLink() const = 0;
|
virtual const Object* getLink() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -341,26 +491,74 @@ struct NodeAttribute : Object
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Geometry : Object
|
struct Vec2Attributes {
|
||||||
{
|
const Vec2* values = nullptr;
|
||||||
|
const int* indices = nullptr;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
Vec2Attributes() {}
|
||||||
|
Vec2Attributes(const Vec2* v, const int* i, int c) : values(v), indices(i), count(c) {}
|
||||||
|
|
||||||
|
Vec2 get(int i) const { return indices ? values[indices[i]] : values[i]; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Vec3Attributes {
|
||||||
|
const Vec3* values = nullptr;
|
||||||
|
const int* indices = nullptr;
|
||||||
|
int count = 0;
|
||||||
|
int values_count = 0;
|
||||||
|
|
||||||
|
Vec3Attributes() {}
|
||||||
|
Vec3Attributes(const Vec3* v, const int* i, int c, int vc) : values(v), indices(i), count(c), values_count(vc) {}
|
||||||
|
|
||||||
|
Vec3 get(int i) const { return indices ? values[indices[i]] : values[i]; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Vec4Attributes {
|
||||||
|
const Vec4* values = nullptr;
|
||||||
|
const int* indices = nullptr;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
Vec4Attributes() {}
|
||||||
|
Vec4Attributes(const Vec4* v, const int* i, int c) : values(v), indices(i), count(c) {}
|
||||||
|
|
||||||
|
Vec4 get(int i) const { return indices ? values[indices[i]] : values[i]; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// subset of polygons with same material
|
||||||
|
struct GeometryPartition {
|
||||||
|
struct Polygon {
|
||||||
|
const int from_vertex; // index into VecNAttributes::indices
|
||||||
|
const int vertex_count;
|
||||||
|
};
|
||||||
|
const Polygon* polygons;
|
||||||
|
const int polygon_count;
|
||||||
|
const int max_polygon_triangles; // max triangles in single polygon, can be used for preallocation
|
||||||
|
const int triangles_count; // number of triangles after polygon triangulation, can be used for preallocation
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GeometryData {
|
||||||
|
virtual ~GeometryData() {}
|
||||||
|
|
||||||
|
virtual Vec3Attributes getPositions() const = 0;
|
||||||
|
virtual Vec3Attributes getNormals() const = 0;
|
||||||
|
virtual Vec2Attributes getUVs(int index = 0) const = 0;
|
||||||
|
virtual Vec4Attributes getColors() const = 0;
|
||||||
|
virtual Vec3Attributes getTangents() const = 0;
|
||||||
|
virtual int getPartitionCount() const = 0;
|
||||||
|
virtual GeometryPartition getPartition(int partition_index) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Geometry : Object {
|
||||||
static const Type s_type = Type::GEOMETRY;
|
static const Type s_type = Type::GEOMETRY;
|
||||||
static const int s_uvs_max = 4;
|
static const int s_uvs_max = 4;
|
||||||
|
|
||||||
Geometry(const Scene& _scene, const IElement& _element);
|
Geometry(const Scene& _scene, const IElement& _element);
|
||||||
|
|
||||||
virtual const Vec3* getVertices() const = 0;
|
virtual const GeometryData& getGeometryData() const = 0;
|
||||||
virtual int getVertexCount() const = 0;
|
|
||||||
|
|
||||||
virtual const int* getFaceIndices() const = 0;
|
|
||||||
virtual int getIndexCount() const = 0;
|
|
||||||
|
|
||||||
virtual const Vec3* getNormals() const = 0;
|
|
||||||
virtual const Vec2* getUVs(int index = 0) const = 0;
|
|
||||||
virtual const Vec4* getColors() const = 0;
|
|
||||||
virtual const Vec3* getTangents() const = 0;
|
|
||||||
virtual const Skin* getSkin() const = 0;
|
virtual const Skin* getSkin() const = 0;
|
||||||
virtual const BlendShape* getBlendShape() const = 0;
|
virtual const BlendShape* getBlendShape() const = 0;
|
||||||
virtual const int* getMaterials() const = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -373,21 +571,27 @@ struct Shape : Object
|
|||||||
virtual const Vec3* getVertices() const = 0;
|
virtual const Vec3* getVertices() const = 0;
|
||||||
virtual int getVertexCount() const = 0;
|
virtual int getVertexCount() const = 0;
|
||||||
|
|
||||||
|
virtual const int* getIndices() const = 0;
|
||||||
|
virtual int getIndexCount() const = 0;
|
||||||
|
|
||||||
virtual const Vec3* getNormals() const = 0;
|
virtual const Vec3* getNormals() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Mesh : Object
|
struct Mesh : Object {
|
||||||
{
|
|
||||||
static const Type s_type = Type::MESH;
|
static const Type s_type = Type::MESH;
|
||||||
|
|
||||||
Mesh(const Scene& _scene, const IElement& _element);
|
Mesh(const Scene& _scene, const IElement& _element);
|
||||||
|
|
||||||
virtual const Pose* getPose() const = 0;
|
virtual const Pose* getPose() const = 0;
|
||||||
virtual const Geometry* getGeometry() const = 0;
|
virtual const Geometry* getGeometry() const = 0;
|
||||||
virtual Matrix getGeometricMatrix() const = 0;
|
virtual DMatrix getGeometricMatrix() const = 0;
|
||||||
virtual const Material* getMaterial(int idx) const = 0;
|
virtual const Material* getMaterial(int idx) const = 0;
|
||||||
virtual int getMaterialCount() const = 0;
|
virtual int getMaterialCount() const = 0;
|
||||||
|
// this will use data from `Geometry` if available and from `Mesh` otherwise
|
||||||
|
virtual const GeometryData& getGeometryData() const = 0;
|
||||||
|
virtual const Skin* getSkin() const = 0;
|
||||||
|
virtual const BlendShape* getBlendShape() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -429,8 +633,9 @@ struct AnimationCurveNode : Object
|
|||||||
|
|
||||||
AnimationCurveNode(const Scene& _scene, const IElement& _element);
|
AnimationCurveNode(const Scene& _scene, const IElement& _element);
|
||||||
|
|
||||||
|
virtual DataView getBoneLinkProperty() const = 0;
|
||||||
virtual const AnimationCurve* getCurve(int idx) const = 0;
|
virtual const AnimationCurve* getCurve(int idx) const = 0;
|
||||||
virtual Vec3 getNodeLocalTransform(double time) const = 0;
|
virtual DVec3 getNodeLocalTransform(double time) const = 0;
|
||||||
virtual const Object* getBone() const = 0;
|
virtual const Object* getBone() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -449,17 +654,9 @@ struct TakeInfo
|
|||||||
// Specifies which canonical axis represents up in the system (typically Y or Z).
|
// Specifies which canonical axis represents up in the system (typically Y or Z).
|
||||||
enum UpVector
|
enum UpVector
|
||||||
{
|
{
|
||||||
UpVector_AxisX = 1,
|
UpVector_AxisX = 0,
|
||||||
UpVector_AxisY = 2,
|
UpVector_AxisY = 1,
|
||||||
UpVector_AxisZ = 3
|
UpVector_AxisZ = 2
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Vector with origin at the screen pointing toward the camera.
|
|
||||||
enum FrontVector
|
|
||||||
{
|
|
||||||
FrontVector_ParityEven = 1,
|
|
||||||
FrontVector_ParityOdd = 2
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -494,9 +691,11 @@ enum FrameRate
|
|||||||
|
|
||||||
struct GlobalSettings
|
struct GlobalSettings
|
||||||
{
|
{
|
||||||
UpVector UpAxis = UpVector_AxisX;
|
UpVector UpAxis = UpVector_AxisY;
|
||||||
int UpAxisSign = 1;
|
int UpAxisSign = 1;
|
||||||
FrontVector FrontAxis = FrontVector_ParityOdd;
|
// this seems to be 1-2 in Autodesk (odd/even parity), and 0-2 in Blender (axis as in UpAxis)
|
||||||
|
// I recommend to ignore FrontAxis and use just UpVector
|
||||||
|
int FrontAxis = 1;
|
||||||
int FrontAxisSign = 1;
|
int FrontAxisSign = 1;
|
||||||
CoordSystem CoordAxis = CoordSystem_RightHanded;
|
CoordSystem CoordAxis = CoordSystem_RightHanded;
|
||||||
int CoordAxisSign = 1;
|
int CoordAxisSign = 1;
|
||||||
@@ -511,41 +710,105 @@ struct GlobalSettings
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct GlobalInfo
|
|
||||||
{
|
|
||||||
char AppVendor[128];
|
|
||||||
char AppName[128];
|
|
||||||
char AppVersion[128];
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct IScene
|
struct IScene
|
||||||
{
|
{
|
||||||
virtual void destroy() = 0;
|
virtual void destroy() = 0;
|
||||||
|
|
||||||
|
// Root Node
|
||||||
virtual const IElement* getRootElement() const = 0;
|
virtual const IElement* getRootElement() const = 0;
|
||||||
virtual const Object* getRoot() const = 0;
|
virtual const Object* getRoot() const = 0;
|
||||||
virtual const TakeInfo* getTakeInfo(const char* name) const = 0;
|
|
||||||
|
// Meshes
|
||||||
virtual int getMeshCount() const = 0;
|
virtual int getMeshCount() const = 0;
|
||||||
virtual float getSceneFrameRate() const = 0;
|
|
||||||
virtual const GlobalInfo* getGlobalInfo() const = 0;
|
|
||||||
virtual const GlobalSettings* getGlobalSettings() const = 0;
|
|
||||||
virtual const Mesh* getMesh(int index) const = 0;
|
virtual const Mesh* getMesh(int index) const = 0;
|
||||||
|
|
||||||
|
// Geometry
|
||||||
|
virtual int getGeometryCount() const = 0;
|
||||||
|
virtual const Geometry* getGeometry(int index) const = 0;
|
||||||
|
|
||||||
|
// Animations
|
||||||
virtual int getAnimationStackCount() const = 0;
|
virtual int getAnimationStackCount() const = 0;
|
||||||
virtual const AnimationStack* getAnimationStack(int index) const = 0;
|
virtual const AnimationStack* getAnimationStack(int index) const = 0;
|
||||||
|
|
||||||
|
// Cameras
|
||||||
|
virtual int getCameraCount() const = 0;
|
||||||
|
virtual const Camera* getCamera(int index) const = 0;
|
||||||
|
|
||||||
|
// Lights
|
||||||
|
virtual int getLightCount() const = 0;
|
||||||
|
virtual const Light* getLight(int index) const = 0;
|
||||||
|
|
||||||
|
// Scene Objects (Everything in scene)
|
||||||
virtual const Object* const* getAllObjects() const = 0;
|
virtual const Object* const* getAllObjects() const = 0;
|
||||||
virtual int getAllObjectCount() const = 0;
|
virtual int getAllObjectCount() const = 0;
|
||||||
|
|
||||||
|
// Embedded files/Data
|
||||||
virtual int getEmbeddedDataCount() const = 0;
|
virtual int getEmbeddedDataCount() const = 0;
|
||||||
virtual DataView getEmbeddedData(int index) const = 0;
|
virtual DataView getEmbeddedData(int index) const = 0;
|
||||||
virtual DataView getEmbeddedFilename(int index) const = 0;
|
virtual DataView getEmbeddedFilename(int index) const = 0;
|
||||||
|
virtual bool isEmbeddedBase64(int index) const = 0;
|
||||||
|
// data are encoded in returned property and all ->next properties
|
||||||
|
virtual const IElementProperty* getEmbeddedBase64Data(int index) const = 0;
|
||||||
|
|
||||||
|
// Scene Misc
|
||||||
|
virtual const TakeInfo* getTakeInfo(const char* name) const = 0;
|
||||||
|
virtual float getSceneFrameRate() const = 0;
|
||||||
|
virtual const GlobalSettings* getGlobalSettings() const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
virtual ~IScene() {}
|
virtual ~IScene() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
IScene* load(const u8* data, int size, u64 flags, JobProcessor job_processor = nullptr, void* job_user_ptr = nullptr);
|
IScene* load(const u8* data, usize size, u16 flags, JobProcessor job_processor = nullptr, void* job_user_ptr = nullptr);
|
||||||
const char* getError();
|
const char* getError();
|
||||||
double fbxTimeToSeconds(i64 value);
|
double fbxTimeToSeconds(i64 value);
|
||||||
i64 secondsToFbxTime(double value);
|
i64 secondsToFbxTime(double value);
|
||||||
|
|
||||||
|
// TODO nonconvex
|
||||||
|
inline u32 triangulate(const GeometryData& geom, const GeometryPartition::Polygon& polygon, int* tri_indices) {
|
||||||
|
if (polygon.vertex_count < 3) return 0;
|
||||||
|
if (polygon.vertex_count == 3) {
|
||||||
|
tri_indices[0] = polygon.from_vertex;
|
||||||
|
tri_indices[1] = polygon.from_vertex + 1;
|
||||||
|
tri_indices[2] = polygon.from_vertex + 2;
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
else if (polygon.vertex_count == 4) {
|
||||||
|
tri_indices[0] = polygon.from_vertex + 0;
|
||||||
|
tri_indices[1] = polygon.from_vertex + 1;
|
||||||
|
tri_indices[2] = polygon.from_vertex + 2;
|
||||||
|
|
||||||
|
tri_indices[3] = polygon.from_vertex + 0;
|
||||||
|
tri_indices[4] = polygon.from_vertex + 2;
|
||||||
|
tri_indices[5] = polygon.from_vertex + 3;
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int tri = 0; tri < polygon.vertex_count - 2; ++tri) {
|
||||||
|
tri_indices[tri * 3 + 0] = polygon.from_vertex;
|
||||||
|
tri_indices[tri * 3 + 1] = polygon.from_vertex + 1 + tri;
|
||||||
|
tri_indices[tri * 3 + 2] = polygon.from_vertex + 2 + tri;
|
||||||
|
}
|
||||||
|
return 3 * (polygon.vertex_count - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace ofbx
|
} // namespace ofbx
|
||||||
|
|
||||||
|
#ifdef OFBX_DEFAULT_DELETER
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
template <> struct ::std::default_delete<ofbx::IScene>
|
||||||
|
{
|
||||||
|
default_delete() = default;
|
||||||
|
template <class U> constexpr default_delete(default_delete<U>) noexcept {}
|
||||||
|
void operator()(ofbx::IScene* scene) const noexcept
|
||||||
|
{
|
||||||
|
if (scene)
|
||||||
|
{
|
||||||
|
scene->destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user