Update OpenFBX

Updated to commit 365f52c1edad6bd283c8a645f1d8d2347dbd1e35
This commit is contained in:
2024-05-25 11:30:48 +03:00
parent e0791eacad
commit 7454e9abd2
5 changed files with 6693 additions and 1423 deletions

View File

@@ -49,7 +49,7 @@ Quaternion ToQuaternion(const ofbx::Quat& v)
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;
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)
{
return aMesh->getGeometry()->getVertexCount() == 0;
return aMesh->getGeometry()->getGeometryData().getPositions().count == 0;
}
bool ImportBones(OpenFbxImporterData& data, String& errorMsg)
@@ -524,56 +524,56 @@ bool ImportBones(OpenFbxImporterData& data, String& errorMsg)
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();
mesh.Name = aMesh->name;
ZoneText(*mesh.Name, mesh.Name.Length());
const int32 firstVertexOffset = triangleStart * 3;
const int32 lastVertexOffset = triangleEnd * 3;
const ofbx::Geometry* aGeometry = aMesh->getGeometry();
const int vertexCount = lastVertexOffset - firstVertexOffset + 3;
ASSERT(firstVertexOffset + vertexCount <= aGeometry->getVertexCount());
const ofbx::Vec3* vertices = aGeometry->getVertices();
const ofbx::Vec3* normals = aGeometry->getNormals();
const ofbx::Vec3* tangents = aGeometry->getTangents();
const ofbx::Vec4* colors = aGeometry->getColors();
const ofbx::Vec2* uvs = aGeometry->getUVs();
const ofbx::GeometryData& geometryData = aMesh->getGeometryData();
const ofbx::GeometryPartition& partition = geometryData.getPartition(partitionIndex);
const int vertexCount = partition.triangles_count * 3;
const ofbx::Vec3Attributes& positions = geometryData.getPositions();
const ofbx::Vec2Attributes& uvs = geometryData.getUVs();
const ofbx::Vec3Attributes& normals = geometryData.getNormals();
const ofbx::Vec3Attributes& tangents = geometryData.getTangents();
const ofbx::Vec4Attributes& colors = geometryData.getColors();
const ofbx::Skin* skin = aGeometry->getSkin();
const ofbx::BlendShape* blendShape = aGeometry->getBlendShape();
static Array<int> triangulatedIndices;
triangulatedIndices.Resize(vertexCount, false);
// Properties
const ofbx::Material* aMaterial = nullptr;
if (aMesh->getMaterialCount() > 0)
{
if (aGeometry->getMaterials())
aMaterial = aMesh->getMaterial(aGeometry->getMaterials()[triangleStart]);
else
aMaterial = aMesh->getMaterial(0);
}
aMaterial = aMesh->getMaterial(partitionIndex);
mesh.MaterialSlotIndex = data.AddMaterial(result, aMaterial);
// Vertex positions
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)
if (vertexCount % 3 != 0)
{
errorMsg = TEXT("Invalid vertex count. It must be multiple of 3.");
return true;
}
mesh.Indices.Resize(vertexCount, false);
for (int i = 0; i < vertexCount; i++)
mesh.Indices.Get()[i] = i;
// Texture coordinates
if (uvs)
if (uvs.values)
{
mesh.UVs.Resize(vertexCount, false);
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)
{
for (int32 v = 0; v < vertexCount; v++)
@@ -582,7 +582,7 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
}
// Normals
if (data.Options.CalculateNormals || !normals)
if (data.Options.CalculateNormals || !normals.values)
{
if (mesh.GenerateNormals(data.Options.SmoothingNormalsAngle))
{
@@ -590,11 +590,11 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
return true;
}
}
else if (normals)
else if (normals.values)
{
mesh.Normals.Resize(vertexCount, false);
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)
{
// Mirror normals along the Z axis
@@ -604,15 +604,15 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
}
// Tangents
if ((data.Options.CalculateTangents || !tangents) && mesh.UVs.HasItems())
if ((data.Options.CalculateTangents || !tangents.values) && mesh.UVs.HasItems())
{
// Generated after full mesh data conversion
}
else if (tangents)
else if (tangents.values)
{
mesh.Tangents.Resize(vertexCount, false);
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)
{
// 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
const auto lightmapUVs = aGeometry->getUVs(inputChannelIndex);
if (lightmapUVs)
const auto lightmapUVs = geometryData.getUVs(inputChannelIndex);
if (lightmapUVs.values)
{
mesh.LightmapUVs.Resize(vertexCount, false);
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)
{
for (int32 v = 0; v < vertexCount; v++)
@@ -677,11 +677,11 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
}
// Vertex Colors
if (data.Options.ImportVertexColors && colors)
if (data.Options.ImportVertexColors && colors.values)
{
mesh.Colors.Resize(vertexCount, false);
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
@@ -718,7 +718,7 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
const double* clusterWeights = cluster->getWeights();
for (int j = 0; j < cluster->getIndicesCount(); j++)
{
int vtxIndex = clusterIndices[j] - firstVertexOffset;
int vtxIndex = clusterIndices[j];
float vtxWeight = (float)clusterWeights[j];
if (vtxWeight <= 0 || vtxIndex < 0 || vtxIndex >= vertexCount)
continue;
@@ -762,9 +762,9 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
continue;
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;
}
@@ -779,14 +779,14 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
auto shapeVertices = shape->getVertices();
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;
}
auto shapeNormals = shape->getNormals();
for (int32 i = 0; i < blendShapeData.Vertices.Count(); i++)
{
auto delta = ToFloat3(shapeNormals[i + firstVertexOffset]);
auto delta = ToFloat3(shapeNormals[i]);
if (data.ConvertRH)
{
// 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]);
}
if ((data.Options.CalculateTangents || !tangents) && mesh.UVs.HasItems())
if ((data.Options.CalculateTangents || !tangents.values) && mesh.UVs.HasItems())
{
if (mesh.GenerateTangents(data.Options.SmoothingTangentsAngle))
{
@@ -858,7 +858,7 @@ bool ProcessMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
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();
@@ -899,7 +899,7 @@ bool ImportMesh(ModelData& result, OpenFbxImporterData& data, const ofbx::Mesh*
// Import mesh data
MeshData* meshData = New<MeshData>();
if (ProcessMesh(result, data, aMesh, *meshData, errorMsg, triangleStart, triangleEnd))
if (ProcessMesh(result, data, aMesh, *meshData, errorMsg, partitionIndex))
return true;
// Link mesh
@@ -917,35 +917,17 @@ bool ImportMesh(int32 index, ModelData& result, OpenFbxImporterData& data, Strin
{
const auto aMesh = data.Scene->getMesh(index);
const auto aGeometry = aMesh->getGeometry();
const auto trianglesCount = aGeometry->getVertexCount() / 3;
if (IsMeshInvalid(aMesh))
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
if (ImportMesh(result, data, aMesh, errorMsg, 0, trianglesCount - 1))
return true;
}
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;
const auto& partition = geomData.getPartition(i);
if (partition.polygon_count == 0)
continue;
// Start a new range
rangeStart = triangleIndex;
rangeStartVal = materials[triangleIndex];
}
}
if (ImportMesh(result, data, aMesh, errorMsg, rangeStart, trianglesCount - 1))
if (ImportMesh(result, data, aMesh, errorMsg, i))
return true;
}
return false;
@@ -962,24 +944,24 @@ struct AnimInfo
struct Frame
{
ofbx::Vec3 Translation;
ofbx::Vec3 Rotation;
ofbx::Vec3 Scaling;
ofbx::DVec3 Translation;
ofbx::DVec3 Rotation;
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));
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 }));
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
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>
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)
return;
@@ -1008,7 +990,7 @@ void ImportCurve(const ofbx::AnimationCurveNode* curveNode, LinearCurve<T>& curv
key.Time = (float)i;
ofbx::Vec3 trans = curveNode->getNodeLocalTransform(t);
ofbx::DVec3 trans = curveNode->getNodeLocalTransform(t);
ExtractKeyframe(bone, trans, localFrame, key.Value);
}
}
@@ -1125,10 +1107,9 @@ bool ModelTool::ImportDataOpenFBX(const String& path, ModelData& data, Options&
errorMsg = TEXT("Cannot load file.");
return true;
}
ofbx::u64 loadFlags = 0;
ofbx::u16 loadFlags = 0;
if (EnumHasAnyFlags(options.ImportTypes, ImportDataTypes::Geometry))
{
loadFlags |= (ofbx::u64)ofbx::LoadFlags::TRIANGULATE;
if (!options.ImportBlendShapes)
loadFlags |= (ofbx::u64)ofbx::LoadFlags::IGNORE_BLEND_SHAPES;
}

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
View 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 */

