diff --git a/include/echo/Graphics/ElementBuffer.h b/include/echo/Graphics/ElementBuffer.h --- a/include/echo/Graphics/ElementBuffer.h +++ b/include/echo/Graphics/ElementBuffer.h @@ -1,409 +1,413 @@ #ifndef _ECHOELEMENTBUFFER_H_ #define _ECHOELEMENTBUFFER_H_ #include #include #include #include namespace Echo { /** * ElementBuffer wraps a buffer of indices to be accessed as Graphics primitive elements. * ElementBuffers are used to describe how vertices in an VertexBuffer are related to * create the graphics primitives. For example, three vertices would create a triangle however * they may not be in order in the VertexBuffer. The ElementBuffer would contain indices in * order that point to the corresponding vertices. * * ElementBuffer is also designed to be a higher level access to indices rather than client * code dealing with an index buffer directly and worrying about element stride. Code written * using the Accessors naturally describes in detail what is being manipulated. For example * compare the two snippets: * * someIndexBuffer[i] = triangleIndexBase; * someIndexBuffer[i+1] = triangleIndexBase+1; * someIndexBuffer[i+2] = triangleIndexBase+2; * someIndexBuffer[i+3] = triangleIndexBase+3; * someIndexBuffer[i+4] = triangleIndexBase+4; * someIndexBuffer[i+5] = triangleIndexBase+5; * * Vs: * * ElementBuffer::Triangle< u16 > triangles = elementBuffer->GetAccessor< ElementBuffer::Triangle< u16 > >(); * triangles[0].mA = triangleIndexBase; * triangles[0].mB = triangleIndexBase+1; * triangles[0].mC = triangleIndexBase+2; * triangles[1].mA = triangleIndexBase+3; * triangles[1].mB = triangleIndexBase+4; * triangles[1].mC = triangleIndexBase+5; * * While the code blocks are similar, the second communicates more that we are creating triangles where as the * first block it is less obvious at first glance or without additional comments. */ class ElementBuffer { public: struct ElementTypes { enum _ { UNDEFINED, POINTS, LINES, LINE_STRIP, LINE_LOOP, TRIANGLE, TRIANGLE_STRIP, TRIANGLE_FAN }; }; typedef ElementTypes::_ ElementType; struct IndexTypes { enum _ { UNDEFINED, UNSIGNED_16BIT, // Use when there are up to 65535 vertices UNSIGNED_32BIT // Use when you have more than 65535 vertices }; }; typedef IndexTypes::_ IndexType; struct Types { enum _ { STATIC, DYNAMIC }; }; typedef Types::_ Type; template < typename T > struct Point { T mIndex; }; template < typename T > struct Line { T mA; T mB; }; template < typename T > struct Triangle { T mA; T mB; T mC; }; /** * Element buffer constructor * @param type The type of element buffer. This is a hint to indicate expected usage. * STATIC suggests that the buffer contents aren't going to change * DYNAMIC suggests the buffer will change frequently. * Hint DYNAMIC if you plan on changing the buffer contents every frame or two, otherwise * STATIC should be sufficient. The platform implementation may not even use this. */ ElementBuffer(Type type); ~ElementBuffer(); + ElementBuffer(const ElementBuffer& rhs); + ElementBuffer(ElementBuffer&& rhs); + ElementBuffer& operator=(const ElementBuffer& rhs); + ElementBuffer& operator=(ElementBuffer&& rhs); IndexType GetIndexType() const; ElementType GetElementType() const; /** * Allocate a buffer big enough to contain the specified number of elements. * @note If a buffer has previously been allocated it will be deallocated first. * @param indexType The index type. * @param elementType The type of element you want to allocate. * @param numberOfElements The number of elements this buffer needs to be able to hold. * @return true if allocation was successful, false if the stride or nulberOfElements is zero. */ bool Allocate(IndexType indexType, ElementType elementType, Size numberOfElements); /** * Version of Allocate() that uses the currently set values for index and element type. * @see Allocate(IndexType,ElementType,Size); * @param onlyIfNeeded if true an allocation will only occur if the number of elements requested exceeds the current capacity. */ bool Allocate(Size numberOfElements, bool onlyIfNeeded = true); /** * Deallocate the buffer and set the capacity and number of elements to 0. */ void Deallocate(); /** * An Accessor is an element component accessor. * Accessor provides convenient access to the element component of by index of the given type. * You can request an Accessor from using VertexBuffer::GetAccessor(). * You can check validity of an Accessor by converting it to a bool. For example: * if(accessor) * { * //Ok to use * } */ template class Accessor { public: Accessor() : mBase(nullptr), mStride(0), mCapacity(0){} Accessor(char* base, Size stride, Size elementCapacity, IndexType indexType, ElementType elementType) : mBase(base), mStride(stride), mCapacity(elementCapacity), mIndexType(indexType), mElementType(elementType) {} Accessor(const Accessor& rhs) { mBase = rhs.mBase; mStride = rhs.mStride; mCapacity = rhs.mCapacity; mIndexType = rhs.mIndexType; mElementType = rhs.mElementType; } Accessor& operator=(const Accessor& rhs) { mBase = rhs.mBase; mStride = rhs.mStride; mCapacity = rhs.mCapacity; mIndexType = rhs.mIndexType; mElementType = rhs.mElementType; return *this; } T& operator[](size_t index) { assert(index < mCapacity && "Index needs to be less than the capacity"); return *reinterpret_cast(&(mBase[mStride*index])); } const T& operator[](size_t index) const { assert(index < mCapacity && "Index needs to be less than the capacity"); return *reinterpret_cast(&(mBase[mStride*index])); } inline operator bool() const { return (mBase!=nullptr); } inline Size GetCapacity() const {return mCapacity;} private: char* mBase; Size mStride; Size mCapacity; IndexType mIndexType; ElementType mElementType; }; /** * Typesafe access to the buffer. * Usage: * Accessor< ElementBuffer::Point< IndexType > > GetAccessor< ElementBuffer::Point< IndexType > >() * Accessor< ElementBuffer::Line< IndexType > > GetAccessor< ElementBuffer::Line< IndexType > >() * Accessor< ElementBuffer::Triangle< IndexType > > GetAccessor< ElementBuffer::Triangle< IndexType > >() * Where IndexType is u16 or u32. * The Accessor will be configured to step as per the buffer type. For example * GetAccessor< ElementBuffer::Triangle >() will return an accessor that will correctly * iterate over the buffer for TRIANGLE and TRIANGLE_STRIP. * @note For some element types some elements will share indices with adjacent ones, for example Triangle * strip at index 1 will share point A and B with index 0 (B and C). * @note for some element types, such as TRIANGLE_FAN and LINE_LOOP, it is not possible to iterate * over elements with the Accessor class due to the way they are indexed. For those types you will * need to access the indices directly with GetAccesor() rather than the element type. */ template Accessor GetAccessor() { assert(mDataSize && "No allocation has been made. Did you forget to call Allocate()?"); assert(GetElementSize()==sizeof(T) && "The specified type does not match the element size."); return Accessor(mData, GetElementStride(), mCapacity, mIndexType, mElementType); } /** * Const version of GetAccessor() * @see GetAccessor() */ template const Accessor GetAccessor() const { assert(mDataSize && "No allocation has been made. Did you forget to call Allocate()?"); assert(GetElementSize()==sizeof(T) && "The specified type does not match the element size."); return Accessor(mData, GetElementStride(), mCapacity, mIndexType, mElementType); } /** * Get access to indices. */ template Accessor GetIndexAccessor() { assert(mDataSize && "No allocation has been made. Did you forget to call Allocate()?"); assert(((mIndexType==IndexTypes::UNSIGNED_16BIT && sizeof(T)!=2) || (mIndexType==IndexTypes::UNSIGNED_32BIT && sizeof(T)!=4)) && "The specified type does not match the element size."); return Accessor(mData, GetIndexSize(), mCapacity, mIndexType, mElementType); } /** * Get access to const indices. */ template const Accessor GetIndexAccessor() const { assert(mDataSize && "No allocation has been made. Did you forget to call Allocate()?"); assert(((mIndexType==IndexTypes::UNSIGNED_16BIT && sizeof(T)!=2) || (mIndexType==IndexTypes::UNSIGNED_32BIT && sizeof(T)!=4)) && "The specified type does not match the element size."); return Accessor(mData, GetIndexSize(), mCapacity, mIndexType, mElementType); } Size GetBufferSize() const {return mDataSize;} /** * Set the number of elements this ElementBuffer has had written. * @note This value should not exceed the capacity of the buffer, the number of elements will * be clamped to the capacity. In debug mode the method will assert. * @param numberOfElements The number of elements written to the buffer. */ void SetNumberOfElements(Size numberOfElements); /** * Get the number of elements this buffer contains. * @note For convenience, if SetNumberOfElements() has not been called then this method will * return the capacity since it is assumed that a ElementBuffer is used entirely. * @return The number of elements this ElementBuffer contains. */ Size GetNumberOfElements() const {return mNumberOfElements;} /** * Get the number of indices this buffer contains. * @return The number of indices this ElementBuffer contains. */ Size GetNumberOfIndices() const {return mNumberOfIndices;} /** * Get the capacity of the element buffer, this is the number of elements this buffer can have. */ Size GetCapacity() const {return mCapacity;} /** * Get the pointer to the data. * @return A pointer to the start of the allocated buffer. */ const char* GetDataPointer() const { return mData; } /** * Set point or line size. * @note this is for legacy point and line size support. Eventually this will be moved. * @param pointOrLineSize The point or line size. The value may be in pixels but might be a scalar * based on the platform API. Platform implementations should try and convert the value so it is * reasonably consistent. */ void SetPointOrLineSize(Scalar pointOrLineSize) { mPointOrLineSize = pointOrLineSize; } /** * Get point or line size. * @note This is for legacy point and line size support. Eventually this will be moved. * @param pointOrLineSize The point or line size. */ Scalar GetPointOrLineSize() const { return mPointOrLineSize; } /** * Get the byte stride between elements. * This is not necessarily the element size if the element type is overlapping such as * in the case of strip element types. */ inline Size GetElementStride() const { switch(mElementType) { case ElementTypes::POINTS: return GetIndexSize(); case ElementTypes::LINES: return 2*GetIndexSize(); case ElementTypes::LINE_STRIP: return GetIndexSize(); case ElementTypes::LINE_LOOP: return GetIndexSize(); case ElementTypes::TRIANGLE: return 3*GetIndexSize(); case ElementTypes::TRIANGLE_STRIP: return GetIndexSize(); case ElementTypes::TRIANGLE_FAN: return GetIndexSize(); } assert(false && "Cannot calculate element size. Element type is not valid."); return 0; } /** * Get the element size in bytes */ inline Size GetElementSize() const { switch(mElementType) { case ElementTypes::POINTS: return GetIndexSize(); case ElementTypes::LINES: return 2*GetIndexSize(); case ElementTypes::LINE_STRIP: return 2*GetIndexSize(); case ElementTypes::LINE_LOOP: return 2*GetIndexSize(); case ElementTypes::TRIANGLE: return 3*GetIndexSize(); case ElementTypes::TRIANGLE_STRIP: return 3*GetIndexSize(); case ElementTypes::TRIANGLE_FAN: return 3*GetIndexSize(); } assert(false && "Cannot calculate element size. Element type is not valid."); return 0; } /** * Get the size of each index * @return */ inline Size GetIndexSize() const { if(mIndexType==IndexTypes::UNSIGNED_16BIT) { return 2; } return 4; } private: Size CalculateNumberOfIndices(Size numberOfElements) const; Size CalculateBufferSize(Size numberOfElements) const; Type mType; ElementType mElementType; IndexType mIndexType; Size mVersion; char* mData; Size mDataSize; Size mNumberOfElements; Size mNumberOfIndices; Size mCapacity; Scalar mPointOrLineSize; }; } #endif diff --git a/include/echo/Graphics/VertexBuffer.h b/include/echo/Graphics/VertexBuffer.h --- a/include/echo/Graphics/VertexBuffer.h +++ b/include/echo/Graphics/VertexBuffer.h @@ -1,257 +1,261 @@ #ifndef _ECHOVERTEXBUFFER_H_ #define _ECHOVERTEXBUFFER_H_ #include #include #include #include #include namespace Echo { /** * Simple abstraction of VertexBuffers. * A VertexBuffer is made up of a number of VertexAttributes which correspond to the * mesh properties. For example: a Mesh with vertices containing positions, normals * and colours would have a VertexBuffer with three attributes a Vector3,Vector3 and * Colour respectively. The vertex buffer defines where each of these components are * positioned (based on the order the attributes are added) in each vertex. * * VertexBuffers are much more explicit and flexible and ultimately more predictable * than when using a default rendering pipeline which allows for additional * performance improvements to be made in shaders. * * The buffer stride is determined by the sum of the width of the vertex attributes. */ class VertexBuffer { public: struct Types { enum _ { STATIC, DYNAMIC }; }; typedef Types::_ Type; VertexBuffer(Type type); ~VertexBuffer(); + VertexBuffer(const VertexBuffer& rhs); + VertexBuffer(VertexBuffer&& rhs); + VertexBuffer& operator=(const VertexBuffer& rhs); + VertexBuffer& operator=(VertexBuffer&& rhs); Size GetStride() const; Size AddVertexAttribute(VertexAttribute vertexAttribute); Size AddVertexAttribute(std::string name, VertexAttribute vertexAttribute); /** * Get a vertex attribute. * @param attributePosition The index of the attribute. * @return nullptr if the index exceeds the number of attributes, otherwise the * attribute at that index. */ VertexAttribute* GetVertexAttribute(Size attributePosition) { assert(attributePosition < mVertexAttributes.size()); if(attributePosition >= mVertexAttributes.size()) { return nullptr; } return &mVertexAttributes[attributePosition]; } /** * Get a vertex attribute by name. * @param name Name of the attribute. * @return nullptr if the name does not point to an attribute, otherwise the attribute. */ VertexAttribute* GetVertexAttribute(const std::string& name) { std::map< std::string, Size >::iterator it = mNamedAttributes.find(name); if(it==mNamedAttributes.end()) { return nullptr; } return GetVertexAttribute(it->second); } /** * Allocate a buffer big enough to contain the specified number of vertices. * This method needs to be called after all of the VertexAttributes have been added. * In debug mode this method will assert if attributes have not been added first. * @note If a buffer has previously been allocated it will be deallocated first. * @param numberOfVertices The number of vertices this buffer needs to be able to hold. * @return true if allocation was successful, false if the stride is zero. */ bool Allocate(Size numberOfVertices); /** * Deallocate the buffer and set the capacity and number of elements to 0. */ void Deallocate(); /** * An Accessor is an element component accessor. * Accessor provides convenient access to the element component of by index of the given type. * You can request an Accessor from using VertexBuffer::GetAccessor(). * You can check validity of an Accessor by converting it to a bool. For example: * if(accessor) * { * //Ok to use * } */ template class Accessor { public: Accessor() : mBase(nullptr), mStride(0), mCapacity(0){} Accessor(char* base, Size stride, Size elementCapacity) : mBase(base), mStride(stride), mCapacity(elementCapacity){} Accessor(const Accessor& rhs) { mBase = rhs.mBase; mStride = rhs.mStride; mCapacity = rhs.mCapacity; } Accessor& operator=(const Accessor& rhs) { mBase = rhs.mBase; mStride = rhs.mStride; mCapacity = rhs.mCapacity; return *this; } T& operator[](size_t index) { return *reinterpret_cast(&(mBase[mStride*index])); } const T& operator[](size_t index) const { return *reinterpret_cast(&(mBase[mStride*index])); } inline operator bool() const { return (mBase!=nullptr); } inline Size GetCapacity() const {return mCapacity;} private: char* mBase; Size mStride; Size mCapacity; }; /** * Get an Accessor for elements of of the format at the specified attribute index. * @note The only sanity check performed on the type is a comparison of the size of the specified type * and the size of the component as determined by the VertexAttribute. You need to you make sure you * specify the type that matches the attributes data format otherwise your buffer results may not be * as you expect. * @param attributePosition The attribute index. The index is the value returned by AddVertexAttribute() * @return An Accessor if the attribute position is valid, otherwise a null Accessor. */ template Accessor GetAccessor(Size attributePosition) { assert(mDataSize && "No allocation has been made. Did you forget to call Allocate()?"); assert(attributePosition < mVertexAttributes.size()); if(attributePosition >= mVertexAttributes.size()) { return Accessor(); } VertexAttribute& attribute = mVertexAttributes[attributePosition]; assert(attribute.GetWidth()==sizeof(T) && "The specified type does not match the attribute width."); return Accessor(mData+attribute.GetOffset(), mStride, mCapacity); } /** * Get an Accessor by name. * @param name The name of the element data to access, this name is the name of the VertexAttribute. * @see GetAccessor(Size) * @return An Accessor if the name is valid, otherwise a null Accessor. */ template Accessor GetAccessor(std::string name) { std::map< std::string, Size >::iterator it = mNamedAttributes.find(name); if(it==mNamedAttributes.end()) { return Accessor(); } return GetAccessor(it->second); } /** * Const version of GetAccessor(Size) * @see GetAccessor(Size) */ template const Accessor GetAccessor(Size attributePosition) const { assert(mDataSize && "No allocation has been made. Did you forget to call Allocate()?"); assert(attributePosition < mVertexAttributes.size()); VertexAttribute& attribute = mVertexAttributes[attributePosition]; assert(attribute.GetWidth()==sizeof(T) && "The specified type does not match the attribute width."); return Accessor(mData+attribute.GetOffset(), mStride, mCapacity); } /** * Const version of GetAccessor(std::string) * @see GetAccessor(std::string) */ template const Accessor GetAccessor(std::string name) const { std::map< std::string, Size >::iterator it = mNamedAttributes.find(name); assert(it!=mNamedAttributes.end() && "No attribute found with specified name"); if(it==mNamedAttributes.end()) { return Accessor(); } return GetAccessor(it->second); } Size GetBufferSize() const {return mDataSize;} /** * Set the number of elements this VertexBuffer has had written. * @note This value should not exceed the capacity of the buffer, the number of elements will * be clamped to the capacity. In debug mode the method will assert. * @param numberOfElements The number of elements written to the buffer. */ void SetNumberOfElements(Size numberOfElements); /** * Get the number of elements this buffer contains. * @note For convenience, if SetNumberOfElements() has not been called then this method will * return the capacity since it is assumed that a VertexBuffer is used entirely. * @return The number of elements this VertexBuffer contains. */ Size GetNumberOfElements() const {return mNumberOfElements;} /** * Get the capacity of the vertex buffer, this is the number of vertices this buffer can have. */ Size GetCapacity() const {return mCapacity;} /** * Get the pointer to the data. * @return A pointer to the start of the allocated buffer. */ const char* GetDataPointer() const { return mData; } private: Type mType; Size mVersion; Size mStride; std::vector< VertexAttribute > mVertexAttributes; std::map< std::string, Size > mNamedAttributes; char* mData; Size mDataSize; Size mNumberOfElements; Size mCapacity; }; } #endif diff --git a/src/Graphics/ElementBuffer.cpp b/src/Graphics/ElementBuffer.cpp --- a/src/Graphics/ElementBuffer.cpp +++ b/src/Graphics/ElementBuffer.cpp @@ -1,121 +1,207 @@ #include namespace Echo { ElementBuffer::ElementBuffer(Type type) : mType(type), mElementType(ElementTypes::UNDEFINED), mIndexType(IndexTypes::UNDEFINED), mVersion(0), mData(nullptr), mDataSize(0), mNumberOfElements(0), mNumberOfIndices(0), mCapacity(0), mPointOrLineSize(1) {} ElementBuffer::~ElementBuffer() { } + + ElementBuffer::ElementBuffer(const ElementBuffer& rhs) : + mType(rhs.mType), + mElementType(rhs.mElementType), + mIndexType(rhs.mIndexType), + mVersion(rhs.mVersion), + mNumberOfElements(rhs.mNumberOfElements), + mNumberOfIndices(rhs.mNumberOfIndices), + mCapacity(rhs.mCapacity), + mPointOrLineSize(rhs.mPointOrLineSize) + { + if(rhs.mDataSize!=0) + { + mData = new char[rhs.mDataSize]; + std::copy(rhs.mData,mData+rhs.mDataSize,mData); + mDataSize = rhs.mDataSize; + }else + { + mData = nullptr; + mDataSize = 0; + } + } + + ElementBuffer::ElementBuffer(ElementBuffer&& rhs) : + mType(rhs.mType), + mElementType(rhs.mElementType), + mIndexType(rhs.mIndexType), + mVersion(rhs.mVersion), + mNumberOfElements(rhs.mNumberOfElements), + mNumberOfIndices(rhs.mNumberOfIndices), + mCapacity(rhs.mCapacity), + mPointOrLineSize(rhs.mPointOrLineSize) + { + mData = rhs.mData; + mDataSize = rhs.mDataSize; + rhs.mData = nullptr; + rhs.mDataSize = 0; + rhs.mCapacity = 0; + rhs.mNumberOfIndices = 0; + rhs.mNumberOfElements = 0; + rhs.mVersion = 0; + rhs.mIndexType = IndexTypes::UNDEFINED; + rhs.mElementType = ElementTypes::UNDEFINED; + // Type doesn't really matter . + } + + ElementBuffer& ElementBuffer::operator=(const ElementBuffer& rhs) + { + if(&rhs == this) + { + return *this; + } + delete [] mData; + *this = rhs; + return *this; + } + + ElementBuffer& ElementBuffer::operator=(ElementBuffer&& rhs) + { + if(&rhs == this) + { + return *this; + } + mType = rhs.mType; + mElementType = rhs.mElementType; + mIndexType = rhs.mIndexType; + mVersion = rhs.mVersion; + mNumberOfElements = rhs.mNumberOfElements; + mNumberOfIndices = rhs.mNumberOfIndices; + mCapacity = rhs.mCapacity; + mPointOrLineSize = rhs.mPointOrLineSize; + + delete [] mData; + mData = rhs.mData; + mDataSize = rhs.mDataSize; + rhs.mData = nullptr; + rhs.mDataSize = 0; + rhs.mCapacity = 0; + rhs.mNumberOfIndices = 0; + rhs.mNumberOfElements = 0; + rhs.mVersion = 0; + rhs.mIndexType = IndexTypes::UNDEFINED; + rhs.mElementType = ElementTypes::UNDEFINED; + // Type doesn't really matter. + return *this; + } ElementBuffer::IndexType ElementBuffer::GetIndexType() const { return mIndexType; } ElementBuffer::ElementType ElementBuffer::GetElementType() const { return mElementType; } bool ElementBuffer::Allocate(Size numberOfElements, bool onlyIfNeeded) { if(numberOfElements>mCapacity || !onlyIfNeeded) { return Allocate(mIndexType, mElementType, numberOfElements); } return true; } bool ElementBuffer::Allocate(IndexType indexType, ElementType elementType, Size numberOfElements) { if(indexType==IndexTypes::UNDEFINED || elementType==ElementTypes::UNDEFINED || numberOfElements==0) { return false; } mIndexType = indexType; mElementType = elementType; mCapacity = numberOfElements; mNumberOfElements = numberOfElements; mNumberOfIndices = CalculateNumberOfIndices(numberOfElements); mDataSize = CalculateBufferSize(numberOfElements); delete [] mData; mData = new char[mDataSize]; return true; } void ElementBuffer::Deallocate() { mData = nullptr; mDataSize = 0; mNumberOfElements = 0; mNumberOfIndices = 0; mCapacity = 0; } void ElementBuffer::SetNumberOfElements(Size numberOfElements) { assert(numberOfElements<=mCapacity && "Number of elements should be no larger than the capacity of the ElementBuffer. The value will be capped."); mNumberOfElements = std::min(mCapacity,numberOfElements); mNumberOfIndices = CalculateNumberOfIndices(mNumberOfElements); } Size ElementBuffer::CalculateNumberOfIndices(Size numberOfElements) const { switch(mElementType) { case ElementTypes::POINTS: return numberOfElements; case ElementTypes::LINES: return numberOfElements * 2; case ElementTypes::LINE_STRIP: return (numberOfElements + 1); case ElementTypes::LINE_LOOP: return (numberOfElements + 1); case ElementTypes::TRIANGLE: return numberOfElements * 3; case ElementTypes::TRIANGLE_STRIP: return (2+numberOfElements); case ElementTypes::TRIANGLE_FAN: return (2+numberOfElements); } assert(false && "Cannot calculate buffer size. Element type is not valid."); return 0; } Size ElementBuffer::CalculateBufferSize(Size numberOfElements) const { switch(mElementType) { case ElementTypes::POINTS: return GetIndexSize() * numberOfElements; case ElementTypes::LINES: return 2 * GetIndexSize() * numberOfElements; case ElementTypes::LINE_STRIP: return GetIndexSize() * (numberOfElements + 1); case ElementTypes::LINE_LOOP: return GetIndexSize() * (numberOfElements + 1); case ElementTypes::TRIANGLE: return 3 * GetIndexSize() * numberOfElements; case ElementTypes::TRIANGLE_STRIP: return GetIndexSize() * (2+numberOfElements); case ElementTypes::TRIANGLE_FAN: return GetIndexSize() * (2+numberOfElements); } assert(false && "Cannot calculate buffer size. Element type is not valid."); return 0; } } diff --git a/src/Graphics/VertexBuffer.cpp b/src/Graphics/VertexBuffer.cpp --- a/src/Graphics/VertexBuffer.cpp +++ b/src/Graphics/VertexBuffer.cpp @@ -1,64 +1,148 @@ #include namespace Echo { - VertexBuffer::VertexBuffer(Type type) : mVersion(0), mStride(0), mData(nullptr), mDataSize(0), mNumberOfElements(0), mCapacity(0) + VertexBuffer::VertexBuffer(Type type) : mType(type), mVersion(0), mStride(0), mData(nullptr), mDataSize(0), mNumberOfElements(0), mCapacity(0) { } VertexBuffer::~VertexBuffer() { delete [] mData; } + + VertexBuffer::VertexBuffer(const VertexBuffer& rhs) + { + mType = rhs.mType; + mVersion = rhs.mVersion; + mStride = rhs.mStride; + mVertexAttributes = rhs.mVertexAttributes; + mNamedAttributes = rhs.mNamedAttributes; + mNumberOfElements = rhs.mNumberOfElements; + mCapacity = rhs.mCapacity; + if(rhs.mDataSize!=0) + { + mData = new char[rhs.mDataSize]; + std::copy(rhs.mData,mData+rhs.mDataSize,mData); + mDataSize = rhs.mDataSize; + }else + { + mData = nullptr; + mDataSize = 0; + } + } + + VertexBuffer::VertexBuffer(VertexBuffer&& rhs) + { + mType = rhs.mType; + mVersion = rhs.mVersion; + mStride = rhs.mStride; + mVertexAttributes = rhs.mVertexAttributes; + mNamedAttributes = rhs.mNamedAttributes; + mNumberOfElements = rhs.mNumberOfElements; + mCapacity = rhs.mCapacity; + mDataSize = rhs.mDataSize; + mData = rhs.mData; + rhs.mDataSize = 0;; + rhs.mData = nullptr; + } + + VertexBuffer& VertexBuffer::operator=(const VertexBuffer& rhs) + { + if(&rhs==this) + { + return *this; + } + mType = rhs.mType; + mVersion = rhs.mVersion; + mStride = rhs.mStride; + mVertexAttributes = rhs.mVertexAttributes; + mNamedAttributes = rhs.mNamedAttributes; + mNumberOfElements = rhs.mNumberOfElements; + mCapacity = rhs.mCapacity; + delete [] mData; + if(rhs.mDataSize!=0) + { + mData = new char[rhs.mDataSize]; + std::copy(rhs.mData,mData+rhs.mDataSize,mData); + mDataSize = rhs.mDataSize; + }else + { + mData = nullptr; + mDataSize = 0; + } + return *this; + } + + VertexBuffer& VertexBuffer::operator=(VertexBuffer&& rhs) + { + if(&rhs==this) + { + return *this; + } + mType = rhs.mType; + mVersion = rhs.mVersion; + mStride = rhs.mStride; + mVertexAttributes = rhs.mVertexAttributes; + mNamedAttributes = rhs.mNamedAttributes; + mNumberOfElements = rhs.mNumberOfElements; + mCapacity = rhs.mCapacity; + delete [] mData; + mDataSize = rhs.mDataSize; + mData = rhs.mData; + rhs.mDataSize = 0;; + rhs.mData = nullptr; + return *this; + } Size VertexBuffer::GetStride() const { return mStride; } Size VertexBuffer::AddVertexAttribute(VertexAttribute vertexAttribute) { vertexAttribute.SetOffset(mStride); mStride+=vertexAttribute.GetWidth(); Size position = mVertexAttributes.size(); mVertexAttributes.push_back(vertexAttribute); return position; } Size VertexBuffer::AddVertexAttribute(std::string name, VertexAttribute vertexAttribute) { Size position = AddVertexAttribute(std::move(vertexAttribute)); mNamedAttributes.insert(std::make_pair(std::move(name), position)); return position; } bool VertexBuffer::Allocate(Size numberOfVertices) { if(mStride==0) { ECHO_LOG_ERROR_LOCATION("Cannot allocate a buffer of zero size. The stride is zero."); return false; } delete [] mData; mNumberOfElements = numberOfVertices; mCapacity = numberOfVertices; mDataSize = mStride*mCapacity; mData = new char[mDataSize]; return true; } void VertexBuffer::Deallocate() { delete [] mData; mData = nullptr; mDataSize = 0; mNumberOfElements = 0; mCapacity = 0; } void VertexBuffer::SetNumberOfElements(Size numberOfElements) { assert(numberOfElements<=mCapacity && "Number of elements should be no larger than the capacity of the VertexBuffer. The value will be capped."); mNumberOfElements = std::min(mCapacity,numberOfElements); } }