// Copyright 2023 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once #include #include #include #include #include #include #include "video_core/custom_textures/custom_format.h" namespace Frontend { class ImageInterface; } namespace VideoCore { enum class MapType : u32 { Color = 0, Normal = 1, MapCount = 2, }; constexpr std::size_t MAX_MAPS = static_cast(MapType::MapCount); enum class DecodeState : u32 { None = 0, Pending = 1, Decoded = 2, Failed = 3, }; class CustomTexture { public: explicit CustomTexture(Frontend::ImageInterface& image_interface); ~CustomTexture(); void LoadFromDisk(bool flip_png); [[nodiscard]] bool IsParsed() const noexcept { return file_format != CustomFileFormat::None && !hashes.empty(); } [[nodiscard]] bool IsLoaded() const noexcept { return !data.empty(); } private: void LoadPNG(std::span input, bool flip_png); void LoadDDS(std::span input); public: Frontend::ImageInterface& image_interface; std::string path; u32 width; u32 height; std::vector hashes; std::mutex decode_mutex; CustomPixelFormat format; CustomFileFormat file_format; std::vector data; MapType type; }; struct Material { u32 width; u32 height; u64 size; u64 hash; CustomPixelFormat format; std::array textures; std::atomic state{}; void LoadFromDisk(bool flip_png) noexcept; void AddMapTexture(CustomTexture* texture) noexcept; [[nodiscard]] CustomTexture* Map(MapType type) const noexcept { return textures.at(static_cast(type)); } [[nodiscard]] bool IsPending() const noexcept { return state == DecodeState::Pending; } [[nodiscard]] bool IsFailed() const noexcept { return state == DecodeState::Failed; } [[nodiscard]] bool IsDecoded() const noexcept { return state == DecodeState::Decoded; } [[nodiscard]] bool IsUnloaded() const noexcept { return state == DecodeState::None; } }; } // namespace VideoCore