File diff suppressed because it is too large Load Diff

View File

@@ -9,10 +9,10 @@ typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
#ifdef _WIN32
typedef long long i64;
typedef unsigned long long u64;
#else
typedef long i64;
typedef long long i64;
typedef unsigned long long u64;
#else
typedef long i64;
typedef unsigned long u64;
#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(i64) == 8, "i64 is not 8 bytes");
typedef decltype(sizeof(0)) usize;
using JobFunction = void (*)(void*);
using JobProcessor = void (*)(JobFunction, void*, void*, u32, u32);
enum class LoadFlags : u64 {
TRIANGULATE = 1 << 0,
// Ignoring certain nodes will only stop them from being processed not tokenised (i.e. they will still be in the tree)
enum class LoadFlags : u16
{
NONE = 0,
UNUSED = 1 << 0, // can be reused
IGNORE_GEOMETRY = 1 << 1,
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,
};
struct Vec2
constexpr LoadFlags operator|(LoadFlags lhs, LoadFlags rhs)
{
double x, y;
};
return static_cast<LoadFlags>(static_cast<u16>(lhs) | static_cast<u16>(rhs));
}
struct Vec3
inline LoadFlags& operator|=(LoadFlags& lhs, LoadFlags rhs)
{
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
{
double x, y, z, w;
};
struct Matrix
{
double m[16]; // last 4 are translation
};
struct Quat
{
double x, y, z, w;
};
struct FVec2 { float x, y; };
struct FVec3 { float x, y, z; };
struct FVec4 { float x, y, z, w; };
struct FMatrix { float m[16]; };
struct FQuat{ float 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
{
@@ -81,9 +106,10 @@ struct DataView
i64 toI64() const;
int toInt() const;
u32 toU32() const;
bool toBool() const;
double toDouble() const;
float toFloat() const;
template <int N>
void toString(char(&out)[N]) const
{
@@ -113,7 +139,8 @@ struct IElementProperty
ARRAY_INT = 'i',
ARRAY_LONG = 'l',
ARRAY_FLOAT = 'f',
BINARY = 'R'
BINARY = 'R',
NONE = ' '
};
virtual ~IElementProperty() {}
virtual Type getType() const = 0;
@@ -168,6 +195,8 @@ struct Object
TEXTURE,
LIMB_NODE,
NULL_NODE,
CAMERA,
LIGHT,
NODE_ATTRIBUTE,
CLUSTER,
SKIN,
@@ -189,22 +218,22 @@ struct Object
Object* resolveObjectLink(int idx) const;
Object* resolveObjectLink(Type type, const char* property, int idx) const;
Object* resolveObjectLinkReverse(Type type) const;
Object* getParent() const;
Object* getParent() const { return parent; }
RotationOrder getRotationOrder() const;
Vec3 getRotationOffset() const;
Vec3 getRotationPivot() const;
Vec3 getPostRotation() const;
Vec3 getScalingOffset() const;
Vec3 getScalingPivot() const;
Vec3 getPreRotation() const;
Vec3 getLocalTranslation() const;
Vec3 getLocalRotation() const;
Vec3 getLocalScaling() const;
Matrix getGlobalTransform() const;
Matrix getLocalTransform() const;
Matrix evalLocal(const Vec3& translation, const Vec3& rotation) const;
Matrix evalLocal(const Vec3& translation, const Vec3& rotation, const Vec3& scaling) const;
DVec3 getRotationOffset() const;
DVec3 getRotationPivot() const;
DVec3 getPostRotation() const;
DVec3 getScalingOffset() const;
DVec3 getScalingPivot() const;
DVec3 getPreRotation() const;
DVec3 getLocalTranslation() const;
DVec3 getLocalRotation() const;
DVec3 getLocalScaling() const;
DMatrix getGlobalTransform() const;
DMatrix getLocalTransform() const;
DMatrix evalLocal(const DVec3& translation, const DVec3& rotation) const;
DMatrix evalLocal(const DVec3& translation, const DVec3& rotation, const DVec3& scaling) const;
bool isNode() const { return is_node; }
@@ -214,11 +243,14 @@ struct Object
}
u64 id;
u32 depth = 0xffFFffFF;
Object* parent = nullptr;
char name[128];
const IElement& element;
const Object* node_attribute;
protected:
friend struct Scene;
bool is_node;
const Scene& scene;
};
@@ -228,7 +260,7 @@ struct Pose : Object {
static const Type s_type = Type::POSE;
Pose(const Scene& _scene, const IElement& _element);
virtual Matrix getMatrix() const = 0;
virtual DMatrix getMatrix() const = 0;
virtual const Object* getNode() const = 0;
};
@@ -255,6 +287,124 @@ struct Texture : Object
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
{
@@ -291,8 +441,8 @@ struct Cluster : Object
virtual int getIndicesCount() const = 0;
virtual const double* getWeights() const = 0;
virtual int getWeightsCount() const = 0;
virtual Matrix getTransformMatrix() const = 0;
virtual Matrix getTransformLinkMatrix() const = 0;
virtual DMatrix getTransformMatrix() const = 0;
virtual DMatrix getTransformLinkMatrix() 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 int s_uvs_max = 4;
Geometry(const Scene& _scene, const IElement& _element);
virtual const Vec3* getVertices() 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 GeometryData& getGeometryData() const = 0;
virtual const Skin* getSkin() 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 int getVertexCount() const = 0;
virtual const int* getIndices() const = 0;
virtual int getIndexCount() const = 0;
virtual const Vec3* getNormals() const = 0;
};
struct Mesh : Object
{
struct Mesh : Object {
static const Type s_type = Type::MESH;
Mesh(const Scene& _scene, const IElement& _element);
virtual const Pose* getPose() 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 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);
virtual DataView getBoneLinkProperty() 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;
};
@@ -449,17 +654,9 @@ struct TakeInfo
// Specifies which canonical axis represents up in the system (typically Y or Z).
enum UpVector
{
UpVector_AxisX = 1,
UpVector_AxisY = 2,
UpVector_AxisZ = 3
};
// Vector with origin at the screen pointing toward the camera.
enum FrontVector
{
FrontVector_ParityEven = 1,
FrontVector_ParityOdd = 2
UpVector_AxisX = 0,
UpVector_AxisY = 1,
UpVector_AxisZ = 2
};
@@ -494,9 +691,11 @@ enum FrameRate
struct GlobalSettings
{
UpVector UpAxis = UpVector_AxisX;
UpVector UpAxis = UpVector_AxisY;
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;
CoordSystem CoordAxis = CoordSystem_RightHanded;
int CoordAxisSign = 1;
@@ -511,41 +710,105 @@ struct GlobalSettings
};
struct GlobalInfo
{
char AppVendor[128];
char AppName[128];
char AppVersion[128];
};
struct IScene
{
virtual void destroy() = 0;
// Root Node
virtual const IElement* getRootElement() const = 0;
virtual const Object* getRoot() const = 0;
virtual const TakeInfo* getTakeInfo(const char* name) const = 0;
// Meshes
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;
// Geometry
virtual int getGeometryCount() const = 0;
virtual const Geometry* getGeometry(int index) const = 0;
// Animations
virtual int getAnimationStackCount() 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 int getAllObjectCount() const = 0;
// Embedded files/Data
virtual int getEmbeddedDataCount() const = 0;
virtual DataView getEmbeddedData(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() {}
};
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();
double fbxTimeToSeconds(i64 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
#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