diff --git a/source/MRViewer/MRRenderGLHelpers.cpp b/source/MRViewer/MRRenderGLHelpers.cpp new file mode 100644 index 000000000000..bc8546500c64 --- /dev/null +++ b/source/MRViewer/MRRenderGLHelpers.cpp @@ -0,0 +1,91 @@ +#include "MRRenderGLHelpers.h" +#include "MRViewer.h" +#include "MRGLMacro.h" + +namespace MR +{ + +void GlBuffer::gen() +{ + del(); + GL_EXEC( glGenBuffers( 1, &bufferID_ ) ); + assert( valid() ); +} + +void GlBuffer::del() +{ + if ( !valid() ) + return; + if ( Viewer::constInstance()->isGLInitialized() && loadGL() ) + { + GL_EXEC( glDeleteBuffers( 1, &bufferID_ ) ); + } + bufferID_ = NO_BUF; + size_ = 0; +} + +void GlBuffer::bind() +{ + assert( valid() ); + GL_EXEC( glBindBuffer( GL_ARRAY_BUFFER, bufferID_ ) ); +} + +void GlBuffer::loadData( const char * arr, size_t arrSize ) +{ + if ( !valid() ) + gen(); + bind(); + GLint64 bufSize = arrSize; + auto maxUploadSize = ( GLint64( 1 ) << 32 ) - 4096; //4Gb - 4096, 4Gb is already too much + if ( bufSize <= maxUploadSize ) + { + // buffers less than 4Gb are ok to load immediately + GL_EXEC( glBufferData( GL_ARRAY_BUFFER, bufSize, arr, GL_DYNAMIC_DRAW ) ); + } + else + { + // buffers more than 4Gb are better to split on chunks to avoid strange errors from GL or drivers + GL_EXEC( glBufferData( GL_ARRAY_BUFFER, bufSize, nullptr, GL_DYNAMIC_DRAW ) ); + GLint64 remStart = 0; + auto remSize = bufSize; + for ( ; remSize > maxUploadSize; remSize -= maxUploadSize, remStart += maxUploadSize ) + { + GL_EXEC( glBufferSubData( GL_ARRAY_BUFFER, remStart, maxUploadSize, arr + remStart ) ); + } + GL_EXEC( glBufferSubData( GL_ARRAY_BUFFER, remStart, remSize, arr + remStart ) ); + } + size_ = arrSize; +} + +GLint bindVertexAttribArray( const BindVertexAttribArraySettings & settings ) +{ + GL_EXEC( GLint id = glGetAttribLocation( settings.program_shader, settings.name ) ); + if ( id < 0 ) + return id; + if ( settings.arrSize == 0 && !settings.forceUse ) + { + GL_EXEC( glDisableVertexAttribArray( id ) ); + settings.buf.del(); + return id; + } + + if ( settings.refresh ) + settings.buf.loadData( settings.arr, settings.arrSize ); + else + settings.buf.bind(); + + // GL_FLOAT is left here consciously + if ( settings.isColor ) + { + GL_EXEC( glVertexAttribPointer( id, settings.baseTypeElementsNumber, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0 ) ); + } + else + { + GL_EXEC( glVertexAttribPointer( id, settings.baseTypeElementsNumber, GL_FLOAT, GL_FALSE, 0, 0 ) ); + } + + GL_EXEC( glEnableVertexAttribArray( id ) ); + return id; +} + +} //namespace MR diff --git a/source/MRViewer/MRRenderGLHelpers.h b/source/MRViewer/MRRenderGLHelpers.h index 113d4df2c817..a0f9d7be01ef 100644 --- a/source/MRViewer/MRRenderGLHelpers.h +++ b/source/MRViewer/MRRenderGLHelpers.h @@ -1,8 +1,8 @@ #pragma once #include "MRGladGlfw.h" -#include "MRGLMacro.h" -#include "MRViewer.h" +#include "exports.h" +#include "MRMesh/MRColor.h" #include namespace MR @@ -25,32 +25,18 @@ class GlBuffer size_t size() const { return size_; } // generates new buffer - void gen() - { - del(); - GL_EXEC( glGenBuffers( 1, &bufferID_ ) ); - assert( valid() ); - } + MRVIEWER_API void gen(); // deletes the buffer - void del() - { - if ( !valid() ) - return; - if ( Viewer::constInstance()->isGLInitialized() && loadGL() ) - { - GL_EXEC( glDeleteBuffers( 1, &bufferID_ ) ); - } - bufferID_ = NO_BUF; - size_ = 0; - } + MRVIEWER_API void del(); // binds current buffer to OpenGL context - void bind() { assert( valid() ); GL_EXEC( glBindBuffer( GL_ARRAY_BUFFER, bufferID_ ) ); } + MRVIEWER_API void bind(); // creates GL data buffer using given data + MRVIEWER_API void loadData( const char * arr, size_t arrSize ); template - void loadData( const T * arr, size_t arrSize ); + void loadData( const T * arr, size_t arrSize ) { loadData( (const char *)arr, sizeof( T ) * arrSize ); } private: /// another object takes control over the GL buffer @@ -61,70 +47,44 @@ class GlBuffer size_t size_ = 0; }; -template -void GlBuffer::loadData( const T * arr, size_t arrSize ) +struct BindVertexAttribArraySettings { - if ( !valid() ) - gen(); - bind(); - GLint64 bufSize = sizeof( T ) * arrSize; - auto maxUploadSize = ( GLint64( 1 ) << 32 ) - 4096; //4Gb - 4096, 4Gb is already too much - if ( bufSize <= maxUploadSize ) - { - // buffers less than 4Gb are ok to load immediately - GL_EXEC( glBufferData( GL_ARRAY_BUFFER, bufSize, arr, GL_DYNAMIC_DRAW ) ); - } - else - { - // buffers more than 4Gb are better to split on chunks to avoid strange errors from GL or drivers - GL_EXEC( glBufferData( GL_ARRAY_BUFFER, bufSize, nullptr, GL_DYNAMIC_DRAW ) ); - GLint64 remStart = 0; - auto remSize = bufSize; - for ( ; remSize > maxUploadSize; remSize -= maxUploadSize, remStart += maxUploadSize ) - { - GL_EXEC( glBufferSubData( GL_ARRAY_BUFFER, remStart, maxUploadSize, (const char *)arr + remStart ) ); - } - GL_EXEC( glBufferSubData( GL_ARRAY_BUFFER, remStart, remSize, (const char *)arr + remStart ) ); - } - size_ = size_t( bufSize ); -} + GLuint program_shader = 0; + const char * name = nullptr; + GlBuffer & buf; + const char * arr = nullptr; + size_t arrSize = 0; + int baseTypeElementsNumber = 0; + bool refresh = false; + bool forceUse = false; + bool isColor = false; +}; + +MRVIEWER_API GLint bindVertexAttribArray( const BindVertexAttribArraySettings & settings ); template class C, typename... args> -GLint bindVertexAttribArray( +inline GLint bindVertexAttribArray( const GLuint program_shader, - const std::string& name, + const char * name, GlBuffer & buf, const C& V, int baseTypeElementsNumber, bool refresh, bool forceUse = false ) { - GL_EXEC( GLint id = glGetAttribLocation( program_shader, name.c_str() ) ); - if ( id < 0 ) - return id; - if ( V.size() == 0 && !forceUse ) + BindVertexAttribArraySettings settings = { - GL_EXEC( glDisableVertexAttribArray( id ) ); - buf.del(); - return id; - } - - if ( refresh ) - buf.loadData( V.data(), V.size() ); - else - buf.bind(); - - // GL_FLOAT is left here consciously - if constexpr ( std::is_same_v ) - { - GL_EXEC( glVertexAttribPointer( id, baseTypeElementsNumber, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0 ) ); - } - else - { - GL_EXEC( glVertexAttribPointer( id, baseTypeElementsNumber, GL_FLOAT, GL_FALSE, 0, 0 ) ); - } - - GL_EXEC( glEnableVertexAttribArray( id ) ); - return id; + .program_shader = program_shader, + .name = name, + .buf = buf, + .arr = (const char*)V.data(), + .arrSize = sizeof(T) * V.size(), + .baseTypeElementsNumber = baseTypeElementsNumber, + .refresh = refresh, + .forceUse = forceUse, + .isColor = std::is_same_v + }; + return bindVertexAttribArray( settings ); } -} \ No newline at end of file + +} //namespace MR diff --git a/source/MRViewer/MRViewer.vcxproj b/source/MRViewer/MRViewer.vcxproj index 5b94acb73074..2a3bb16514df 100644 --- a/source/MRViewer/MRViewer.vcxproj +++ b/source/MRViewer/MRViewer.vcxproj @@ -23,6 +23,7 @@ + diff --git a/source/MRViewer/MRViewer.vcxproj.filters b/source/MRViewer/MRViewer.vcxproj.filters index 6fbec2827b41..0fcc93ec5d1b 100644 --- a/source/MRViewer/MRViewer.vcxproj.filters +++ b/source/MRViewer/MRViewer.vcxproj.filters @@ -217,6 +217,9 @@ IO + + Render\Implementations +