spnda / fastgltf

A modern C++17 glTF 2.0 library focused on speed, correctness, and usability
https://fastgltf.readthedocs.io/v0.8.x/
MIT License
275 stars 42 forks source link

getTransformMatrix redefinition #60

Closed bobby3605 closed 4 months ago

bobby3605 commented 4 months ago

I'm having an issue with tools.hpp:728 getTransformMatrix getting redefined. tools.hpp does have #pragma once, so I'm not sure why this is happening. The lsp server I'm using is warning me that function definitions in a header file can lead to one definition rule violations. Maybe I'm including fastgltf wrong? I added fastgltf as a git submodule and have the following in my CMakeLists.txt

add_subdirectory(external/fastgltf/fastgltf/)
target_include_directories("{$PROJECT_NAME}" PUBLIC external/fastgltf)
target_link_libraries("{$PROJECT_NAME}" PUBLIC fastgltf)

My header files all use ifndef, so mine shouldn't be getting included twice, but maybe I made a mistake there. Here's an example of a header include definition.

#ifndef MODEL_H_
#define MODEL_H_
#define GLM_FORCE_RADIANS
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
#include <glm/gtx/hash.hpp>
#include <fastgltf/core.hpp>
#include <fastgltf/glm_element_traits.hpp>
...
#endif // MODEL_H_

If I move getTransformMatrix into iterateSceneNodes as a lambda function, it does fix the issue, but this isn't an ideal solution.

/**
 * Iterates over every node within a scene recursively, computing the world space transform of each node,
 * and calling the callback function with that node and the transform.
 */
template <typename Callback>
void iterateSceneNodes(fastgltf::Asset& asset, std::size_t sceneIndex, math::fmat4x4 initial, Callback callback) {
    auto& scene = asset.scenes[sceneIndex];

    /**
     * Computes the transform matrix for a given node, and multiplies the given base with that matrix.
     */
    auto getTransformMatrix = [](const Node& node, const math::fmat4x4& base = math::fmat4x4()) {
        return std::visit(visitor{[&](const math::fmat4x4& matrix) { return base * matrix; },
                                  [&](const TRS& trs) {
                                      return base * translate(math::fmat4x4(), trs.translation) * asMatrix(trs.rotation) *
                                             scale(math::fmat4x4(), trs.scale);
                                  }},
                          node.transform);
    };

    auto function = [&](std::size_t nodeIndex, math::fmat4x4 nodeMatrix, auto& self) -> void {
        assert(asset.nodes.size() > nodeIndex);
        auto& node = asset.nodes[nodeIndex];
        nodeMatrix = getTransformMatrix(node, nodeMatrix);

        callback(node, nodeMatrix);

        for (auto& child : node.children) {
            self(child, nodeMatrix, self);
        }
    };

    for (auto& sceneNode : scene.nodeIndices) {
        function(sceneNode, initial, function);
    }
}
spnda commented 4 months ago

I seem to have just forgotten to mark the function as inline. I've pushed a quick fix, could you please see and confirm that it works for you? Thanks.

bobby3605 commented 4 months ago

That fixed it