#pragma once #include "AftrOpenGLIncludes.h" #include #include "Vector.h" #include #include #include #include #include //import std; namespace Aftr { /// Set STORAGE_TYPE to GLubyte if idxCount <= 255 indices /// Set STORAGE_TYPE to GLushort if idxCount <= 65535 indices /// Set STORAGE_TYPE to GLuint if idxCount >= 65536 indices //template< std::integral STORAGE_TYPE > //struct IndexedGeometry_TE_Index_Storage_Type //{ // using value_type = STORAGE_TYPE; // size_t variantIdx = -1; // IndexedGeometry_TE_Index_Storage_Type( size_t idx_size ) // { // std::printf( "User should prefer to use IndexedGeometry_TE_Index_Storage_Size of " ); // if( idx_size < std::pow( 2, sizeof( GLubyte ) * 8 ) ) // { // std::printf( "IndexedGeometry_TE_Index_Storage_Size< ..., GLubyte> ...\n" ); // variantIdx = 0; // if( std::is_same_v< GLubyte, STORAGE_TYPE > ) // std::printf( "Optimal Index usage for %zu indices...\n", idx_size ); // } // else if( idx_size < std::pow( 2, sizeof( GLushort ) * 8 ) ) // { // std::printf( "IndexedGeometry_TE_Index_Storage_Size< ..., GLushort>...\n" ); // variantIdx = 1; // if( std::is_same_v< GLushort, STORAGE_TYPE > ) // std::printf( "Optimal Index usage for %zu indices...\n", idx_size ); // } // else // { // std::printf( "IndexedGeometry_TE_Index_Storage_Size< ..., GLuint>...\n" ); // variantIdx = 2; // if( std::is_same_v< GLuint, STORAGE_TYPE > ) // std::printf( "Optimal Index usage for %zu indices...\n", idx_size ); // } // if( std::numeric_limits::max() < idx_size ) // { // std::printf( "ERROR: %s: Your IndexedGeometry_TE cannot support %zu indices, set STORAGE_TYPE to\n" // "GLubyte if idx <= 255; GLushort if idx <= 65535; GLuint if idx >= 65536...\n", AFTR_FILE_LINE_STR, idx_size ); // std::abort(); // } // } // std::vector const& getIndices( std::variant< // std::vector, // std::vector, // std::vector > const& v ) const noexcept // { // return std::get>( v ); // } // template // std::vector operator()( std::vector&& idx ) // { // std::vector ret( idx.size(), 0 ); // std::transform( idx.begin(), idx.end(), ret.begin(), []( I const i ) { return STORAGE_TYPE( i ); } ); // return ret; // } //}; class IndexedGeometry_TE { public: //Main methods used by the user using INDEX_LIST_VARIANT = std::variant< std::vector, std::vector, std::vector >; //Type Erased methods specified in the IndexedGeometry_TEIFace (type erased Interface) void render() const noexcept; void renderGL32() const noexcept; void renderCompatibility() const noexcept; void renderSelection( GLubyte red, GLubyte green, GLubyte blue ) const noexcept; void setGLPrimType( GLenum x ) { renderType = x; } void updateColorBuffer() noexcept; void updateVertexBuffer() noexcept; void updateNormalBuffer() noexcept; void updateTextureCoordsBuffer() noexcept; private: //vertex attributes and topology data std::vector< Vector > verts; //xyz verts INDEX_LIST_VARIANT ilist; //topology describing the faces, depends on renderType. Internal size of each index depends on index_memory_type std::vector< Vector > normals; std::vector< std::array > texCoords; std::vector< aftrColor4ub > colors; //OpenGL specific data, populated within createVAO GLenum renderType = GL_TRIANGLES; GLenum index_memory_type = GL_UNSIGNED_SHORT; //type of integer composing the ilist. Set in onCreate() GLuint vertexLocation = -1; ///< GLSL Attribute locations within the shader, queried and populated during creation GLuint normalLocation = -1; /// These are initialized to -1 even though they are unsigned because "0" is a valid GL attribute location GLuint colorLocation = -1; GLuint texCoordLocation = -1; GLuint vao = 0; ///< Vertex Array Object which stores all buffer binding states required to render this VAO GLuint indexBuffer = 0; ///< OpenGL Buffer containing indices to render the geometry GLuint vertexBuffer = 0; ///< OpenGL Buffer location for the vertex attributes (set of vertices passed to shader) GLuint normalBuffer = 0; ///< OpenGL Buffer location for the normal attributes (set of normals passed to shader) GLuint colorBuffer = 0; ///< OpenGL Buffer location for the colors attributes (set of colors passed to shader) GLuint textureBuffer = 0;///< OpenGL Buffer location for the textures attributes (set of textures passed to shader) public: //Here is how one could declare a sample builder function. It assumes each function returns the respective data. // For example: //IndexedGeometry_TE::fill_indexed_geometry_func igBuilder = [=]( // std::vector< Vector >& verts, // IndexedGeometry_TE::INDEX_LIST_VARIANT& ilist, // std::vector< Vector >& normals, // std::vector< std::array >& texCoords, // std::vector< aftrColor4ub >& colors ) // { // //the minimum needed is verts and ilist, other lists can be left empty // verts = vertFunc(); // ilist = idxFunc(); // normals = normFunc(); // texCoords = texFunc(); // //colors = colorFunc(); //if no colors are used, leave this empty // }; //This assumes each Func() returns -- vertFunc and idxFunc *must* return valid values; the other funcs can return empty if not used // vertFunc() -> std::vector // idxFunc() -> std::vector //(up to 256 indices or std::vector (65536) or std::vector (4 billion) ) // normFunc() -> std::vector // texFunc() -> std::vector< std::array > // colorFunc() -> std::vector< aftrColor4ub > using fill_indexed_geometry_func = std::function< void( decltype(verts)&, //std::vector< Vector >& verts INDEX_LIST_VARIANT&, //INDEX_LIST_VARIANT& ilist, decltype(normals)&, //std::vector< Vector >& normals decltype(texCoords)&, //std::vector< std::array >& texCoords decltype(colors)& ) >; //std::vector< aftrColor4ub >& colors INDEX_LIST_VARIANT const& getIndexListVariant() const noexcept { return this->ilist; } size_t getIndexCount() const noexcept { switch( this->ilist.index() ) { case 0: return std::get<0>( this->ilist ).size(); case 1: return std::get<1>( this->ilist ).size(); case 2: return std::get<2>( this->ilist ).size(); default: std::printf( "ERROR: %s: Invalid index storage unit in index list!\n" "For your index list in your IndexedGeometry_TE, have\n" "your index list in fill_indexed_geometry_func return\n" "one of the following types:\n" "std::vector\n" "std::vector\n" "std::vector...\n", AFTR_FILE_LINE_STR ); std::abort(); } } //Accessor methods to access the geometry of this data. //Visits the INDEX_LIST_VARIANT, converts all indices to std::vector, and returns that as a copy std::vector getIndicesCopy() const; std::span getVertices() const noexcept { return std::span{ verts }; } std::span getNormals() const noexcept { return std::span{ normals }; } std::span getTextureCoords() const noexcept { return std::span{ texCoords }; } std::span getColors() const noexcept { return std::span{ colors }; } GLsizei getVertexCount() const noexcept { return static_cast(verts.size()); }//number of vertices std::vector< decltype(verts)::value_type> getVerticesVec() const noexcept { return verts; } std::span getVertices() noexcept { return std::span{ verts }; } std::span getNormals() noexcept { return std::span{ normals }; } std::span getTextureCoords() noexcept { return std::span{ texCoords }; } std::span getColors() noexcept { return std::span{ colors }; } private: void onCreate( fill_indexed_geometry_func&& builder ); void createVAO(); void reattach(); //updates glGetAttribLocation indicies given the currently bound shader struct Cache { GLsizei saved_idx_size = 0; GLsizei saved_idx_buffer_size_bytes = 0; //populated in onCreate() and used to avoid re-looking up the ilist variant data each render GLvoid const* saved_idx_ptr = nullptr; //populated in onCreate() and used to avoid re-looking up the ilist variant data each render }; Cache cache; static std::tuple check_idx_size( INDEX_LIST_VARIANT const& var ); //friend std::tuple check_idx_size( IndexedGeometry_TE::INDEX_LIST_VARIANT const& var ); public: //Primary ctor -- pass in a func that simply places data in at least verts and ilist. //If the user wants normals, colors, or tex coords, simply make those vectors non-zero //in size as well. IndexedGeometry_TE( fill_indexed_geometry_func&& createGeometryFunc ); //Big 5 Overloads - ctor, copy ctor, copy assign operator, move ctor, move assign operator, + d'tor (should be virtual if any method in this class is virtual) IndexedGeometry_TE() = delete; ~IndexedGeometry_TE(); IndexedGeometry_TE( IndexedGeometry_TE const& toCopy ); IndexedGeometry_TE& operator=( IndexedGeometry_TE const& toCopyAssign ); IndexedGeometry_TE( IndexedGeometry_TE&& toMove ) noexcept; IndexedGeometry_TE& operator=( IndexedGeometry_TE&& toMoveAssign ) noexcept; }; }