diff --git a/CMakeLists.txt b/CMakeLists.txt index 57a10372..f17c74e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,9 @@ set(SOURCE_FILES MobileGL/MG_State/GLState/BufferState/BufferObject.cpp MobileGL/MG_State/GLState/VertexArrayState/VertexArrayState.cpp MobileGL/MG_State/GLState/VertexArrayState/VertexArrayObject.cpp + MobileGL/MG_State/GLState/TextureState/TextureObject.cpp + MobileGL/MG_State/GLState/TextureState/TextureUnit.cpp + MobileGL/MG_State/GLState/TextureState/TextureState.cpp ) add_library(${CMAKE_PROJECT_NAME} SHARED diff --git a/MobileGL/MG_State/GLState/Core.cpp b/MobileGL/MG_State/GLState/Core.cpp index 46ce47f5..1f97e7c7 100644 --- a/MobileGL/MG_State/GLState/Core.cpp +++ b/MobileGL/MG_State/GLState/Core.cpp @@ -8,7 +8,7 @@ namespace MobileGL { m_errorState.RecordError(code, info); } - bool GLContext::HasGLError() const { + Bool GLContext::HasGLError() const { return m_errorState.HasGLError(); } @@ -20,7 +20,7 @@ namespace MobileGL { return m_errorState.PopGLError(); } - bool GLContext::HasNonGLError() const { + Bool GLContext::HasNonGLError() const { return m_errorState.HasNonGLError(); } @@ -79,11 +79,11 @@ namespace MobileGL { m_bufferState.MarkBufferObjectForDeletion(index); } - bool GLContext::ValidateBufferName(Uint index) const { + Bool GLContext::ValidateBufferName(Uint index) const { return m_bufferState.ValidateName(index); } - bool GLContext::ValidateBufferObject(Uint index) const { + Bool GLContext::ValidateBufferObject(Uint index) const { return m_bufferState.ValidateBufferObject(index); } @@ -108,17 +108,54 @@ namespace MobileGL { m_vertexArrayState.MarkVertexArrayForDeletion(index); } - bool GLContext::ValidateVertexArrayName(Uint index) const { + Bool GLContext::ValidateVertexArrayName(Uint index) const { return m_vertexArrayState.ValidateName(index); } - bool GLContext::ValidateVertexArrayObject(Uint index) const { + Bool GLContext::ValidateVertexArrayObject(Uint index) const { return m_vertexArrayState.ValidateVertexArrayObject(index); } SharedPtr GLContext::GetBoundVertexArray() { return m_vertexArrayState.GetBoundVertexArray(); } + // Texture + Vector GLContext::GenTextureNames(Uint number) { + return m_textureState.GenerateNames(number); + } + + SharedPtr GLContext::GetTextureObject(Uint index) { + return m_textureState.GetTextureObject(index); + } + + SharedPtr GLContext::CreateTextureObject(Uint index, TextureTarget target) { + return m_textureState.CreateTextureObject(index, target); + } + + void GLContext::MarkTextureObjectForDeletion(Uint index) { + m_textureState.MarkTextureObjectForDeletion(index); + } + + TextureUnit& GLContext::GetTextureUnitObject() { + return m_textureState.GetUnitObject(); + } + + Bool GLContext::ValidateTextureName(Uint index) const { + return m_textureState.ValidateName(index); + } + + Bool GLContext::ValidateTextureObject(Uint index) const { + return m_textureState.ValidateTextureObject(index); + } + + Int GLContext::GetActiveTextureUnit() const { + return m_textureState.GetActiveTextureUnit(); + } + + void GLContext::SetActiveTextureUnit(Int unit) { + m_textureState.SetActiveTextureUnit(unit); + } + } // namespace GLState GLState::GLContext* pGLContext; diff --git a/MobileGL/MG_State/GLState/Core.h b/MobileGL/MG_State/GLState/Core.h index 2add10ee..fe013a5a 100644 --- a/MobileGL/MG_State/GLState/Core.h +++ b/MobileGL/MG_State/GLState/Core.h @@ -1,9 +1,11 @@ #pragma once #include #include "BufferState/BufferState.h" +#include "MG_Util/Types.h" #include "VertexArrayState/VertexArrayState.h" #include "ErrorState/Error.h" #include "ProgramState/ProgramState.h" +#include "TextureState/TextureState.h" namespace MobileGL { namespace MG_State { @@ -14,10 +16,10 @@ namespace MobileGL { // Error void RecordError(ErrorCode code, SharedPtr info = nullptr); - bool HasGLError() const; + Bool HasGLError() const; Optional PeekGLError() const; Optional PopGLError(); - bool HasNonGLError() const; + Bool HasNonGLError() const; Optional PeekNonGLError() const; Optional PopNonGLError(); void ClearErrors(); @@ -28,8 +30,8 @@ namespace MobileGL { BindingSlot& GetBufferBindingSlot(BufferTarget target); SharedPtr CreateBufferObject(Uint index); void MarkBufferObjectForDeletion(Uint index); - bool ValidateBufferName(Uint index) const; - bool ValidateBufferObject(Uint index) const; + Bool ValidateBufferName(Uint index) const; + Bool ValidateBufferObject(Uint index) const; // VertexArray Vector GenVertexArrayNames(Uint number); @@ -37,10 +39,21 @@ namespace MobileGL { void BindVertexArray(Uint index); SharedPtr CreateVertexArrayObject(Uint index); void MarkVertexArrayForDeletion(Uint index); - bool ValidateVertexArrayName(Uint index) const; - bool ValidateVertexArrayObject(Uint index) const; + Bool ValidateVertexArrayName(Uint index) const; + Bool ValidateVertexArrayObject(Uint index) const; SharedPtr GetBoundVertexArray(); + // Texture + Vector GenTextureNames(Uint number); + SharedPtr GetTextureObject(Uint index); + SharedPtr CreateTextureObject(Uint index, TextureTarget target); + void MarkTextureObjectForDeletion(Uint index); + TextureUnit& GetTextureUnitObject(); + Bool ValidateTextureName(Uint index) const; + Bool ValidateTextureObject(Uint index) const; + Int GetActiveTextureUnit() const; + void SetActiveTextureUnit(Int unit); + private: // Error ErrorState m_errorState; @@ -50,6 +63,9 @@ namespace MobileGL { // VertexArray VertexArrayState m_vertexArrayState; + + // Texture + TextureState m_textureState; }; } // namespace GLState diff --git a/MobileGL/MG_State/GLState/TextureState/SamplerObject.h b/MobileGL/MG_State/GLState/TextureState/SamplerObject.h new file mode 100644 index 00000000..ced34b58 --- /dev/null +++ b/MobileGL/MG_State/GLState/TextureState/SamplerObject.h @@ -0,0 +1,100 @@ +#pragma once +#include "MG_Util/Types.h" +#include + +namespace MobileGL { + enum class SamplerFilterMode { + Nearest, + Linear, + SamplerFilterCount, + Unknown = -1 + }; + + enum class SamplerMipmapMode { + None, + Nearest, + SamplerMipmapModeCount, + Unknown = -1 + }; + + enum class SamplerWrapMode { + ClampToEdge, + MirroredRepeat, + Repeat, + ClampToBorder, + SamplerWrapModeCount, + Unknown = -1 + }; + + enum class SamplerCompareMode { + None, + CompareToTexture, + SamplerCompareModeCount, + Unknown = -1 + }; + + enum class CompareFunc { + Never, + Less, + Equal, + LessEqual, + Greater, + NotEqual, + GreaterEqual, + Always, + CompareFuncCount, + Unknown = -1 + }; + + namespace MG_State { + namespace GLState { + class SamplerObject { + public: + SamplerObject() + : m_wrapS(SamplerWrapMode::Repeat), m_wrapT(SamplerWrapMode::Repeat), + m_wrapR(SamplerWrapMode::Repeat), m_minFilter(SamplerFilterMode::Linear), + m_magFilter(SamplerFilterMode::Linear), m_mipmapMode(SamplerMipmapMode::None), m_minLod(0.0f), + m_maxLod(1000.0f), m_lodBias(0.0f), m_compareMode(SamplerCompareMode::None), + m_compareFunc(CompareFunc::Less) {} + + void SetWrapS(SamplerWrapMode mode) { m_wrapS = mode; } + void SetWrapT(SamplerWrapMode mode) { m_wrapT = mode; } + void SetWrapR(SamplerWrapMode mode) { m_wrapR = mode; } + void SetMinFilter(SamplerFilterMode mode) { m_minFilter = mode; } + void SetMagFilter(SamplerFilterMode mode) { m_magFilter = mode; } + void SetMipmapMode(SamplerMipmapMode mode) { m_mipmapMode = mode; } + void SetLodRange(Float minLod, Float maxLod) { + if (minLod > maxLod) { + THROW_EXCEPTION("minLod cannot be greater than maxLod"); + } + m_minLod = minLod; + m_maxLod = maxLod; + } + void SetLodBias(Float bias) { m_lodBias = bias; } + void SetCompareFunc(CompareFunc func) { m_compareFunc = func; } + void SetCompareMode(SamplerCompareMode mode) { m_compareMode = mode; } + + SamplerWrapMode GetWrapS() const { return m_wrapS; } + SamplerWrapMode GetWrapT() const { return m_wrapT; } + SamplerWrapMode GetWrapR() const { return m_wrapR; } + SamplerFilterMode GetMinFilter() const { return m_minFilter; } + SamplerFilterMode GetMagFilter() const { return m_magFilter; } + SamplerMipmapMode GetMipmapMode() const { return m_mipmapMode; } + Float GetMinLod() const { return m_minLod; } + Float GetMaxLod() const { return m_maxLod; } + Float GetLodBias() const { return m_lodBias; } + SamplerCompareMode GetCompareMode() const { return m_compareMode; } + CompareFunc GetCompareFunc() const { return m_compareFunc; } + + private: + SamplerWrapMode m_wrapS, m_wrapT, m_wrapR; + SamplerFilterMode m_minFilter, m_magFilter; + SamplerMipmapMode m_mipmapMode; + Float m_minLod, m_maxLod; + Float m_lodBias; + SamplerCompareMode m_compareMode; + CompareFunc m_compareFunc; + }; + } // namespace GLState + } // namespace MG_State +} // namespace MobileGL \ No newline at end of file diff --git a/MobileGL/MG_State/GLState/TextureState/TextureObject.cpp b/MobileGL/MG_State/GLState/TextureState/TextureObject.cpp new file mode 100644 index 00000000..237c4a56 --- /dev/null +++ b/MobileGL/MG_State/GLState/TextureState/TextureObject.cpp @@ -0,0 +1,72 @@ +#include "TextureObject.h" +#include + +namespace MobileGL { + namespace MG_State { + namespace GLState { + // TextureObjectBase implementations + TextureObjectBase::TextureObjectBase(TextureTarget target) : m_target(target), m_sampler(nullptr) {} + + void TextureObjectBase::SetMipmapLevel(const MipmapLevelInput& level) { + SetMipmapImpl(level); + } + + TextureSizedInternalFormat TextureObjectBase::GetFormat() const { + return m_internalFormat; + } + + TextureTarget TextureObjectBase::GetTarget() const { + return m_target; + } + + IntVec3 TextureObjectBase::GetBaseSize() const { + if (m_mipmaps.empty()) { + return {0, 0, 0}; + } + return m_mipmaps[0].size; + } + + SharedPtr TextureObjectBase::GetSamplerObject() const { + return m_sampler; + } + + const Vector& TextureObjectBase::GetMipmaps() const { + return m_mipmaps; + } + + void TextureObjectBase::SetInternalFormat(TextureSizedInternalFormat format) { + m_internalFormat = format; + } + + // TextureObject1D + TextureObject1D::TextureObject1D() : TextureObjectBase(TextureTarget::Texture1D) {} + + void TextureObject1D::SetMipmapImpl(const MipmapLevelInput& level) { + if (level.size.x() > 0) { + m_mipmaps.push_back(level); + } + } + + // TextureObject2D + TextureObject2D::TextureObject2D() : TextureObjectBase(TextureTarget::Texture2D) {} + + void TextureObject2D::SetMipmapImpl(const MipmapLevelInput& level) { + if (level.size.x() > 0 && level.size.y() > 0) { + m_mipmaps.push_back(level); + } + } + + // TextureObject3D + TextureObject3D::TextureObject3D() : TextureObjectBase(TextureTarget::Texture3D) {} + + void TextureObject3D::SetMipmapImpl(const MipmapLevelInput& level) { + if (level.size.x() > 0 && level.size.y() > 0 && level.size.z() > 0) { + m_mipmaps.push_back(level); + } + } + + // TODO: Add other texture types as needed + + } // namespace GLState + } // namespace MG_State +} // namespace MobileGL diff --git a/MobileGL/MG_State/GLState/TextureState/TextureObject.h b/MobileGL/MG_State/GLState/TextureState/TextureObject.h new file mode 100644 index 00000000..6c04d3d4 --- /dev/null +++ b/MobileGL/MG_State/GLState/TextureState/TextureObject.h @@ -0,0 +1,221 @@ +#pragma once +#include +#include +#include "MG_Util/Types.h" +#include "SamplerObject.h" + +namespace MobileGL { + enum class TextureTarget { + Texture1D, + Texture2D, + Texture3D, + TextureCubeMap, + Texture2DArray, + Texture2DMultisample, + TextureCubeMapArray, + TextureTargetCount, + Unknown = -1 + }; + + enum class TextureInputFormat { + Red, + RG, + RGB, + BFR, + RGBA, + BGRA, + RInteger, + RGInteger, + RGBInteger, + BGRInteger, + RGBAInteger, + BGRAInteger, + StencilIndex, + DepthComponent, + DepthStencil, + + FormatCount, + Unknown = -1 + }; + + enum class TextureSizedInternalFormat { + R8, + R8Snorm, + R16, + R16Snorm, + RG8, + RG8Snorm, + RG16, + RG16Snorm, + R3G3B2, + RGB4, + RGB5, + RGB8, + RGB8Snorm, + RGB10, + RGB12, + RGB16Snorm, + RGBA2, + RGBA4, + RGB5A1, + RGBA8, + RGBA8Snorm, + RGB10A2, + RGB10A2UI, + RGBA12, + RGBA16, + SRGB8, + SRGB8Alpha8, + R16F, + RG16F, + RGB16F, + RGBA16F, + R32F, + RG32F, + RGB32F, + RGBA32F, + R11FG11FB10F, + RGB9E5, + R8I, + R8UI, + R16I, + R16UI, + R32I, + R32UI, + RG8I, + RG8UI, + RG16I, + RG16UI, + RG32I, + RG32UI, + RGB8I, + RGB8UI, + RGB16I, + RGB16UI, + RGB32I, + RGB32UI, + RGBA8I, + RGBA8UI, + RGBA16I, + RGBA16UI, + RGBA32I, + RGBA32UI, + + TextureSizedInternalFormatCount, + Unknown = -1 + }; + + enum class TexturePixelDataType { + UnsignedByte, + Byte, + UnsignedShort, + Short, + UnsignedInt, + Int, + Float, + UnsignedByte332, + UnsignedByte233Rev, + UnsignedShort565, + UnsignedShort565Rev, + UnsignedShort4444, + UnsignedShort4444Rev, + UnsignedShort5551, + UnsignedShort1555Rev, + UnsignedInt8888, + UnsignedInt8888Rev, + UnsignedInt1010102, + UnsignedInt2101010Rev, + + TypeCount, + Unknown = -1 + }; + + namespace MG_State { + namespace GLState { + struct MipmapLevelBase { + IntVec3 size = {0, 0, 0}; + Int level = 0; + Bool compressed = false; + Int compressedSize = 0; + }; + + struct MipmapLevelInput : MipmapLevelBase { + DataPtr inputData = {nullptr, 0}; + }; + + struct MipmapLevelInternal : MipmapLevelBase { + Data data; + + MipmapLevelInternal(const MipmapLevelInput& input) : MipmapLevelBase(input) { + if (input.inputData.data && input.inputData.size > 0) { + const Uint8* src = static_cast(input.inputData.data); + data.assign(src, src + input.inputData.size); + } + } + }; + + class ITextureObject { + public: + using TargetEnum = TextureTarget; + virtual ~ITextureObject() = default; + + virtual void SetMipmapLevel(const MipmapLevelInput& level) = 0; + virtual TextureSizedInternalFormat GetFormat() const = 0; + virtual TextureTarget GetTarget() const = 0; + virtual IntVec3 GetBaseSize() const = 0; + virtual SharedPtr GetSamplerObject() const = 0; + virtual const Vector& GetMipmaps() const = 0; + virtual void SetInternalFormat(TextureSizedInternalFormat format) = 0; + }; + + class TextureObjectBase : public ITextureObject { + public: + TextureObjectBase(TextureTarget target); + virtual ~TextureObjectBase() = default; + + void SetMipmapLevel(const MipmapLevelInput& level) override; + TextureSizedInternalFormat GetFormat() const override; + TextureTarget GetTarget() const override; + IntVec3 GetBaseSize() const override; + SharedPtr GetSamplerObject() const override; + const Vector& GetMipmaps() const override; + void SetInternalFormat(TextureSizedInternalFormat format) override; + + protected: + virtual void SetMipmapImpl(const MipmapLevelInput& level) = 0; + + const TextureTarget m_target = TextureTarget::Unknown; + TextureSizedInternalFormat m_internalFormat = TextureSizedInternalFormat::Unknown; + Vector m_mipmaps = {}; + SharedPtr m_sampler = nullptr; + }; + + class TextureObject1D : public TextureObjectBase { + public: + explicit TextureObject1D(); + + protected: + void SetMipmapImpl(const MipmapLevelInput& level) override; + }; + + class TextureObject2D : public TextureObjectBase { + public: + explicit TextureObject2D(); + + protected: + void SetMipmapImpl(const MipmapLevelInput& level) override; + }; + + class TextureObject3D : public TextureObjectBase { + public: + explicit TextureObject3D(); + + protected: + void SetMipmapImpl(const MipmapLevelInput& level) override; + }; + + // TODO: Add other texture types as needed + + } // namespace GLState + } // namespace MG_State +} // namespace MobileGL diff --git a/MobileGL/MG_State/GLState/TextureState/TextureState.cpp b/MobileGL/MG_State/GLState/TextureState/TextureState.cpp new file mode 100644 index 00000000..12800dcc --- /dev/null +++ b/MobileGL/MG_State/GLState/TextureState/TextureState.cpp @@ -0,0 +1,91 @@ +#include "TextureState.h" +#include "MG_State/GLState/TextureState/TextureObject.h" +#include "MG_Util/Types.h" + +namespace MobileGL { + namespace MG_State { + namespace GLState { + TextureState::TextureState() : m_indexGenerator(1024, 1) { + for (int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i) { + m_textureUnits[i] = TextureUnit(); + } + } + + SharedPtr TextureState::GetTextureObject(Uint index) { + auto it = m_textureObjects.find(index); + if (it != m_textureObjects.end()) { + return it->second; + } + return nullptr; + } + + Vector TextureState::GenerateNames(Uint number) { + Vector textures(number); + m_indexGenerator.Generate(number, textures.data()); + return textures; + } + + SharedPtr TextureState::CreateTextureObject(Uint index, TextureTarget target) { + SharedPtr textureObject = nullptr; + switch (target) { + case TextureTarget::Texture1D: + textureObject = MakeShared(); + break; + case TextureTarget::Texture2D: + textureObject = MakeShared(); + break; + case TextureTarget::Texture3D: + textureObject = MakeShared(); + break; + default: + // TODO: implement more texture types + return nullptr; + } + + m_textureObjects[index] = textureObject; + return textureObject; + } + + void TextureState::MarkTextureObjectForDeletion(Uint index) { + if (m_indexGenerator.IsValid(index)) { + auto it = m_textureObjects.find(index); + if (it != m_textureObjects.end()) { + for (auto& unit : m_textureUnits) { + auto& bindingSlots = unit.GetAllBindingSlots(); + for (SizeT i = 0; i < bindingSlots.size(); ++i) { + if (bindingSlots[i].GetBoundObject() == it->second) { + bindingSlots[i].Bind(nullptr); + } + } + } + m_textureObjects.erase(it); + } + m_indexGenerator.Delete(index); + } + } + + TextureUnit& TextureState::GetUnitObject() { + if (m_activeTextureUnit < 0 || m_activeTextureUnit >= MAX_TEXTURE_IMAGE_UNITS) { + THROW_EXCEPTION("Active texture unit is out of range"); + } + return m_textureUnits[m_activeTextureUnit]; + } + + Int TextureState::GetActiveTextureUnit() const { + return m_activeTextureUnit; + } + + void TextureState::SetActiveTextureUnit(Int unit) { + m_activeTextureUnit = unit; + } + + Bool TextureState::ValidateName(Uint index) const { + return m_indexGenerator.IsValid(index); + } + + Bool TextureState::ValidateTextureObject(Uint index) const { + return m_textureObjects.find(index) != m_textureObjects.end(); + } + } // namespace GLState + } // namespace MG_State +} // namespace MobileGL diff --git a/MobileGL/MG_State/GLState/TextureState/TextureState.h b/MobileGL/MG_State/GLState/TextureState/TextureState.h new file mode 100644 index 00000000..0d143113 --- /dev/null +++ b/MobileGL/MG_State/GLState/TextureState/TextureState.h @@ -0,0 +1,35 @@ +#pragma once +#include +#include +#include "MG_State/GLState/TextureState/TextureObject.h" +#include "MG_Util/Types.h" +#include "TextureUnit.h" + +namespace MobileGL { + namespace MG_State { + namespace GLState { + + class TextureState { + public: + static constexpr int MAX_TEXTURE_IMAGE_UNITS = 32; + + TextureState(); + Vector GenerateNames(Uint number); + SharedPtr CreateTextureObject(Uint index, TextureTarget target); + SharedPtr GetTextureObject(Uint index); + TextureUnit& GetUnitObject(); + Int GetActiveTextureUnit() const; + void SetActiveTextureUnit(Int unit); + void MarkTextureObjectForDeletion(Uint index); + Bool ValidateName(Uint index) const; + Bool ValidateTextureObject(Uint index) const; + + private: + Int m_activeTextureUnit = 0; + Array m_textureUnits; + IndexGenerator m_indexGenerator; + UnorderedMap> m_textureObjects; + }; + } // namespace GLState + } // namespace MG_State +} // namespace MobileGL \ No newline at end of file diff --git a/MobileGL/MG_State/GLState/TextureState/TextureUnit.cpp b/MobileGL/MG_State/GLState/TextureState/TextureUnit.cpp new file mode 100644 index 00000000..487be899 --- /dev/null +++ b/MobileGL/MG_State/GLState/TextureState/TextureUnit.cpp @@ -0,0 +1,23 @@ +#include "TextureUnit.h" +#include "MG_Util/Types.h" + +namespace MobileGL { + namespace MG_State { + namespace GLState { + TextureUnit::TextureUnit() : m_sampler(nullptr) { + for (int i = 0; i < (int)TextureTarget::TextureTargetCount; ++i) { + m_slots[i] = BindingSlot(static_cast(i)); + } + } + + BindingSlot& TextureUnit::GetBindingSlot(TextureTarget target) { + return m_slots[(int)target]; + } + + Array, (int)TextureTarget::TextureTargetCount>& TextureUnit:: + GetAllBindingSlots() { + return m_slots; + } + } // namespace GLState + } // namespace MG_State +} // namespace MobileGL \ No newline at end of file diff --git a/MobileGL/MG_State/GLState/TextureState/TextureUnit.h b/MobileGL/MG_State/GLState/TextureState/TextureUnit.h new file mode 100644 index 00000000..3a9c829e --- /dev/null +++ b/MobileGL/MG_State/GLState/TextureState/TextureUnit.h @@ -0,0 +1,23 @@ +#pragma once +#include +#include "MG_State/GLState/TextureState/SamplerObject.h" +#include "MG_Util/Types.h" +#include "TextureObject.h" + +namespace MobileGL { + namespace MG_State { + namespace GLState { + class TextureUnit { + public: + TextureUnit(); + BindingSlot& GetBindingSlot(TextureTarget target); + SharedPtr GetSamplerObject() const; + Array, (int)TextureTarget::TextureTargetCount>& GetAllBindingSlots(); + + private: + Array, (int)TextureTarget::TextureTargetCount> m_slots; + SharedPtr m_sampler; + }; + } // namespace GLState + } // namespace MG_State +} // namespace MobileGL \ No newline at end of file diff --git a/MobileGL/MG_Util/Math/VectorTypes.h b/MobileGL/MG_Util/Math/VectorTypes.h new file mode 100644 index 00000000..2af329b8 --- /dev/null +++ b/MobileGL/MG_Util/Math/VectorTypes.h @@ -0,0 +1,191 @@ +#pragma once + +#include + +namespace MobileGL { + + template + struct VecBase { + Array data; + + VecBase() { std::fill(data.begin(), data.end(), T(0)); } + + VecBase(std::initializer_list init) { + std::copy_n(init.begin(), std::min(N, init.size()), data.begin()); + if (init.size() < N) { + std::fill(data.begin() + init.size(), data.end(), T(0)); + } + } + + explicit VecBase(T scalar) { std::fill(data.begin(), data.end(), scalar); } + + T& operator[](SizeT index) { + if (index >= N) throw std::out_of_range("Vector index out of range"); + return data[index]; + } + + const T& operator[](SizeT index) const { + if (index >= N) throw std::out_of_range("Vector index out of range"); + return data[index]; + } + + bool operator==(const VecBase& rhs) const { return data == rhs.data; } + bool operator!=(const VecBase& rhs) const { return !(*this == rhs); } + + Derived operator+(const VecBase& rhs) const { + Derived result; + for (SizeT i = 0; i < N; ++i) + result[i] = data[i] + rhs[i]; + return result; + } + + Derived operator-(const VecBase& rhs) const { + Derived result; + for (SizeT i = 0; i < N; ++i) + result[i] = data[i] - rhs[i]; + return result; + } + + Derived operator*(T scalar) const { + Derived result; + for (SizeT i = 0; i < N; ++i) + result[i] = data[i] * scalar; + return result; + } + + Derived operator/(T scalar) const { + if (scalar == 0) throw std::domain_error("Division by zero"); + T inv = T(1) / scalar; + return *this * inv; + } + + T Dot(const VecBase& rhs) const { + T result = T(0); + for (SizeT i = 0; i < N; ++i) + result += data[i] * rhs[i]; + return result; + } + + T Length() const { return std::sqrt(Dot(*this)); } + + Derived Normalized() const { + T len = Length(); + if (len > 0) { + return *this * (T(1) / len); + } + return static_cast(*this); + } + }; + + template + struct Vec2 : public VecBase, T, 2> { + using Base = VecBase, T, 2>; + using Base::Base; + + Vec2(T x, T y) : Base{x, y} {} + + T& x() { return (*this)[0]; } + T& y() { return (*this)[1]; } + const T& x() const { return (*this)[0]; } + const T& y() const { return (*this)[1]; } + + T Cross(const Vec2& rhs) const { return x() * rhs.y() - y() * rhs.x(); } + + Vec2 Rotated(T angle) const { + T cosA = std::cos(angle); + T sinA = std::sin(angle); + return {x() * cosA - y() * sinA, x() * sinA + y() * cosA}; + } + }; + + template + struct Vec3 : public VecBase, T, 3> { + using Base = VecBase, T, 3>; + using Base::Base; + + Vec3(T x, T y, T z) : Base{x, y, z} {} + explicit Vec3(const Vec2& v2, T z = T(0)) : Base{v2.x(), v2.y(), z} {} + + T& x() { return (*this)[0]; } + T& y() { return (*this)[1]; } + T& z() { return (*this)[2]; } + const T& x() const { return (*this)[0]; } + const T& y() const { return (*this)[1]; } + const T& z() const { return (*this)[2]; } + + Vec2 xy() const { return {x(), y()}; } + Vec2 xz() const { return {x(), z()}; } + Vec2 yz() const { return {y(), z()}; } + + Vec3 Cross(const Vec3& rhs) const { + return {y() * rhs.z() - z() * rhs.y(), z() * rhs.x() - x() * rhs.z(), x() * rhs.y() - y() * rhs.x()}; + } + }; + + template + struct Vec4 : public VecBase, T, 4> { + using Base = VecBase, T, 4>; + using Base::Base; + + Vec4(T x, T y, T z, T w) : Base{x, y, z, w} {} + explicit Vec4(const Vec3& v3, T w = T(1)) : Base{v3.x(), v3.y(), v3.z(), w} {} + + T& x() { return (*this)[0]; } + T& y() { return (*this)[1]; } + T& z() { return (*this)[2]; } + T& w() { return (*this)[3]; } + const T& x() const { return (*this)[0]; } + const T& y() const { return (*this)[1]; } + const T& z() const { return (*this)[2]; } + const T& w() const { return (*this)[3]; } + + Vec3 xyz() const { return {x(), y(), z()}; } + Vec3 Homogenized() const { return (w() != 0) ? xyz() / w() : xyz(); } + }; + + using IntVec2 = Vec2; + using IntVec3 = Vec3; + using IntVec4 = Vec4; + using UintVec2 = Vec2; + using UintVec3 = Vec3; + using UintVec4 = Vec4; + using FloatVec2 = Vec2; + using FloatVec3 = Vec3; + using FloatVec4 = Vec4; + + using Size2D = IntVec2; + using Size3D = IntVec3; + using TextureSize = IntVec3; + + using ColorRGB = FloatVec3; + using ColorRGBA = FloatVec4; + using ColorRGB8 = UintVec3; + using ColorRGBA8 = UintVec4; + + namespace MG_Util { + template + Derived Lerp(const VecBase& a, const VecBase& b, Float t) { + Derived result; + for (SizeT i = 0; i < N; ++i) + result[i] = a[i] + (b[i] - a[i]) * t; + return result; + } + + template + Derived MultiplyComponents(const VecBase& a, const VecBase& b) { + Derived result; + for (SizeT i = 0; i < N; ++i) + result[i] = a[i] * b[i]; + return result; + } + + template + T Distance(const VecBase& a, const VecBase& b) { + return (a - b).Length(); + } + + inline FloatVec3 Reflect(const FloatVec3& incident, const FloatVec3& normal) { + return incident - normal * (2.0f * incident.Dot(normal)); + } + } // namespace MG_Util +} // namespace MobileGL \ No newline at end of file diff --git a/MobileGL/MG_Util/Metrics/TextureMetrics.cpp b/MobileGL/MG_Util/Metrics/TextureMetrics.cpp new file mode 100644 index 00000000..9910d772 --- /dev/null +++ b/MobileGL/MG_Util/Metrics/TextureMetrics.cpp @@ -0,0 +1,85 @@ +#include "TextureMetrics.h" + +namespace MobileGL { + namespace MG_Util { + SizeT GetTexturePixelSize(TextureSizedInternalFormat internal) { + switch (internal) { + case TextureSizedInternalFormat::R8: + case TextureSizedInternalFormat::R8Snorm: + case TextureSizedInternalFormat::R8I: + case TextureSizedInternalFormat::R8UI: + return 1; + + case TextureSizedInternalFormat::R16: + case TextureSizedInternalFormat::R16Snorm: + case TextureSizedInternalFormat::R16I: + case TextureSizedInternalFormat::R16UI: + case TextureSizedInternalFormat::R16F: + case TextureSizedInternalFormat::RG8: + case TextureSizedInternalFormat::RG8Snorm: + case TextureSizedInternalFormat::RG8I: + case TextureSizedInternalFormat::RG8UI: + return 2; + + case TextureSizedInternalFormat::R3G3B2: + case TextureSizedInternalFormat::RGB4: + case TextureSizedInternalFormat::RGB5: + case TextureSizedInternalFormat::RGB8: + case TextureSizedInternalFormat::RGB8Snorm: + case TextureSizedInternalFormat::SRGB8: + case TextureSizedInternalFormat::RGB8I: + case TextureSizedInternalFormat::RGB8UI: + return 3; + + case TextureSizedInternalFormat::RGBA2: + case TextureSizedInternalFormat::RGBA4: + case TextureSizedInternalFormat::RGB5A1: + case TextureSizedInternalFormat::RGBA8: + case TextureSizedInternalFormat::RGBA8Snorm: + case TextureSizedInternalFormat::RGBA8I: + case TextureSizedInternalFormat::RGBA8UI: + case TextureSizedInternalFormat::SRGB8Alpha8: + case TextureSizedInternalFormat::RGB10A2: + case TextureSizedInternalFormat::RGB10A2UI: + case TextureSizedInternalFormat::R32F: + + case TextureSizedInternalFormat::RG16: + case TextureSizedInternalFormat::RG16Snorm: + case TextureSizedInternalFormat::RG16I: + case TextureSizedInternalFormat::RG16UI: + case TextureSizedInternalFormat::RG16F: + return 4; + + case TextureSizedInternalFormat::RGBA12: + case TextureSizedInternalFormat::RGBA16: + case TextureSizedInternalFormat::RGBA16I: + case TextureSizedInternalFormat::RGBA16UI: + case TextureSizedInternalFormat::RGBA16F: + case TextureSizedInternalFormat::RG32F: + case TextureSizedInternalFormat::RG32I: + case TextureSizedInternalFormat::RG32UI: + return 8; + + case TextureSizedInternalFormat::RGB16F: + case TextureSizedInternalFormat::RGB32F: + case TextureSizedInternalFormat::RGB16I: + case TextureSizedInternalFormat::RGB16UI: + case TextureSizedInternalFormat::RGB32I: + case TextureSizedInternalFormat::RGB32UI: + return 12; + + case TextureSizedInternalFormat::RGBA32F: + case TextureSizedInternalFormat::RGBA32I: + case TextureSizedInternalFormat::RGBA32UI: + return 16; + + case TextureSizedInternalFormat::R11FG11FB10F: + case TextureSizedInternalFormat::RGB9E5: + return 4; + + default: + return 0; + } + } + } // namespace MG_Util +} // namespace MobileGL diff --git a/MobileGL/MG_Util/Metrics/TextureMetrics.h b/MobileGL/MG_Util/Metrics/TextureMetrics.h new file mode 100644 index 00000000..e61296ab --- /dev/null +++ b/MobileGL/MG_Util/Metrics/TextureMetrics.h @@ -0,0 +1,9 @@ +#pragma once +#include +#include + +namespace MobileGL { + namespace MG_Util { + SizeT GetTexturePixelSize(TextureSizedInternalFormat internal); + } +} // namespace MobileGL