#ifndef __VERTEXARRAY_H__ #define __VERTEXARRAY_H__ #include "renderer/VertexBuffer.h" // Iterator template class VertexArrayIterator { public: typedef T Type; public: VertexArrayIterator() : m_Data(0), m_Stride(0) { } VertexArrayIterator(char* data, size_t stride) : m_Data(data), m_Stride(stride) { } VertexArrayIterator(const VertexArrayIterator& rhs) : m_Data(rhs.m_Data), m_Stride(rhs.m_Stride) { } VertexArrayIterator& operator=(const VertexArrayIterator& rhs) { m_Data = rhs.m_Data; m_Stride = rhs.m_Stride; return *this; } // Accessors T& operator*() const { return *(T*)m_Data; } T* operator->() const { return (T*)m_Data; } T& operator[](ssize_t idx) const { return *(T*)(m_Data + idx*m_Stride); } // Walking VertexArrayIterator& operator++() { m_Data += m_Stride; return *this; } VertexArrayIterator operator++(int) { VertexArrayIterator tmp = *this; m_Data += m_Stride; return tmp; } VertexArrayIterator& operator--() { m_Data -= m_Stride; return *this; } VertexArrayIterator operator--(int) { VertexArrayIterator tmp = *this; m_Data -= m_Stride; return tmp; } VertexArrayIterator& operator+=(ssize_t rhs) { m_Data += rhs*m_Stride; return *this; } VertexArrayIterator& operator-=(ssize_t rhs) { m_Data -= rhs*m_Stride; return *this; } VertexArrayIterator operator+(ssize_t rhs) const { VertexArrayIterator tmp = *this; tmp.m_Data += rhs*m_Stride; return tmp; } VertexArrayIterator operator-(ssize_t rhs) const { VertexArrayIterator tmp = *this; tmp.m_Data -= rhs*m_Stride; return tmp; } private: char* m_Data; size_t m_Stride; }; // Manage a vertex array with a runtime-determined set of attributes. // // Purpose: Different rendering paths sometimes require different sets of // attributes (e.g. normal vector vs. color data), which is difficult to // support with hardcoded vertex structures. // This class chooses the vertex layout at runtime, based on the attributes // that are actually needed. // Furthermore, it stores dynamic and static attributes in different // vertex buffers, so that needless re-uploads of static data is avoided. // // Note that this class will not allocate any OpenGL resources until one // of the Upload functions is called. class VertexArray { public: struct Attribute { // Data type. Currently supported: GL_FLOAT GLenum type; // How many elements per vertex (e.g. 3 for RGB, 2 for UV) GLuint elems; // Offset (in bytes) into a vertex structure (filled in by Layout()) size_t offset; VertexArray* vertexArray; Attribute() : type(0), elems(0), offset(0), vertexArray(0) { } // Get an iterator for the given attribute that initially points at the first vertex. // Supported types T: CVector3D, CVector4D, float[], SColor3ub, SColor4ub // This function verifies at runtime that the requested type T matches // the attribute definition passed to AddAttribute(). template VertexArrayIterator GetIterator() const; }; public: VertexArray(bool dynamic); ~VertexArray(); // Set the number of vertices stored in the array void SetNumVertices(size_t num); // Add vertex attributes void AddAttribute(Attribute* attr); size_t GetNumVertices() const { return m_NumVertices; } size_t GetStride() const { return m_Stride; } // Layout the vertex array format and create backing buffer in RAM. // You must call Layout() after changing the number of vertices or // attributes. // All vertex data is lost when a vertex array is re-layouted. void Layout(); // (Re-)Upload the static/dynamic attributes of the vertex array. void Upload(); // Bind this array, returns the base address for calls to glVertexPointer etc. u8* Bind(); // If you know for certain that you'll never have to change the data again, // call this to free some memory. void FreeBackingStore(); private: void Free(); template VertexArrayIterator MakeIterator(const Attribute* attr) { debug_assert(attr->type && attr->elems); return VertexArrayIterator(m_BackingStore + attr->offset, m_Stride); } bool m_Dynamic; size_t m_NumVertices; std::vector m_Attributes; CVertexBuffer::VBChunk* m_VB; size_t m_Stride; char* m_BackingStore; }; #endif // __VERTEXARRAY_H__