diff --git a/README.md b/README.md index 386d72415..80917fd48 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,9 @@ glTF parsers, it does not automatically load textures and external buffers to al optimise to their liking. It does, however, load embedded data and also decodes base64 encoded buffers using high speed SIMD algorithms. +fastgltf also provides a C99 API header which includes all the features of the C++ API so that you +can use fastgltf with virtually any language you want. + By utilising simdjson, this library can take advantage of SSE4, AVX2, AVX512, and ARM Neon. ## Features @@ -42,6 +45,8 @@ the CMake script. The library is tested on GCC 9, GCC 10, Clang 12, and MSVC 14 using CI. The project uses a simple CMake 3.11, and can be simply used by adding fastgltf as a subdirectory. Also, fastgltf is available from [vcpkg](https://github.com/microsoft/vcpkg). +### C++ API + ```cpp #include #include @@ -86,6 +91,41 @@ All the nodes, meshes, buffers, textures, ... can now be accessed through the `f type. References in between objects are done with a single `size_t`, which is used to index into the various vectors in the asset. +### C99 API + +```c +#include + +void load(const char* path, const char* directory) { + // Creates a parser object + fastgltf_parser* parser = fastgltf_create_parser(0); + + fastgltf_gltf_data_buffer* data = fastgltf_create_gltf_data_buffer_from_path(path); + + // For GLB files, use fastgltf_load_binary_gltf + fastgltf_gltf* gltf = fastgltf_load_gltf(parser, data, directory, OptionsDontRequireValidAssetMember); + if (fastgltf_get_parser_error(parser) != ErrorNone) { + // error + } + + // Tell fastgltf to parse the whole glTF structure. Optionally, you can parse individual + // aspects of glTF files by calling the various parse methods. + fastgltf_parse_all(gltf); + + // You can now destroy the parser and JSON data. It is advised, however, to reuse parsers. + fastgltf_destroy_gltf_data_buffer(data); + fastgltf_destroy_parser(parser); + + // You can now query the parsed asset and destroy the glTF object. + fastgltf_asset* asset = fastgltf_get_parsed_asset(gltf); + fastgltf_destroy_gltf(gltf); + + // Use the parsed asset here. + + fastgltf_destroy_asset(asset); +} +``` + ## Performance [spreadsheet-link]: https://docs.google.com/spreadsheets/d/1ocdHGoty-rF0N46ZlAlswzcPHVRsqG_tncy8paD3iMY/edit?usp=sharing diff --git a/cmake/compiler_flags.cmake b/cmake/compiler_flags.cmake index a4c675ce5..87b1512aa 100644 --- a/cmake/compiler_flags.cmake +++ b/cmake/compiler_flags.cmake @@ -9,7 +9,13 @@ macro(compiler_flags) # cpuid, meaning no architecture flags or other compile flags need to be passed. # See https://github.com/simdjson/simdjson/blob/master/doc/implementation-selection.md. if (MSVC) - target_compile_options(${PARAM_TARGET} PRIVATE /EHsc $<$:/O2 /Ob3 /Ot>) + target_compile_options(${PARAM_TARGET} PRIVATE /EHsc $<$:/O2>) + if (MSVC_VERSION GREATER_EQUAL 1920) + # With VS 16 (2019) /Ob3 was added to more aggressively inline functions. + target_compile_options(${PARAM_TARGET} PRIVATE $<$:/Ob3>) + else() + target_compile_options(${PARAM_TARGET} PRIVATE $<$:/Ob2>) + endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU") target_compile_options(${PARAM_TARGET} PRIVATE $<$:-O3>) endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a077fb901..bcd7efd88 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,10 +1,11 @@ add_library(fastgltf "fastgltf.cpp" "fastgltf_util.hpp" "fastgltf_types.hpp" "fastgltf_parser.hpp" - "base64_decode.cpp" "base64_decode.hpp") + "base64_decode.cpp" "base64_decode.hpp" + "fastgltf_c.cpp" "fastgltf_c.h") add_library(fastgltf::fastgltf ALIAS fastgltf) target_include_directories(fastgltf PUBLIC $ $) -target_compile_features(fastgltf PUBLIC cxx_std_17) +target_compile_features(fastgltf PUBLIC cxx_std_17 c_std_99) compiler_flags(TARGET fastgltf) enable_debug_inlining(TARGET fastgltf_simdjson) @@ -23,7 +24,7 @@ endif() target_compile_definitions(fastgltf PRIVATE "FASTGLTF_USE_CUSTOM_SMALLVECTOR=$") install( - FILES "base64_decode.hpp" "fastgltf_parser.hpp" "fastgltf_types.hpp" "fastgltf_util.hpp" + FILES "base64_decode.hpp" "fastgltf_parser.hpp" "fastgltf_types.hpp" "fastgltf_util.hpp" "fastgltf_c.h" TYPE INCLUDE ) diff --git a/src/fastgltf.cpp b/src/fastgltf.cpp index d0e922267..7e2cc0017 100644 --- a/src/fastgltf.cpp +++ b/src/fastgltf.cpp @@ -28,11 +28,8 @@ #error "fastgltf requires C++17" #endif -#include -#include #include #include -#include #ifdef _MSC_VER #pragma warning(push) @@ -283,20 +280,22 @@ std::pair fg::glTF::decodeUri(std::string_view uri) c } fg::MimeType fg::glTF::getMimeTypeFromString(std::string_view mime) { - if (mime == mimeTypeJpeg) { - return MimeType::JPEG; - } else if (mime == mimeTypePng) { - return MimeType::PNG; - } else if (mime == mimeTypeKtx) { - return MimeType::KTX2; - } else if (mime == mimeTypeDds) { - return MimeType::DDS; - } else if (mime == mimeTypeGltfBuffer) { - return MimeType::GltfBuffer; - } else if (mime == mimeTypeOctetStream) { - return MimeType::OctetStream; - } else { - return MimeType::None; + auto hash = crc32(mime); + switch (hash) { + case force_consteval: + return MimeType::JPEG; + case force_consteval: + return MimeType::PNG; + case force_consteval: + return MimeType::KTX2; + case force_consteval: + return MimeType::DDS; + case force_consteval: + return MimeType::GltfBuffer; + case force_consteval: + return MimeType::OctetStream; + default: + return MimeType::None; } } @@ -2147,7 +2146,7 @@ std::unique_ptr fg::Parser::loadGLTF(GltfDataBuffer* buffer, fs::path data->decodeCallback = decodeCallback; data->userPointer = userPointer; - return std::unique_ptr(new glTF(std::move(data), std::move(directory), options, extensions)); + return std::unique_ptr(new (std::nothrow) glTF(std::move(data), std::move(directory), options, extensions)); } std::unique_ptr fg::Parser::loadBinaryGLTF(GltfDataBuffer* buffer, fs::path directory, Options options) { @@ -2203,7 +2202,7 @@ std::unique_ptr fg::Parser::loadBinaryGLTF(GltfDataBuffer* buffer, fs: data->decodeCallback = decodeCallback; data->userPointer = userPointer; - auto gltf = std::unique_ptr(new glTF(std::move(data), std::move(directory), options, extensions)); + auto gltf = std::unique_ptr(new (std::nothrow) glTF(std::move(data), std::move(directory), options, extensions)); // Is there enough room for another chunk header? if (header.length > (offset + sizeof(BinaryGltfChunk))) { diff --git a/src/fastgltf_c.cpp b/src/fastgltf_c.cpp new file mode 100644 index 000000000..9ffaf9312 --- /dev/null +++ b/src/fastgltf_c.cpp @@ -0,0 +1,171 @@ +#include + +#include + +#include +#include + +// Some checks to ensure some conversions are correct. +static_assert(DataSourceCount == std::variant_size_v, + "fastgltf_data_source does not properly reflect the fastgltf::DataSource variant."); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); +static_assert(std::is_same_v>); + +fastgltf_component_type fastgltf_get_component_type(unsigned int componentType) { + return static_cast(fastgltf::getComponentType( + static_cast>(componentType))); +} + +fastgltf_accessor_type fastgltf_get_accessor_type(const char* string) { + return static_cast(fastgltf::getAccessorType(std::string_view { string })); +} + +fastgltf_parser* fastgltf_create_parser(fastgltf_extensions extensions) { + return reinterpret_cast( + new (std::nothrow) fastgltf::Parser(static_cast(extensions))); +} + +void fastgltf_destroy_parser(fastgltf_parser* parser) { + delete reinterpret_cast(parser); +} + +fastgltf_gltf_data_buffer* fastgltf_create_gltf_data_buffer(unsigned char* bytes, size_t size) { + auto data = new (std::nothrow) fastgltf::GltfDataBuffer(); + data->copyBytes(bytes, size); + return reinterpret_cast(data); +} + +fastgltf_gltf_data_buffer* fastgltf_create_gltf_data_buffer_from_path(const char* file) { + auto data = new (std::nothrow) fastgltf::GltfDataBuffer(); + data->loadFromFile(std::string_view { file }); + return reinterpret_cast(data); +} + +fastgltf_gltf_data_buffer* fastgltf_create_gltf_data_buffer_from_wpath(const wchar_t* file) { + auto data = new (std::nothrow) fastgltf::GltfDataBuffer(); + data->loadFromFile(std::wstring_view { file }); + return reinterpret_cast(data); +} + +void fastgltf_destroy_gltf_data_buffer(fastgltf_gltf_data_buffer* data) { + delete reinterpret_cast(data); +} + +fastgltf_error fastgltf_get_parser_error(fastgltf_parser* parser) { + return static_cast( + reinterpret_cast(parser)->getError()); +} + +fastgltf_gltf* fastgltf_load_gltf(fastgltf_parser* parser, fastgltf_gltf_data_buffer* json, const char* directory, fastgltf_options options) { + auto gltf = reinterpret_cast(parser)->loadGLTF( + reinterpret_cast(json), std::string_view { directory }, static_cast(options)); + return reinterpret_cast(gltf.release()); +} + +fastgltf_gltf* fastgltf_load_binary_gltf(fastgltf_parser* parser, fastgltf_gltf_data_buffer* data, const char* directory, fastgltf_options options) { + auto gltf = reinterpret_cast(parser)->loadBinaryGLTF( + reinterpret_cast(data), std::string_view { directory }, static_cast(options)); + return reinterpret_cast(gltf.release()); +} + +fastgltf_gltf* fastgltf_load_gltf_w(fastgltf_parser* parser, fastgltf_gltf_data_buffer* json, const wchar_t* directory, fastgltf_options options) { + auto gltf = reinterpret_cast(parser)->loadGLTF( + reinterpret_cast(json), std::wstring_view { directory }, static_cast(options)); + return reinterpret_cast(gltf.release()); +} + +fastgltf_gltf* fastgltf_load_binary_gltf_w(fastgltf_parser* parser, fastgltf_gltf_data_buffer* data, const wchar_t* directory, fastgltf_options options) { + auto gltf = reinterpret_cast(parser)->loadBinaryGLTF( + reinterpret_cast(data), std::wstring_view { directory }, static_cast(options)); + return reinterpret_cast(gltf.release()); +} + +void fastgltf_destroy_gltf(fastgltf_gltf* gltf) { + delete reinterpret_cast(gltf); +} + +fastgltf_error fastgltf_parse_all(fastgltf_gltf* gltf) { + return static_cast( + reinterpret_cast(gltf)->parse()); +} + +fastgltf_error fastgltf_parse(fastgltf_gltf* gltf, fastgltf_category categories) { + return static_cast( + reinterpret_cast(gltf)->parse(static_cast(categories))); +} + +fastgltf_asset* fastgltf_get_parsed_asset(fastgltf_gltf* gltf) { + // Obtain the unique_ptr from the glTF and release it. Otherwise, it gets destroyed with the + // destructor of fastgltf::glTF. + auto asset = reinterpret_cast(gltf)->getParsedAsset(); + return reinterpret_cast(asset.release()); +} + +void fastgltf_destroy_asset(fastgltf_asset* asset) { + delete reinterpret_cast(asset); +} + +size_t fastgltf_get_buffer_count(fastgltf_asset* casset) { + auto* asset = reinterpret_cast(casset); + return asset->buffers.size(); +} + +fastgltf_buffer* fastgltf_get_buffer(fastgltf_asset* casset, size_t index) { + auto* asset = reinterpret_cast(casset); + assert(index <= asset->buffers.size()); + return reinterpret_cast(&asset->buffers.at(index)); +} + +size_t fastgltf_get_buffer_length(fastgltf_buffer* buffer) { + return reinterpret_cast(buffer)->byteLength; +} + +fastgltf_data_source fastgltf_get_buffer_data_source_type(fastgltf_buffer* buffer) { + return static_cast( + reinterpret_cast(buffer)->data.index()); +} + +MimeType fastgltf_get_buffer_data_mime(fastgltf_buffer* buffer) { + return std::visit([](auto& arg) { + using namespace fastgltf::sources; + using T = std::decay_t; + if constexpr (fastgltf::is_any()) { + return static_cast<::MimeType>(arg.mimeType); + } else { + return MimeTypeNone; + } + }, reinterpret_cast(buffer)->data); +} + +void fastgltf_buffer_data_get_buffer_view(fastgltf_buffer* buffer, size_t* bufferView) { + auto* v = std::get_if( + &reinterpret_cast(buffer)->data); + assert(v != nullptr); + *bufferView = v->bufferViewIndex; +} + +void fastgltf_buffer_data_get_file_path(fastgltf_buffer* buffer, size_t* offset, const wchar_t** path) { + auto* v = std::get_if( + &reinterpret_cast(buffer)->data); + assert(v != nullptr); + *path = v->path.c_str(); + *offset = v->fileByteOffset; +} + +void fastgltf_buffer_data_get_vector(fastgltf_buffer* buffer, size_t* size, uint8_t** data) { + auto* v = std::get_if( + &reinterpret_cast(buffer)->data); + assert(v != nullptr); + *data = v->bytes.data(); + *size = v->bytes.size(); +} + +fastgltf_custom_buffer fastgltf_buffer_data_get_custom_buffer(fastgltf_buffer* buffer) { + auto* v = std::get_if( + &reinterpret_cast(buffer)->data); + assert(v != nullptr); + return static_cast(v->id); +} diff --git a/src/fastgltf_c.h b/src/fastgltf_c.h new file mode 100644 index 000000000..ede549b4f --- /dev/null +++ b/src/fastgltf_c.h @@ -0,0 +1,278 @@ +#ifndef FASTGLTF_C_H +#define FASTGLTF_C_H + +#ifdef __cplusplus +#include +#include +#else +#include +#include +#endif + +enum fastgltf_extensions { + KHR_texture_transform = 1 << 1, + KHR_texture_basisu = 1 << 2, + MSFT_texture_dds = 1 << 3, + KHR_mesh_quantization = 1 << 4, + EXT_meshopt_compression = 1 << 5, + KHR_lights_punctual = 1 << 6, + EXT_mesh_gpu_instancing = 1 << 7, + EXT_texture_webp = 1 << 8, +}; + +enum fastgltf_options { + OptionsAllowDouble = 1 << 0, + OptionsDontRequireValidAssetMember = 1 << 1, + OptionsLoadGLBBuffers = 1 << 3, + OptionsLoadExternalBuffers = 1 << 4, + OptionsDecomposeNodeMatrices = 1 << 5, + OptionsMinimiseJsonBeforeParsing = 1 << 6, +}; + +enum fastgltf_error { + ErrorNone = 0, + ErrorInvalidPath = 1, + ErrorMissingExtensions = 2, + ErrorUnsupportedExtensions = 3, + ErrorInvalidJson = 4, + ErrorInvalidGltf = 5, + ErrorInvalidOrMissingAssetField = 6, + ErrorInvalidGLB = 6, + ErrorMissingField = 7, + ErrorMissingExternalBuffer = 8, + ErrorUnsupportedVersion = 9, +}; + +enum fastgltf_category { + CategoryNone = 0, + + CategoryBuffers = 1 << 0, + CategoryBufferViews = 1 << 1 | CategoryBuffers, + CategoryAccessors = 1 << 2 | CategoryBufferViews, + CategoryImages = 1 << 3 | CategoryBufferViews, + CategorySamplers = 1 << 4, + CategoryTextures = 1 << 5 | CategoryImages | CategorySamplers, + CategoryAnimations = 1 << 6 | CategoryAccessors, + CategoryCameras = 1 << 7, + CategoryMaterials = 1 << 8 | CategoryTextures, + CategoryMeshes = 1 << 9 | CategoryAccessors | CategoryMaterials, + CategorySkins = 1 << 10 | CategoryAccessors | (1 << 11), + CategoryNodes = 1 << 11 | CategoryCameras | CategoryMeshes | CategorySkins, + CategoryScenes = 1 << 12 | CategoryNodes, + CategoryAsset = 1 << 13, + + CategoryAll = CategoryAsset | CategoryScenes | CategoryAnimations, +}; + +// These indices here correlate to the index of the corresponding type in the std::variant +// declaration of fastgltf::DataSource. These need to be updated accordingly. +enum fastgltf_data_source { + DataSourceNone = 0, + DataSourceBufferView = 1, + DataSourceFilePath = 2, + DataSourceVector = 3, + DataSourceCustomBuffer = 4, + + DataSourceCount = 5, +}; + +enum fastgltf_primitive_type { + PrimitiveTypePoints = 0, + PrimitiveTypeLines = 1, + PrimitiveTypeLineLoop = 2, + PrimitiveTypeLineStrip = 3, + PrimitiveTypeTriangles = 4, + PrimitiveTypeTriangleStrip = 5, + PrimitiveTypeTriangleFan = 6, +}; + +enum fastgltf_accessor_type { + AccessorTypeInvalid = 0, + AccessorTypeScalar = (1 << 8) | 1, + AccessorTypeVec2 = (2 << 8) | 2, + AccessorTypeVec3 = (3 << 8) | 3, + AccessorTypeVec4 = ( 4 << 8) | 4, + AccessorTypeMat2 = ( 4 << 8) | 5, + AccessorTypeMat3 = ( 9 << 8) | 6, + AccessorTypeMat4 = (16 << 8) | 7, +}; + +enum fastgltf_component_type { + ComponentTypeInvalid = 0, + ComponentTypeByte = ( 8 << 16) | 5120, + ComponentTypeUnsignedByte = ( 8 << 16) | 5121, + ComponentTypeShort = (16 << 16) | 5122, + ComponentTypeUnsignedShort = (16 << 16) | 5123, + ComponentTypeUnsignedInt = (32 << 16) | 5125, + ComponentTypeFloat = (32 << 16) | 5126, + ComponentTypeDouble = (64 << 16) | 5130, +}; + +enum fastgltf_filter { + FilterNearest = 9728, + FilterLinear = 9729, + FilterNearestMipMapNearest = 9984, + FilterLinearMipMapNearest = 9985, + FilterNearestMipMapLinear = 9986, + FilterLinearMipMapLinear = 9987, +}; + +enum fastgltf_wrap { + WrapClampToEdge = 33071, + WrapMirroredRepeat = 33648, + WrapRepeat = 10497, +}; + +enum BufferTarget { + BufferTargetArrayBuffer = 34962, + BufferTargetElementArrayBuffer = 34963, +}; + +enum MimeType { + MimeTypeNone = 0, + MimeTypeJPEG = 1, + MimeTypePNG = 2, + MimeTypeKTX2 = 3, + MimeTypeDDS = 4, + MimeTypeGltfBuffer = 5, + MimeTypeOctetStream = 6, +}; + +enum AnimationInterpolation { + AnimationInterpolationLinear = 0, + AnimationInterpolationStep = 1, + AnimationInterpolationCubicSpline = 2, +}; + +enum AnimationPath { + AnimationPathTranslation = 1, + AnimationPathRotation = 2, + AnimationPathScale = 3, + AnimationPathWeights = 4, +}; + +enum CameraType { + CameraTypePerspective = 0, + CameraTypeOrthographic = 1, +}; + +enum AlphaMode { + AlphaModeOpaque = 0, + AlphaModeMask = 1, + AlphaModeBlend = 2, +}; + +enum MeshoptCompressionMode { + MeshoptCompressionModeNone = 0, + MeshoptCompressionModeAttributes = 1, + MeshoptCompressionModeTriangles = 2, + MeshoptCompressionModeIndices = 3, +}; + +enum MeshoptCompressionFilter { + MeshoptCompressionFilterNone = 0, + MeshoptCompressionFilterOctahedral = 1, + MeshoptCompressionFilterQuaternion = 2, + MeshoptCompressionFilterExponential = 3, +}; + +enum LighType { + LighTypeDirectional = 0, + LighTypeSpot = 1, + LighTypePoint = 2, +}; + +inline unsigned int getNumComponents(fastgltf_accessor_type type) { + return (type >> 8) & 0xFF; +} + +inline unsigned int getComponentBitSize(fastgltf_component_type type) { + return (type & 0xFFFF0000) >> 16; +} + +inline unsigned int getElementByteSize(fastgltf_accessor_type type, fastgltf_component_type componentType) { + return getNumComponents(type) * (getComponentBitSize(componentType) / 8); +} + +inline unsigned int getGLComponentType(fastgltf_component_type type) { + return type & 0xFFFF; +} + +#define FASTGLTF_EXPORT + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct fastgltf_parser_s fastgltf_parser; +typedef struct fastgltf_gltf_data_buffer_s fastgltf_gltf_data_buffer; +typedef struct fastgltf_gltf_s fastgltf_gltf; +typedef struct fastgltf_asset_s fastgltf_asset; + +typedef uint64_t fastgltf_custom_buffer; + +typedef struct fastgltf_accessor_s fastgltf_accessor; +typedef struct fastgltf_animation_s fastgltf_animation; +typedef struct fastgltf_buffer_s fastgltf_buffer; +typedef struct fastgltf_buffer_view_s fastgltf_buffer_view; +typedef struct fastgltf_camera_s fastgltf_camera; +typedef struct fastgltf_image_s fastgltf_image; +typedef struct fastgltf_light_s fastgltf_light; +typedef struct fastgltf_material_s fastgltf_material; +typedef struct fastgltf_mesh_s fastgltf_mesh; +typedef struct fastgltf_node_s fastgltf_node; +typedef struct fastgltf_sampler_s fastgltf_sampler; +typedef struct fastgltf_scene_s fastgltf_scene; +typedef struct fastgltf_skin_s fastgltf_skin; +typedef struct fastgltf_texture_s fastgltf_texture; + +struct fastgltf_array { + void* data; + size_t size; +}; + +FASTGLTF_EXPORT fastgltf_component_type fastgltf_get_component_type(unsigned int componentType); +FASTGLTF_EXPORT fastgltf_accessor_type fastgltf_get_accessor_type(const char* string); + +FASTGLTF_EXPORT fastgltf_parser* fastgltf_create_parser(fastgltf_extensions extensions); +FASTGLTF_EXPORT void fastgltf_destroy_parser(fastgltf_parser* parser); + +FASTGLTF_EXPORT fastgltf_gltf_data_buffer_s* fastgltf_create_gltf_data_buffer(unsigned char* bytes, size_t size); +FASTGLTF_EXPORT fastgltf_gltf_data_buffer_s* fastgltf_create_gltf_data_buffer_from_path(const char* filePath); +FASTGLTF_EXPORT fastgltf_gltf_data_buffer_s* fastgltf_create_gltf_data_buffer_from_wpath(const wchar_t* filePath); +FASTGLTF_EXPORT void fastgltf_destroy_gltf_data_buffer(fastgltf_gltf_data_buffer* data); + +FASTGLTF_EXPORT fastgltf_error fastgltf_get_parser_error(fastgltf_parser* parser); +FASTGLTF_EXPORT fastgltf_gltf* fastgltf_load_gltf(fastgltf_parser* parser, fastgltf_gltf_data_buffer* json, const char* directory, fastgltf_options options); +FASTGLTF_EXPORT fastgltf_gltf* fastgltf_load_binary_gltf(fastgltf_parser* parser, fastgltf_gltf_data_buffer* data, const char* directory, fastgltf_options options); +FASTGLTF_EXPORT fastgltf_gltf* fastgltf_load_gltf_w(fastgltf_parser* parser, fastgltf_gltf_data_buffer* json, const wchar_t* directory, fastgltf_options options); +FASTGLTF_EXPORT fastgltf_gltf* fastgltf_load_binary_gltf_w(fastgltf_parser* parser, fastgltf_gltf_data_buffer* data, const wchar_t* directory, fastgltf_options options); +FASTGLTF_EXPORT void fastgltf_destroy_gltf(fastgltf_gltf* gltf); + +FASTGLTF_EXPORT fastgltf_error fastgltf_parse_all(fastgltf_gltf* gltf); +FASTGLTF_EXPORT fastgltf_error fastgltf_parse(fastgltf_gltf* gltf, fastgltf_category categories); + +FASTGLTF_EXPORT fastgltf_asset* fastgltf_get_parsed_asset(fastgltf_gltf* gltf); +FASTGLTF_EXPORT void fastgltf_destroy_asset(fastgltf_asset* asset); + +FASTGLTF_EXPORT size_t fastgltf_get_buffer_count(fastgltf_asset* asset); +FASTGLTF_EXPORT fastgltf_buffer* fastgltf_get_buffer(fastgltf_asset* asset, size_t index); +FASTGLTF_EXPORT size_t fastgltf_get_buffer_length(fastgltf_buffer* buffer); +FASTGLTF_EXPORT fastgltf_data_source fastgltf_get_buffer_data_source_type(fastgltf_buffer* buffer); +FASTGLTF_EXPORT MimeType fastgltf_get_buffer_data_mime(fastgltf_buffer* buffer); +// Only call this when fastgltf_get_buffer_data_source_type returned DataSourceBufferView. +FASTGLTF_EXPORT void fastgltf_buffer_data_get_buffer_view(fastgltf_buffer* buffer, size_t* bufferView); +// Only call this when fastgltf_get_buffer_data_source_type returned DataSourceFilePath +FASTGLTF_EXPORT void fastgltf_buffer_data_get_file_path(fastgltf_buffer* buffer, size_t* offset, const wchar_t** path); +// Only call this when fastgltf_get_buffer_data_source_type returned DataSourceBufferVector. +FASTGLTF_EXPORT void fastgltf_buffer_data_get_vector(fastgltf_buffer* buffer, size_t* size, uint8_t** data); +// Only call this when fastgltf_get_buffer_data_source_type returned DataSourceCustomBuffer. +FASTGLTF_EXPORT fastgltf_custom_buffer fastgltf_buffer_data_get_custom_buffer(fastgltf_buffer* buffer); + +#ifdef __cplusplus +} +#endif + +#undef FASTGLTF_EXPORT + +#endif diff --git a/src/fastgltf_parser.hpp b/src/fastgltf_parser.hpp index 47c9a85f0..e0c9a266f 100644 --- a/src/fastgltf_parser.hpp +++ b/src/fastgltf_parser.hpp @@ -26,13 +26,8 @@ #pragma once -#include #include -#include -#include #include -#include -#include #include "fastgltf_types.hpp" #include "fastgltf_util.hpp" diff --git a/src/fastgltf_types.hpp b/src/fastgltf_types.hpp index 164c4b8a7..7fd7deaa1 100644 --- a/src/fastgltf_types.hpp +++ b/src/fastgltf_types.hpp @@ -26,11 +26,12 @@ #pragma once -#include #include #include #include #include +#include +#include #include #include #include @@ -183,29 +184,29 @@ namespace fastgltf { }; enum class AlphaMode : uint8_t { - Opaque, - Mask, - Blend, + Opaque = 0, + Mask = 1, + Blend = 2, }; enum class MeshoptCompressionMode : uint8_t { None = 0, - Attributes, - Triangles, - Indices, + Attributes = 1, + Triangles = 2, + Indices = 3, }; enum class MeshoptCompressionFilter : uint8_t { None = 0, - Octahedral, - Quaternion, - Exponential, + Octahedral = 1, + Quaternion = 2, + Exponential = 3, }; enum class LightType : uint8_t { - Directional, - Spot, - Point, + Directional = 0, + Spot = 1, + Point = 2, }; // clang-format on #pragma endregion @@ -216,13 +217,11 @@ namespace fastgltf { * a Vec3 accessor type this will return 3, as a Vec3 contains 3 components. */ constexpr uint32_t getNumComponents(AccessorType type) noexcept { - return static_cast( - (static_cast())>(type) >> 8) & 0xFF); + return static_cast((to_underlying(type) >> 8) & 0xFF); } constexpr uint32_t getComponentBitSize(ComponentType componentType) noexcept { - auto masked = - static_cast())>(componentType) & 0xFFFF0000; + auto masked = to_underlying(componentType) & 0xFFFF0000; return (masked >> 16); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8715e1010..be1052c1e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,7 +1,8 @@ set_directory_properties(PROPERTIES EXCLUDE_FROM_ALL TRUE) # We want these tests to be a optional executable. -add_executable(fastgltf_tests EXCLUDE_FROM_ALL "base64_tests.cpp" "basic_test.cpp" "benchmarks.cpp" "glb_tests.cpp" "gltf_path.hpp" "vector_tests.cpp") +add_executable(fastgltf_tests EXCLUDE_FROM_ALL + "base64_tests.cpp" "basic_test.cpp" "benchmarks.cpp" "glb_tests.cpp" "gltf_path.hpp" "vector_tests.cpp" "c_api_test.cpp") target_compile_features(fastgltf_tests PRIVATE cxx_std_20) target_link_libraries(fastgltf_tests PRIVATE fastgltf fastgltf_simdjson) if (TARGET glm::glm) diff --git a/tests/c_api_test.cpp b/tests/c_api_test.cpp new file mode 100644 index 000000000..92f29a2f8 --- /dev/null +++ b/tests/c_api_test.cpp @@ -0,0 +1,37 @@ +#include + +#include +#include "gltf_path.hpp" + +TEST_CASE("Test basic C API", "[gltf-loader]") { + auto cubeFolder = sampleModels / "2.0" / "Cube" / "glTF"; + auto cubePath = cubeFolder / "Cube.gltf"; + + fastgltf_parser* parser = fastgltf_create_parser((fastgltf_extensions)0); + fastgltf_gltf_data_buffer* data = fastgltf_create_gltf_data_buffer_from_wpath(cubePath.c_str()); + + fastgltf_gltf* gltf = fastgltf_load_gltf_w(parser, data, cubeFolder.c_str(), OptionsDontRequireValidAssetMember); + REQUIRE(fastgltf_get_parser_error(parser) == ErrorNone); + REQUIRE(fastgltf_parse_all(gltf) == ErrorNone); + + fastgltf_destroy_parser(parser); + fastgltf_destroy_gltf_data_buffer(data); + + fastgltf_asset* asset = fastgltf_get_parsed_asset(gltf); + REQUIRE(asset != nullptr); + fastgltf_destroy_gltf(gltf); + + auto bufferCount = fastgltf_get_buffer_count(asset); + REQUIRE(bufferCount == 1); + auto* buffer = fastgltf_get_buffer(asset, 0); + REQUIRE(fastgltf_get_buffer_length(buffer) == 1800); + auto sourceType = fastgltf_get_buffer_data_source_type(buffer); + REQUIRE(sourceType == DataSourceFilePath); + const wchar_t* bufferPath; + size_t offset; + fastgltf_buffer_data_get_file_path(buffer, &offset, &bufferPath); + REQUIRE(offset == 0); + REQUIRE(std::filesystem::exists(bufferPath)); + + fastgltf_destroy_asset(asset); +}