/* * Copyright (c) Contributors to the Open 3D Engine Project. * For complete copyright and license terms please see the LICENSE at the root of this distribution. * * SPDX-License-Identifier: Apache-2.0 OR MIT * */ #pragma once #include "PackedFloat2.h" #include #include #include #include #include #include #include namespace WhiteBox { //! Get the Atom format for the specified vertex stream type. template constexpr AZ::RHI::Format GetFormatForVertexStreamDataType() { if (std::is_same_v) { return AZ::RHI::Format::R32_UINT; } else if (std::is_same_v) { return AZ::RHI::Format::R32G32_FLOAT; } else if (std::is_same_v) { return AZ::RHI::Format::R32G32B32_FLOAT; } else if (std::is_same_v) { return AZ::RHI::Format::R32G32B32A32_FLOAT; } else { // will result in a compile time assertion failure in the Buffer class. return AZ::RHI::Format::Unknown; } } //! Buffer for holding vertex attribute data to be trasferred to the GPU for mesh rendering. template class Buffer { public: //! Constructs the buffer from the specified data in vertex stream format. Buffer(const AZStd::vector& data); //! Retrieves the buffer asset. const AZ::Data::Asset& GetBuffer() const; //! Retrieves the buffer view descriptor. const AZ::RHI::BufferViewDescriptor& GetBufferViewDescriptor() const; //! Retrieves the buffer asset view. const AZ::RPI::BufferAssetView& GetBufferAssetView() const; //! Returns true of the buffer is valid, otherwise false. bool IsValid() const; //! Update the buffer contents with the new data. bool UpdateData(const AZStd::vector& data); private: AZ::Data::Asset m_buffer; AZ::RHI::BufferViewDescriptor m_bufferViewDescriptor; AZ::RPI::BufferAssetView m_bufferAssetView; bool m_isValid = false; //! The format used by the buffer (must be one of the supported types in GetFormatForVertexStreamDataType). static constexpr auto VertexStreamFormat = GetFormatForVertexStreamDataType(); static_assert( VertexStreamFormat != AZ::RHI::Format::Unknown, "Cannot initialize a buffer with an unknown format."); }; template Buffer::Buffer(const AZStd::vector& data) { const uint32_t elementCount = static_cast(data.size()); const uint32_t elementSize = sizeof(VertexStreamDataType); const uint32_t bufferSize = elementCount * elementSize; // create a buffer view spanning the entire buffer m_bufferViewDescriptor = AZ::RHI::BufferViewDescriptor::CreateTyped(0, elementCount, VertexStreamFormat); // specify the data format for vertex stream data AZ::RHI::BufferDescriptor bufferDescriptor; bufferDescriptor.m_bindFlags = AZ::RHI::BufferBindFlags::InputAssembly | AZ::RHI::BufferBindFlags::ShaderRead; bufferDescriptor.m_byteCount = bufferSize; bufferDescriptor.m_alignment = elementSize; // create the buffer with the specified data AZ::RPI::BufferAssetCreator bufferAssetCreator; bufferAssetCreator.Begin(AZ::Uuid::CreateRandom()); bufferAssetCreator.SetUseCommonPool(AZ::RPI::CommonBufferPoolType::StaticInputAssembly); bufferAssetCreator.SetBuffer(data.data(), bufferDescriptor.m_byteCount, bufferDescriptor); bufferAssetCreator.SetBufferViewDescriptor(m_bufferViewDescriptor); if (!bufferAssetCreator.End(m_buffer)) { AZ_Error("Buffer", false, "Couldn't create buffer asset."); } else if (!m_buffer.IsReady()) { AZ_Error("Buffer", false, "Asset is not ready."); } else if (!m_buffer.Get()) { AZ_Error("Buffer", false, "Asset is nullptr."); } else { m_bufferAssetView = AZ::RPI::BufferAssetView{m_buffer, m_bufferViewDescriptor}; m_isValid = true; } } template const AZ::Data::Asset& Buffer::GetBuffer() const { return m_buffer; } template const AZ::RHI::BufferViewDescriptor& Buffer::GetBufferViewDescriptor() const { return m_bufferViewDescriptor; } template const AZ::RPI::BufferAssetView& Buffer::GetBufferAssetView() const { return m_bufferAssetView; } template bool Buffer::IsValid() const { return m_isValid; ; } template bool Buffer::UpdateData(const AZStd::vector& data) { if (!IsValid()) { AZ_Error("UpdateData", false, "Buffer is not valid."); return false; } auto buffer = AZ::RPI::Buffer::FindOrCreate(m_buffer); if (!buffer) { AZ_Error("UpdateData", false, "Buffer could not be found."); return false; } const uint32_t elementCount = static_cast(data.size()); const uint32_t elementSize = sizeof(VertexStreamDataType); const uint32_t bufferSize = elementCount * elementSize; if (bufferSize > m_bufferViewDescriptor.m_elementCount * m_bufferViewDescriptor.m_elementSize) { AZ_Error("UpdateData", false, "Specfied buffer update exceeds capacity."); return false; } if (!buffer->UpdateData(data.data(), bufferSize)) { AZ_Error("UpdateData", false, "Buffer could not be updated."); m_isValid = false; return false; } return true; } //! Buffer alias for unsigned 32 bit integer indices. using IndexBuffer = Buffer; //! Buffer alias for PackedFloat2 vertices. using Vector2Buffer = Buffer; //! Buffer alias for AZ::PackedVector3f vertices. using Vector3Buffer = Buffer; //! Buffer alias for AZ::Vector4 vertices. using Vector4Buffer = Buffer; } // namespace WhiteBox