diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index 96a7cf64..21c4c17d 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -151,19 +151,39 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/OpenGL/OpenGLRenderTargetView.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/OpenGL/OpenGLDepthStencilView.cpp - # Resources - TEMPORARILY DISABLED - # ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/Resources.h - # ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/ResourceTypes.h - # ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/IResource.h - # ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/ResourceHandle.h - # ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/IResourceLoader.h - # ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/ResourceManager.h - # ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/ResourceCache.h - # ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/AsyncLoader.h - # ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/ResourceManager.cpp - # ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/ResourceCache.cpp - # ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/AsyncLoader.cpp - # ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/ResourceTypes.cpp + # Resources + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/Resources.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/ResourceTypes.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/IResource.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/ResourceHandle.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/IResourceLoader.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/ResourceManager.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/ResourceCache.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/AsyncLoader.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/Texture.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/Mesh.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/TextureLoader.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/MeshLoader.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/Material.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/MaterialLoader.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/Shader.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/ShaderLoader.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/AudioClip.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/AudioLoader.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/ResourceManager.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/ResourceCache.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/AsyncLoader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/ResourceTypes.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Texture.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Mesh.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/TextureLoader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/MeshLoader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Material.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/MaterialLoader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/ShaderLoader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/AudioClip.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/AudioLoader.cpp ) target_include_directories(XCEngine PUBLIC diff --git a/engine/include/XCEngine/Containers/HashMap.h b/engine/include/XCEngine/Containers/HashMap.h index 098af91e..5345718a 100644 --- a/engine/include/XCEngine/Containers/HashMap.h +++ b/engine/include/XCEngine/Containers/HashMap.h @@ -237,7 +237,10 @@ bool HashMap::Erase(const Key& key) { auto it = FindInBucket(bucket, key); if (it != bucket.pairs.end()) { size_t index = it - bucket.pairs.begin(); - bucket.pairs[index] = bucket.pairs.Back(); + + if (index != bucket.pairs.Size() - 1) { + bucket.pairs[index] = std::move(bucket.pairs.Back()); + } bucket.pairs.PopBack(); --m_size; return true; diff --git a/engine/include/XCEngine/Math/AABB.h b/engine/include/XCEngine/Math/AABB.h index b339dd2e..d1b83b25 100644 --- a/engine/include/XCEngine/Math/AABB.h +++ b/engine/include/XCEngine/Math/AABB.h @@ -4,12 +4,11 @@ #include "Vector3.h" #include "Bounds.h" #include "Matrix4.h" +#include "Sphere.h" namespace XCEngine { namespace Math { -struct Sphere; - struct OBB { Vector3 center; Vector3 extents; diff --git a/engine/include/XCEngine/Resources/AsyncLoader.h b/engine/include/XCEngine/Resources/AsyncLoader.h index 6960a5a6..c9aced21 100644 --- a/engine/include/XCEngine/Resources/AsyncLoader.h +++ b/engine/include/XCEngine/Resources/AsyncLoader.h @@ -13,16 +13,38 @@ struct LoadRequest { Containers::String path; ResourceType type; std::function callback; - Core::UniqueRef settings; + ImportSettings* settings; Core::uint64 requestId; - LoadRequest() : requestId(0) {} + LoadRequest() : requestId(0), settings(nullptr) {} LoadRequest(const Containers::String& p, ResourceType t, std::function cb, ImportSettings* s = nullptr) : path(p), type(t), callback(std::move(cb)), settings(s), requestId(GenerateRequestId()) {} + LoadRequest(LoadRequest&& other) noexcept + : path(std::move(other.path)), type(other.type), + callback(std::move(other.callback)), settings(other.settings), + requestId(other.requestId) { + other.settings = nullptr; + } + + LoadRequest& operator=(LoadRequest&& other) noexcept { + if (this != &other) { + path = std::move(other.path); + type = other.type; + callback = std::move(other.callback); + settings = other.settings; + requestId = other.requestId; + other.settings = nullptr; + } + return *this; + } + + LoadRequest(const LoadRequest&) = default; + LoadRequest& operator=(const LoadRequest&) = default; + private: static Core::uint64 GenerateRequestId(); }; @@ -46,11 +68,12 @@ public: void CancelAll(); void Cancel(Core::uint64 requestId); -private: - AsyncLoader() = default; ~AsyncLoader() = default; - void SubmitInternal(LoadRequest& request); + AsyncLoader() = default; + +private: + void SubmitInternal(LoadRequest request); IResourceLoader* FindLoader(ResourceType type) const; void QueueCompleted(LoadRequest request, LoadResult result); diff --git a/engine/include/XCEngine/Resources/AudioClip.h b/engine/include/XCEngine/Resources/AudioClip.h new file mode 100644 index 00000000..3fca17dc --- /dev/null +++ b/engine/include/XCEngine/Resources/AudioClip.h @@ -0,0 +1,86 @@ +#pragma once + +#include "IResource.h" +#include "../Containers/Array.h" +#include "../Core/Types.h" + +namespace XCEngine { +namespace Resources { + +enum class AudioFormat : Core::uint8 { + Unknown, + WAV, + OGG, + MP3, + FLAC +}; + +enum class AudioType : Core::uint8 { + SoundEffect, + Music, + Voice, + Ambient +}; + +class AudioClip : public IResource { +public: + AudioClip(); + virtual ~AudioClip() override; + + ResourceType GetType() const override { return ResourceType::AudioClip; } + const Containers::String& GetName() const override { return m_name; } + const Containers::String& GetPath() const override { return m_path; } + ResourceGUID GetGUID() const override { return m_guid; } + bool IsValid() const override { return m_isValid; } + size_t GetMemorySize() const override { return m_memorySize; } + void Release() override; + + void SetAudioData(const Containers::Array& data); + const Containers::Array& GetAudioData() const { return m_audioData; } + + void SetSampleRate(Core::uint32 rate) { m_sampleRate = rate; } + Core::uint32 GetSampleRate() const { return m_sampleRate; } + + void SetChannels(Core::uint32 channels) { m_channels = channels; } + Core::uint32 GetChannels() const { return m_channels; } + + void SetBitsPerSample(Core::uint32 bits) { m_bitsPerSample = bits; } + Core::uint32 GetBitsPerSample() const { return m_bitsPerSample; } + + void SetDuration(float seconds) { m_duration = seconds; } + float GetDuration() const { return m_duration; } + + void SetAudioFormat(AudioFormat format) { m_format = format; } + AudioFormat GetAudioFormat() const { return m_format; } + + void SetAudioType(AudioType type) { m_audioType = type; } + AudioType GetAudioType() const { return m_audioType; } + + void SetIs3D(bool is3D) { m_is3D = is3D; } + bool Is3D() const { return m_is3D; } + + void SetLoop(bool loop) { m_loop = loop; } + bool IsLoop() const { return m_loop; } + + class IRHIAudioBuffer* GetRHIResource() const { return m_rhiResource; } + void SetRHIResource(class IRHIAudioBuffer* resource); + +private: + Containers::Array m_audioData; + + Core::uint32 m_sampleRate = 44100; + Core::uint32 m_channels = 2; + Core::uint32 m_bitsPerSample = 16; + float m_duration = 0.0f; + + AudioFormat m_format = AudioFormat::WAV; + AudioType m_audioType = AudioType::SoundEffect; + + bool m_is3D = false; + bool m_loop = false; + + class IRHIAudioBuffer* m_rhiResource = nullptr; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/include/XCEngine/Resources/AudioLoader.h b/engine/include/XCEngine/Resources/AudioLoader.h new file mode 100644 index 00000000..3448aac3 --- /dev/null +++ b/engine/include/XCEngine/Resources/AudioLoader.h @@ -0,0 +1,26 @@ +#pragma once + +#include "IResourceLoader.h" +#include "AudioClip.h" + +namespace XCEngine { +namespace Resources { + +class AudioLoader : public IResourceLoader { +public: + AudioLoader(); + virtual ~AudioLoader() override; + + ResourceType GetResourceType() const override { return ResourceType::AudioClip; } + Containers::Array GetSupportedExtensions() const override; + bool CanLoad(const Containers::String& path) const override; + LoadResult Load(const Containers::String& path, const ImportSettings* settings = nullptr) override; + ImportSettings* GetDefaultSettings() const override; + +private: + bool ParseWAVData(const Containers::Array& data, AudioClip* audioClip); + AudioFormat DetectAudioFormat(const Containers::String& path, const Containers::Array& data); +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/include/XCEngine/Resources/IResource.h b/engine/include/XCEngine/Resources/IResource.h index c7c5e61f..640a5992 100644 --- a/engine/include/XCEngine/Resources/IResource.h +++ b/engine/include/XCEngine/Resources/IResource.h @@ -18,7 +18,6 @@ public: virtual size_t GetMemorySize() const = 0; virtual void Release() = 0; -protected: struct ConstructParams { Containers::String name; Containers::String path; diff --git a/engine/include/XCEngine/Resources/Material.h b/engine/include/XCEngine/Resources/Material.h new file mode 100644 index 00000000..56d7f428 --- /dev/null +++ b/engine/include/XCEngine/Resources/Material.h @@ -0,0 +1,93 @@ +#pragma once +#include "IResource.h" +#include "ResourceHandle.h" +#include "ResourceManager.h" +#include "Texture.h" +#include "Shader.h" +#include "../Containers/HashMap.h" +#include "../Core/Types.h" +#include "../Math/Vector2.h" +#include "../Math/Vector3.h" +#include "../Math/Vector4.h" +#include + +namespace XCEngine { +namespace Resources { + +enum class MaterialPropertyType { + Float, Float2, Float3, Float4, + Int, Int2, Int3, Int4, + Bool, Texture, Cubemap +}; + +struct MaterialProperty { + Containers::String name; + MaterialPropertyType type; + + union Value { + float floatValue[4]; + Core::int32 intValue[4]; + bool boolValue; + + Value() { memset(this, 0, sizeof(Value)); } + } value; + + Core::uint32 refCount = 0; + + MaterialProperty() : type(MaterialPropertyType::Float), refCount(0) {} +}; + +class Material : public IResource { +public: + Material(); + virtual ~Material() override; + + ResourceType GetType() const override { return ResourceType::Material; } + const Containers::String& GetName() const override { return m_name; } + const Containers::String& GetPath() const override { return m_path; } + ResourceGUID GetGUID() const override { return m_guid; } + bool IsValid() const override { return m_isValid; } + size_t GetMemorySize() const override { return m_memorySize; } + void Release() override; + + void SetShader(const ResourceHandle& shader); + class Shader* GetShader() const { return m_shader.Get(); } + + void SetFloat(const Containers::String& name, float value); + void SetFloat2(const Containers::String& name, const Math::Vector2& value); + void SetFloat3(const Containers::String& name, const Math::Vector3& value); + void SetFloat4(const Containers::String& name, const Math::Vector4& value); + void SetInt(const Containers::String& name, Core::int32 value); + void SetBool(const Containers::String& name, bool value); + void SetTexture(const Containers::String& name, const ResourceHandle& texture); + + float GetFloat(const Containers::String& name) const; + Math::Vector2 GetFloat2(const Containers::String& name) const; + Math::Vector3 GetFloat3(const Containers::String& name) const; + Math::Vector4 GetFloat4(const Containers::String& name) const; + Core::int32 GetInt(const Containers::String& name) const; + bool GetBool(const Containers::String& name) const; + ResourceHandle GetTexture(const Containers::String& name) const; + + const Containers::Array& GetConstantBufferData() const { return m_constantBufferData; } + void UpdateConstantBuffer(); + + bool HasProperty(const Containers::String& name) const; + void RemoveProperty(const Containers::String& name); + void ClearAllProperties(); + +private: + ResourceHandle m_shader; + Containers::HashMap m_properties; + Containers::Array m_constantBufferData; + + struct TextureBinding { + Containers::String name; + Core::uint32 slot; + ResourceHandle texture; + }; + Containers::Array m_textureBindings; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/include/XCEngine/Resources/MaterialLoader.h b/engine/include/XCEngine/Resources/MaterialLoader.h new file mode 100644 index 00000000..91c0c737 --- /dev/null +++ b/engine/include/XCEngine/Resources/MaterialLoader.h @@ -0,0 +1,25 @@ +#pragma once + +#include "IResourceLoader.h" +#include "Material.h" + +namespace XCEngine { +namespace Resources { + +class MaterialLoader : public IResourceLoader { +public: + MaterialLoader(); + virtual ~MaterialLoader() override; + + ResourceType GetResourceType() const override { return ResourceType::Material; } + Containers::Array GetSupportedExtensions() const override; + bool CanLoad(const Containers::String& path) const override; + LoadResult Load(const Containers::String& path, const ImportSettings* settings = nullptr) override; + ImportSettings* GetDefaultSettings() const override; + +private: + bool ParseMaterialData(const Containers::Array& data, Material* material); +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/include/XCEngine/Resources/Mesh.h b/engine/include/XCEngine/Resources/Mesh.h new file mode 100644 index 00000000..c84bf975 --- /dev/null +++ b/engine/include/XCEngine/Resources/Mesh.h @@ -0,0 +1,68 @@ +#pragma once + +#include "IResource.h" +#include "../Containers/Array.h" +#include "../Core/Types.h" + +namespace XCEngine { +namespace Resources { + +enum class VertexAttribute : Core::uint32 { + Position = 1 << 0, Normal = 1 << 1, Tangent = 1 << 2, + Color = 1 << 3, UV0 = 1 << 4, UV1 = 1 << 5, + UV2 = 1 << 6, UV3 = 1 << 7, BoneWeights = 1 << 8, BoneIndices = 1 << 9 +}; + +struct MeshSection { + Core::uint32 baseVertex; + Core::uint32 vertexCount; + Core::uint32 startIndex; + Core::uint32 indexCount; + Core::uint32 materialID; +}; + +class Mesh : public IResource { +public: + Mesh(); + virtual ~Mesh() override; + + ResourceType GetType() const override { return ResourceType::Mesh; } + const Containers::String& GetName() const override { return m_name; } + const Containers::String& GetPath() const override { return m_path; } + ResourceGUID GetGUID() const override { return m_guid; } + bool IsValid() const override { return m_isValid; } + size_t GetMemorySize() const override { return m_memorySize; } + void Release() override; + + void SetVertexData(const void* data, size_t size, Core::uint32 vertexCount, + Core::uint32 vertexStride, VertexAttribute attributes); + const void* GetVertexData() const { return m_vertexData.Data(); } + size_t GetVertexDataSize() const { return m_vertexData.Size(); } + Core::uint32 GetVertexCount() const { return m_vertexCount; } + Core::uint32 GetVertexStride() const { return m_vertexStride; } + VertexAttribute GetVertexAttributes() const { return m_attributes; } + + void SetIndexData(const void* data, size_t size, Core::uint32 indexCount, bool use32Bit); + const void* GetIndexData() const { return m_indexData.Data(); } + size_t GetIndexDataSize() const { return m_indexData.Size(); } + Core::uint32 GetIndexCount() const { return m_indexCount; } + bool IsUse32BitIndex() const { return m_use32BitIndex; } + + void AddSection(const MeshSection& section); + const Containers::Array& GetSections() const { return m_sections; } + +private: + Core::uint32 m_vertexCount = 0; + Core::uint32 m_vertexStride = 0; + VertexAttribute m_attributes = VertexAttribute::Position; + + Core::uint32 m_indexCount = 0; + bool m_use32BitIndex = false; + + Containers::Array m_vertexData; + Containers::Array m_indexData; + Containers::Array m_sections; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/include/XCEngine/Resources/MeshLoader.h b/engine/include/XCEngine/Resources/MeshLoader.h new file mode 100644 index 00000000..8606f6fa --- /dev/null +++ b/engine/include/XCEngine/Resources/MeshLoader.h @@ -0,0 +1,22 @@ +#pragma once + +#include "IResourceLoader.h" +#include "Mesh.h" + +namespace XCEngine { +namespace Resources { + +class MeshLoader : public IResourceLoader { +public: + MeshLoader(); + virtual ~MeshLoader() override; + + ResourceType GetResourceType() const override { return ResourceType::Mesh; } + Containers::Array GetSupportedExtensions() const override; + bool CanLoad(const Containers::String& path) const override; + LoadResult Load(const Containers::String& path, const ImportSettings* settings = nullptr) override; + ImportSettings* GetDefaultSettings() const override; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/include/XCEngine/Resources/ResourceManager.h b/engine/include/XCEngine/Resources/ResourceManager.h index 45c233a6..bda08de3 100644 --- a/engine/include/XCEngine/Resources/ResourceManager.h +++ b/engine/include/XCEngine/Resources/ResourceManager.h @@ -98,7 +98,7 @@ private: Containers::HashMap m_resourceCache; Containers::HashMap m_refCounts; Containers::HashMap m_guidToPath; - Containers::HashMap> m_loaders; + Containers::HashMap m_loaders; size_t m_memoryUsage = 0; size_t m_memoryBudget = 512 * 1024 * 1024; diff --git a/engine/include/XCEngine/Resources/ResourceTypes.h b/engine/include/XCEngine/Resources/ResourceTypes.h index 016a4bea..e9bb8384 100644 --- a/engine/include/XCEngine/Resources/ResourceTypes.h +++ b/engine/include/XCEngine/Resources/ResourceTypes.h @@ -64,6 +64,22 @@ inline ResourceGUID MakeResourceGUID(const char* path) { return ResourceGUID::Generate(path); } +} // namespace Resources + +} // namespace XCEngine + +namespace std { +template<> +struct hash { + size_t operator()(const XCEngine::Resources::ResourceGUID& guid) const noexcept { + return static_cast(guid.value); + } +}; +} + +namespace XCEngine { +namespace Resources { + template ResourceType GetResourceType(); diff --git a/engine/include/XCEngine/Resources/Resources.h b/engine/include/XCEngine/Resources/Resources.h index 3d6c0d0c..e3b0d4ec 100644 --- a/engine/include/XCEngine/Resources/Resources.h +++ b/engine/include/XCEngine/Resources/Resources.h @@ -9,15 +9,21 @@ #include "ResourceCache.h" #include "AsyncLoader.h" +#include "Texture.h" +#include "TextureLoader.h" +#include "Mesh.h" +#include "MeshLoader.h" +#include "Material.h" +#include "MaterialLoader.h" +#include "Shader.h" +#include "ShaderLoader.h" +#include "AudioClip.h" +#include "AudioLoader.h" + // Forward declarations for concrete resource types namespace XCEngine { namespace Resources { -class Texture; -class Mesh; -class Material; -class Shader; -class AudioClip; class BinaryResource; } // namespace Resources diff --git a/engine/include/XCEngine/Resources/Shader.h b/engine/include/XCEngine/Resources/Shader.h new file mode 100644 index 00000000..3cd71b2e --- /dev/null +++ b/engine/include/XCEngine/Resources/Shader.h @@ -0,0 +1,87 @@ +#pragma once + +#include "IResource.h" +#include "../Containers/Array.h" +#include "../Core/Types.h" + +namespace XCEngine { +namespace Resources { + +enum class ShaderType : Core::uint8 { + Vertex, + Fragment, + Geometry, + Compute, + Hull, + Domain +}; + +enum class ShaderLanguage : Core::uint8 { + GLSL, + HLSL, + SPIRV +}; + +struct ShaderUniform { + Containers::String name; + Core::uint32 location; + Core::uint32 size; + Core::uint32 type; +}; + +struct ShaderAttribute { + Containers::String name; + Core::uint32 location; + Core::uint32 size; + Core::uint32 type; +}; + +class Shader : public IResource { +public: + Shader(); + virtual ~Shader() override; + + ResourceType GetType() const override { return ResourceType::Shader; } + const Containers::String& GetName() const override { return m_name; } + const Containers::String& GetPath() const override { return m_path; } + ResourceGUID GetGUID() const override { return m_guid; } + bool IsValid() const override { return m_isValid; } + size_t GetMemorySize() const override { return m_memorySize; } + void Release() override; + + void SetShaderType(ShaderType type) { m_shaderType = type; } + ShaderType GetShaderType() const { return m_shaderType; } + + void SetShaderLanguage(ShaderLanguage lang) { m_language = lang; } + ShaderLanguage GetShaderLanguage() const { return m_language; } + + void SetSourceCode(const Containers::String& source); + const Containers::String& GetSourceCode() const { return m_sourceCode; } + + void SetCompiledBinary(const Containers::Array& binary); + const Containers::Array& GetCompiledBinary() const { return m_compiledBinary; } + + void AddUniform(const ShaderUniform& uniform); + const Containers::Array& GetUniforms() const { return m_uniforms; } + + void AddAttribute(const ShaderAttribute& attribute); + const Containers::Array& GetAttributes() const { return m_attributes; } + + class IRHIShader* GetRHIResource() const { return m_rhiResource; } + void SetRHIResource(class IRHIShader* resource); + +private: + ShaderType m_shaderType = ShaderType::Fragment; + ShaderLanguage m_language = ShaderLanguage::GLSL; + + Containers::String m_sourceCode; + Containers::Array m_compiledBinary; + + Containers::Array m_uniforms; + Containers::Array m_attributes; + + class IRHIShader* m_rhiResource = nullptr; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/include/XCEngine/Resources/ShaderLoader.h b/engine/include/XCEngine/Resources/ShaderLoader.h new file mode 100644 index 00000000..e92c85bb --- /dev/null +++ b/engine/include/XCEngine/Resources/ShaderLoader.h @@ -0,0 +1,26 @@ +#pragma once + +#include "IResourceLoader.h" +#include "Shader.h" + +namespace XCEngine { +namespace Resources { + +class ShaderLoader : public IResourceLoader { +public: + ShaderLoader(); + virtual ~ShaderLoader() override; + + ResourceType GetResourceType() const override { return ResourceType::Shader; } + Containers::Array GetSupportedExtensions() const override; + bool CanLoad(const Containers::String& path) const override; + LoadResult Load(const Containers::String& path, const ImportSettings* settings = nullptr) override; + ImportSettings* GetDefaultSettings() const override; + +private: + ShaderType DetectShaderType(const Containers::String& path, const Containers::String& source); + bool ParseShaderSource(const Containers::String& source, Shader* shader); +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/include/XCEngine/Resources/Texture.h b/engine/include/XCEngine/Resources/Texture.h new file mode 100644 index 00000000..742c0347 --- /dev/null +++ b/engine/include/XCEngine/Resources/Texture.h @@ -0,0 +1,73 @@ +#pragma once + +#include "IResource.h" +#include "../Core/Types.h" + +namespace XCEngine { +namespace Resources { + +enum class TextureType { + Texture2D, Texture3D, TextureCube, Texture2DArray, TextureCubeArray +}; + +enum class TextureFormat { + Unknown, R8_UNORM, RG8_UNORM, RGBA8_UNORM, RGBA8_SRGB, + R16_FLOAT, RG16_FLOAT, RGBA16_FLOAT, + R32_FLOAT, RG32_FLOAT, RGBA32_FLOAT, + D16_UNORM, D24_UNORM_S8_UINT, D32_FLOAT, D32_FLOAT_S8_X24_UINT, + BC1_UNORM, BC1_UNORM_SRGB, BC2_UNORM, BC2_UNORM_SRGB, + BC3_UNORM, BC3_UNORM_SRGB, BC4_UNORM, BC5_UNORM, BC6H_UF16, + BC7_UNORM, BC7_UNORM_SRGB +}; + +enum class TextureUsage : Core::uint8 { + None = 0, ShaderResource = 1 << 0, RenderTarget = 1 << 1, + DepthStencil = 1 << 2, UnorderedAccess = 1 << 3, + TransferSrc = 1 << 4, TransferDst = 1 << 5 +}; + +class Texture : public IResource { +public: + Texture(); + virtual ~Texture() override; + + ResourceType GetType() const override { return ResourceType::Texture; } + const Containers::String& GetName() const override { return m_name; } + const Containers::String& GetPath() const override { return m_path; } + ResourceGUID GetGUID() const override { return m_guid; } + bool IsValid() const override { return m_isValid; } + size_t GetMemorySize() const override { return m_memorySize; } + void Release() override; + + Core::uint32 GetWidth() const { return m_width; } + Core::uint32 GetHeight() const { return m_height; } + Core::uint32 GetDepth() const { return m_depth; } + Core::uint32 GetMipLevels() const { return m_mipLevels; } + Core::uint32 GetArraySize() const { return m_arraySize; } + TextureType GetTextureType() const { return m_textureType; } + TextureFormat GetFormat() const { return m_format; } + TextureUsage GetUsage() const { return m_usage; } + + const void* GetPixelData() const { return m_pixelData.Data(); } + size_t GetPixelDataSize() const { return m_pixelData.Size(); } + + bool Create(Core::uint32 width, Core::uint32 height, Core::uint32 depth, + Core::uint32 mipLevels, TextureType type, TextureFormat format, + const void* data, size_t dataSize); + bool GenerateMipmaps(); + +private: + Core::uint32 m_width = 0; + Core::uint32 m_height = 0; + Core::uint32 m_depth = 1; + Core::uint32 m_mipLevels = 1; + Core::uint32 m_arraySize = 1; + TextureType m_textureType = TextureType::Texture2D; + TextureFormat m_format = TextureFormat::RGBA8_UNORM; + TextureUsage m_usage = TextureUsage::ShaderResource; + + Containers::Array m_pixelData; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/include/XCEngine/Resources/TextureLoader.h b/engine/include/XCEngine/Resources/TextureLoader.h new file mode 100644 index 00000000..ab2addd1 --- /dev/null +++ b/engine/include/XCEngine/Resources/TextureLoader.h @@ -0,0 +1,22 @@ +#pragma once + +#include "IResourceLoader.h" +#include "Texture.h" + +namespace XCEngine { +namespace Resources { + +class TextureLoader : public IResourceLoader { +public: + TextureLoader(); + virtual ~TextureLoader() override; + + ResourceType GetResourceType() const override { return ResourceType::Texture; } + Containers::Array GetSupportedExtensions() const override; + bool CanLoad(const Containers::String& path) const override; + LoadResult Load(const Containers::String& path, const ImportSettings* settings = nullptr) override; + ImportSettings* GetDefaultSettings() const override; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/include/XCEngine/Threading/Mutex.h b/engine/include/XCEngine/Threading/Mutex.h index 0d7fb10f..1c5d808d 100644 --- a/engine/include/XCEngine/Threading/Mutex.h +++ b/engine/include/XCEngine/Threading/Mutex.h @@ -14,12 +14,12 @@ public: void Unlock() { m_mutex.unlock(); } bool TryLock() { return m_mutex.try_lock(); } - void lock() { Lock(); } - void unlock() { Unlock(); } - bool try_lock() { return TryLock(); } + void lock() const { m_mutex.lock(); } + void unlock() const { m_mutex.unlock(); } + bool try_lock() const { return m_mutex.try_lock(); } private: - std::mutex m_mutex; + mutable std::mutex m_mutex; }; } // namespace Threading diff --git a/engine/src/Resources/AsyncLoader.cpp b/engine/src/Resources/AsyncLoader.cpp index 43420a3e..277e8009 100644 --- a/engine/src/Resources/AsyncLoader.cpp +++ b/engine/src/Resources/AsyncLoader.cpp @@ -31,10 +31,10 @@ void AsyncLoader::Submit(const Containers::String& path, ResourceType type, void AsyncLoader::Submit(const Containers::String& path, ResourceType type, ImportSettings* settings, std::function callback) { LoadRequest request(path, type, std::move(callback), settings); - SubmitInternal(request); + SubmitInternal(std::move(request)); } -void AsyncLoader::SubmitInternal(LoadRequest& request) { +void AsyncLoader::SubmitInternal(LoadRequest request) { IResourceLoader* loader = FindLoader(request.type); if (!loader) { @@ -48,7 +48,7 @@ void AsyncLoader::SubmitInternal(LoadRequest& request) { { std::lock_guard lock(m_queueMutex); - m_pendingQueue.PushBack(request); + m_pendingQueue.PushBack(std::move(request)); m_pendingCount++; m_totalRequested++; } diff --git a/engine/src/Resources/AudioClip.cpp b/engine/src/Resources/AudioClip.cpp new file mode 100644 index 00000000..8fec8354 --- /dev/null +++ b/engine/src/Resources/AudioClip.cpp @@ -0,0 +1,31 @@ +#include "Resources/AudioClip.h" + +namespace XCEngine { +namespace Resources { + +AudioClip::AudioClip() = default; + +AudioClip::~AudioClip() = default; + +void AudioClip::Release() { + m_audioData.Clear(); + m_rhiResource = nullptr; + m_isValid = false; +} + +void AudioClip::SetAudioData(const Containers::Array& data) { + m_audioData = data; + + if (m_sampleRate > 0 && m_channels > 0 && m_bitsPerSample > 0) { + size_t bytesPerSample = m_bitsPerSample / 8; + size_t totalSamples = data.Size() / bytesPerSample; + m_duration = static_cast(totalSamples) / static_cast(m_sampleRate); + } +} + +void AudioClip::SetRHIResource(class IRHIAudioBuffer* resource) { + m_rhiResource = resource; +} + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Resources/AudioLoader.cpp b/engine/src/Resources/AudioLoader.cpp new file mode 100644 index 00000000..ad9f4e32 --- /dev/null +++ b/engine/src/Resources/AudioLoader.cpp @@ -0,0 +1,77 @@ +#include "Resources/AudioLoader.h" +#include "Resources/ResourceManager.h" +#include "Resources/ResourceTypes.h" + +namespace XCEngine { +namespace Resources { + +AudioLoader::AudioLoader() = default; + +AudioLoader::~AudioLoader() = default; + +Containers::Array AudioLoader::GetSupportedExtensions() const { + Containers::Array extensions; + extensions.PushBack("wav"); + extensions.PushBack("ogg"); + extensions.PushBack("mp3"); + extensions.PushBack("flac"); + extensions.PushBack("aiff"); + extensions.PushBack("aif"); + return extensions; +} + +bool AudioLoader::CanLoad(const Containers::String& path) const { + Containers::String ext = GetExtension(path); + return ext == "wav" || ext == "ogg" || ext == "mp3" || + ext == "flac" || ext == "aiff" || ext == "aif"; +} + +LoadResult AudioLoader::Load(const Containers::String& path, const ImportSettings* settings) { + Containers::Array data = ReadFileData(path); + if (data.Empty()) { + return LoadResult("Failed to read audio file: " + path); + } + + AudioClip* audioClip = new AudioClip(); + audioClip->m_path = path; + audioClip->m_name = path; + audioClip->m_guid = ResourceGUID::Generate(path); + + AudioFormat format = DetectAudioFormat(path, data); + audioClip->SetAudioFormat(format); + audioClip->SetAudioData(data); + + audioClip->m_isValid = true; + audioClip->m_memorySize = sizeof(AudioClip) + audioClip->m_name.Length() + + audioClip->m_path.Length() + audioClip->GetAudioData().Size(); + + return LoadResult(audioClip); +} + +ImportSettings* AudioLoader::GetDefaultSettings() const { + return nullptr; +} + +bool AudioLoader::ParseWAVData(const Containers::Array& data, AudioClip* audioClip) { + return true; +} + +AudioFormat AudioLoader::DetectAudioFormat(const Containers::String& path, const Containers::Array& data) { + Containers::String ext = GetExtension(path); + + if (ext == "wav") return AudioFormat::WAV; + if (ext == "ogg") return AudioFormat::OGG; + if (ext == "mp3") return AudioFormat::MP3; + if (ext == "flac") return AudioFormat::FLAC; + + if (data.Size() >= 4) { + if (data[0] == 'R' && data[1] == 'I' && data[2] == 'F' && data[3] == 'F') { + return AudioFormat::WAV; + } + } + + return AudioFormat::Unknown; +} + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Resources/Material.cpp b/engine/src/Resources/Material.cpp new file mode 100644 index 00000000..f5b75872 --- /dev/null +++ b/engine/src/Resources/Material.cpp @@ -0,0 +1,174 @@ +#include "Resources/Material.h" +#include "Resources/Shader.h" + +namespace XCEngine { +namespace Resources { + +Material::Material() = default; + +Material::~Material() = default; + +void Material::Release() { + m_shader.Reset(); + m_properties.Clear(); + m_textureBindings.Clear(); + m_constantBufferData.Clear(); + m_isValid = false; +} + +void Material::SetShader(const ResourceHandle& shader) { + m_shader = shader; +} + +void Material::SetFloat(const Containers::String& name, float value) { + MaterialProperty prop; + prop.name = name; + prop.type = MaterialPropertyType::Float; + prop.value.floatValue[0] = value; + prop.refCount = 1; + m_properties.Insert(name, prop); +} + +void Material::SetFloat2(const Containers::String& name, const Math::Vector2& value) { + MaterialProperty prop; + prop.name = name; + prop.type = MaterialPropertyType::Float2; + prop.value.floatValue[0] = value.x; + prop.value.floatValue[1] = value.y; + prop.refCount = 1; + m_properties.Insert(name, prop); +} + +void Material::SetFloat3(const Containers::String& name, const Math::Vector3& value) { + MaterialProperty prop; + prop.name = name; + prop.type = MaterialPropertyType::Float3; + prop.value.floatValue[0] = value.x; + prop.value.floatValue[1] = value.y; + prop.value.floatValue[2] = value.z; + prop.refCount = 1; + m_properties.Insert(name, prop); +} + +void Material::SetFloat4(const Containers::String& name, const Math::Vector4& value) { + MaterialProperty prop; + prop.name = name; + prop.type = MaterialPropertyType::Float4; + prop.value.floatValue[0] = value.x; + prop.value.floatValue[1] = value.y; + prop.value.floatValue[2] = value.z; + prop.value.floatValue[3] = value.w; + prop.refCount = 1; + m_properties.Insert(name, prop); +} + +void Material::SetInt(const Containers::String& name, Core::int32 value) { + MaterialProperty prop; + prop.name = name; + prop.type = MaterialPropertyType::Int; + prop.value.intValue[0] = value; + prop.refCount = 1; + m_properties.Insert(name, prop); +} + +void Material::SetBool(const Containers::String& name, bool value) { + MaterialProperty prop; + prop.name = name; + prop.type = MaterialPropertyType::Bool; + prop.value.boolValue = value; + prop.refCount = 1; + m_properties.Insert(name, prop); +} + +void Material::SetTexture(const Containers::String& name, const ResourceHandle& texture) { + MaterialProperty prop; + prop.name = name; + prop.type = MaterialPropertyType::Texture; + prop.refCount = 1; + m_properties.Insert(name, prop); + + TextureBinding binding; + binding.name = name; + binding.slot = static_cast(m_textureBindings.Size()); + binding.texture = texture; + m_textureBindings.PushBack(binding); +} + +float Material::GetFloat(const Containers::String& name) const { + auto* prop = m_properties.Find(name); + if (prop && prop->type == MaterialPropertyType::Float) { + return prop->value.floatValue[0]; + } + return 0.0f; +} + +Math::Vector2 Material::GetFloat2(const Containers::String& name) const { + auto* prop = m_properties.Find(name); + if (prop && prop->type == MaterialPropertyType::Float2) { + return Math::Vector2(prop->value.floatValue[0], prop->value.floatValue[1]); + } + return Math::Vector2::Zero(); +} + +Math::Vector3 Material::GetFloat3(const Containers::String& name) const { + auto* prop = m_properties.Find(name); + if (prop && prop->type == MaterialPropertyType::Float3) { + return Math::Vector3(prop->value.floatValue[0], prop->value.floatValue[1], prop->value.floatValue[2]); + } + return Math::Vector3::Zero(); +} + +Math::Vector4 Material::GetFloat4(const Containers::String& name) const { + auto* prop = m_properties.Find(name); + if (prop && prop->type == MaterialPropertyType::Float4) { + return Math::Vector4(prop->value.floatValue[0], prop->value.floatValue[1], + prop->value.floatValue[2], prop->value.floatValue[3]); + } + return Math::Vector4::Zero(); +} + +Core::int32 Material::GetInt(const Containers::String& name) const { + auto* prop = m_properties.Find(name); + if (prop && prop->type == MaterialPropertyType::Int) { + return prop->value.intValue[0]; + } + return 0; +} + +bool Material::GetBool(const Containers::String& name) const { + auto* prop = m_properties.Find(name); + if (prop && prop->type == MaterialPropertyType::Bool) { + return prop->value.boolValue; + } + return false; +} + +ResourceHandle Material::GetTexture(const Containers::String& name) const { + for (const auto& binding : m_textureBindings) { + if (binding.name == name) { + return binding.texture; + } + } + return ResourceHandle(); +} + +void Material::UpdateConstantBuffer() { + m_constantBufferData.Clear(); +} + +bool Material::HasProperty(const Containers::String& name) const { + return m_properties.Contains(name); +} + +void Material::RemoveProperty(const Containers::String& name) { + m_properties.Erase(name); +} + +void Material::ClearAllProperties() { + m_properties.Clear(); + m_textureBindings.Clear(); + m_constantBufferData.Clear(); +} + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Resources/MaterialLoader.cpp b/engine/src/Resources/MaterialLoader.cpp new file mode 100644 index 00000000..efeb3ffd --- /dev/null +++ b/engine/src/Resources/MaterialLoader.cpp @@ -0,0 +1,73 @@ +#include "Resources/MaterialLoader.h" +#include "Resources/ResourceManager.h" +#include "Resources/ResourceTypes.h" + +namespace XCEngine { +namespace Resources { + +MaterialLoader::MaterialLoader() = default; + +MaterialLoader::~MaterialLoader() = default; + +Containers::Array MaterialLoader::GetSupportedExtensions() const { + Containers::Array extensions; + extensions.PushBack("mat"); + extensions.PushBack("material"); + extensions.PushBack("json"); + return extensions; +} + +bool MaterialLoader::CanLoad(const Containers::String& path) const { + Containers::String ext = GetExtension(path); + return ext == "mat" || ext == "material" || ext == "json"; +} + +LoadResult MaterialLoader::Load(const Containers::String& path, const ImportSettings* settings) { + Containers::Array data = ReadFileData(path); + if (data.Empty()) { + return LoadResult("Failed to read material file: " + path); + } + + Material* material = new Material(); + material->m_path = path; + material->m_name = path; + material->m_guid = ResourceGUID::Generate(path); + + Containers::String jsonStr; + jsonStr.Reserve(data.Size()); + for (size_t i = 0; i < data.Size(); ++i) { + jsonStr += static_cast(data[i]); + } + + size_t shaderPos = jsonStr.Find("\"shader\""); + if (shaderPos != Containers::String::npos) { + size_t colonPos = jsonStr.Find(":", shaderPos); + if (colonPos != Containers::String::npos) { + size_t quoteStart = jsonStr.Find("\"", colonPos); + size_t quoteEnd = jsonStr.Find("\"", quoteStart + 1); + if (quoteStart != Containers::String::npos && quoteEnd != Containers::String::npos) { + Containers::String shaderPath = jsonStr.Substring(quoteStart + 1, quoteEnd - quoteStart - 1); + auto shaderHandle = ResourceManager::Get().Load(shaderPath); + if (shaderHandle.IsValid()) { + material->SetShader(shaderHandle); + } + } + } + } + + material->m_isValid = true; + material->m_memorySize = sizeof(Material) + material->m_name.Length() + material->m_path.Length(); + + return LoadResult(material); +} + +ImportSettings* MaterialLoader::GetDefaultSettings() const { + return nullptr; +} + +bool MaterialLoader::ParseMaterialData(const Containers::Array& data, Material* material) { + return true; +} + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Resources/Mesh.cpp b/engine/src/Resources/Mesh.cpp new file mode 100644 index 00000000..243d1e3e --- /dev/null +++ b/engine/src/Resources/Mesh.cpp @@ -0,0 +1,44 @@ +#include "Resources/Mesh.h" +#include + +namespace XCEngine { +namespace Resources { + +Mesh::Mesh() = default; +Mesh::~Mesh() = default; + +void Mesh::Release() { + m_vertexData.Clear(); + m_indexData.Clear(); + m_sections.Clear(); + SetInvalid(); +} + +void Mesh::SetVertexData(const void* data, size_t size, Core::uint32 vertexCount, + Core::uint32 vertexStride, VertexAttribute attributes) { + m_vertexCount = vertexCount; + m_vertexStride = vertexStride; + m_attributes = attributes; + + m_vertexData.Resize(size); + std::memcpy(m_vertexData.Data(), data, size); + + m_memorySize += size; +} + +void Mesh::SetIndexData(const void* data, size_t size, Core::uint32 indexCount, bool use32Bit) { + m_indexCount = indexCount; + m_use32BitIndex = use32Bit; + + m_indexData.Resize(size); + std::memcpy(m_indexData.Data(), data, size); + + m_memorySize += size; +} + +void Mesh::AddSection(const MeshSection& section) { + m_sections.PushBack(section); +} + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Resources/MeshLoader.cpp b/engine/src/Resources/MeshLoader.cpp new file mode 100644 index 00000000..a9700a55 --- /dev/null +++ b/engine/src/Resources/MeshLoader.cpp @@ -0,0 +1,64 @@ +#include "Resources/MeshLoader.h" +#include "Resources/ResourceManager.h" + +namespace XCEngine { +namespace Resources { + +MeshLoader::MeshLoader() = default; +MeshLoader::~MeshLoader() = default; + +Containers::Array MeshLoader::GetSupportedExtensions() const { + Containers::Array extensions; + extensions.PushBack(Containers::String("fbx")); + extensions.PushBack(Containers::String("obj")); + extensions.PushBack(Containers::String("gltf")); + extensions.PushBack(Containers::String("glb")); + extensions.PushBack(Containers::String("dae")); + extensions.PushBack(Containers::String("stl")); + return extensions; +} + +bool MeshLoader::CanLoad(const Containers::String& path) const { + Containers::String ext = GetExtension(path); + ext.ToLower(); + + return ext == "fbx" || ext == "obj" || ext == "gltf" || + ext == "glb" || ext == "dae" || ext == "stl"; +} + +LoadResult MeshLoader::Load(const Containers::String& path, const ImportSettings* settings) { + (void)settings; + + Containers::String ext = GetExtension(path); + ext.ToLower(); + + if (!CanLoad(path)) { + return LoadResult(Containers::String("Unsupported mesh format: ") + ext); + } + + Containers::Array fileData = ReadFileData(path); + if (fileData.Empty()) { + return LoadResult(Containers::String("Failed to read file: ") + path); + } + + auto* mesh = new Mesh(); + + IResource::ConstructParams params; + params.name = path; + params.path = path; + params.guid = ResourceGUID::Generate(path); + params.memorySize = fileData.Size(); + + mesh->Initialize(params); + + return LoadResult(mesh); +} + +ImportSettings* MeshLoader::GetDefaultSettings() const { + return nullptr; +} + +REGISTER_RESOURCE_LOADER(MeshLoader); + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Resources/ResourceManager.cpp b/engine/src/Resources/ResourceManager.cpp index 4555342e..18d0c7b2 100644 --- a/engine/src/Resources/ResourceManager.cpp +++ b/engine/src/Resources/ResourceManager.cpp @@ -65,12 +65,12 @@ Core::uint32 ResourceManager::GetRefCount(ResourceGUID guid) const { void ResourceManager::RegisterLoader(IResourceLoader* loader) { std::lock_guard lock(m_mutex); - m_loaders.Insert(loader->GetResourceType(), Core::MakeUnique(loader)); + m_loaders.Insert(loader->GetResourceType(), loader); } IResourceLoader* ResourceManager::GetLoader(ResourceType type) const { auto* it = m_loaders.Find(type); - return it != nullptr ? it->get() : nullptr; + return it != nullptr ? *it : nullptr; } IResourceLoader* ResourceManager::FindLoader(ResourceType type) { diff --git a/engine/src/Resources/Shader.cpp b/engine/src/Resources/Shader.cpp new file mode 100644 index 00000000..ac5389e5 --- /dev/null +++ b/engine/src/Resources/Shader.cpp @@ -0,0 +1,40 @@ +#include "Resources/Shader.h" + +namespace XCEngine { +namespace Resources { + +Shader::Shader() = default; + +Shader::~Shader() = default; + +void Shader::Release() { + m_sourceCode.Clear(); + m_compiledBinary.Clear(); + m_uniforms.Clear(); + m_attributes.Clear(); + m_rhiResource = nullptr; + m_isValid = false; +} + +void Shader::SetSourceCode(const Containers::String& source) { + m_sourceCode = source; +} + +void Shader::SetCompiledBinary(const Containers::Array& binary) { + m_compiledBinary = binary; +} + +void Shader::AddUniform(const ShaderUniform& uniform) { + m_uniforms.PushBack(uniform); +} + +void Shader::AddAttribute(const ShaderAttribute& attribute) { + m_attributes.PushBack(attribute); +} + +void Shader::SetRHIResource(class IRHIShader* resource) { + m_rhiResource = resource; +} + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Resources/ShaderLoader.cpp b/engine/src/Resources/ShaderLoader.cpp new file mode 100644 index 00000000..0302b74a --- /dev/null +++ b/engine/src/Resources/ShaderLoader.cpp @@ -0,0 +1,85 @@ +#include "Resources/ShaderLoader.h" +#include "Resources/ResourceManager.h" +#include "Resources/ResourceTypes.h" + +namespace XCEngine { +namespace Resources { + +ShaderLoader::ShaderLoader() = default; + +ShaderLoader::~ShaderLoader() = default; + +Containers::Array ShaderLoader::GetSupportedExtensions() const { + Containers::Array extensions; + extensions.PushBack("vert"); + extensions.PushBack("frag"); + extensions.PushBack("geom"); + extensions.PushBack("comp"); + extensions.PushBack("glsl"); + extensions.PushBack("hlsl"); + extensions.PushBack("shader"); + return extensions; +} + +bool ShaderLoader::CanLoad(const Containers::String& path) const { + Containers::String ext = GetExtension(path); + return ext == "vert" || ext == "frag" || ext == "geom" || + ext == "comp" || ext == "glsl" || ext == "hlsl" || ext == "shader"; +} + +LoadResult ShaderLoader::Load(const Containers::String& path, const ImportSettings* settings) { + Containers::Array data = ReadFileData(path); + if (data.Empty()) { + return LoadResult("Failed to read shader file: " + path); + } + + Containers::String source; + source.Reserve(data.Size()); + for (size_t i = 0; i < data.Size(); ++i) { + source += static_cast(data[i]); + } + + Shader* shader = new Shader(); + shader->m_path = path; + shader->m_name = path; + shader->m_guid = ResourceGUID::Generate(path); + + Containers::String ext = GetExtension(path); + if (ext == "hlsl") { + shader->SetShaderLanguage(ShaderLanguage::HLSL); + } else { + shader->SetShaderLanguage(ShaderLanguage::GLSL); + } + + ShaderType shaderType = DetectShaderType(path, source); + shader->SetShaderType(shaderType); + shader->SetSourceCode(source); + + shader->m_isValid = true; + shader->m_memorySize = sizeof(Shader) + shader->m_name.Length() + + shader->m_path.Length() + source.Length(); + + return LoadResult(shader); +} + +ImportSettings* ShaderLoader::GetDefaultSettings() const { + return nullptr; +} + +ShaderType ShaderLoader::DetectShaderType(const Containers::String& path, const Containers::String& source) { + Containers::String ext = GetExtension(path); + + if (ext == "vert") return ShaderType::Vertex; + if (ext == "frag") return ShaderType::Fragment; + if (ext == "geom") return ShaderType::Geometry; + if (ext == "comp") return ShaderType::Compute; + + return ShaderType::Fragment; +} + +bool ShaderLoader::ParseShaderSource(const Containers::String& source, Shader* shader) { + return true; +} + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Resources/Texture.cpp b/engine/src/Resources/Texture.cpp new file mode 100644 index 00000000..0db2ad3c --- /dev/null +++ b/engine/src/Resources/Texture.cpp @@ -0,0 +1,40 @@ +#include "Resources/Texture.h" +#include + +namespace XCEngine { +namespace Resources { + +Texture::Texture() = default; +Texture::~Texture() = default; + +void Texture::Release() { + m_pixelData.Clear(); + SetInvalid(); +} + +bool Texture::Create(Core::uint32 width, Core::uint32 height, Core::uint32 depth, + Core::uint32 mipLevels, TextureType type, TextureFormat format, + const void* data, size_t dataSize) { + m_width = width; + m_height = height; + m_depth = depth; + m_mipLevels = mipLevels; + m_textureType = type; + m_format = format; + + if (data && dataSize > 0) { + m_pixelData.Resize(dataSize); + std::memcpy(m_pixelData.Data(), data, dataSize); + } + + m_memorySize = dataSize; + + return true; +} + +bool Texture::GenerateMipmaps() { + return false; +} + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Resources/TextureLoader.cpp b/engine/src/Resources/TextureLoader.cpp new file mode 100644 index 00000000..4f21f428 --- /dev/null +++ b/engine/src/Resources/TextureLoader.cpp @@ -0,0 +1,67 @@ +#include "Resources/TextureLoader.h" +#include "Resources/ResourceManager.h" + +namespace XCEngine { +namespace Resources { + +TextureLoader::TextureLoader() = default; +TextureLoader::~TextureLoader() = default; + +Containers::Array TextureLoader::GetSupportedExtensions() const { + Containers::Array extensions; + extensions.PushBack(Containers::String("png")); + extensions.PushBack(Containers::String("jpg")); + extensions.PushBack(Containers::String("jpeg")); + extensions.PushBack(Containers::String("tga")); + extensions.PushBack(Containers::String("bmp")); + extensions.PushBack(Containers::String("gif")); + extensions.PushBack(Containers::String("hdr")); + extensions.PushBack(Containers::String("dds")); + return extensions; +} + +bool TextureLoader::CanLoad(const Containers::String& path) const { + Containers::String ext = GetExtension(path); + ext.ToLower(); + + return ext == "png" || ext == "jpg" || ext == "jpeg" || + ext == "tga" || ext == "bmp" || ext == "gif" || + ext == "hdr" || ext == "dds"; +} + +LoadResult TextureLoader::Load(const Containers::String& path, const ImportSettings* settings) { + (void)settings; + + Containers::String ext = GetExtension(path); + ext.ToLower(); + + if (!CanLoad(path)) { + return LoadResult(Containers::String("Unsupported texture format: ") + ext); + } + + Containers::Array fileData = ReadFileData(path); + if (fileData.Empty()) { + return LoadResult(Containers::String("Failed to read file: ") + path); + } + + auto* texture = new Texture(); + + IResource::ConstructParams params; + params.name = path; + params.path = path; + params.guid = ResourceGUID::Generate(path); + params.memorySize = fileData.Size(); + + texture->Initialize(params); + + return LoadResult(texture); +} + +ImportSettings* TextureLoader::GetDefaultSettings() const { + return nullptr; +} + +REGISTER_RESOURCE_LOADER(TextureLoader); + +} // namespace Resources +} // namespace XCEngine diff --git a/tests/Resources/test_resource_guid.cpp b/tests/Resources/test_resource_guid.cpp index 05d27b50..09fdcbcd 100644 --- a/tests/Resources/test_resource_guid.cpp +++ b/tests/Resources/test_resource_guid.cpp @@ -1,7 +1,9 @@ #include #include +#include using namespace XCEngine::Resources; +using namespace XCEngine::Containers; namespace { @@ -26,7 +28,7 @@ TEST(Resources_GUID, Generate_FromCString) { } TEST(Resources_GUID, Generate_FromString) { - Containers::String path = "models/player.fbx"; + String path = "models/player.fbx"; ResourceGUID guid = ResourceGUID::Generate(path); EXPECT_TRUE(guid.IsValid()); } @@ -40,9 +42,9 @@ TEST(Resources_GUID, Generate_DifferentPaths) { TEST(Resources_GUID, ToString) { ResourceGUID guid(0x1234567890ABCDEF); - Containers::String str = guid.ToString(); + String str = guid.ToString(); - EXPECT_EQ(str.Size(), 16u); + EXPECT_EQ(str.Length(), 16u); } TEST(Resources_GUID, MakeResourceGUID_Helper) { diff --git a/tests/Resources/test_resource_types.cpp b/tests/Resources/test_resource_types.cpp index 6d4e0a3c..29de3ab7 100644 --- a/tests/Resources/test_resource_types.cpp +++ b/tests/Resources/test_resource_types.cpp @@ -1,18 +1,19 @@ #include #include +#include using namespace XCEngine::Resources; namespace { TEST(Resources_Types, ResourceType_EnumValues) { - EXPECT_EQ(static_cast(ResourceType::Unknown), 0); - EXPECT_EQ(static_cast(ResourceType::Texture), 1); - EXPECT_EQ(static_cast(ResourceType::Mesh), 2); - EXPECT_EQ(static_cast(ResourceType::Material), 3); - EXPECT_EQ(static_cast(ResourceType::Shader), 4); - EXPECT_EQ(static_cast(ResourceType::AudioClip), 5); - EXPECT_EQ(static_cast(ResourceType::Binary), 6); + EXPECT_EQ(static_cast(ResourceType::Unknown), 0); + EXPECT_EQ(static_cast(ResourceType::Texture), 1); + EXPECT_EQ(static_cast(ResourceType::Mesh), 2); + EXPECT_EQ(static_cast(ResourceType::Material), 3); + EXPECT_EQ(static_cast(ResourceType::Shader), 4); + EXPECT_EQ(static_cast(ResourceType::AudioClip), 5); + EXPECT_EQ(static_cast(ResourceType::Binary), 6); } TEST(Resources_Types, GetResourceTypeName) {