Program Listing for File assetimporter.hpp

Return to documentation for file (/home/runner/work/Legion-Engine/Legion-Engine/legion/engine/core/filesystem/assetimporter.hpp)

#pragma once
#include <any>
#include <core/containers/containers.hpp>
#include <core/filesystem/resource.hpp>
#include <core/filesystem/view.hpp>
#include <core/logging/logging.hpp>

#include <Optick/optick.h>

namespace legion::core::filesystem
{
    namespace detail
    {
        struct resource_converter_base
        {
            virtual id_type result_type() LEGION_PURE;
        };

    }

    template<typename result, typename... Settings>
    struct resource_converter : public detail::resource_converter_base
    {

        virtual id_type result_type() override { return typeHash<result>(); }

        virtual common::result_decay_more<result, fs_error> load_default(const basic_resource& resource) LEGION_PURE;
        virtual common::result_decay_more<result, fs_error> load(const basic_resource& resource, Settings&&...) LEGION_PURE;

    };

    struct basic_resource_converter final : public resource_converter<basic_resource>
    {
        common::result_decay_more<basic_resource, fs_error> load_default(const basic_resource& resource) override { return load(resource); }
        virtual common::result_decay_more<basic_resource, fs_error> load(const basic_resource& resource) override { return common::result_decay_more<basic_resource, fs_error>(common::Ok(basic_resource(resource))); }
    };

    template<typename T>
    struct basic_converter final : public resource_converter<T>
    {
        virtual common::result_decay_more<T, fs_error> load(const basic_resource& resource) { return common::result_decay_more<T, fs_error>(common::Ok(from_resource<T>(resource))); }
    };

    class AssetImporter
    {
    private:
        static sparse_map<id_type, std::vector<detail::resource_converter_base*>> m_converters;

    public:
        template<typename T>
        static void reportConverter(cstring extension)
        {
            OPTICK_EVENT();
            m_converters[nameHash(extension)].push_back(new T());
        }


        template<typename T, typename... Settings>
        static common::result_decay_more<T, fs_error> tryLoad(const view& view, Settings&&... settings)
        {
            OPTICK_EVENT();
            using common::Err, common::Ok;
            // Decay overloads the operator of ok_type and operator== for valid_t.
            using decay = common::result_decay_more<T, fs_error>;

            // Debug log the settings used for loading the files so that you can track down why something got loaded wrong if it did.
            if constexpr (sizeof...(settings) == 0)
                log::trace("Tried to load asset of type{}", nameOfType<T>());
            else if constexpr (sizeof...(settings) == 1)
                log::trace("Tried to load asset of type{} with settings of type:{}", nameOfType<T>(), (std::string(nameOfType<Settings>()) + ...));
            else
                log::trace("Tried to load asset of type{} with settings of types:{}", nameOfType<T>(), ((std::string(nameOfType<Settings>()) + ", ") + ...));

            // Check if the view is valid to load as a file.
            if (!view.is_valid() || !view.file_info().is_file)
                return decay(Err(legion_fs_error("requested asset load on view that isn't a valid file.")));

            // Get data from file and check validity.
            auto result = view.get();
            if (result != common::valid)
                return decay(Err(result.get_error()));

            for (detail::resource_converter_base* base : m_converters[nameHash(view.get_extension())])
            {
                // Do a safety check if the cast was valid before we call any functions on it.
                if (typeHash<T>() == base->result_type())
                {
                    // Retrieve the correct converter to use.
                    auto* converter = reinterpret_cast<resource_converter<T, Settings...>*>(base);

                    // Attempt the conversion and return the result.
                    auto loadresult = converter->load(result, std::forward<Settings>(settings)...);
                    if (loadresult == common::valid)
                        return decay(Ok(static_cast<T>(loadresult)));

                    return decay(Err(loadresult.get_error()));
                }
            }

            return decay(Err(legion_fs_error("requested asset load on file that stores a different type of asset.")));
        }

    };
}