diff --git a/include/Nazara/Utility/Enums.hpp b/include/Nazara/Utility/Enums.hpp index 7ac18a697..0e652448e 100644 --- a/include/Nazara/Utility/Enums.hpp +++ b/include/Nazara/Utility/Enums.hpp @@ -309,6 +309,40 @@ namespace Nz SamplerWrap_Max = SamplerWrap_Repeat }; + enum StructFieldType + { + StructFieldType_Bool1, + StructFieldType_Bool2, + StructFieldType_Bool3, + StructFieldType_Bool4, + StructFieldType_Float1, + StructFieldType_Float2, + StructFieldType_Float3, + StructFieldType_Float4, + StructFieldType_Double1, + StructFieldType_Double2, + StructFieldType_Double3, + StructFieldType_Double4, + StructFieldType_Int1, + StructFieldType_Int2, + StructFieldType_Int3, + StructFieldType_Int4, + StructFieldType_UInt1, + StructFieldType_UInt2, + StructFieldType_UInt3, + StructFieldType_UInt4, + + StructFieldType_Max = StructFieldType_UInt4 + }; + + enum StructLayout + { + StructLayout_Packed, + StructLayout_Std140, + + StructLayout_Max = StructLayout_Std140 + }; + enum StencilOperation { StencilOperation_Decrement, diff --git a/include/Nazara/Utility/FieldOffsets.hpp b/include/Nazara/Utility/FieldOffsets.hpp new file mode 100644 index 000000000..7cdeb83a9 --- /dev/null +++ b/include/Nazara/Utility/FieldOffsets.hpp @@ -0,0 +1,52 @@ +// Copyright (C) 2019 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_FIELDOFFSETS_HPP +#define NAZARA_FIELDOFFSETS_HPP + +#include +#include + +namespace Nz +{ + class NAZARA_UTILITY_API FieldOffsets + { + public: + inline FieldOffsets(StructLayout layout); + FieldOffsets(const FieldOffsets&) = default; + FieldOffsets(FieldOffsets&&) = default; + ~FieldOffsets() = default; + + std::size_t AddField(StructFieldType type); + std::size_t AddFieldArray(StructFieldType type, std::size_t arraySize); + std::size_t AddMatrix(StructFieldType cellType, unsigned int columns, unsigned int rows, bool columnMajor); + std::size_t AddMatrixArray(StructFieldType cellType, unsigned int columns, unsigned int rows, bool columnMajor, std::size_t arraySize); + std::size_t AddStruct(const FieldOffsets& fieldStruct); + std::size_t AddStructArray(const FieldOffsets& fieldStruct, std::size_t arraySize); + + inline std::size_t GetLargestFieldAlignement() const; + inline std::size_t GetSize() const; + + FieldOffsets& operator=(const FieldOffsets&) = default; + FieldOffsets& operator=(FieldOffsets&&) = default; + + static std::size_t GetAlignement(StructLayout layout, StructFieldType fieldType); + static std::size_t GetCount(StructFieldType fieldType); + static std::size_t GetSize(StructFieldType fieldType); + + private: + static inline std::size_t Align(std::size_t source, std::size_t alignment); + + std::size_t m_largestFieldAlignment; + std::size_t m_offsetRounding; + std::size_t m_size; + StructLayout m_layout; + }; +} + +#include + +#endif // NAZARA_FIELDOFFSETS_HPP diff --git a/include/Nazara/Utility/FieldOffsets.inl b/include/Nazara/Utility/FieldOffsets.inl new file mode 100644 index 000000000..899e6a241 --- /dev/null +++ b/include/Nazara/Utility/FieldOffsets.inl @@ -0,0 +1,169 @@ +// Copyright (C) 2019 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include + +namespace Nz +{ + inline FieldOffsets::FieldOffsets(StructLayout layout) : + m_largestFieldAlignment(1), + m_offsetRounding(1), + m_size(0), + m_layout(layout) + { + } + + inline std::size_t FieldOffsets::GetLargestFieldAlignement() const + { + return m_largestFieldAlignment; + } + + inline std::size_t FieldOffsets::GetSize() const + { + return m_size; + } + + inline std::size_t FieldOffsets::GetAlignement(StructLayout layout, StructFieldType fieldType) + { + switch (layout) + { + case StructLayout_Packed: + return 1; + + case StructLayout_Std140: + { + switch (fieldType) + { + case StructFieldType_Bool1: + case StructFieldType_Float1: + case StructFieldType_Int1: + case StructFieldType_UInt1: + return 4; + + case StructFieldType_Bool2: + case StructFieldType_Float2: + case StructFieldType_Int2: + case StructFieldType_UInt2: + return 2 * 4; + + case StructFieldType_Bool3: + case StructFieldType_Float3: + case StructFieldType_Int3: + case StructFieldType_UInt3: + case StructFieldType_Bool4: + case StructFieldType_Float4: + case StructFieldType_Int4: + case StructFieldType_UInt4: + return 4 * 4; + + case StructFieldType_Double1: + return 8; + + case StructFieldType_Double2: + return 2 * 8; + + case StructFieldType_Double3: + case StructFieldType_Double4: + return 4 * 8; + } + } + } + + return 0; + } + + inline std::size_t FieldOffsets::GetCount(StructFieldType fieldType) + { + switch (fieldType) + { + case StructFieldType_Bool1: + case StructFieldType_Double1: + case StructFieldType_Float1: + case StructFieldType_Int1: + case StructFieldType_UInt1: + return 1; + + case StructFieldType_Bool2: + case StructFieldType_Double2: + case StructFieldType_Float2: + case StructFieldType_Int2: + case StructFieldType_UInt2: + return 2; + + case StructFieldType_Bool3: + case StructFieldType_Double3: + case StructFieldType_Float3: + case StructFieldType_Int3: + case StructFieldType_UInt3: + return 3; + + case StructFieldType_Bool4: + case StructFieldType_Double4: + case StructFieldType_Float4: + case StructFieldType_Int4: + case StructFieldType_UInt4: + return 4; + } + + return 0; + } + + inline std::size_t FieldOffsets::GetSize(StructFieldType fieldType) + { + switch (fieldType) + { + case StructFieldType_Bool1: + case StructFieldType_Float1: + case StructFieldType_Int1: + case StructFieldType_UInt1: + return 4; + + case StructFieldType_Bool2: + case StructFieldType_Float2: + case StructFieldType_Int2: + case StructFieldType_UInt2: + return 2 * 4; + + case StructFieldType_Bool3: + case StructFieldType_Float3: + case StructFieldType_Int3: + case StructFieldType_UInt3: + return 3 * 4; + + case StructFieldType_Bool4: + case StructFieldType_Float4: + case StructFieldType_Int4: + case StructFieldType_UInt4: + return 4 * 4; + + case StructFieldType_Double1: + return 8; + + case StructFieldType_Double2: + return 2 * 8; + + case StructFieldType_Double3: + return 3 * 8; + + case StructFieldType_Double4: + return 4 * 8; + } + + return 0; + } + + inline std::size_t FieldOffsets::Align(std::size_t source, std::size_t alignment) + { + if (source == 0) + return source; + + assert(alignment > 0); + return ((source + alignment - 1) / alignment) * alignment; + } +} + +#include diff --git a/src/Nazara/Utility/FieldOffsets.cpp b/src/Nazara/Utility/FieldOffsets.cpp new file mode 100644 index 000000000..76cb50e71 --- /dev/null +++ b/src/Nazara/Utility/FieldOffsets.cpp @@ -0,0 +1,101 @@ +// Copyright (C) 2019 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include + +namespace Nz +{ + std::size_t FieldOffsets::AddField(StructFieldType type) + { + std::size_t fieldAlignement = GetAlignement(m_layout, type); + + m_largestFieldAlignment = std::max(m_largestFieldAlignment, fieldAlignement); + + std::size_t offset = Align(m_size, Align(fieldAlignement, m_offsetRounding)); + m_size = offset + GetSize(type); + + m_offsetRounding = 1; + + return offset; + } + + std::size_t FieldOffsets::AddFieldArray(StructFieldType type, std::size_t arraySize) + { + std::size_t fieldAlignement = GetAlignement(m_layout, type); + if (m_layout == StructLayout_Std140) + fieldAlignement = Align(fieldAlignement, GetAlignement(StructLayout_Std140, StructFieldType_Float4)); + + m_largestFieldAlignment = std::max(fieldAlignement, m_largestFieldAlignment); + + std::size_t offset = Align(m_size, Align(fieldAlignement, m_offsetRounding)); + m_size = offset + GetSize(type) * arraySize; + + m_offsetRounding = 1; + + return offset; + } + + std::size_t FieldOffsets::AddMatrix(StructFieldType cellType, unsigned int columns, unsigned int rows, bool columnMajor) + { + assert(GetCount(cellType) == 1); + assert(columns >= 2 && columns <= 4); + assert(rows >= 2 && rows <= 4); + + if (columnMajor) + return AddFieldArray(static_cast(cellType + rows - 1), columns); + else + return AddFieldArray(static_cast(cellType + columns - 1), rows); + } + + std::size_t FieldOffsets::AddMatrixArray(StructFieldType cellType, unsigned int columns, unsigned int rows, bool columnMajor, std::size_t arraySize) + { + assert(GetCount(cellType) == 1); + assert(columns >= 2 && columns <= 4); + assert(rows >= 2 && rows <= 4); + + if (columnMajor) + return AddFieldArray(static_cast(cellType + rows - 1), columns * arraySize); + else + return AddFieldArray(static_cast(cellType + columns - 1), rows * arraySize); + } + + std::size_t FieldOffsets::AddStruct(const FieldOffsets& fieldStruct) + { + std::size_t fieldAlignement = fieldStruct.GetLargestFieldAlignement(); + if (m_layout == StructLayout_Std140) + fieldAlignement = Align(fieldAlignement, GetAlignement(StructLayout_Std140, StructFieldType_Float4)); + + m_largestFieldAlignment = std::max(m_largestFieldAlignment, fieldAlignement); + + std::size_t offset = Align(m_size, Align(fieldAlignement, m_offsetRounding)); + m_size = offset + fieldStruct.GetSize(); + + m_offsetRounding = std::max(Align(fieldStruct.GetSize(), fieldAlignement) - fieldStruct.GetSize(), 1); + + return offset; + } + + std::size_t FieldOffsets::AddStructArray(const FieldOffsets& fieldStruct, std::size_t arraySize) + { + assert(arraySize > 0); + + std::size_t fieldAlignement = fieldStruct.GetLargestFieldAlignement(); + if (m_layout == StructLayout_Std140) + fieldAlignement = Align(fieldAlignement, GetAlignement(StructLayout_Std140, StructFieldType_Float4)); + + m_largestFieldAlignment = std::max(m_largestFieldAlignment, fieldAlignement); + + std::size_t offset = Align(m_size, Align(fieldAlignement, m_offsetRounding)); + m_size = offset + + fieldStruct.GetSize() * arraySize + + (Align(fieldStruct.GetSize(), fieldAlignement) - fieldStruct.GetSize()) * (arraySize - 1); + + m_offsetRounding = fieldAlignement; + + return offset; + } +}