Move from tinygltf to tiniergltf (#13)

* Remove tinygltf

* Integrate tiniergltf

* Update build.yml to include jsoncpp

* Namespace target

* Undo noexcept removal, readd move constructor

* Remove debug throw

* Remove now obsolete build code

* Bump CMake minimum version to 3.12

* Fix oops

* Remove unnecessary install/export

* Remove tinygltf from Config.cmake.in

* Take inspiration from Minetest's FindJson.cmake

* Move tiniergltf to separate repo

* CI: Install git

* Bump tiniergltf version (obtain jsoncpp via FetchContent)

* Remove jsoncpp from build dependency list
This commit is contained in:
Lars Müller 2024-01-19 15:52:20 +01:00 committed by Josiah VanderZee
parent 777ec9d130
commit 0faf1320c5
10 changed files with 109 additions and 34867 deletions

View File

@ -42,9 +42,15 @@ endif()
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
enable_testing()
add_subdirectory(src)
add_subdirectory(src/lib/catch2)
add_subdirectory(src/lib/tinygltf)
add_subdirectory(source/lib/catch2)
include(FetchContent)
FetchContent_Declare(
tiniergltf
GIT_REPOSITORY https://github.com/appgurueu/tiniergltf.git
GIT_TAG 05572e691ecf8bc3fce2da76251e73779b3577e6
)
FetchContent_MakeAvailable(tiniergltf)
add_subdirectory(source/Irrlicht)
add_subdirectory(test)
option(BUILD_EXAMPLES "Build example applications" FALSE)

View File

@ -2,9 +2,6 @@
include(CMakeFindDependencyMacro)
find_package(tinygltf 2.6 REQUIRED
PATHS "${CMAKE_CURRENT_LIST_DIR}"
if(NOT TARGET IrrlichtMt::IrrlichtMt)
# private dependency only explicitly needed with static libs
if(@USE_SDL2@ AND NOT @BUILD_SHARED_LIBS@)

View File

@ -12,15 +12,14 @@
#include "SColor.h"
#include "SMesh.h"
#include "vector3d.h"
#define TINYGLTF_IMPLEMENTATION
#include <tiny_gltf.h>
#include <cstddef>
#include <cstring>
#include <memory>
#include <optional>
#include <stdexcept>
#include <string>
#include <utility>
#include <variant>
#include <vector>
/* Notes on the coordinate system.
@ -81,13 +80,23 @@ bool CGLTFMeshFileLoader::isALoadableFileExtension(
*/
IAnimatedMesh* CGLTFMeshFileLoader::createMesh(io::IReadFile* file)
{
tinygltf::Model model {};
if (file->getSize() <= 0 || !tryParseGLTF(file, model)) {
if (file->getSize() <= 0) {
return nullptr;
}
std::optional<tiniergltf::GlTF> model = tryParseGLTF(file);
if (!model.has_value()) {
return nullptr;
}
MeshExtractor parser(std::move(model));
if (!(model->buffers.has_value()
&& model->bufferViews.has_value()
&& model->accessors.has_value()
&& model->meshes.has_value()
&& model->nodes.has_value())) {
return nullptr;
}
MeshExtractor parser(std::move(model.value()));
SMesh* baseMesh(new SMesh {});
loadPrimitives(parser, baseMesh);
@ -123,13 +132,13 @@ void CGLTFMeshFileLoader::loadPrimitives(
}
CGLTFMeshFileLoader::MeshExtractor::MeshExtractor(
const tinygltf::Model& model) noexcept
const tiniergltf::GlTF& model) noexcept
: m_model(model)
{
}
CGLTFMeshFileLoader::MeshExtractor::MeshExtractor(
const tinygltf::Model&& model) noexcept
const tiniergltf::GlTF&& model) noexcept
: m_model(model)
{
}
@ -141,11 +150,14 @@ std::vector<u16> CGLTFMeshFileLoader::MeshExtractor::getIndices(
const std::size_t meshIdx,
const std::size_t primitiveIdx) const
{
// FIXME this need not exist. What do we do if it doesn't?
const auto accessorIdx = getIndicesAccessorIdx(meshIdx, primitiveIdx);
const auto& buf = getBuffer(accessorIdx);
const auto& buf = getBuffer(accessorIdx.value());
// FIXME check accessor type (which could also be u8 or u32).
std::vector<u16> indices{};
const auto count = getElemCount(accessorIdx);
const auto count = getElemCount(accessorIdx.value());
for (std::size_t i = 0; i < count; ++i) {
std::size_t elemIdx = count - i - 1;
indices.push_back(readPrimitive<u16>(
@ -170,14 +182,14 @@ std::vector<video::S3DVertex> CGLTFMeshFileLoader::MeshExtractor::getVertices(
const auto normalAccessorIdx = getNormalAccessorIdx(
meshIdx, primitiveIdx);
if (normalAccessorIdx != static_cast<std::size_t>(-1)) {
copyNormals(normalAccessorIdx, vertices);
if (normalAccessorIdx.has_value()) {
copyNormals(normalAccessorIdx.value(), vertices);
}
const auto tCoordAccessorIdx = getTCoordAccessorIdx(
meshIdx, primitiveIdx);
if (tCoordAccessorIdx != static_cast<std::size_t>(-1)) {
copyTCoords(tCoordAccessorIdx, vertices);
if (tCoordAccessorIdx.has_value()) {
copyTCoords(tCoordAccessorIdx.value(), vertices);
}
return vertices;
@ -188,7 +200,7 @@ std::vector<video::S3DVertex> CGLTFMeshFileLoader::MeshExtractor::getVertices(
*/
std::size_t CGLTFMeshFileLoader::MeshExtractor::getMeshCount() const
{
return m_model.meshes.size();
return m_model.meshes->size();
}
/**
@ -197,7 +209,7 @@ std::size_t CGLTFMeshFileLoader::MeshExtractor::getMeshCount() const
std::size_t CGLTFMeshFileLoader::MeshExtractor::getPrimitiveCount(
const std::size_t meshIdx) const
{
return m_model.meshes[meshIdx].primitives.size();
return m_model.meshes->at(meshIdx).primitives.size();
}
/**
@ -314,10 +326,15 @@ void CGLTFMeshFileLoader::MeshExtractor::copyTCoords(
core::vector3df CGLTFMeshFileLoader::MeshExtractor::getScale() const
{
core::vector3df buffer{1.0f,1.0f,1.0f};
if (m_model.nodes[0].scale.size() == 3) {
buffer.X = static_cast<float>(m_model.nodes[0].scale[0]);
buffer.Y = static_cast<float>(m_model.nodes[0].scale[1]);
buffer.Z = static_cast<float>(m_model.nodes[0].scale[2]);
// FIXME this just checks the first node
const auto &node = m_model.nodes->at(0);
// FIXME this does not take the matrix into account
// (fix: properly map glTF -> Irrlicht node hierarchy)
if (std::holds_alternative<tiniergltf::Node::TRS>(node.transform)) {
const auto &trs = std::get<tiniergltf::Node::TRS>(node.transform);
buffer.X = static_cast<float>(trs.scale[0]);
buffer.Y = static_cast<float>(trs.scale[1]);
buffer.Z = static_cast<float>(trs.scale[2]);
}
return buffer;
}
@ -331,7 +348,7 @@ core::vector3df CGLTFMeshFileLoader::MeshExtractor::getScale() const
std::size_t CGLTFMeshFileLoader::MeshExtractor::getElemCount(
const std::size_t accessorIdx) const
{
return m_model.accessors[accessorIdx].count;
return m_model.accessors->at(accessorIdx).count;
}
/**
@ -344,9 +361,10 @@ std::size_t CGLTFMeshFileLoader::MeshExtractor::getElemCount(
std::size_t CGLTFMeshFileLoader::MeshExtractor::getByteStride(
const std::size_t accessorIdx) const
{
const auto& accessor = m_model.accessors[accessorIdx];
const auto& view = m_model.bufferViews[accessor.bufferView];
return accessor.ByteStride(view);
const auto& accessor = m_model.accessors->at(accessorIdx);
// FIXME this does not work with sparse / zero-initialized accessors
const auto& view = m_model.bufferViews->at(accessor.bufferView.value());
return view.byteStride.value_or(accessor.elementSize());
}
/**
@ -359,7 +377,7 @@ std::size_t CGLTFMeshFileLoader::MeshExtractor::getByteStride(
bool CGLTFMeshFileLoader::MeshExtractor::isAccessorNormalized(
const std::size_t accessorIdx) const
{
const auto& accessor = m_model.accessors[accessorIdx];
const auto& accessor = m_model.accessors->at(accessorIdx);
return accessor.normalized;
}
@ -370,9 +388,10 @@ bool CGLTFMeshFileLoader::MeshExtractor::isAccessorNormalized(
CGLTFMeshFileLoader::BufferOffset CGLTFMeshFileLoader::MeshExtractor::getBuffer(
const std::size_t accessorIdx) const
{
const auto& accessor = m_model.accessors[accessorIdx];
const auto& view = m_model.bufferViews[accessor.bufferView];
const auto& buffer = m_model.buffers[view.buffer];
const auto& accessor = m_model.accessors->at(accessorIdx);
// FIXME this does not work with sparse / zero-initialized accessors
const auto& view = m_model.bufferViews->at(accessor.bufferView.value());
const auto& buffer = m_model.buffers->at(view.buffer);
return BufferOffset(buffer.data, view.byteOffset);
}
@ -385,11 +404,11 @@ CGLTFMeshFileLoader::BufferOffset CGLTFMeshFileLoader::MeshExtractor::getBuffer(
* Type: Integer
* Required: NO
*/
std::size_t CGLTFMeshFileLoader::MeshExtractor::getIndicesAccessorIdx(
std::optional<std::size_t> CGLTFMeshFileLoader::MeshExtractor::getIndicesAccessorIdx(
const std::size_t meshIdx,
const std::size_t primitiveIdx) const
{
return m_model.meshes[meshIdx].primitives[primitiveIdx].indices;
return m_model.meshes->at(meshIdx).primitives[primitiveIdx].indices;
}
/**
@ -397,13 +416,15 @@ std::size_t CGLTFMeshFileLoader::MeshExtractor::getIndicesAccessorIdx(
* Documentation: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#meshes-overview
* Type: VEC3 (Float)
* ! Required: YES (Appears so, needs another pair of eyes to research.)
* Second pair of eyes says: "When positions are not specified, client implementations SHOULD skip primitives rendering"
*/
std::size_t CGLTFMeshFileLoader::MeshExtractor::getPositionAccessorIdx(
const std::size_t meshIdx,
const std::size_t primitiveIdx) const
{
return m_model.meshes[meshIdx].primitives[primitiveIdx]
.attributes.find("POSITION")->second;
// FIXME position-less primitives should be skipped.
return m_model.meshes->at(meshIdx).primitives[primitiveIdx]
.attributes.position.value();
}
/**
@ -412,70 +433,53 @@ std::size_t CGLTFMeshFileLoader::MeshExtractor::getPositionAccessorIdx(
* Type: VEC3 (Float)
* ! Required: NO (Appears to not be, needs another pair of eyes to research.)
*/
std::size_t CGLTFMeshFileLoader::MeshExtractor::getNormalAccessorIdx(
std::optional<std::size_t> CGLTFMeshFileLoader::MeshExtractor::getNormalAccessorIdx(
const std::size_t meshIdx,
const std::size_t primitiveIdx) const
{
const auto& attributes = m_model.meshes[meshIdx]
.primitives[primitiveIdx].attributes;
const auto result = attributes.find("NORMAL");
if (result == attributes.end()) {
return -1;
} else {
return result->second;
}
return m_model.meshes->at(meshIdx).primitives[primitiveIdx].attributes.normal;
}
/**
* The index of the accessor that contains the NORMALs.
* The index of the accessor that contains the TEXCOORDs.
* Documentation: https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#meshes-overview
* Type: VEC3 (Float)
* ! Required: YES (Appears so, needs another pair of eyes to research.)
*/
std::size_t CGLTFMeshFileLoader::MeshExtractor::getTCoordAccessorIdx(
std::optional<std::size_t> CGLTFMeshFileLoader::MeshExtractor::getTCoordAccessorIdx(
const std::size_t meshIdx,
const std::size_t primitiveIdx) const
{
const auto& attributes = m_model.meshes[meshIdx]
.primitives[primitiveIdx].attributes;
const auto result = attributes.find("TEXCOORD_0");
if (result == attributes.end()) {
return -1;
} else {
return result->second;
}
const auto& texcoords = m_model.meshes->at(meshIdx).primitives[primitiveIdx].attributes.texcoord;
if (!texcoords.has_value())
return std::nullopt;
return texcoords->at(0);
}
/**
* This is where the actual model's GLTF file is loaded and parsed by tinygltf.
* This is where the actual model's GLTF file is loaded and parsed by tiniergltf.
*/
bool CGLTFMeshFileLoader::tryParseGLTF(io::IReadFile* file,
tinygltf::Model& model)
std::optional<tiniergltf::GlTF> CGLTFMeshFileLoader::tryParseGLTF(io::IReadFile* file)
{
tinygltf::TinyGLTF loader {};
// Stop embedded textures from making model fail to load
loader.SetImageLoader(nullptr, nullptr);
std::string err {};
std::string warn {};
auto buf = std::make_unique<char[]>(file->getSize());
file->read(buf.get(), file->getSize());
if (warn != "") {
os::Printer::log(warn.c_str(), ELL_WARNING);
}
if (err != "") {
os::Printer::log(err.c_str(), ELL_ERROR);
return false;
auto size = file->getSize();
auto buf = std::make_unique<char[]>(size + 1);
file->read(buf.get(), size);
// We probably don't need this, but add it just to be sure.
buf[size] = '\0';
Json::CharReaderBuilder builder;
const std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
Json::Value json;
JSONCPP_STRING err;
if (!reader->parse(buf.get(), buf.get() + size, &json, &err)) {
return std::nullopt;
}
try {
return tiniergltf::GlTF(json);
} catch (const std::runtime_error &e) {
return std::nullopt;
} catch (const std::out_of_range &e) {
return std::nullopt;
}
return loader.LoadASCIIFromString(&model, &err, &warn, buf.get(),
file->getSize(), "", 1);
}
} // namespace scene

View File

@ -11,7 +11,7 @@
#include "vector2d.h"
#include "vector3d.h"
#include <tiny_gltf.h>
#include <tiniergltf.hpp>
#include <cstddef>
#include <vector>
@ -52,9 +52,9 @@ private:
public:
using vertex_t = video::S3DVertex;
MeshExtractor(const tinygltf::Model& model) noexcept;
MeshExtractor(const tiniergltf::GlTF& model) noexcept;
MeshExtractor(const tinygltf::Model&& model) noexcept;
MeshExtractor(const tiniergltf::GlTF&& model) noexcept;
/* Gets indices for the given mesh/primitive.
*
@ -71,7 +71,7 @@ private:
std::size_t getPrimitiveCount(const std::size_t meshIdx) const;
private:
tinygltf::Model m_model;
tiniergltf::GlTF m_model;
template <typename T>
static T readPrimitive(const BufferOffset& readFrom);
@ -110,31 +110,26 @@ private:
BufferOffset getBuffer(const std::size_t accessorIdx) const;
std::size_t getIndicesAccessorIdx(const std::size_t meshIdx,
std::optional<std::size_t> getIndicesAccessorIdx(const std::size_t meshIdx,
const std::size_t primitiveIdx) const;
std::size_t getPositionAccessorIdx(const std::size_t meshIdx,
const std::size_t primitiveIdx) const;
/* Get the accessor id of the normals of a primitive.
*
* -1 is returned if none are present.
*/
std::size_t getNormalAccessorIdx(const std::size_t meshIdx,
std::optional<std::size_t> getNormalAccessorIdx(const std::size_t meshIdx,
const std::size_t primitiveIdx) const;
/* Get the accessor id for the tcoords of a primitive.
*
* -1 is returned if none are present.
*/
std::size_t getTCoordAccessorIdx(const std::size_t meshIdx,
std::optional<std::size_t> getTCoordAccessorIdx(const std::size_t meshIdx,
const std::size_t primitiveIdx) const;
};
void loadPrimitives(const MeshExtractor& parser, SMesh* mesh);
static bool tryParseGLTF(io::IReadFile* file,
tinygltf::Model& model);
std::optional<tiniergltf::GlTF> tryParseGLTF(io::IReadFile* file);
};
} // namespace scene

View File

@ -1,65 +0,0 @@
cmake_minimum_required(VERSION 3.5)
project(tinygltf
VERSION 2.6.3
LANGUAGES CXX
)
add_library(tinygltf INTERFACE)
add_library(tinygltf::tinygltf ALIAS tinygltf)
target_compile_definitions(tinygltf
INTERFACE
TINYGLTF_NO_EXTERNAL_IMAGE
TINYGLTF_NO_STB_IMAGE
TINYGLTF_NO_STB_IMAGE_WRITE
)
target_include_directories(tinygltf
INTERFACE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
"$<INSTALL_INTERFACE:./>"
)
include(GNUInstallDirs)
install(TARGETS tinygltf
EXPORT tinygltf-export
DESTINATION "${CMAKE_INSTALL_LIBDIR}"
)
export(EXPORT tinygltf-export
FILE "${CMAKE_BINARY_DIR}/cmake/tinygltfTargets.cmake"
NAMESPACE tinygltf::
)
install(
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/tinygltf"
)
install(EXPORT tinygltf-export
FILE tinygltfTargets.cmake
NAMESPACE tinygltf::
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/tinygltf"
)
include(CMakePackageConfigHelpers)
configure_package_config_file("${PROJECT_SOURCE_DIR}/tinygltfConfig.cmake.in"
"${CMAKE_BINARY_DIR}/cmake/tinygltfConfig.cmake"
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/tinygltf"
NO_SET_AND_CHECK_MACRO
NO_CHECK_REQUIRED_COMPONENTS_MACRO
)
write_basic_package_version_file(
"${CMAKE_BINARY_DIR}/cmake/tinygltfConfigVersion.cmake"
COMPATIBILITY AnyNewerVersion
)
install(
FILES
"${CMAKE_BINARY_DIR}/cmake/tinygltfConfig.cmake"
"${CMAKE_BINARY_DIR}/cmake/tinygltfConfigVersion.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/tinygltf"
)

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2017 Syoyo Fujita, Aurélien Chatelain and many contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +0,0 @@
@PACKAGE_INIT@
if(NOT TARGET tinygltf::tinygltf)
include("${CMAKE_CURRENT_LIST_DIR}/tinygltfTargets.cmake")
endif()

View File

@ -24,14 +24,18 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_definitions(-D_DEBUG)
endif()
set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(CMAKE_CXX_COMPILER_ID MATCHES "^(GNU|Clang|AppleClang)$")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
set(CMAKE_CXX_FLAGS_DEBUG "-g")
<<<<<<< HEAD:src/CMakeLists.txt
add_compile_options(-Wall -pipe -fno-exceptions)
=======
add_compile_options(-Wall -pipe -fno-rtti)
>>>>>>> 1320fc97a (Move from tinygltf to tiniergltf (#13)):source/Irrlicht/CMakeLists.txt
# Enable SSE for floating point math on 32-bit x86 by default
# reasoning see minetest issue #11810 and https://gcc.gnu.org/wiki/FloatingPointMath
@ -327,22 +331,11 @@ endif()
# Only for the glTF loader and dependents; we can't link targets
# to object libraries on cmake<3.12 so usage requirements don't
# propogate to all dependents.
get_property(tinygltf_INCLUDE_DIRS
TARGET tinygltf::tinygltf
# propagate to all dependents.
get_property(tiniergltf_INCLUDE_DIRS
TARGET tiniergltf
PROPERTY INTERFACE_INCLUDE_DIRECTORIES
)
get_property(tinygltf_COMPILE_DEFS
TARGET tinygltf::tinygltf
PROPERTY INTERFACE_COMPILE_DEFINITIONS
)
if(CMAKE_VERSION VERSION_LESS 3.12)
foreach(TINYGLTF_DEF ${tinygltf_COMPILE_DEFS})
add_definitions("-D${TINYGLTF_DEF}")
endforeach(TINYGLTF_DEF)
else()
add_compile_definitions(${tinygltf_COMPILE_DEFS})
endif()
set(link_includes
"${PROJECT_SOURCE_DIR}/include"
@ -351,7 +344,7 @@ set(link_includes
"${ZLIB_INCLUDE_DIR}"
"${JPEG_INCLUDE_DIR}"
"${PNG_INCLUDE_DIR}"
"${tinygltf_INCLUDE_DIRS}"
"${tiniergltf_INCLUDE_DIRS}"
"$<$<BOOL:${USE_SDL2}>:${SDL2_INCLUDE_DIRS}>"
${OPENGL_INCLUDE_DIR}