From 75eb5491d58f705b65c647b5b27174550ad4e0b8 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Mon, 22 Jul 2013 10:41:12 +0200 Subject: [PATCH] Code refactorization. VBO_CONTAINER is split to [NON]CACHED_MANAGER, GPU_MANAGER and VERTEX_MANAGER. --- common/CMakeLists.txt | 8 +- common/drawpanel_gal.cpp | 2 +- common/gal/cairo/cairo_gal.cpp | 24 +- ...vbo_container.cpp => cached_container.cpp} | 413 ++++++----- common/gal/opengl/gpu_manager.cpp | 283 ++++++++ common/gal/opengl/noncached_container.cpp | 94 +++ common/gal/opengl/opengl_gal.cpp | 681 +++++++----------- common/gal/opengl/vbo_item.cpp | 116 --- common/gal/opengl/vertex_container.cpp | 57 ++ common/gal/opengl/vertex_item.cpp | 53 ++ common/gal/opengl/vertex_manager.cpp | 203 ++++++ include/gal/cairo/cairo_gal.h | 4 +- include/gal/opengl/cached_container.h | 185 +++++ include/gal/opengl/gpu_manager.h | 164 +++++ include/gal/opengl/noncached_container.h | 73 ++ include/gal/opengl/opengl_gal.h | 146 +--- include/gal/opengl/vbo_container.h | 344 --------- include/gal/opengl/vbo_item.h | 177 ----- include/gal/opengl/vertex_common.h | 75 ++ include/gal/opengl/vertex_container.h | 158 ++++ include/gal/opengl/vertex_item.h | 103 +++ include/gal/opengl/vertex_manager.h | 341 +++++++++ 22 files changed, 2326 insertions(+), 1378 deletions(-) rename common/gal/opengl/{vbo_container.cpp => cached_container.cpp} (55%) create mode 100644 common/gal/opengl/gpu_manager.cpp create mode 100644 common/gal/opengl/noncached_container.cpp delete mode 100644 common/gal/opengl/vbo_item.cpp create mode 100644 common/gal/opengl/vertex_container.cpp create mode 100644 common/gal/opengl/vertex_item.cpp create mode 100644 common/gal/opengl/vertex_manager.cpp create mode 100644 include/gal/opengl/cached_container.h create mode 100644 include/gal/opengl/gpu_manager.h create mode 100644 include/gal/opengl/noncached_container.h delete mode 100644 include/gal/opengl/vbo_container.h delete mode 100644 include/gal/opengl/vbo_item.h create mode 100644 include/gal/opengl/vertex_common.h create mode 100644 include/gal/opengl/vertex_container.h create mode 100644 include/gal/opengl/vertex_item.h create mode 100644 include/gal/opengl/vertex_manager.h diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 0c5fd78172..b6adf0d275 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -36,8 +36,12 @@ set(GAL_SRCS gal/color4d.cpp gal/opengl/opengl_gal.cpp gal/opengl/shader.cpp - gal/opengl/vbo_item.cpp - gal/opengl/vbo_container.cpp + gal/opengl/vertex_item.cpp + gal/opengl/vertex_container.cpp + gal/opengl/cached_container.cpp + gal/opengl/noncached_container.cpp + gal/opengl/vertex_manager.cpp + gal/opengl/gpu_manager.cpp gal/cairo/cairo_gal.cpp view/wx_view_controls.cpp ) diff --git a/common/drawpanel_gal.cpp b/common/drawpanel_gal.cpp index 7837cf8d04..3549455245 100644 --- a/common/drawpanel_gal.cpp +++ b/common/drawpanel_gal.cpp @@ -132,7 +132,7 @@ void EDA_DRAW_PANEL_GAL::Refresh( bool eraseBackground, const wxRect* rect ) #endif /* __WXDEBUG__ */ m_gal->BeginDrawing(); - m_gal->SetBackgroundColor( KiGfx::COLOR4D( 0, 0, 0, 1.0 ) ); + m_gal->SetBackgroundColor( KiGfx::COLOR4D( 0.0, 0.0, 0.0, 1.0 ) ); m_gal->ClearScreen(); m_gal->DrawGrid(); diff --git a/common/gal/cairo/cairo_gal.cpp b/common/gal/cairo/cairo_gal.cpp index d21a1a8286..ba944e842f 100644 --- a/common/gal/cairo/cairo_gal.cpp +++ b/common/gal/cairo/cairo_gal.cpp @@ -37,7 +37,7 @@ using namespace KiGfx; CAIRO_GAL::CAIRO_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener, wxEvtHandler* aPaintListener, const wxString& aName ) : - wxWindow( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxEXPAND, aName ) + wxWindow( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxEXPAND, aName ) { // Default values fillColor = COLOR4D( 0, 0, 0, 1 ); @@ -141,7 +141,7 @@ void CAIRO_GAL::initSurface() cairoSurface = cairo_image_surface_create_for_data( (unsigned char*) bitmapBuffer, CAIRO_FORMAT_RGB24, clientRectangle.width, clientRectangle.height, stride ); - cairoImage = cairo_create ( cairoSurface ); + cairoImage = cairo_create( cairoSurface ); #ifdef __WXDEBUG__ cairo_status_t status = cairo_status( cairoImage ); wxASSERT_MSG( status == CAIRO_STATUS_SUCCESS, "Cairo context creation error" ); @@ -194,10 +194,10 @@ void CAIRO_GAL::deinitSurface() } -unsigned int CAIRO_GAL::getGroupNumber() +unsigned int CAIRO_GAL::getNewGroupNumber() { wxASSERT_MSG( groups.size() < std::numeric_limits::max(), - wxT( "There are no free slots to store a group" ) ); + wxT( "There are no free slots to store a group" ) ); while( groups.find( groupCounter ) != groups.end() ) { @@ -230,6 +230,7 @@ void CAIRO_GAL::EndDrawing() // Now translate the raw image data from the format stored // by cairo into a format understood by wxImage. unsigned char* wxOutputPtr = wxOutput; + for( size_t count = 0; count < bufferSize; count++ ) { unsigned int value = bitmapBuffer[count]; @@ -287,7 +288,8 @@ void CAIRO_GAL::DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint } -void CAIRO_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, double aWidth ) +void CAIRO_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, + double aWidth ) { if( isFillEnabled ) { @@ -317,7 +319,6 @@ void CAIRO_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPo cairo_line_to( cairoImage, lineLength, -aWidth / 2.0 ); cairo_restore( cairoImage ); - } isElementAdded = true; @@ -351,7 +352,8 @@ void CAIRO_GAL::DrawPolyline( std::deque& aPointList ) bool isFirstPoint = true; // Iterate over the point list and draw the segments - for( std::deque::const_iterator it = aPointList.begin(); it != aPointList.end(); ++it ) + std::deque::const_iterator it; + for( it = aPointList.begin(); it != aPointList.end(); ++it ) { if( isFirstPoint ) { @@ -373,7 +375,8 @@ void CAIRO_GAL::DrawPolygon( const std::deque& aPointList ) bool isFirstPoint = true; // Iterate over the point list and draw the polygon - for( std::deque::const_iterator it = aPointList.begin(); it != aPointList.end(); ++it ) + std::deque::const_iterator it; + for( it = aPointList.begin(); it != aPointList.end(); ++it ) { if( isFirstPoint ) { @@ -644,10 +647,10 @@ int CAIRO_GAL::BeginGroup() storePath(); Group group; - int groupNumber = getGroupNumber(); + int groupNumber = getNewGroupNumber(); groups.insert( std::make_pair( groupNumber, group ) ); currentGroup = &groups[groupNumber]; - isGrouping = true; + isGrouping = true; return groupNumber; } @@ -677,6 +680,7 @@ void CAIRO_GAL::DeleteGroup( int aGroupNumber ) // Delete the Cairo paths std::deque::iterator it, end; + for( it = groups[aGroupNumber].begin(), end = groups[aGroupNumber].end(); it != end; ++it ) { if( it->command == CMD_FILL_PATH || it->command == CMD_STROKE_PATH ) diff --git a/common/gal/opengl/vbo_container.cpp b/common/gal/opengl/cached_container.cpp similarity index 55% rename from common/gal/opengl/vbo_container.cpp rename to common/gal/opengl/cached_container.cpp index fd6dea86f3..ea718530ce 100644 --- a/common/gal/opengl/vbo_container.cpp +++ b/common/gal/opengl/cached_container.cpp @@ -23,171 +23,67 @@ */ /** - * @file vbo_container.cpp - * @brief Class to store VBO_ITEMs. + * @file cached_container.cpp + * @brief Class to store instances of VERTEX with caching. It allows storing VERTEX objects and + * associates them with VERTEX_ITEMs. This leads to a possibility of caching vertices data in the + * GPU memory and a fast reuse of that data. */ -#include -#include -#include +#include +#include +#include +#include #include +#include #ifdef __WXDEBUG__ #include #endif /* __WXDEBUG__ */ using namespace KiGfx; -VBO_CONTAINER::VBO_CONTAINER( unsigned int aSize ) : - m_freeSpace( aSize ), m_currentSize( aSize ), m_initialSize( aSize ), m_transform( NULL ), - m_failed( false ) +CACHED_CONTAINER::CACHED_CONTAINER( unsigned int aSize ) : + VERTEX_CONTAINER( aSize ) { - // By default no shader is used - m_shader[0] = 0; - - m_vertices = static_cast( malloc( aSize * sizeof( VBO_VERTEX ) ) ); - // In the beginning there is only free space m_freeChunks.insert( Chunk( aSize, 0 ) ); } -VBO_CONTAINER::~VBO_CONTAINER() +void CACHED_CONTAINER::SetItem( VERTEX_ITEM* aItem ) { - free( m_vertices ); -} + if( aItem == NULL ) + { + wxASSERT( m_item != NULL ); + // Finishing the item + if( m_itemSize < m_chunkSize ) + { + // There is some not used but reserved memory left, so we should return it to the pool + int itemOffset = m_item->GetOffset(); -void VBO_CONTAINER::StartItem( VBO_ITEM* aItem ) -{ - m_item = aItem; - m_itemSize = aItem->GetSize(); - m_chunkSize = m_itemSize; + // Add the not used memory back to the pool + m_freeChunks.insert( Chunk( m_chunkSize - m_itemSize, itemOffset + m_itemSize ) ); + m_freeSpace += ( m_chunkSize - m_itemSize ); + // mergeFreeChunks(); + } - if( m_itemSize == 0 ) - m_items.insert( m_item ); // The item was not stored before + m_item = NULL; + } else - m_chunkOffset = m_item->GetOffset(); -} - - -void VBO_CONTAINER::EndItem() -{ - if( m_itemSize < m_chunkSize ) { - // Add the not used memory back to the pool - m_freeChunks.insert( Chunk( m_chunkSize - m_itemSize, m_chunkOffset + m_itemSize ) ); - m_freeSpace += ( m_chunkSize - m_itemSize ); - } + m_item = aItem; + m_itemSize = m_item->GetSize(); + m_chunkSize = m_itemSize; - m_item = NULL; -} - - -void VBO_CONTAINER::Add( const VBO_VERTEX* aVertex, unsigned int aSize ) -{ - // Pointer to the vertex that we are currently adding - VBO_VERTEX* vertexPtr = allocate( aSize ); - - if( vertexPtr == NULL ) - return; - - for( unsigned int i = 0; i < aSize; ++i ) - { - // Modify the vertex according to the currently used transformations - if( m_transform != NULL ) - { - // Apply transformations - glm::vec4 vertex( aVertex[i].x, aVertex[i].y, aVertex[i].z, 1.0f ); - vertex = *m_transform * vertex; - - // Replace only coordinates, leave color as it is - vertexPtr->x = vertex.x; - vertexPtr->y = vertex.y; - vertexPtr->z = vertex.z; - } + if( m_itemSize == 0 ) + m_items.insert( m_item ); // The item was not stored before else - { - // Simply copy coordinates - vertexPtr->x = aVertex[i].x; - vertexPtr->y = aVertex[i].y; - vertexPtr->z = aVertex[i].z; - } - - // Apply currently used color - vertexPtr->r = m_color[0]; - vertexPtr->g = m_color[1]; - vertexPtr->b = m_color[2]; - vertexPtr->a = m_color[3]; - - // Apply currently used shader - for( unsigned int j = 0; j < VBO_ITEM::ShaderStride; ++j ) - { - vertexPtr->shader[j] = m_shader[j]; - } - - vertexPtr++; - } - -} - - -void VBO_CONTAINER::Clear() -{ - // Change size to the default one - m_vertices = static_cast( realloc( m_vertices, - m_initialSize * sizeof( VBO_VERTEX ) ) ); - - // Set the size of all the stored VERTEX_ITEMs to 0, so it is clear that they are not held - // in the container anymore - Items::iterator it; - for( it = m_items.begin(); it != m_items.end(); ++it ) - { - ( *it )->setSize( 0 ); - } - m_items.clear(); - - // Reset state variables - m_transform = NULL; - m_failed = false; - - // By default no shader is used - m_shader[0] = 0; - - // In the beginning there is only free space - m_freeSpace = m_initialSize; - m_currentSize = m_initialSize; - m_freeChunks.clear(); - m_freeChunks.insert( Chunk( m_freeSpace, 0 ) ); -} - - -void VBO_CONTAINER::Free( VBO_ITEM* aItem ) -{ - freeItem( aItem ); - - // Dynamic memory freeing, there is no point in holding - // a large amount of memory when there is no use for it - if( m_freeSpace > ( m_currentSize / 2 ) && m_currentSize > defaultInitSize ) - { - resizeContainer( m_currentSize / 2 ); + m_chunkOffset = m_item->GetOffset(); } } -VBO_VERTEX* VBO_CONTAINER::GetAllVertices() const -{ - return m_vertices; -} - - -VBO_VERTEX* VBO_CONTAINER::GetVertices( const VBO_ITEM* aItem ) const -{ - int offset = aItem->GetOffset(); - - return &m_vertices[offset]; -} - -VBO_VERTEX* VBO_CONTAINER::allocate( unsigned int aSize ) +VERTEX* CACHED_CONTAINER::Allocate( unsigned int aSize ) { wxASSERT( m_item != NULL ); @@ -198,8 +94,9 @@ VBO_VERTEX* VBO_CONTAINER::allocate( unsigned int aSize ) { // There is not enough space in the currently reserved chunk, so we have to resize it - // Reserve a bigger memory chunk for the current item - m_chunkSize = std::max( ( 2 * m_itemSize ) + aSize, (unsigned) 3 ); + // Reserve a bigger memory chunk for the current item and + // make it multiple of 3 to store triangles + m_chunkSize = ( 2 * m_itemSize ) + aSize + ( 3 - aSize % 3 ); // Save the current size before reallocating m_chunkOffset = reallocate( m_chunkSize ); @@ -210,16 +107,81 @@ VBO_VERTEX* VBO_CONTAINER::allocate( unsigned int aSize ) } } - VBO_VERTEX* reserved = &m_vertices[m_chunkOffset + m_itemSize]; + VERTEX* reserved = &m_vertices[m_chunkOffset + m_itemSize]; m_itemSize += aSize; m_item->setSize( m_itemSize ); + // The content has to be updated + m_dirty = true; + +#if CACHED_CONTAINER_TEST > 1 + test(); +#endif + return reserved; } -unsigned int VBO_CONTAINER::reallocate( unsigned int aSize ) +void CACHED_CONTAINER::Erase() { + wxASSERT( m_item != NULL ); + + freeItem( m_item ); + + // Dynamic memory freeing, there is no point in holding + // a large amount of memory when there is no use for it + if( m_freeSpace > ( m_currentSize / 2 ) && m_currentSize > m_initialSize ) + { + resizeContainer( m_currentSize / 2 ); + } +} + + +void CACHED_CONTAINER::Clear() +{ + // Change size to the default one + m_vertices = static_cast( realloc( m_vertices, + m_initialSize * sizeof( VERTEX ) ) ); + + // Reset state variables + m_freeSpace = m_initialSize; + m_currentSize = m_initialSize; + m_failed = false; + + // Set the size of all the stored VERTEX_ITEMs to 0, so it is clear that they are not held + // in the container anymore + Items::iterator it; + + for( it = m_items.begin(); it != m_items.end(); ++it ) + { + ( *it )->setSize( 0 ); + } + + m_items.clear(); + + + // Now there is only free space left + m_freeChunks.clear(); + m_freeChunks.insert( Chunk( m_freeSpace, 0 ) ); +} + + +VERTEX* CACHED_CONTAINER::GetVertices( const VERTEX_ITEM* aItem ) const +{ + int offset = aItem->GetOffset(); + + return &m_vertices[offset]; +} + + +unsigned int CACHED_CONTAINER::reallocate( unsigned int aSize ) +{ +#if CACHED_CONTAINER_TEST > 2 + wxLogDebug( wxT( "Resize 0x%08x to %d" ), (int) m_item, aSize ); + showFreeChunks(); + showReservedChunks(); +#endif + // Is there enough space to store vertices? if( m_freeSpace < aSize ) { @@ -260,7 +222,7 @@ unsigned int VBO_CONTAINER::reallocate( unsigned int aSize ) } // Parameters of the allocated cuhnk - unsigned int chunkSize = newChunk->first; + unsigned int chunkSize = newChunk->first; unsigned int chunkOffset = newChunk->second; wxASSERT( chunkSize >= aSize ); @@ -269,37 +231,57 @@ unsigned int VBO_CONTAINER::reallocate( unsigned int aSize ) // Check if the item was previously stored in the container if( m_itemSize > 0 ) { +#if CACHED_CONTAINER_TEST > 3 + wxLogDebug( wxT( "Moving 0x%08x from 0x%08x to 0x%08x" ), + (int) m_item, oldChunkOffset, chunkOffset ); +#endif // The item was reallocated, so we have to copy all the old data to the new place memcpy( &m_vertices[chunkOffset], &m_vertices[m_chunkOffset], - m_itemSize * VBO_ITEM::VertByteSize ); + m_itemSize * VertexSize ); // Free the space previously used by the chunk m_freeChunks.insert( Chunk( m_itemSize, m_chunkOffset ) ); m_freeSpace += m_itemSize; } + // Remove the allocated chunk from the free space pool m_freeChunks.erase( newChunk ); - m_freeSpace -= chunkSize; // If there is some space left, return it to the pool - add an entry for it if( chunkSize > aSize ) { m_freeChunks.insert( Chunk( chunkSize - aSize, chunkOffset + aSize ) ); - m_freeSpace += chunkSize - aSize; } + m_freeSpace -= aSize; + // mergeFreeChunks(); + m_item->setOffset( chunkOffset ); +#if CACHED_CONTAINER_TEST > 2 + showFreeChunks(); + showReservedChunks(); +#endif + return chunkOffset; } -bool VBO_CONTAINER::defragment( VBO_VERTEX* aTarget ) +bool CACHED_CONTAINER::defragment( VERTEX* aTarget ) { +#if CACHED_CONTAINER_TEST > 0 + wxLogDebug( wxT( "Defragmenting" ) ); +#endif +#ifdef __WXDEBUG__ + prof_counter totalTime; + prof_start( &totalTime, false ); +#endif /* __WXDEBUG__ */ + if( aTarget == NULL ) { // No target was specified, so we have to reallocate our own space - aTarget = static_cast( malloc( m_currentSize * sizeof( VBO_VERTEX ) ) ); + aTarget = static_cast( malloc( m_currentSize * sizeof( VERTEX ) ) ); + if( aTarget == NULL ) { wxLogError( wxT( "Run out of memory" ) ); @@ -309,16 +291,17 @@ bool VBO_CONTAINER::defragment( VBO_VERTEX* aTarget ) int newOffset = 0; Items::iterator it, it_end; + for( it = m_items.begin(), it_end = m_items.end(); it != it_end; ++it ) { - VBO_ITEM* item = *it; - int itemOffset = item->GetOffset(); - int itemSize = item->GetSize(); + VERTEX_ITEM* item = *it; + int itemOffset = item->GetOffset(); + int itemSize = item->GetSize(); // Move an item to the new container - memcpy( &aTarget[newOffset], &m_vertices[itemOffset], itemSize * VBO_ITEM::VertByteSize ); + memcpy( &aTarget[newOffset], &m_vertices[itemOffset], itemSize * VertexSize ); - // Update its offset + // Update new offset item->setOffset( newOffset ); // Move to the next free space @@ -330,17 +313,29 @@ bool VBO_CONTAINER::defragment( VBO_VERTEX* aTarget ) // Now there is only one big chunk of free memory m_freeChunks.clear(); - m_freeChunks.insert( Chunk( m_freeSpace, reservedSpace() ) ); + m_freeChunks.insert( Chunk( m_freeSpace, m_currentSize - m_freeSpace ) ); + +#ifdef __WXDEBUG__ + prof_end( &totalTime ); + + wxLogDebug( wxT( "Defragmented the container storing %d vertices / %.1f ms" ), + m_currentSize - m_freeSpace, (double) totalTime.value / 1000.0 ); +#endif /* __WXDEBUG__ */ return true; } -void VBO_CONTAINER::mergeFreeChunks() +void CACHED_CONTAINER::mergeFreeChunks() { - if( m_freeChunks.size() < 2 ) // There are no chunks that can be merged + if( m_freeChunks.size() <= 1 ) // There are no chunks that can be merged return; +#ifdef __WXDEBUG__ + prof_counter totalTime; + prof_start( &totalTime, false ); +#endif /* __WXDEBUG__ */ + // Reversed free chunks map - this one stores chunk size with its offset as the key std::list freeChunks; @@ -349,6 +344,7 @@ void VBO_CONTAINER::mergeFreeChunks() { freeChunks.push_back( std::make_pair( it->second, it->first ) ); } + m_freeChunks.clear(); freeChunks.sort(); @@ -356,6 +352,7 @@ void VBO_CONTAINER::mergeFreeChunks() unsigned int offset = freeChunks.front().first; unsigned int size = freeChunks.front().second; freeChunks.pop_front(); + for( itf = freeChunks.begin(), itf_end = freeChunks.end(); itf != itf_end; ++itf ) { if( itf->first == offset + size ) @@ -371,17 +368,30 @@ void VBO_CONTAINER::mergeFreeChunks() // and let's check the next chunk offset = itf->first; size = itf->second; + } } // Add the last one m_freeChunks.insert( std::make_pair( size, offset ) ); + +#ifdef __WXDEBUG__ + prof_end( &totalTime ); + + wxLogDebug( wxT( "Merged free chunks / %.1f ms" ), (double) totalTime.value / 1000.0 ); +#endif /* __WXDEBUG__ */ + + test(); } -bool VBO_CONTAINER::resizeContainer( unsigned int aNewSize ) +bool CACHED_CONTAINER::resizeContainer( unsigned int aNewSize ) { - VBO_VERTEX* newContainer; +#if CACHED_CONTAINER_TEST > 0 + wxLogDebug( wxT( "Resizing container from %d to %d" ), m_currentSize, aNewSize ); +#endif + + VERTEX* newContainer; if( aNewSize < m_currentSize ) { @@ -390,7 +400,8 @@ bool VBO_CONTAINER::resizeContainer( unsigned int aNewSize ) if( reservedSpace() > aNewSize ) return false; - newContainer = static_cast( malloc( aNewSize * sizeof( VBO_VERTEX ) ) ); + newContainer = static_cast( malloc( aNewSize * sizeof( VERTEX ) ) ); + if( newContainer == NULL ) { wxLogError( wxT( "Run out of memory" ) ); @@ -407,7 +418,8 @@ bool VBO_CONTAINER::resizeContainer( unsigned int aNewSize ) else { // Enlarging container - newContainer = static_cast( realloc( m_vertices, aNewSize * sizeof( VBO_VERTEX ) ) ); + newContainer = static_cast( realloc( m_vertices, aNewSize * sizeof( VERTEX ) ) ); + if( newContainer == NULL ) { wxLogError( wxT( "Run out of memory" ) ); @@ -420,35 +432,94 @@ bool VBO_CONTAINER::resizeContainer( unsigned int aNewSize ) m_vertices = newContainer; - m_freeSpace += ( aNewSize - m_currentSize ); + m_freeSpace += ( aNewSize - m_currentSize ); m_currentSize = aNewSize; return true; } -void VBO_CONTAINER::freeItem( VBO_ITEM* aItem ) +void CACHED_CONTAINER::freeItem( VERTEX_ITEM* aItem ) { - int size = aItem->GetSize(); - int offset = aItem->GetOffset(); + int size = aItem->GetSize(); + int offset = aItem->GetOffset(); + // Insert a free memory chunk entry in the place where item was stored m_freeChunks.insert( Chunk( size, offset ) ); m_freeSpace += size; m_items.erase( aItem ); - // Item size is set to 0, so it means that it is not stored in the container + // Indicate that the item is not stored in the container anymore aItem->setSize( 0 ); } -void VBO_CONTAINER::test() const +unsigned int CACHED_CONTAINER::getPowerOf2( unsigned int aNumber ) const { - unsigned int freeSpace = 0; - FreeChunkMap::const_iterator it, it_end; + unsigned int power = 1; - // Check if the amount of free memory stored as chunks is the same as reported by m_freeSpace - for( it = m_freeChunks.begin(), it_end = m_freeChunks.end(); it != it_end; ++it ) - freeSpace += it->first; + while( power < aNumber && power != 0 ) + power <<= 1; + + return power; +} + + +#ifdef CACHED_CONTAINER_TEST +void CACHED_CONTAINER::showFreeChunks() +{ + FreeChunkMap::iterator it; + + wxLogDebug( wxT( "Free chunks:" ) ); + + for( it = m_freeChunks.begin(); it != m_freeChunks.end(); ++it ) + { + unsigned int offset = getChunkOffset( *it ); + unsigned int size = getChunkSize( *it ); + + wxLogDebug( wxT( "[0x%08x-0x%08x] (size %d)" ), + offset, offset + size - 1, size ); + } +} + + +void CACHED_CONTAINER::showReservedChunks() +{ + Items::iterator it; + + wxLogDebug( wxT( "Reserved chunks:" ) ); + + for( it = m_items.begin(); it != m_items.end(); ++it ) + { + VERTEX_ITEM* item = *it; + unsigned int offset = item->GetOffset(); + unsigned int size = item->GetSize(); + + wxLogDebug( wxT( "[0x%08x-0x%08x] @ 0x%08x (size %d)" ), + offset, offset + size - 1, (int) item, size ); + } +} + + +void CACHED_CONTAINER::test() +{ + // Free space check + unsigned int freeSpace = 0; + FreeChunkMap::iterator itf; + for( itf = m_freeChunks.begin(); itf != m_freeChunks.end(); ++itf ) + freeSpace += getChunkSize( *itf ); wxASSERT( freeSpace == m_freeSpace ); + + // Reserved space check + /*unsigned int reservedSpace = 0; + Items::iterator itr; + for( itr = m_items.begin(); itr != m_items.end(); ++itr ) + reservedSpace += ( *itr )->GetSize(); + reservedSpace += m_itemSize; // Add the current chunk size + + wxASSERT( ( freeSpace + reservedSpace ) == m_currentSize );*/ + + // Overlapping check TBD } +#endif /* CACHED_CONTAINER_TEST */ diff --git a/common/gal/opengl/gpu_manager.cpp b/common/gal/opengl/gpu_manager.cpp new file mode 100644 index 0000000000..dea8e76f91 --- /dev/null +++ b/common/gal/opengl/gpu_manager.cpp @@ -0,0 +1,283 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Maciej Suminski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * @file gpu_manager.cpp + * @brief Class to handle uploading vertices and indices to GPU in drawing purposes. + */ + +#include +#include +#include +#include +#include +#include +#ifdef __WXDEBUG__ +#include +#endif + +using namespace KiGfx; + +GPU_MANAGER* GPU_MANAGER::MakeManager( VERTEX_CONTAINER* aContainer ) +{ + if( typeid( *aContainer ) == typeid( CACHED_CONTAINER ) ) + return new GPU_CACHED_MANAGER( aContainer ); + else if( typeid( *aContainer ) == typeid( NONCACHED_CONTAINER ) ) + return new GPU_NONCACHED_MANAGER( aContainer ); + + wxASSERT_MSG( false, "Not handled container type" ); + return NULL; +} + + +GPU_MANAGER::GPU_MANAGER( VERTEX_CONTAINER* aContainer ) : + m_container( aContainer ), m_shader( NULL ) +{ +} + + +GPU_MANAGER::~GPU_MANAGER() +{ +} + + +void GPU_MANAGER::SetShader( SHADER& aShader ) +{ + m_shader = &aShader; + + m_shaderAttrib = m_shader->GetAttribute( "attrShaderParams" ); + + if( m_shaderAttrib == -1 ) + { + wxLogFatalError( wxT( "Could not get the shader attribute location" ) ); + } +} + + +// Cached manager +GPU_CACHED_MANAGER::GPU_CACHED_MANAGER( VERTEX_CONTAINER* aContainer ) : + GPU_MANAGER( aContainer ), m_buffersInitialized( false ), m_indicesPtr( NULL ), + m_indicesSize( 0 ) +{ +} + + +GPU_CACHED_MANAGER::~GPU_CACHED_MANAGER() +{ + if( m_buffersInitialized ) + { + glBindBuffer( GL_ARRAY_BUFFER, 0 ); + glDeleteBuffers( 1, &m_verticesBuffer ); + } +} + + +void GPU_CACHED_MANAGER::Initialize() +{ + wxASSERT( !m_buffersInitialized ); + + if( !m_buffersInitialized ) + { + glGenBuffers( 1, &m_verticesBuffer ); + m_buffersInitialized = true; + } +} + + +void GPU_CACHED_MANAGER::BeginDrawing() +{ + wxASSERT( !m_isDrawing ); + + if( m_container->isDirty() ) + uploadToGpu(); + + // Number of vertices to be drawn in the EndDrawing() + m_indicesSize = 0; + // Set the indices pointer to the beginning of the indices-to-draw buffer + m_indicesPtr = m_indices.get(); + + m_isDrawing = true; +} + + +void GPU_CACHED_MANAGER::DrawIndices( unsigned int aOffset, unsigned int aSize ) +{ + wxASSERT( m_isDrawing ); + + // Copy indices of items that should be drawn to GPU memory + for( unsigned int i = aOffset; i < aOffset + aSize; *m_indicesPtr++ = i++ ); + + m_indicesSize += aSize; +} + + +void GPU_CACHED_MANAGER::DrawAll() +{ + wxASSERT( m_isDrawing ); + + m_indicesSize = m_container->GetSize(); + for( unsigned int i = 0; i < m_indicesSize; *m_indicesPtr++ = i++ ); +} + + +void GPU_CACHED_MANAGER::EndDrawing() +{ + wxASSERT( m_isDrawing ); + + // Prepare buffers + glEnableClientState( GL_VERTEX_ARRAY ); + glEnableClientState( GL_COLOR_ARRAY ); + + // Bind vertices data buffers + glBindBuffer( GL_ARRAY_BUFFER, m_verticesBuffer ); + glVertexPointer( CoordStride, GL_FLOAT, VertexSize, 0 ); + glColorPointer( ColorStride, GL_UNSIGNED_BYTE, VertexSize, (GLvoid*) ColorOffset ); + + if( m_shader != NULL ) // Use shader if applicable + { + m_shader->Use(); + glEnableVertexAttribArray( m_shaderAttrib ); + glVertexAttribPointer( m_shaderAttrib, ShaderStride, GL_FLOAT, GL_FALSE, + VertexSize, (GLvoid*) ShaderOffset ); + } + + glDrawElements( GL_TRIANGLES, m_indicesSize, GL_UNSIGNED_INT, (GLvoid*) m_indices.get() ); + + glBindBuffer( GL_ARRAY_BUFFER, 0 ); + + // Deactivate vertex array + glDisableClientState( GL_COLOR_ARRAY ); + glDisableClientState( GL_VERTEX_ARRAY ); + + if( m_shader != NULL ) + { + glDisableVertexAttribArray( m_shaderAttrib ); + m_shader->Deactivate(); + } + + m_isDrawing = false; +} + + +void GPU_CACHED_MANAGER::uploadToGpu() +{ +#ifdef __WXDEBUG__ + prof_counter totalTime; + prof_start( &totalTime, false ); +#endif /* __WXDEBUG__ */ + + if( !m_buffersInitialized ) + Initialize(); + + int bufferSize = m_container->GetSize(); + GLfloat* vertices = (GLfloat*) m_container->GetAllVertices(); + + // Upload vertices coordinates and shader types to GPU memory + glBindBuffer( GL_ARRAY_BUFFER, m_verticesBuffer ); + glBufferData( GL_ARRAY_BUFFER, bufferSize * VertexSize, vertices, GL_DYNAMIC_DRAW ); + glBindBuffer( GL_ARRAY_BUFFER, 0 ); + + // Allocate the biggest possible buffer for indices + m_indices.reset( new GLuint[bufferSize] ); + + if( glGetError() != GL_NO_ERROR ) + { + wxLogError( wxT( "Error during data upload to the GPU memory" ) ); + } + +#ifdef __WXDEBUG__ + prof_end( &totalTime ); + + wxLogDebug( wxT( "Uploading %d vertices to GPU / %.1f ms" ), + bufferSize, (double) totalTime.value / 1000.0 ); +#endif /* __WXDEBUG__ */ +} + + +// Noncached manager +GPU_NONCACHED_MANAGER::GPU_NONCACHED_MANAGER( VERTEX_CONTAINER* aContainer ) : + GPU_MANAGER( aContainer ) +{ +} + + +void GPU_NONCACHED_MANAGER::Initialize() +{ + // Nothing has to be intialized +} + + +void GPU_NONCACHED_MANAGER::BeginDrawing() +{ + // Nothing has to be prepared +} + + +void GPU_NONCACHED_MANAGER::DrawIndices( unsigned int aOffset, unsigned int aSize ) +{ + wxASSERT_MSG( false, wxT( "Not implemented yet" ) ); +} + + +void GPU_NONCACHED_MANAGER::DrawAll() +{ + // This is the default use case, nothing has to be done + // The real rendering takes place in the EndDrawing() function +} + + +void GPU_NONCACHED_MANAGER::EndDrawing() +{ + VERTEX* vertices = m_container->GetAllVertices(); + GLfloat* coordinates = (GLfloat*) ( vertices ); + GLubyte* colors = (GLubyte*) ( vertices ) + ColorOffset; + GLfloat* shaders = (GLfloat*) ( vertices ) + ShaderOffset / sizeof(GLfloat); + + // Prepare buffers + glEnableClientState( GL_VERTEX_ARRAY ); + glEnableClientState( GL_COLOR_ARRAY ); + + glVertexPointer( CoordStride, GL_FLOAT, VertexSize, coordinates ); + glColorPointer( ColorStride, GL_UNSIGNED_BYTE, VertexSize, colors ); + + if( m_shader != NULL ) // Use shader if applicable + { + m_shader->Use(); + glEnableVertexAttribArray( m_shaderAttrib ); + glVertexAttribPointer( m_shaderAttrib, ShaderStride, GL_FLOAT, GL_FALSE, + VertexSize, shaders ); + } + + glDrawArrays( GL_TRIANGLES, 0, m_container->GetSize() ); + + // Deactivate vertex array + glDisableClientState( GL_COLOR_ARRAY ); + glDisableClientState( GL_VERTEX_ARRAY ); + + if( m_shader != NULL ) + { + glDisableVertexAttribArray( m_shaderAttrib ); + m_shader->Deactivate(); + } +} diff --git a/common/gal/opengl/noncached_container.cpp b/common/gal/opengl/noncached_container.cpp new file mode 100644 index 0000000000..f7eb3f897a --- /dev/null +++ b/common/gal/opengl/noncached_container.cpp @@ -0,0 +1,94 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Maciej Suminski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * @file noncached_container.cpp + * @brief Class to store instances of VERTEX without caching. It allows a fast one-frame drawing + * and then clearing the buffer and starting from scratch. + */ + +#include +#include + +using namespace KiGfx; + +NONCACHED_CONTAINER::NONCACHED_CONTAINER( unsigned int aSize ) : + VERTEX_CONTAINER( aSize ), m_freePtr( 0 ) +{ +} + + +NONCACHED_CONTAINER::~NONCACHED_CONTAINER() +{ +} + + +void NONCACHED_CONTAINER::SetItem( VERTEX_ITEM* aItem ) +{ + // Nothing has to be done, as the noncached container + // does not care about VERTEX_ITEMs ownership +} + + +VERTEX* NONCACHED_CONTAINER::Allocate( unsigned int aSize ) +{ + if( m_freeSpace < aSize ) + { + // Double the space + VERTEX* newVertices = static_cast( realloc( m_vertices, + m_currentSize * 2 * + sizeof(VERTEX) ) ); + + if( newVertices != NULL ) + { + m_vertices = newVertices; + m_freeSpace += m_currentSize; + m_currentSize *= 2; + } + else + { + return NULL; + } + } + + VERTEX* freeVertex = &m_vertices[m_freePtr]; + + // Move to the next free chunk + m_freePtr += aSize; + m_freeSpace -= aSize; + + return freeVertex; +} + + +void NONCACHED_CONTAINER::Erase() +{ +} + + +void NONCACHED_CONTAINER::Clear() +{ + m_freePtr = 0; + m_freeSpace = m_currentSize; +} diff --git a/common/gal/opengl/opengl_gal.cpp b/common/gal/opengl/opengl_gal.cpp index a82fa33d30..a76611c974 100644 --- a/common/gal/opengl/opengl_gal.cpp +++ b/common/gal/opengl/opengl_gal.cpp @@ -53,7 +53,8 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener, wxEvtHandler* aPaintListener, bool isUseShaders, const wxString& aName ) : wxGLCanvas( aParent, wxID_ANY, (int*) glAttributes, wxDefaultPosition, wxDefaultSize, wxEXPAND, aName ), - verticesCircle( &precomputedContainer ) + cachedManager( true ), + nonCachedManager( false ) { // Create the OpenGL-Context glContext = new wxGLContext( this ); @@ -73,13 +74,7 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener, isShaderInitialized = false; isGrouping = false; wxSize parentSize = aParent->GetSize(); - - isVboInitialized = false; - vboNeedsUpdate = false; - currentItem = NULL; groupCounter = 0; - transform = glm::mat4( 1.0f ); // Identity matrix - nonCachedItem = NULL; SetSize( parentSize ); @@ -112,11 +107,11 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener, InitTesselatorCallbacks( tesselator ); gluTessProperty( tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE ); - // Compute unit semicircle & circle vertices and store them in a buffer for faster drawing - computeCircleVbo(); + // Compute the unit circle vertices and store them in a buffer for faster drawing + computeCircle(); // By default we draw non-cached objects, it changes on BeginGroup()/EndGroup() - currentContainer = &nonCachedVbo; + currentManager = &nonCachedManager; } @@ -124,8 +119,6 @@ OPENGL_GAL::~OPENGL_GAL() { glFlush(); - delete nonCachedItem; - // Delete the buffers if( isFrameBufferInitialized ) { @@ -134,12 +127,7 @@ OPENGL_GAL::~OPENGL_GAL() } gluDeleteTess( tesselator ); - - if( isVboInitialized ) - { - ClearCache(); - deleteVertexBufferObjects(); - } + ClearCache(); delete glContext; } @@ -239,28 +227,6 @@ void OPENGL_GAL::initFrameBuffers() } -void OPENGL_GAL::initVertexBufferObjects() -{ - // Generate buffers for vertices and indices - glGenBuffers( 1, &cachedVerts ); - glGenBuffers( 1, &cachedInds ); - - isVboInitialized = true; -} - - -void OPENGL_GAL::deleteVertexBufferObjects() -{ - glBindBuffer( GL_ARRAY_BUFFER, 0 ); - glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); - - glDeleteBuffers( 1, &cachedVerts ); - glDeleteBuffers( 1, &cachedInds ); - - isVboInitialized = false; -} - - void OPENGL_GAL::SaveScreen() { glBindFramebuffer( GL_DRAW_FRAMEBUFFER, frameBufferBackup ); @@ -323,8 +289,6 @@ void OPENGL_GAL::initGlew() exit( 1 ); } - initVertexBufferObjects(); - isGlewInitialized = true; } @@ -337,38 +301,26 @@ void OPENGL_GAL::BeginDrawing() // Initialize GLEW, FBOs & VBOs if( !isGlewInitialized ) - { initGlew(); - } if( !isFrameBufferInitialized ) - { initFrameBuffers(); - } // Compile the shaders if( !isShaderInitialized && isUseShader ) { if( !shader.LoadBuiltinShader( 0, SHADER_TYPE_VERTEX ) ) - { - wxLogFatalError( wxT( "Cannot compile vertex shader!" ) ); - } + wxLogFatalError( wxT( "Cannot compile vertex shader!" ) ); if( !shader.LoadBuiltinShader( 1, SHADER_TYPE_FRAGMENT ) ) - { - wxLogFatalError( wxT( "Cannot compile fragment shader!" ) ); - } + wxLogFatalError( wxT( "Cannot compile fragment shader!" ) ); if( !shader.Link() ) - { wxLogFatalError( wxT( "Cannot link the shaders!" ) ); - } - shaderAttrib = shader.GetAttribute( "attrShaderParams" ); - if( shaderAttrib == -1 ) - { - wxLogFatalError( wxT( "Could not get the shader attribute location" ) ); - } + // Make VBOs use shaders + cachedManager.SetShader( shader ); + nonCachedManager.SetShader( shader ); isShaderInitialized = true; } @@ -418,29 +370,10 @@ void OPENGL_GAL::BeginDrawing() SetStrokeColor( strokeColor ); isDeleteSavedPixels = true; - // If any of VBO items is dirty - recache everything - if( vboNeedsUpdate ) - rebuildVbo(); + nonCachedManager.Clear(); - // Number of vertices to be drawn - indicesSize = 0; - - glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, cachedInds ); - // Discard old buffer, so we can use it again - glBufferData( GL_ELEMENT_ARRAY_BUFFER, cachedVbo.GetSize() * VBO_ITEM::IndByteSize, - NULL, GL_STREAM_DRAW ); - - // Map the GPU memory, so we can store indices that are going to be drawn - indicesPtr = static_cast( glMapBuffer( GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY ) ); - if( indicesPtr == NULL ) - { - wxLogError( wxT( "Could not map GPU memory" ) ); - } - - // Prepare buffer for non-cached items - delete nonCachedItem; - nonCachedItem = new VBO_ITEM( &nonCachedVbo ); - currentItem = nonCachedItem; + cachedManager.BeginDrawing(); + nonCachedManager.BeginDrawing(); } @@ -492,55 +425,8 @@ void OPENGL_GAL::blitMainTexture( bool aIsClearFrameBuffer ) void OPENGL_GAL::EndDrawing() { - if( !glUnmapBuffer( GL_ELEMENT_ARRAY_BUFFER ) ) - { - wxLogError( wxT( "Unmapping indices buffer failed" ) ); - } - - // Prepare buffers - glEnableClientState( GL_VERTEX_ARRAY ); - glEnableClientState( GL_COLOR_ARRAY ); - - // Draw non-cached items - GLfloat* vertices = (GLfloat*)( nonCachedVbo.GetAllVertices() ); - GLubyte* colors = (GLubyte*)( nonCachedVbo.GetAllVertices() ) + VBO_ITEM::ColorOffset; - GLfloat* shaders = (GLfloat*)( nonCachedVbo.GetAllVertices() ) + VBO_ITEM::ShaderOffset; - - glVertexPointer( VBO_ITEM::CoordStride, GL_FLOAT, VBO_ITEM::VertByteSize, vertices ); - glColorPointer( VBO_ITEM::ColorStride, GL_UNSIGNED_BYTE, VBO_ITEM::VertByteSize, colors ); - if( isUseShader ) - { - shader.Use(); - glEnableVertexAttribArray( shaderAttrib ); - glVertexAttribPointer( shaderAttrib, VBO_ITEM::ShaderStride, GL_FLOAT, GL_FALSE, - VBO_ITEM::VertByteSize, shaders ); - } - glDrawArrays( GL_TRIANGLES, nonCachedItem->GetOffset(), nonCachedItem->GetSize() ); - - // Draw cached items - glBindBuffer( GL_ARRAY_BUFFER, cachedVerts ); - glVertexPointer( VBO_ITEM::CoordStride, GL_FLOAT, VBO_ITEM::VertByteSize, 0 ); - glColorPointer( VBO_ITEM::ColorStride, GL_UNSIGNED_BYTE, VBO_ITEM::VertByteSize, - (GLvoid*) VBO_ITEM::ColorByteOffset ); - if( isUseShader ) - { - glVertexAttribPointer( shaderAttrib, VBO_ITEM::ShaderStride, GL_FLOAT, GL_FALSE, - VBO_ITEM::VertByteSize, (GLvoid*) VBO_ITEM::ShaderByteOffset ); - } - - - glDrawElements( GL_TRIANGLES, indicesSize, GL_UNSIGNED_INT, (GLvoid*) 0 ); - glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); - glBindBuffer( GL_ARRAY_BUFFER, 0 ); - - // Deactivate vertex array - glDisableClientState( GL_COLOR_ARRAY ); - glDisableClientState( GL_VERTEX_ARRAY ); - if( isUseShader ) - { - glDisableVertexAttribArray( shaderAttrib ); - shader.Deactivate(); - } + cachedManager.EndDrawing(); + nonCachedManager.EndDrawing(); // Draw the remaining contents, blit the main texture to the screen, swap the buffers glFlush(); @@ -551,38 +437,6 @@ void OPENGL_GAL::EndDrawing() } -void OPENGL_GAL::rebuildVbo() -{ -#ifdef __WXDEBUG__ - prof_counter totalTime; - prof_start( &totalTime, false ); -#endif /* __WXDEBUG__ */ - - GLfloat* data = (GLfloat*) cachedVbo.GetAllVertices(); - - // Upload vertices coordinates and shader types to GPU memory - glBindBuffer( GL_ARRAY_BUFFER, cachedVerts ); - glBufferData( GL_ARRAY_BUFFER, cachedVbo.GetSize() * VBO_ITEM::VertByteSize, - data, GL_DYNAMIC_DRAW ); - glBindBuffer( GL_ARRAY_BUFFER, 0 ); - - // Allocate the biggest possible buffer for indices - glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, cachedInds ); - glBufferData( GL_ELEMENT_ARRAY_BUFFER, cachedVbo.GetSize() * VBO_ITEM::IndByteSize, - NULL, GL_STREAM_DRAW ); - glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); - - vboNeedsUpdate = false; - -#ifdef __WXDEBUG__ - prof_end( &totalTime ); - - wxLogDebug( wxT( "Rebuilding VBO::%d vertices / %.1f ms" ), - cachedVbo.GetSize(), (double) totalTime.value / 1000.0 ); -#endif /* __WXDEBUG__ */ -} - - inline void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) { VECTOR2D startEndVector = aEndPoint - aStartPoint; @@ -598,29 +452,27 @@ inline void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2 { glm::vec4 vector( perpendicularVector.x, perpendicularVector.y, 0.0, 0.0 ); - // If transform stack is not empty, then it means that - // there is a transformation matrix that has to be applied - if( !transformStack.empty() ) - vector = transform * vector; + // The perpendicular vector also needs transformations + vector = currentManager->GetTransformation() * vector; // Line width is maintained by the vertex shader - setShader( SHADER_LINE, vector.x, vector.y, lineWidth ); - vertex3( aStartPoint.x, aStartPoint.y, layerDepth ); // v0 + currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth ); + currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); // v0 - setShader( SHADER_LINE, -vector.x, -vector.y, lineWidth ); - vertex3( aStartPoint.x, aStartPoint.y, layerDepth ); // v1 + currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth ); + currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); // v1 - setShader( SHADER_LINE, -vector.x, -vector.y, lineWidth ); - vertex3( aEndPoint.x, aEndPoint.y, layerDepth ); // v3 + currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth ); + currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); // v3 - setShader( SHADER_LINE, vector.x, vector.y, lineWidth ); - vertex3( aStartPoint.x, aStartPoint.y, layerDepth ); // v0 + currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth ); + currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); // v0 - setShader( SHADER_LINE, -vector.x, -vector.y, lineWidth ); - vertex3( aEndPoint.x, aEndPoint.y, layerDepth ); // v3 + currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth ); + currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); // v3 - setShader( SHADER_LINE, vector.x, vector.y, lineWidth ); - vertex3( aEndPoint.x, aEndPoint.y, layerDepth ); // v2 + currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth ); + currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); // v2 } else { @@ -630,13 +482,13 @@ inline void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2 VECTOR2D v2 = aEndPoint + perpendicularVector; VECTOR2D v3 = aEndPoint - perpendicularVector; - vertex3( v0.x, v0.y, layerDepth ); - vertex3( v1.x, v1.y, layerDepth ); - vertex3( v3.x, v3.y, layerDepth ); + currentManager->Vertex( v0.x, v0.y, layerDepth ); + currentManager->Vertex( v1.x, v1.y, layerDepth ); + currentManager->Vertex( v3.x, v3.y, layerDepth ); - vertex3( v0.x, v0.y, layerDepth ); - vertex3( v3.x, v3.y, layerDepth ); - vertex3( v2.x, v2.y, layerDepth ); + currentManager->Vertex( v0.x, v0.y, layerDepth ); + currentManager->Vertex( v3.x, v3.y, layerDepth ); + currentManager->Vertex( v2.x, v2.y, layerDepth ); } } @@ -650,7 +502,7 @@ void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndP if( isFillEnabled ) { // Filled tracks - color4( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); + currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); SetLineWidth( aWidth ); drawLineQuad( aStartPoint, aEndPoint ); @@ -664,12 +516,12 @@ void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndP // Outlined tracks double lineLength = startEndVector.EuclideanNorm(); - color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); + currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); Save(); - translate3( aStartPoint.x, aStartPoint.y, 0.0 ); - Rotate( lineAngle ); + currentManager->Translate( aStartPoint.x, aStartPoint.y, 0.0 ); + currentManager->Rotate( lineAngle, 0.0f, 0.0f, 1.0f ); drawLineQuad( VECTOR2D( 0.0, aWidth / 2.0 ), VECTOR2D( lineLength, aWidth / 2.0 ) ); @@ -686,7 +538,7 @@ void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndP } -unsigned int OPENGL_GAL::getGroupNumber() +unsigned int OPENGL_GAL::getNewGroupNumber() { wxASSERT_MSG( groups.size() < std::numeric_limits::max(), wxT( "There are no free slots to store a group" ) ); @@ -745,7 +597,7 @@ void OPENGL_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEn // Stroke the outline if( isStrokeEnabled ) { - color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); + currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); std::deque pointList; pointList.push_back( aStartPoint ); @@ -759,16 +611,16 @@ void OPENGL_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEn // Fill the rectangle if( isFillEnabled ) { - setShader( SHADER_NONE ); - color4( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); + currentManager->Shader( SHADER_NONE ); + currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); - vertex3( aStartPoint.x, aStartPoint.y, layerDepth ); - vertex3( diagonalPointA.x, diagonalPointA.y, layerDepth ); - vertex3( aEndPoint.x, aEndPoint.y, layerDepth ); + currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); + currentManager->Vertex( diagonalPointA.x, diagonalPointA.y, layerDepth ); + currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); - vertex3( aStartPoint.x, aStartPoint.y, layerDepth ); - vertex3( aEndPoint.x, aEndPoint.y, layerDepth ); - vertex3( diagonalPointB.x, diagonalPointB.y, layerDepth ); + currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); + currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); + currentManager->Vertex( diagonalPointB.x, diagonalPointB.y, layerDepth ); } } @@ -779,7 +631,7 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius ) { if( isFillEnabled ) { - color4( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); + currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); /* Draw a triangle that contains the circle, then shade it leaving only the circle. Parameters given to setShader are indices of the triangle's vertices @@ -790,21 +642,21 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius ) //\\ v0 /_\/_\ v1 */ - setShader( SHADER_FILLED_CIRCLE, 1.0 ); - vertex3( aCenterPoint.x - aRadius * sqrt( 3.0f ), - aCenterPoint.y - aRadius, layerDepth ); // v0 + currentManager->Shader( SHADER_FILLED_CIRCLE, 1.0 ); + currentManager->Vertex( aCenterPoint.x - aRadius * sqrt( 3.0f ), + aCenterPoint.y - aRadius, layerDepth ); // v0 - setShader( SHADER_FILLED_CIRCLE, 2.0 ); - vertex3( aCenterPoint.x + aRadius* sqrt( 3.0f ), - aCenterPoint.y - aRadius, layerDepth ); // v1 + currentManager->Shader( SHADER_FILLED_CIRCLE, 2.0 ); + currentManager->Vertex( aCenterPoint.x + aRadius* sqrt( 3.0f ), + aCenterPoint.y - aRadius, layerDepth ); // v1 - setShader( SHADER_FILLED_CIRCLE, 3.0 ); - vertex3( aCenterPoint.x, aCenterPoint.y + aRadius * 2.0f, layerDepth ); // v2 + currentManager->Shader( SHADER_FILLED_CIRCLE, 3.0 ); + currentManager->Vertex( aCenterPoint.x, aCenterPoint.y + aRadius * 2.0f, layerDepth ); // v2 } if( isStrokeEnabled ) { - color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); + currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); /* Draw a triangle that contains the circle, then shade it leaving only the circle. Parameters given to setShader are indices of the triangle's vertices @@ -817,114 +669,126 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius ) v0 /_\/_\ v1 */ double outerRadius = aRadius + ( lineWidth / 2 ); - setShader( SHADER_STROKED_CIRCLE, 1.0, aRadius, lineWidth ); - vertex3( aCenterPoint.x - outerRadius * sqrt( 3.0f ), - aCenterPoint.y - outerRadius, layerDepth ); // v0 + currentManager->Shader( SHADER_STROKED_CIRCLE, 1.0, aRadius, lineWidth ); + currentManager->Vertex( aCenterPoint.x - outerRadius * sqrt( 3.0f ), + aCenterPoint.y - outerRadius, layerDepth ); // v0 - setShader( SHADER_STROKED_CIRCLE, 2.0, aRadius, lineWidth ); - vertex3( aCenterPoint.x + outerRadius * sqrt( 3.0f ), - aCenterPoint.y - outerRadius, layerDepth ); // v1 + currentManager->Shader( SHADER_STROKED_CIRCLE, 2.0, aRadius, lineWidth ); + currentManager->Vertex( aCenterPoint.x + outerRadius * sqrt( 3.0f ), + aCenterPoint.y - outerRadius, layerDepth ); // v1 - setShader( SHADER_STROKED_CIRCLE, 3.0, aRadius, lineWidth ); - vertex3( aCenterPoint.x, aCenterPoint.y + outerRadius * 2.0f, layerDepth ); // v2 + currentManager->Shader( SHADER_STROKED_CIRCLE, 3.0, aRadius, lineWidth ); + currentManager->Vertex( aCenterPoint.x, aCenterPoint.y + outerRadius * 2.0f, layerDepth ); // v2 + } + } + else + { + if( isStrokeEnabled ) + { + // Compute the factors for the unit circle + double outerScale = lineWidth / aRadius / 2; + double innerScale = -outerScale; + outerScale += 1.0; + innerScale += 1.0; + + if( innerScale < outerScale ) + { + // Draw the outline + VERTEX* circle = circleContainer.GetAllVertices(); + int next; + + currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, + strokeColor.a ); + + Save(); + + currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0 ); + currentManager->Scale( aRadius, aRadius, 0.0f ); + + for( int i = 0; i < 3 * CIRCLE_POINTS; ++i ) + { + // verticesCircle contains precomputed circle points interleaved with vertex + // (0,0,0), so filled circles can be drawn as consecutive triangles, ie: + // { 0,a,b, 0,c,d, 0,e,f, 0,g,h, ... } + // where letters stand for consecutive circle points and 0 for (0,0,0) vertex. + + // We have to skip all (0,0,0) vertices (every third vertex) + if( i % 3 == 0 ) + { + i++; + // Depending on the vertex, next circle point may be stored in the next vertex.. + next = i + 1; + } + else + { + // ..or 2 vertices away (in case it is preceded by (0,0,0) vertex) + next = i + 2; + } + + currentManager->Vertex( circle[i].x * innerScale, + circle[i].y * innerScale, + layerDepth ); + currentManager->Vertex( circle[i].x * outerScale, + circle[i].y * outerScale, + layerDepth ); + currentManager->Vertex( circle[next].x * innerScale, + circle[next].y * innerScale, + layerDepth ); + + currentManager->Vertex( circle[i].x * outerScale, + circle[i].y * outerScale, + layerDepth ); + currentManager->Vertex( circle[next].x * outerScale, + circle[next].y * outerScale, + layerDepth ); + currentManager->Vertex( circle[next].x * innerScale, + circle[next].y * innerScale, + layerDepth ); + } + + Restore(); + } } - return; - } - - if( isStrokeEnabled ) - { - // Compute the factors for the unit circle - double outerScale = lineWidth / aRadius / 2; - double innerScale = -outerScale; - outerScale += 1.0; - innerScale += 1.0; - - if( innerScale < outerScale ) + // Filled circles are easy to draw by using the stored vertices list, scaling and translating + if( isFillEnabled ) { - // Draw the outline - VBO_VERTEX* circle = verticesCircle.GetVertices(); - int next; - - color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); + currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); Save(); - - translate3( aCenterPoint.x, aCenterPoint.y, 0.0 ); - Scale( VECTOR2D( aRadius, aRadius ) ); - - for( int i = 0; i < 3 * CIRCLE_POINTS; ++i ) - { - // verticesCircle contains precomputed circle points interleaved with vertex - // (0,0,0), so filled circles can be drawn as consecutive triangles, ie: - // { 0,a,b, 0,c,d, 0,e,f, 0,g,h, ... } - // where letters stand for consecutive circle points and 0 for (0,0,0) vertex. - - // We have to skip all (0,0,0) vertices (every third vertex) - if( i % 3 == 0) - { - i++; - // Depending on the vertex, next circle point may be stored in the next vertex.. - next = i + 1; - } - else - { - // ..or 2 vertices away (in case it is preceded by (0,0,0) vertex) - next = i + 2; - } - - vertex3( circle[i].x * innerScale, circle[i].y * innerScale, layerDepth ); - vertex3( circle[i].x * outerScale, circle[i].y * outerScale, layerDepth ); - vertex3( circle[next].x * innerScale, circle[next].y * innerScale, layerDepth ); - - vertex3( circle[i].x * outerScale, circle[i].y * outerScale, layerDepth ); - vertex3( circle[next].x * outerScale, circle[next].y * outerScale, layerDepth ); - vertex3( circle[next].x * innerScale, circle[next].y * innerScale, layerDepth ); - } - + currentManager->Translate( aCenterPoint.x, aCenterPoint.y, layerDepth ); + currentManager->Scale( aRadius, aRadius, 0.0f ); + currentManager->Vertices( circleContainer.GetAllVertices(), CIRCLE_POINTS * 3 ); Restore(); } } - - // Filled circles are easy to draw by using the stored display list, scaling and translating - if( isFillEnabled ) - { - color4( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); - - Save(); - translate3( aCenterPoint.x, aCenterPoint.y, layerDepth ); - Scale( VECTOR2D( aRadius, aRadius ) ); - - currentItem->PushVertices( verticesCircle.GetVertices(), CIRCLE_POINTS * 3 ); - - Restore(); - } } void OPENGL_GAL::drawSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle ) { - if( isFillEnabled ) - { - color4( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); - drawFilledSemiCircle( aCenterPoint, aRadius, aAngle ); - } + if( isFillEnabled ) + { + currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); + drawFilledSemiCircle( aCenterPoint, aRadius, aAngle ); + } - if( isStrokeEnabled ) - { - color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); - drawStrokedSemiCircle( aCenterPoint, aRadius, aAngle ); - } + if( isStrokeEnabled ) + { + currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); + drawStrokedSemiCircle( aCenterPoint, aRadius, aAngle ); + } } -void OPENGL_GAL::drawFilledSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle ) +void OPENGL_GAL::drawFilledSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, + double aAngle ) { if( isUseShader ) { Save(); - Translate( aCenterPoint ); - Rotate( aAngle ); + currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0f ); + currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f ); /* Draw a triangle that contains the semicircle, then shade it to leave only the semicircle. Parameters given to setShader are indices of the triangle's vertices @@ -935,41 +799,42 @@ void OPENGL_GAL::drawFilledSemiCircle( const VECTOR2D& aCenterPoint, double aRad /__\ v0 //__\\ v1 */ - setShader( SHADER_FILLED_CIRCLE, 4.0f ); - vertex3( -aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0 + currentManager->Shader( SHADER_FILLED_CIRCLE, 4.0f ); + currentManager->Vertex( -aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0 - setShader( SHADER_FILLED_CIRCLE, 5.0f ); - vertex3( aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1 + currentManager->Shader( SHADER_FILLED_CIRCLE, 5.0f ); + currentManager->Vertex( aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1 - setShader( SHADER_FILLED_CIRCLE, 6.0f ); - vertex3( 0.0f, aRadius * 2.0f, layerDepth ); // v2 + currentManager->Shader( SHADER_FILLED_CIRCLE, 6.0f ); + currentManager->Vertex( 0.0f, aRadius * 2.0f, layerDepth ); // v2 Restore(); } else { Save(); - translate3( aCenterPoint.x, aCenterPoint.y, layerDepth ); - Scale( VECTOR2D( aRadius, aRadius ) ); - Rotate( aAngle ); + currentManager->Translate( aCenterPoint.x, aCenterPoint.y, layerDepth ); + currentManager->Scale( aRadius, aRadius, 0.0f ); + currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f ); - // It is enough just to push just a half of the circle vertices to make a semicircle - currentItem->PushVertices( verticesCircle.GetVertices(), CIRCLE_POINTS / 2 * 3 ); + // It is enough just to draw a half of the circle vertices to make a semicircle + currentManager->Vertices( circleContainer.GetAllVertices(), ( CIRCLE_POINTS * 3 ) / 2 ); Restore(); } } -void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle ) +void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, + double aAngle ) { if( isUseShader ) { double outerRadius = aRadius + ( lineWidth / 2 ); Save(); - Translate( aCenterPoint ); - Rotate( aAngle ); + currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0f ); + currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f ); /* Draw a triangle that contains the semicircle, then shade it to leave only the semicircle. Parameters given to setShader are indices of the triangle's vertices @@ -981,14 +846,14 @@ void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRa /__\ v0 //__\\ v1 */ - setShader( SHADER_STROKED_CIRCLE, 4.0f, aRadius, lineWidth ); - vertex3( -outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0 + currentManager->Shader( SHADER_STROKED_CIRCLE, 4.0f, aRadius, lineWidth ); + currentManager->Vertex( -outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0 - setShader( SHADER_STROKED_CIRCLE, 5.0f, aRadius, lineWidth ); - vertex3( outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1 + currentManager->Shader( SHADER_STROKED_CIRCLE, 5.0f, aRadius, lineWidth ); + currentManager->Vertex( outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1 - setShader( SHADER_STROKED_CIRCLE, 6.0f, aRadius, lineWidth ); - vertex3( 0.0f, outerRadius * 2.0f, layerDepth ); // v2 + currentManager->Shader( SHADER_STROKED_CIRCLE, 6.0f, aRadius, lineWidth ); + currentManager->Vertex( 0.0f, outerRadius * 2.0f, layerDepth ); // v2 Restore(); } @@ -998,13 +863,13 @@ void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRa double innerScale = 1.0 - lineWidth / aRadius; Save(); - translate3( aCenterPoint.x, aCenterPoint.y, layerDepth ); - Scale( VECTOR2D( aRadius, aRadius ) ); - Rotate( aAngle ); + currentManager->Translate( aCenterPoint.x, aCenterPoint.y, layerDepth ); + currentManager->Scale( aRadius, aRadius, 0.0f ); + currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f ); // Draw the outline - VBO_VERTEX* circle = verticesCircle.GetVertices(); - int next; + VERTEX* circle = circleContainer.GetAllVertices(); + int next; for( int i = 0; i < ( 3 * CIRCLE_POINTS ) / 2; ++i ) { @@ -1026,13 +891,13 @@ void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRa next = i + 2; } - vertex3( circle[i].x * innerScale, circle[i].y * innerScale, 0.0 ); - vertex3( circle[i].x, circle[i].y, 0.0 ); - vertex3( circle[next].x * innerScale, circle[next].y * innerScale, 0.0 ); + currentManager->Vertex( circle[i].x * innerScale, circle[i].y * innerScale, 0.0 ); + currentManager->Vertex( circle[i].x, circle[i].y, 0.0 ); + currentManager->Vertex( circle[next].x * innerScale, circle[next].y * innerScale, 0.0 ); - vertex3( circle[i].x, circle[i].y, 0.0 ); - vertex3( circle[next].x, circle[next].y, 0.0 ); - vertex3( circle[next].x * innerScale, circle[next].y * innerScale, 0.0 ); + currentManager->Vertex( circle[i].x, circle[i].y, 0.0 ); + currentManager->Vertex( circle[next].x, circle[next].y, 0.0 ); + currentManager->Vertex( circle[next].x * innerScale, circle[next].y * innerScale, 0.0 ); } Restore(); @@ -1045,9 +910,7 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double a double aEndAngle ) { if( aRadius <= 0 ) - { return; - } // Swap the angles, if start angle is greater than end angle SWAP( aStartAngle, >, aEndAngle ); @@ -1058,17 +921,17 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double a VECTOR2D middlePoint = 0.5 * startEndPoint; Save(); - translate3( aCenterPoint.x, aCenterPoint.y, layerDepth ); + currentManager->Translate( aCenterPoint.x, aCenterPoint.y, layerDepth ); if( isStrokeEnabled ) { if( isUseShader ) { double alphaIncrement = 2.0 * M_PI / CIRCLE_POINTS; - color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); + currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); VECTOR2D p( cos( aStartAngle ) * aRadius, sin( aStartAngle ) * aRadius ); - double alpha; + double alpha; for( alpha = aStartAngle + alphaIncrement; alpha < aEndAngle; alpha += alphaIncrement ) { VECTOR2D p_next( cos( alpha ) * aRadius, sin( alpha ) * aRadius ); @@ -1095,7 +958,8 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double a innerScale += 1.0; double alphaIncrement = 2 * M_PI / CIRCLE_POINTS; - color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); + currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); + for( double alpha = aStartAngle; alpha < aEndAngle; ) { @@ -1110,13 +974,13 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double a double v2[] = { cos( alpha ) * innerScale, sin( alpha ) * innerScale }; double v3[] = { cos( alpha ) * outerScale, sin( alpha ) * outerScale }; - vertex3( v0[0], v0[1], 0.0 ); - vertex3( v1[0], v1[1], 0.0 ); - vertex3( v2[0], v2[1], 0.0 ); + currentManager->Vertex( v0[0], v0[1], 0.0 ); + currentManager->Vertex( v1[0], v1[1], 0.0 ); + currentManager->Vertex( v2[0], v2[1], 0.0 ); - vertex3( v1[0], v1[1], 0.0 ); - vertex3( v3[0], v3[1], 0.0 ); - vertex3( v2[0], v2[1], 0.0 ); + currentManager->Vertex( v1[0], v1[1], 0.0 ); + currentManager->Vertex( v3[0], v3[1], 0.0 ); + currentManager->Vertex( v2[0], v2[1], 0.0 ); } // Draw line caps @@ -1129,19 +993,19 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double a { double alphaIncrement = 2 * M_PI / CIRCLE_POINTS; double alpha; - color4( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); + currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); for( alpha = aStartAngle; ( alpha + alphaIncrement ) < aEndAngle; ) { - vertex3( middlePoint.x, middlePoint.y, 0.0 ); - vertex3( cos( alpha ), sin( alpha ), 0.0 ); + currentManager->Vertex( middlePoint.x, middlePoint.y, 0.0 ); + currentManager->Vertex( cos( alpha ), sin( alpha ), 0.0 ); alpha += alphaIncrement; - vertex3( cos( alpha ), sin( alpha ), 0.0 ); + currentManager->Vertex( cos( alpha ), sin( alpha ), 0.0 ); } - vertex3( middlePoint.x, middlePoint.y, 0.0 ); - vertex3( cos( alpha ), sin( alpha ), 0.0 ); - vertex3( endPoint.x, endPoint.y, 0.0 ); + currentManager->Vertex( middlePoint.x, middlePoint.y, 0.0 ); + currentManager->Vertex( cos( alpha ), sin( alpha ), 0.0 ); + currentManager->Vertex( endPoint.x, endPoint.y, 0.0 ); } Restore(); @@ -1181,8 +1045,7 @@ void OPENGL_GAL::DrawPolygon( const std::deque& aPointList ) { // Any non convex polygon needs to be tesselated // for this purpose the GLU standard functions are used - - setShader( SHADER_NONE ); + currentManager->Shader( SHADER_NONE ); typedef std::vector OGLPOINTS; @@ -1191,11 +1054,11 @@ void OPENGL_GAL::DrawPolygon( const std::deque& aPointList ) OGLPOINTS vertexList( aPointList.size(), OGLPOINT( "fastest" ) ); glNormal3d( 0.0, 0.0, 1.0 ); - color4( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); + currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); glShadeModel( GL_FLAT ); - TessParams params = { currentItem, tessIntersects }; + TessParams params = { currentManager, tessIntersects }; gluTessBeginPolygon( tesselator, ¶ms ); gluTessBeginContour( tesselator ); @@ -1213,10 +1076,12 @@ void OPENGL_GAL::DrawPolygon( const std::deque& aPointList ) // Free allocated intersecting points std::vector::iterator it, it_end; + for( it = tessIntersects.begin(), it_end = tessIntersects.end(); it < it_end; ++it ) { delete[] *it; } + tessIntersects.clear(); // vertexList destroyed here @@ -1261,7 +1126,7 @@ void OPENGL_GAL::SetStrokeColor( const COLOR4D& aColor ) strokeColor = aColor; // This is the default drawing color - color4( aColor.r, aColor.g, aColor.b, aColor.a ); + currentManager->Color( aColor.r, aColor.g, aColor.b, aColor.a ); } @@ -1315,19 +1180,19 @@ void OPENGL_GAL::Transform( MATRIX3x3D aTransformation ) void OPENGL_GAL::Rotate( double aAngle ) { - transform = glm::rotate( transform, (float) aAngle, glm::vec3( 0, 0, 1 ) ); + currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f ); } void OPENGL_GAL::Translate( const VECTOR2D& aVector ) { - transform = glm::translate( transform, glm::vec3( aVector.x, aVector.y, 0 ) ); + currentManager->Translate( aVector.x, aVector.y, 0.0f ); } void OPENGL_GAL::Scale( const VECTOR2D& aScale ) { - transform = glm::scale( transform, glm::vec3( aScale.x, aScale.y, 0 ) ); + currentManager->Scale( aScale.x, aScale.y, 0.0f ); } @@ -1339,21 +1204,13 @@ void OPENGL_GAL::Flush() void OPENGL_GAL::Save() { - transformStack.push( transform ); - currentContainer->SetTransformMatrix( &transform ); + currentManager->PushMatrix(); } void OPENGL_GAL::Restore() { - transform = transformStack.top(); - transformStack.pop(); - - if( transformStack.empty() ) - { - // Disable transforming, as the selected matrix is identity - currentContainer->SetTransformMatrix( NULL ); - } + currentManager->PopMatrix(); } @@ -1361,14 +1218,10 @@ int OPENGL_GAL::BeginGroup() { isGrouping = true; - // There is a new group that is not in VBO yet - vboNeedsUpdate = true; - - // Save the pointer for caching the current item - currentItem = new VBO_ITEM( &cachedVbo ); - currentContainer = &cachedVbo; - int groupNumber = getGroupNumber(); - groups.insert( std::make_pair( groupNumber, currentItem ) ); + boost::shared_ptr newItem( new VERTEX_ITEM( cachedManager ) ); + currentManager = &cachedManager; + int groupNumber = getNewGroupNumber(); + groups.insert( std::make_pair( groupNumber, newItem ) ); return groupNumber; } @@ -1376,9 +1229,7 @@ int OPENGL_GAL::BeginGroup() void OPENGL_GAL::EndGroup() { - currentItem->Finish(); - currentItem = nonCachedItem; - currentContainer = &nonCachedVbo; + currentManager = &nonCachedManager; isGrouping = false; } @@ -1386,75 +1237,57 @@ void OPENGL_GAL::EndGroup() void OPENGL_GAL::ClearCache() { - BOOST_FOREACH( GroupsMap::value_type it, groups ) - { - delete it.second; - } - groups.clear(); + cachedManager.Clear(); } void OPENGL_GAL::DeleteGroup( int aGroupNumber ) { - delete groups[aGroupNumber]; groups.erase( aGroupNumber ); - - vboNeedsUpdate = true; } void OPENGL_GAL::DrawGroup( int aGroupNumber ) { - int size = groups[aGroupNumber]->GetSize(); - int offset = groups[aGroupNumber]->GetOffset(); - - // Copy indices of items that should be drawn to GPU memory - for( int i = offset; i < offset + size; *indicesPtr++ = i++ ); - - indicesSize += size; + cachedManager.DrawItem( *groups[aGroupNumber] ); } void OPENGL_GAL::ChangeGroupColor( int aGroupNumber, const COLOR4D& aNewColor ) { - groups[aGroupNumber]->ChangeColor( aNewColor ); - vboNeedsUpdate = true; + cachedManager.ChangeItemColor( *groups[aGroupNumber], aNewColor ); } void OPENGL_GAL::ChangeGroupDepth( int aGroupNumber, int aDepth ) { - groups[aGroupNumber]->ChangeDepth( aDepth ); - vboNeedsUpdate = true; + cachedManager.ChangeItemDepth( *groups[aGroupNumber], aDepth ); } -void OPENGL_GAL::computeCircleVbo() +void OPENGL_GAL::computeCircle() { + VERTEX* vertex = circleContainer.Allocate( CIRCLE_POINTS ); + // Compute the circle points for a given number of segments - // Insert in a display list and a vector - const VBO_VERTEX v0 = { 0.0f, 0.0f, 0.0f }; - - for( int i = 0; i < CIRCLE_POINTS; i++ ) + for( int i = 0; i < CIRCLE_POINTS; ++i ) { - const VBO_VERTEX v1 = { - cos( 2.0 * M_PI / CIRCLE_POINTS * i ), // x - sin( 2.0 * M_PI / CIRCLE_POINTS * i ), // y - 0.0f // z - }; - const VBO_VERTEX v2 = { - cos( 2.0 * M_PI / CIRCLE_POINTS * ( i + 1 ) ), // x - sin( 2.0 * M_PI / CIRCLE_POINTS * ( i + 1 ) ), // y - 0.0f // z - }; + vertex->x = 0.0f; + vertex->y = 0.0f; + vertex->z = 0.0f; + vertex++; - verticesCircle.PushVertex( &v0 ); - verticesCircle.PushVertex( &v1 ); - verticesCircle.PushVertex( &v2 ); + vertex->x = cos( 2.0 * M_PI / CIRCLE_POINTS * i ); + vertex->y = sin( 2.0 * M_PI / CIRCLE_POINTS * i ); + vertex->z = 0.0f; + vertex++; + + vertex->x = cos( 2.0 * M_PI / CIRCLE_POINTS * ( i + 1 ) ); + vertex->y = sin( 2.0 * M_PI / CIRCLE_POINTS * ( i + 1 ) ); + vertex->z = 0.0f; + vertex++; } - - verticesCircle.Finish(); } @@ -1495,13 +1328,10 @@ void CALLBACK VertexCallback( GLvoid* aVertexPtr, void* aData ) { GLdouble* vertex = static_cast( aVertexPtr ); OPENGL_GAL::TessParams* param = static_cast( aData ); - VBO_ITEM* vboItem = param->vboItem; + VERTEX_MANAGER* vboManager = param->vboManager; - if( vboItem ) - { - VBO_VERTEX newVertex = { vertex[0], vertex[1], vertex[2] }; - vboItem->PushVertex( &newVertex ); - } + if( vboManager ) + vboManager->Vertex( vertex[0], vertex[1], vertex[2] ); } @@ -1524,7 +1354,6 @@ void CALLBACK CombineCallback( GLdouble coords[3], void CALLBACK EdgeCallback(void) { // This callback is needed to force GLU tesselator to use triangles only - return; } @@ -1650,19 +1479,19 @@ void OPENGL_GAL::DrawGridLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEnd VECTOR2D point4 = aEndPoint - perpendicularVector; // Set color - color4( gridColor.r, gridColor.g, gridColor.b, gridColor.a ); + currentManager->Color( gridColor.r, gridColor.g, gridColor.b, gridColor.a ); - setShader( SHADER_NONE ); + currentManager->Shader( SHADER_NONE ); // Draw the quad for the grid line double gridDepth = depthRange.y * 0.75; - vertex3( point1.x, point1.y, gridDepth ); - vertex3( point2.x, point2.y, gridDepth ); - vertex3( point4.x, point4.y, gridDepth ); + currentManager->Vertex( point1.x, point1.y, gridDepth ); + currentManager->Vertex( point2.x, point2.y, gridDepth ); + currentManager->Vertex( point4.x, point4.y, gridDepth ); - vertex3( point1.x, point1.y, gridDepth ); - vertex3( point4.x, point4.y, gridDepth ); - vertex3( point3.x, point3.y, gridDepth ); + currentManager->Vertex( point1.x, point1.y, gridDepth ); + currentManager->Vertex( point4.x, point4.y, gridDepth ); + currentManager->Vertex( point3.x, point3.y, gridDepth ); } diff --git a/common/gal/opengl/vbo_item.cpp b/common/gal/opengl/vbo_item.cpp deleted file mode 100644 index 15bdcc68d4..0000000000 --- a/common/gal/opengl/vbo_item.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2013 CERN - * @author Maciej Suminski - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you may find one here: - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * or you may search the http://www.gnu.org website for the version 2 license, - * or you may write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -/** - * @file vbo_item.cpp - * @brief Class to handle an item held in a Vertex Buffer Object. - */ - -#include -#include -#include - -using namespace KiGfx; - -VBO_ITEM::VBO_ITEM( VBO_CONTAINER* aContainer ) : - m_offset( 0 ), - m_size( 0 ), - m_container( aContainer ), - m_isDirty( true ) -{ - // The item's size is not known yet, so we just start an item in the container - aContainer->StartItem( this ); -} - - -VBO_ITEM::~VBO_ITEM() -{ - m_container->Free( this ); -} - - -void VBO_ITEM::PushVertex( const VBO_VERTEX* aVertex ) -{ - m_container->Add( aVertex ); - - m_isDirty = true; -} - - -void VBO_ITEM::PushVertices( const VBO_VERTEX* aVertices, GLuint aSize ) -{ - for( unsigned int i = 0; i < aSize; ++i ) - { - PushVertex( &aVertices[i] ); - } -} - - -VBO_VERTEX* VBO_ITEM::GetVertices() -{ - if( m_isDirty ) - Finish(); - - return m_container->GetVertices( m_offset ); -} - - -void VBO_ITEM::ChangeColor( const COLOR4D& aColor ) -{ - VBO_VERTEX* vertexPtr = GetVertices(); - - for( unsigned int i = 0; i < m_size; ++i ) - { - vertexPtr->r = aColor.r * 255; - vertexPtr->g = aColor.g * 255; - vertexPtr->b = aColor.b * 255; - vertexPtr->a = aColor.a * 255; - - // Move on to the next vertex - vertexPtr++; - } -} - - -void VBO_ITEM::ChangeDepth( int aDepth ) -{ - VBO_VERTEX* vertexPtr = GetVertices(); - - for( unsigned int i = 0; i < m_size; ++i ) - { - vertexPtr->z = aDepth; - - // Move on to the next vertex - vertexPtr++; - } -} - - -void VBO_ITEM::Finish() -{ - // The unknown-sized item has just ended, so we need to inform the container about it - m_container->EndItem(); - - m_isDirty = false; -} diff --git a/common/gal/opengl/vertex_container.cpp b/common/gal/opengl/vertex_container.cpp new file mode 100644 index 0000000000..02de36e4df --- /dev/null +++ b/common/gal/opengl/vertex_container.cpp @@ -0,0 +1,57 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Maciej Suminski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * @file vertex_container.cpp + * @brief Class to store vertices and handle transfers between system memory and GPU memory. + */ + +#include +#include +#include +#include +#include + +using namespace KiGfx; + +VERTEX_CONTAINER* VERTEX_CONTAINER::MakeContainer( bool aCached ) +{ + if( aCached ) + return new CACHED_CONTAINER; + else + return new NONCACHED_CONTAINER; +} + + +VERTEX_CONTAINER::VERTEX_CONTAINER( unsigned int aSize ) : + m_freeSpace( aSize ), m_currentSize( aSize ), m_initialSize( aSize ), m_failed( false ) +{ + m_vertices = static_cast( malloc( aSize * sizeof( VERTEX ) ) ); +} + + +VERTEX_CONTAINER::~VERTEX_CONTAINER() +{ + free( m_vertices ); +} diff --git a/common/gal/opengl/vertex_item.cpp b/common/gal/opengl/vertex_item.cpp new file mode 100644 index 0000000000..f5cddc6661 --- /dev/null +++ b/common/gal/opengl/vertex_item.cpp @@ -0,0 +1,53 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Maciej Suminski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * @file vertex_item.cpp + * @brief Class to handle an item held in a container. + */ + +#include +#include +#include + +using namespace KiGfx; + +VERTEX_ITEM::VERTEX_ITEM( const VERTEX_MANAGER& aManager ) : + m_manager( aManager ), m_offset( 0 ), m_size( 0 ) +{ + // As the item is created, we are going to modify it, so call to SetItem() is needed + m_manager.SetItem( *this ); +} + + +VERTEX_ITEM::~VERTEX_ITEM() +{ + m_manager.FreeItem( *this ); +} + + +VERTEX* VERTEX_ITEM::GetVertices() const +{ + return m_manager.GetVertices( *this ); +} diff --git a/common/gal/opengl/vertex_manager.cpp b/common/gal/opengl/vertex_manager.cpp new file mode 100644 index 0000000000..d3b9e00f66 --- /dev/null +++ b/common/gal/opengl/vertex_manager.cpp @@ -0,0 +1,203 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Maciej Suminski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * @file vertex_manager.cpp + * @brief Class to control vertex container and GPU with possibility of emulating old-style OpenGL + * 1.0 state machine using modern OpenGL methods. + */ + +#include +#include +#include +#include +#include + +using namespace KiGfx; + +VERTEX_MANAGER::VERTEX_MANAGER( bool aCached ) : + m_noTransform( true ), m_transform( 1.0f ) +{ + m_container.reset( VERTEX_CONTAINER::MakeContainer( aCached ) ); + m_gpu.reset( GPU_MANAGER::MakeManager( m_container.get() ) ); + + // There is no shader used by default + for( unsigned int i = 0; i < ShaderStride; ++i ) + m_shader[i] = 0.0f; +} + + +void VERTEX_MANAGER::Vertex( GLfloat aX, GLfloat aY, GLfloat aZ ) const +{ + // Obtain the pointer to the vertex in the currently used container + VERTEX* newVertex = m_container->Allocate( 1 ); + if( newVertex == NULL ) + { + wxLogError( wxT( "Vertex allocation error" ) ); + return; + } + + putVertex( *newVertex, aX, aY, aZ ); +} + + +void VERTEX_MANAGER::Vertices( const VERTEX aVertices[], unsigned int aSize ) const +{ + // Obtain pointer to the vertex in currently used container + VERTEX* newVertex = m_container->Allocate( aSize ); + if( newVertex == NULL ) + { + wxLogError( wxT( "Vertex allocation error" ) ); + return; + } + + // Put vertices in already allocated memory chunk + for( unsigned int i = 0; i < aSize; ++i ) + { + putVertex( newVertex[i], aVertices[i].x, aVertices[i].y, aVertices[i].z ); + } +} + + +void VERTEX_MANAGER::SetItem( VERTEX_ITEM& aItem ) const +{ + m_container->SetItem( &aItem ); +} + + +void VERTEX_MANAGER::FreeItem( VERTEX_ITEM& aItem ) const +{ + m_container->SetItem( &aItem ); + m_container->Erase(); +} + + +void VERTEX_MANAGER::ChangeItemColor( const VERTEX_ITEM& aItem, const COLOR4D& aColor ) const +{ + unsigned int size = aItem.GetSize(); + unsigned int offset = aItem.GetOffset(); + + VERTEX* vertex = m_container->GetVertices( offset ); + for( unsigned int i = 0; i < size; ++i ) + { + vertex->r = aColor.r; + vertex->g = aColor.g; + vertex->b = aColor.b; + vertex->a = aColor.a; + vertex++; + } +} + + +void VERTEX_MANAGER::ChangeItemDepth( const VERTEX_ITEM& aItem, GLfloat aDepth ) const +{ + unsigned int size = aItem.GetSize(); + unsigned int offset = aItem.GetOffset(); + + VERTEX* vertex = m_container->GetVertices( offset ); + for( unsigned int i = 0; i < size; ++i ) + { + vertex->z = aDepth; + vertex++; + } +} + + +VERTEX* VERTEX_MANAGER::GetVertices( const VERTEX_ITEM& aItem ) const +{ + if( aItem.GetSize() == 0 ) + return NULL; // The item is not stored in the container + + return m_container->GetVertices( aItem.GetOffset() ); +} + + +void VERTEX_MANAGER::SetShader( SHADER& aShader ) const +{ + m_gpu->SetShader( aShader ); +} + + +void VERTEX_MANAGER::Clear() const +{ + m_container->Clear(); +} + + +void VERTEX_MANAGER::BeginDrawing() const +{ + m_gpu->BeginDrawing(); +} + + +void VERTEX_MANAGER::DrawItem( const VERTEX_ITEM& aItem ) const +{ + int size = aItem.GetSize(); + if( size > 0 ) + { + int offset = aItem.GetOffset(); + m_gpu->DrawIndices( offset, size ); + } +} + + +void VERTEX_MANAGER::EndDrawing() const +{ + m_gpu->EndDrawing(); +} + + +void VERTEX_MANAGER::putVertex( VERTEX& aTarget, GLfloat aX, GLfloat aY, GLfloat aZ ) const +{ + // Modify the vertex according to the currently used transformations + if( m_noTransform ) + { + // Simply copy coordinates, when the transform matrix is the identity matrix + aTarget.x = aX; + aTarget.y = aY; + aTarget.z = aZ; + } + else + { + // Apply transformations + glm::vec4 transVertex( aX, aY, aZ, 1.0f ); + transVertex = m_transform * transVertex; + + aTarget.x = transVertex.x; + aTarget.y = transVertex.y; + aTarget.z = transVertex.z; + } + + // Apply currently used color + aTarget.r = m_color[0]; + aTarget.g = m_color[1]; + aTarget.b = m_color[2]; + aTarget.a = m_color[3]; + + // Apply currently used shader + for( unsigned int j = 0; j < ShaderStride; ++j ) + { + aTarget.shader[j] = m_shader[j]; + } +} diff --git a/include/gal/cairo/cairo_gal.h b/include/gal/cairo/cairo_gal.h index 0ae26b6fd8..96035763de 100644 --- a/include/gal/cairo/cairo_gal.h +++ b/include/gal/cairo/cairo_gal.h @@ -401,11 +401,11 @@ private: void deinitSurface(); /** - * @brief Returns a valid key that can be used as a group number. + * @brief Returns a valid key that can be used as a new group number. * * @return An unique group number that is not used by any other group. */ - unsigned int getGroupNumber(); + unsigned int getNewGroupNumber(); }; } // namespace KiGfx diff --git a/include/gal/opengl/cached_container.h b/include/gal/opengl/cached_container.h new file mode 100644 index 0000000000..6c2c8b92bf --- /dev/null +++ b/include/gal/opengl/cached_container.h @@ -0,0 +1,185 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Maciej Suminski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * @file cached_container.h + * @brief Class to store instances of VERTEX with caching. It allows storing VERTEX objects and + * associates them with VERTEX_ITEMs. This leads to a possibility of caching vertices data in the + * GPU memory and a fast reuse of that data. + */ + +#ifndef CACHED_CONTAINER_H_ +#define CACHED_CONTAINER_H_ + +#include +#include +#include + +#ifdef __WXDEBUG__ +// Debug messages verbosity level +// #define CACHED_CONTAINER_TEST 2 +#endif + +namespace KiGfx +{ +class VERTEX_ITEM; +class SHADER; + +class CACHED_CONTAINER : public VERTEX_CONTAINER +{ +public: + CACHED_CONTAINER( unsigned int aSize = defaultInitSize ); + + ///< @copydoc VERTEX_CONTAINER::SetItem() + virtual void SetItem( VERTEX_ITEM* aItem ); + + ///< @copydoc VERTEX_CONTAINER::Allocate() + virtual VERTEX* Allocate( unsigned int aSize ); + + ///< @copydoc VERTEX_CONTAINER::Erase() + virtual void Erase(); + + ///< @copydoc VERTEX_CONTAINER::Clear() + virtual void Clear(); + + /** + * Function GetVertices() + * returns the vertices stored by the specific item. + * + * @param aItem is the item. + */ + virtual VERTEX* GetVertices( const VERTEX_ITEM* aItem ) const; + +protected: + ///< Maps size of free memory chunks to their offsets + typedef std::pair Chunk; + typedef std::multimap FreeChunkMap; + + /// List of all the stored items + typedef std::set Items; + + ///< Stores size & offset of free chunks. + FreeChunkMap m_freeChunks; + + ///< Stored VERTEX_ITEMs + Items m_items; + + ///< Currently modified item + VERTEX_ITEM* m_item; + + ///< Properties of currently modified chunk & item + unsigned int m_chunkSize; + unsigned int m_chunkOffset; + unsigned int m_itemSize; + + /** + * Function reallocate() + * resizes the chunk that stores the current item to the given size. + * + * @param aSize is the number of vertices to be stored. + * @return offset of the new chunk. + */ + virtual unsigned int reallocate( unsigned int aSize ); + + /** + * Function defragment() + * removes empty spaces between chunks, so after that there is a long continous space + * for storing vertices at the and of the container. + * + * @param aTarget is the already allocated destination for defragmented data. It has to be + * at least of the same size as the current container. If left NULL, it will be allocated + * inside the defragment() function. + * @return false in case of failure (eg. memory shortage) + */ + virtual bool defragment( VERTEX* aTarget = NULL ); + + /** + * Function mergeFreeChunks() + * looks for consecutive free memory chunks and merges them, decreasing fragmentation of + * memory. + */ + virtual void mergeFreeChunks(); + + /** + * Function resizeContainer() + * + * prepares a bigger container of a given size. + * @param aNewSize is the new size of container, expressed in vertices + * @return false in case of failure (eg. memory shortage) + */ + virtual bool resizeContainer( unsigned int aNewSize ); + + /** + * Function freeItem() + * frees the space occupied by the item and returns it to the free space pool. + * + * @param aItem is the item to be freed. + */ + virtual void freeItem( VERTEX_ITEM* aItem ); + + /** + * Function getPowerOf2() + * returns the nearest power of 2, bigger than aNumber. + * + * @param aNumber is the number for which we look for a bigger power of 2. + */ + unsigned int getPowerOf2( unsigned int aNumber ) const; + +private: + /** + * Function getChunkSize() + * returns size of the given chunk. + * + * @param aChunk is the chunk. + */ + inline int getChunkSize( const Chunk& aChunk ) const + { + return aChunk.first; + } + + /** + * Function getChunkOffset() + * returns offset of the chunk. + * + * @param aChunk is the chunk. + */ + inline unsigned int getChunkOffset( const Chunk& aChunk ) const + { + return aChunk.second; + } + + /// Debug & test functions +#ifdef CACHED_CONTAINER_TEST + void showFreeChunks(); + void showReservedChunks(); + void test(); +#else + inline void showFreeChunks() {} + inline void showReservedChunks() {} + inline void test() {} +#endif /* CACHED_CONTAINER_TEST */ +}; +} // namespace KiGfx + +#endif /* CACHED_CONTAINER_H_ */ diff --git a/include/gal/opengl/gpu_manager.h b/include/gal/opengl/gpu_manager.h new file mode 100644 index 0000000000..5b7e6e62ba --- /dev/null +++ b/include/gal/opengl/gpu_manager.h @@ -0,0 +1,164 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Maciej Suminski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * @file gpu_manager.h + * @brief Class to handle uploading vertices and indices to GPU in drawing purposes. + */ + +#ifndef GPU_MANAGER_H_ +#define GPU_MANAGER_H_ + +#include +#include + +namespace KiGfx +{ +class SHADER; +class VERTEX_CONTAINER; +class CACHED_CONTAINER; +class NONCACHED_CONTAINER; + +class GPU_MANAGER +{ +public: + static GPU_MANAGER* MakeManager( VERTEX_CONTAINER* aContainer ); + + virtual ~GPU_MANAGER(); + + // TODO docs + /** + * @brief Initializes everything needed to use vertex buffer objects (should be called when + * there is an OpenGL context available). + */ + virtual void Initialize() = 0; + + /** + * Function BeginDrawing() + * Prepares the stored data to be drawn. + */ + virtual void BeginDrawing() = 0; + + /** + * Function DrawIndices() + * Makes the GPU draw given range of vertices. + * @param aOffset is the beginning of the range. + * @param aSize is the number of vertices to be drawn. + */ + virtual void DrawIndices( unsigned int aOffset, unsigned int aSize ) = 0; + + /** + * Function DrawIndices() + * Makes the GPU draw all the vertices stored in the container. + */ + virtual void DrawAll() = 0; + + /** + * Function EndDrawing() + * Clears the container after drawing routines. + */ + virtual void EndDrawing() = 0; + + /** + * Function SetShader() + * Allows using shaders with the stored data. + * @param aShader is the object that allows using shaders. + */ + virtual void SetShader( SHADER& aShader ); + +protected: + GPU_MANAGER( VERTEX_CONTAINER* aContainer ); + + ///< Drawing status flag. + bool m_isDrawing; + + ///< Container that stores vertices data. + VERTEX_CONTAINER* m_container; + + ///< Shader handling + SHADER* m_shader; + int m_shaderAttrib; ///< Location of shader attributes (for glVertexAttribPointer) +}; + + +class GPU_CACHED_MANAGER : public GPU_MANAGER +{ +public: + GPU_CACHED_MANAGER( VERTEX_CONTAINER* aContainer ); + ~GPU_CACHED_MANAGER(); + + ///< @copydoc GPU_MANAGER::Initialize() + virtual void Initialize(); + + ///< @copydoc GPU_MANAGER::BeginDrawing() + virtual void BeginDrawing(); + + ///< @copydoc GPU_MANAGER::DrawIndices() + virtual void DrawIndices( unsigned int aOffset, unsigned int aSize ); + + ///< @copydoc GPU_MANAGER::DrawAll() + virtual void DrawAll(); + + ///< @copydoc GPU_MANAGER::EndDrawing() + virtual void EndDrawing(); + + /** + * Function uploadToGpu + * Rebuilds vertex buffer object using stored VERTEX_ITEMs and sends it to the graphics card + * memory. + */ + virtual void uploadToGpu(); + +protected: + bool m_buffersInitialized; + boost::scoped_array m_indices; + GLuint* m_indicesPtr; + GLuint m_verticesBuffer; + unsigned int m_indicesSize; + +}; + + +class GPU_NONCACHED_MANAGER : public GPU_MANAGER +{ +public: + GPU_NONCACHED_MANAGER( VERTEX_CONTAINER* aContainer ); + + ///< @copydoc GPU_MANAGER::Initialize() + virtual void Initialize(); + + ///< @copydoc GPU_MANAGER::BeginDrawing() + virtual void BeginDrawing(); + + ///< @copydoc GPU_MANAGER::DrawIndices() + virtual void DrawIndices( unsigned int aOffset, unsigned int aSize ); + + ///< @copydoc GPU_MANAGER::DrawAll() + virtual void DrawAll(); + + ///< @copydoc GPU_MANAGER::EndDrawing() + virtual void EndDrawing(); +}; +} // namespace KiGfx +#endif /* GPU_MANAGER_H_ */ diff --git a/include/gal/opengl/noncached_container.h b/include/gal/opengl/noncached_container.h new file mode 100644 index 0000000000..0ff2f20a27 --- /dev/null +++ b/include/gal/opengl/noncached_container.h @@ -0,0 +1,73 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Maciej Suminski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * @file noncached_container.h + * @brief Class to store instances of VERTEX without caching. It allows a fast one-frame drawing + * and then clearing the buffer and starting from scratch. + */ + +#ifndef NONCACHED_CONTAINER_H_ +#define NONCACHED_CONTAINER_H_ + +#include + +namespace KiGfx +{ +class VERTEX_ITEM; +class SHADER; + +class NONCACHED_CONTAINER : public VERTEX_CONTAINER +{ +public: + NONCACHED_CONTAINER( unsigned int aSize = defaultInitSize ); + virtual ~NONCACHED_CONTAINER(); + + ///< @copydoc VERTEX_CONTAINER::SetItem() + virtual void SetItem( VERTEX_ITEM* aItem ); + + ///< @copydoc VERTEX_CONTAINER::Allocate() + virtual VERTEX* Allocate( unsigned int aSize ); + + ///< @copydoc VERTEX_CONTAINER::Erase() + virtual void Erase(); + + ///< @copydoc VERTEX_CONTAINER::Clear() + virtual void Clear(); + + ///< @copydoc VERTEX_CONTAINER::GetSize() + virtual inline unsigned int GetSize() const + { + // As the m_freePtr points to the first free space, we can safely assume + // that this is the number of vertices stored inside + return m_freePtr; + } + +protected: + ///< Index of the free first space where a vertex can be stored + unsigned int m_freePtr; +}; +} // namespace KiGfx + +#endif /* NONCACHED_CONTAINER_H_ */ diff --git a/include/gal/opengl/opengl_gal.h b/include/gal/opengl/opengl_gal.h index 235c8082fb..9338b44187 100644 --- a/include/gal/opengl/opengl_gal.h +++ b/include/gal/opengl/opengl_gal.h @@ -31,25 +31,21 @@ // GAL imports #include -#include - -// OpenGL mathematics library -#define GLM_FORCE_RADIANS -#include - -#include #include +#include +#include +#include -// wxWidgets imports #include #include -// STL imports #include #include #include #include -#include +#include +#include +#include #include #include @@ -312,7 +308,7 @@ public: ///< Parameters passed to the GLU tesselator typedef struct { - VBO_ITEM* vboItem; ///< VBO_ITEM for storing new vertices + VERTEX_MANAGER* vboManager; ///< VERTEX_ITEM for storing new vertices std::vector& intersectPoints; ///< Intersect points, that have to be freed } TessParams; @@ -325,11 +321,6 @@ private: static const int CIRCLE_POINTS = 64; ///< The number of points for circle approximation static const int CURVE_POINTS = 32; ///< The number of points for curve approximation - static const double MITER_LIMIT = 1.5; ///< Limit for mitered edges ( * lineWidth ) - - /// This factor is used to for correct merging of antialiased edges, - /// a very small value is required - static const double DEPTH_ADJUST_FACTOR = ( 1.0 / (1 << 23) ); wxClientDC* clientDC; ///< Drawing context wxGLContext* glContext; ///< OpenGL context of wxWidgets @@ -338,43 +329,22 @@ private: wxEvtHandler* paintListener; // VBO buffered vertices for faster circle & semicircle drawing - VBO_CONTAINER precomputedContainer; ///< Container for storing display lists - VBO_ITEM verticesCircle; ///< Buffer for circle & semicircle vertices + NONCACHED_CONTAINER circleContainer; ///< Container for storing circle vertices // Vertex buffer objects related fields - typedef boost::unordered_map GroupsMap; + typedef std::map< unsigned int, boost::shared_ptr > GroupsMap; GroupsMap groups; ///< Stores informations about VBO objects (groups) unsigned int groupCounter; ///< Counter used for generating keys for groups - VBO_ITEM* currentItem; ///< Currently used VBO_ITEM (for grouping) - VBO_CONTAINER* currentContainer; ///< Currently used VBO_CONTAINER (for storing VBO_ITEMs) - VBO_CONTAINER cachedVbo; ///< Container for storing VBO_ITEMs - GLuint cachedVerts; ///< Currently used vertices VBO handle - GLuint cachedInds; ///< Currently used indices VBO handle - bool vboNeedsUpdate; ///< Flag indicating if VBO should be rebuilt - VBO_CONTAINER nonCachedVbo; ///< Container for storing non-cached VBO_ITEMs - VBO_ITEM* nonCachedItem; ///< Item that is gathering non-cached vertices - - glm::mat4 transform; ///< Current transformation matrix - std::stack transformStack; ///< Stack of transformation matrices - int indicesSize; ///< Number of indices to be drawn - GLuint* indicesPtr; ///< Pointer to mapped GPU memory + VERTEX_MANAGER* currentManager; ///< Currently used VERTEX_MANAGER (for storing VERTEX_ITEMs) + VERTEX_MANAGER cachedManager; ///< Container for storing cached VERTEX_ITEMs + VERTEX_MANAGER nonCachedManager; ///< Container for storing non-cached VERTEX_ITEMs // Polygon tesselation - GLUtesselator* tesselator; ///< Pointer to the tesselator + GLUtesselator* tesselator; ///< Pointer to the tesselator std::vector tessIntersects; ///< Storage of intersecting points // Shader - // Possible types of shaders - typedef enum - { - SHADER_NONE = 0, - SHADER_LINE, - SHADER_FILLED_CIRCLE, - SHADER_STROKED_CIRCLE, - } SHADER_TYPE; - SHADER shader; ///< There is only one shader used for different objects - int shaderAttrib; ///< Location of shader attributes (for glVertexAttribPointer) // Cursor int cursorSize; ///< Size of the cursor in pixels @@ -394,7 +364,6 @@ private: // Internal flags bool isGlewInitialized; ///< Is GLEW initialized? bool isFrameBufferInitialized; ///< Are the frame buffers initialized? - bool isVboInitialized; bool isShaderInitialized; ///< Was the shader initialized? bool isUseShader; ///< Should the shaders be used? bool isGrouping; ///< Was a group started? @@ -430,8 +399,8 @@ private: */ void drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle ); - /// Compute the points of an unit circle & semicircle and store them in VBO. - void computeCircleVbo(); + /// Compute the points of the unit circle and store them in VBO. + void computeCircle(); // Event handling /** @@ -493,22 +462,6 @@ private: */ void deleteFrameBuffer( GLuint* aFrameBuffer, GLuint* aDepthBuffer, GLuint* aTexture ); - /** - * @brief Initializes everything needed to use vertex buffer objects. - */ - void initVertexBufferObjects(); - - /** - * @brief Deinitializes everything when vertex buffer objects are not used anymore. - */ - void deleteVertexBufferObjects(); - - /** - * @brief Rebuilds vertex buffer object using stored VBO_ITEMS and sends it to - * the graphics card memory. - */ - void rebuildVbo(); - /** * @brief Draw a quad for the line. * @@ -518,76 +471,11 @@ private: inline void drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ); /** - * @brief Returns a valid key that can be used as a group number. + * @brief Returns a valid key that can be used as a new group number. * * @return An unique group number that is not used by any other group. */ - unsigned int getGroupNumber(); - - /** - * @brief Adds vertex to the current item or draws it in immediate mode. - * @param aX is X coordinate. - * @param aY is Y coordinate. - * @param aZ is Z coordinate. - */ - inline void vertex3( double aX, double aY, double aZ ) - { - // New vertex coordinates for VBO - const VBO_VERTEX vertex = { aX, aY, aZ }; - currentItem->PushVertex( &vertex ); - } - - /** - * @brief Function that replaces glTranslate. It modifies transformation matrix. - * - * @param aX is translation in X axis direction. - * @param aY is translation in Y axis direction. - * @param aZ is translation in Z axis direction. - */ - inline void translate3( double aX, double aY, double aZ ) - { - transform = glm::translate( transform, glm::vec3( aX, aY, aZ ) ); - } - - /** - * @brief Function that replaces glColor. It modifies color used by current VBO_ITEM. - * - * @param aR is red component. - * @param aG is green component. - * @param aB is blue component. - * @param aA is alpha component. - */ - inline void color4( double aRed, double aGreen, double aBlue, double aAlpha ) - { - currentContainer->UseColor( aRed, aGreen, aBlue, aAlpha ); - } - - /** - * @brief Function that replaces glColor. It modifies color used by current VBO_ITEM. - * - * @param aColor is the new color. - */ - inline void color4( const COLOR4D& aColor ) - { - currentContainer->UseColor( aColor ); - } - - /** - * @brief Function that sets shader and its parameters for the currently used VBO_ITEM. - * It should be used before adding any vertices that have to be shaded. - * @param aShader is the type of shader used for vertices. - * @param aParam[1..3] are shader's parameters. Their meaning depends on the type of used shader. - * For more information you may check shaders' source code. - */ - inline void setShader( SHADER_TYPE aShader, GLfloat aParam1 = 0.0f, - GLfloat aParam2 = 0.0f, GLfloat aParam3 = 0.0f ) - { - if( isUseShader ) - { - const GLfloat shader[] = { aShader, aParam1, aParam2, aParam3 }; - currentContainer->UseShader( shader ); - } - } + unsigned int getNewGroupNumber(); }; } // namespace KiGfx diff --git a/include/gal/opengl/vbo_container.h b/include/gal/opengl/vbo_container.h deleted file mode 100644 index cb48204fc7..0000000000 --- a/include/gal/opengl/vbo_container.h +++ /dev/null @@ -1,344 +0,0 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2013 CERN - * @author Maciej Suminski - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you may find one here: - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * or you may search the http://www.gnu.org website for the version 2 license, - * or you may write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -/** - * @file vbo_container.h - * @brief Class to store VBO_ITEMs. - */ - -#ifndef VBO_CONTAINER_H_ -#define VBO_CONTAINER_H_ - -#include -#include -#include -#include -#include -#include - -namespace KiGfx -{ -class VBO_ITEM; -typedef struct VBO_VERTEX VBO_VERTEX; - -class VBO_CONTAINER -{ -public: - VBO_CONTAINER( unsigned int aSize = defaultInitSize ); - virtual ~VBO_CONTAINER(); - - ///< Maps size of free memory chunks to their offsets - typedef std::pair Chunk; - typedef std::multimap FreeChunkMap; - - /// List of all the stored items - typedef std::set Items; - - /** - * Function StartItem() - * Sets an item to start its modifications. After calling the function it is possible to add - * vertices using function Add(). - * @param aItem is the item that is going to store vertices in the container. - */ - void StartItem( VBO_ITEM* aItem ); - - /** - * Function EndItem() - * Marks current item as finished and returns unused memory to the pool. StartItem() function - * has to be called first. - */ - void EndItem(); - - /** - * Function Add() - * Stores given number of vertices in the container for the specific VBO_ITEM (started by - * StartItem() function). - * @param aItem is the owner of the vertices. - * @param aVertex are vertices data to be stored. - * @param aSize is the number of vertices to be added. - */ - void Add( const VBO_VERTEX* aVertex, unsigned int aSize = 1 ); - - /** - * Function Free() - * Frees the chunk reserved by the aItem. - * @param aItem is the owner of the chunk to be freed. - */ - void Free( VBO_ITEM* aItem ); - - /** - * Function Clear() - * Removes all the data stored in the container. - */ - void Clear(); - - /** - * Function GetAllVertices() - * Returns all vertices stored in the container. It is especially useful for transferring - * data to the GPU memory. - */ - VBO_VERTEX* GetAllVertices() const; - - /** - * Function GetVertices() - * Returns vertices stored by the specific item. - * @aItem is the specific item. - */ - VBO_VERTEX* GetVertices( const VBO_ITEM* aItem ) const; - - /** - * Function GetVertices() - * Returns vertices stored at the specific offset. - * @aOffset is the specific offset. - */ - inline VBO_VERTEX* GetVertices( unsigned int aOffset ) const - { - return &m_vertices[aOffset]; - } - - /** - * Function GetSize() - * Returns amount of vertices currently stored in the container. - */ - inline int GetSize() const - { - return m_currentSize; - } - - /** - * Function SetTransformMatrix() - * Sets transformation matrix for vertices that are added to VBO_ITEM. If you do not want to - * transform vertices at all, pass NULL as the argument. - * @param aMatrix is the new transform matrix or NULL if you do not want to use transformation - * matrix. - */ - inline void SetTransformMatrix( const glm::mat4* aMatrix ) - { - m_transform = aMatrix; - } - - /** - * Function UseColor() - * Sets color used for all added vertices. - * @param aColor is the color used for added vertices. - */ - inline void UseColor( const COLOR4D& aColor ) - { - m_color[0] = aColor.r * 255; - m_color[1] = aColor.g * 255; - m_color[2] = aColor.b * 255; - m_color[3] = aColor.a * 255; - } - - /** - * Function UseColor() - * Sets color used for all added vertices. - * @param aColor is the color used for added vertices. - */ - inline void UseColor( const GLfloat aColor[VBO_ITEM::ColorStride] ) - { - for( unsigned int i = 0; i < VBO_ITEM::ColorStride; ++i ) - { - m_color[i] = aColor[i] * 255; - } - } - - /** - * Function UseColor() - * Sets color used for all added vertices. - * @param aR is the red component of the color. - * @param aG is the green component of the color. - * @param aB is the blue component of the color. - * @param aA is the alpha component of the color. - */ - inline void UseColor( GLfloat aR, GLfloat aG, GLfloat aB, GLfloat aA ) - { - m_color[0] = aR * 255; - m_color[1] = aG * 255; - m_color[2] = aB * 255; - m_color[3] = aA * 255; - } - - /** - * Function UseShader() - * Sets shader and its parameters used for all added vertices. - * @param aShader is the array that contains shader number followed by its parameters. - */ - inline void UseShader( const GLfloat aShader[VBO_ITEM::ShaderStride] ) - { - for( unsigned int i = 0; i < VBO_ITEM::ShaderStride; ++i ) - { - m_shader[i] = aShader[i]; - } - } - -private: - ///< Stores size & offset of free chunks. - FreeChunkMap m_freeChunks; - ///< Stored VERTEX_ITEMs - Items m_items; - - /** - * Function allocate() - * Allocates the given amount of memory for the current VBO_ITEM (set by StartItem() function). - * @param aSize is the number of vertices that are requested to be allocated. - * @return Pointer to the allocated space. - */ - VBO_VERTEX* allocate( unsigned int aSize ); - - /** - * Function reallocate() - * Resizes the chunk that stores the current item to the given size. - * @param aSize is the number of vertices to be stored. - * @return Offset of the new chunk. - */ - unsigned int reallocate( unsigned int aSize ); - - /** - * Function getChunkSize() - * Returns size of the given chunk. - * @param aChunk is the chunk. - * @return Size of the chunk. - */ - inline unsigned int getChunkSize( const Chunk& aChunk ) const - { - return aChunk.first; - } - - /** - * Function getChunkOffset() - * Returns offset of the given chunk. - * @param aChunk is the chunk. - * @return Offset of the chunk. - */ - inline unsigned int getChunkOffset( const Chunk& aChunk ) const - { - return aChunk.second; - } - - /** - * Function setChunkOffset() - * Updates offset of the given chunk. - * !! IMPORTANT: it does not reallocate the chunk, it just changes its properties. - * @param aChunk is the chunk. - */ - inline void setChunkOffset( Chunk& aChunk, unsigned int aOffset ) const - { - aChunk.second = aOffset; - } - - /** - * Function defragment() - * Removes empty spaces between chunks, so after that there is a long continous space - * for storing vertices at the and of the container. - * @return false in case of failure (eg. memory shortage). - */ - bool defragment( VBO_VERTEX* aTarget = NULL ); - - /** - * Function mergeFreeChunks() - * Looks for consecutive free memory chunks and merges them, decreasing fragmentation of - * memory. - */ - void mergeFreeChunks(); - - /** - * Function resizeContainer() - * Prepares a bigger container of a given size. - * @param aNewSize is the new size of container, expressed in vertices - * @return false in case of failure (eg. memory shortage). - */ - bool resizeContainer( unsigned int aNewSize ); - - /** - * Function freeItem() - * Frees the space occupied by the item and returns it to the free space pool. - * @param aItem is the item to be freed. - */ - void freeItem( VBO_ITEM* aItem ); - - /** - * Function reservedSpace() - * Returns size of the reserved memory space. - * @return Size of the reserved memory space (expressed as a number of vertices). - */ - unsigned int reservedSpace() - { - return m_currentSize - m_freeSpace; - } - - ///< How many vertices we can store in the container - unsigned int m_freeSpace; - - ///< How big is the current container, expressed in vertices - unsigned int m_currentSize; - - ///< Actual storage memory - VBO_VERTEX* m_vertices; - - ///< Initial size, used on clearing the container - unsigned int m_initialSize; - - ///< Variables holding the state of the item currently being modified - unsigned int m_itemSize; - unsigned int m_chunkSize; - unsigned int m_chunkOffset; - VBO_ITEM* m_item; - - ///< Color used for the new vertices pushed. - GLubyte m_color[VBO_ITEM::ColorStride]; - - ///< Shader and its parameters used for new vertices pushed - GLfloat m_shader[VBO_ITEM::ShaderStride]; - - ///< Current transform matrix applied for every new vertex pushed. - const glm::mat4* m_transform; - - ///< Failure flag - bool m_failed; - - /** - * Function getPowerOf2() - * Returns the nearest power of 2, bigger than aNumber. - * @param aNumber is the number for which we look for a bigger power of 2. - */ - unsigned int getPowerOf2( unsigned int aNumber ) const - { - unsigned int power = 1; - - while( power < aNumber && power ) - power <<= 1; - - return power; - } - - ///< Default initial size of a container (expressed in vertices) - static const unsigned int defaultInitSize = 1048576; - - ///< Basic tests for the container, use only for debugging. - void test() const; -}; -} // namespace KiGfx - -#endif /* VBO_CONTAINER_H_ */ diff --git a/include/gal/opengl/vbo_item.h b/include/gal/opengl/vbo_item.h deleted file mode 100644 index e30f92d8ec..0000000000 --- a/include/gal/opengl/vbo_item.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * This program source code file is part of KiCad, a free EDA CAD application. - * - * Copyright (C) 2013 CERN - * @author Maciej Suminski - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you may find one here: - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * or you may search the http://www.gnu.org website for the version 2 license, - * or you may write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -/** - * @file vbo_item.h - * @brief Class to handle an item held in a Vertex Buffer Object. - */ - -#ifndef VBO_ITEM_H_ -#define VBO_ITEM_H_ - -#include -#include -#include - -namespace KiGfx -{ -typedef struct VBO_VERTEX -{ - GLfloat x, y, z; // Coordinates - GLubyte r, g, b, a; // Color - GLfloat shader[4]; // Shader type & params -} VBO_VERTEX; - -class VBO_CONTAINER; - -class VBO_ITEM -{ -friend class VBO_CONTAINER; - -public: - VBO_ITEM( VBO_CONTAINER* aContainer ); - ~VBO_ITEM(); - - /** - * Function PushVertex() - * Adds a single vertex to the VBO_ITEM. Vertex contains information about coordinates and - * colors and has to follow the specified format {X,Y,Z,R,G,B,A}. - * @param aVertex is a vertex to be added. - * @param aShader is an attribute for shader. - */ - void PushVertex( const VBO_VERTEX* aVertex ); - - /** - * Function PushVertices() - * Adds multiple vertices to the VBO_ITEM. This function is recommended over multiple calls to - * PushVertex, as it does less memory reallocations. Vertices contain information about - * coordinates and colors and has to follow the specified format {X,Y,Z,R,G,B,A}. - * @param aVertices are vertices to be added. - * @param aSize is an amount of vertices to be added. - * @param aShader is an attribute for shader. - */ - void PushVertices( const VBO_VERTEX* aVertices, GLuint aSize ); - - /** - * Function GetVertices() - * Returns a pointer to the array containing all vertices. - * @return Pointer to vertices packed in format {X, Y, Z, R, G, B, A}. - */ - VBO_VERTEX* GetVertices(); - - - /** - * Function GetSize() - * Returns information about number of vertices stored. - * @param Amount of vertices. - */ - inline unsigned int GetSize() const - { - return m_size; - } - - /** - * Function GetOffset() - * Returns data offset in the VBO. - * @return Data offset expressed as a number of vertices. - */ - inline unsigned int GetOffset() const - { - return m_offset; - } - - /** - * Function ChangeColor() - * Colors all vertices to the specified color. - * @param aColor is the new color for vertices. - */ - void ChangeColor( const COLOR4D& aColor ); - - /** - * Function ChangeDepth() - * Moves all vertices to the specified depth. - * @param aDepth is the new depth for vertices. - */ - void ChangeDepth( int aDepth ); - - ///< Informs the container that there will be no more vertices for the current VBO_ITEM - void Finish(); - - ///< Data structure for vertices {X,Y,Z,R,G,B,A,shader¶m} (@see VBO_VERTEX). - static const unsigned int VertByteSize = sizeof(VBO_VERTEX); - static const unsigned int VertStride = VertByteSize / sizeof(GLfloat); - - static const unsigned int CoordByteSize = sizeof(VBO_VERTEX().x) + sizeof(VBO_VERTEX().y) + - sizeof(VBO_VERTEX().z); - static const unsigned int CoordStride = CoordByteSize / sizeof(GLfloat); - - // Offset of color data from the beginning of each vertex data - static const unsigned int ColorByteOffset = offsetof(VBO_VERTEX, r); - static const unsigned int ColorOffset = ColorByteOffset / sizeof(GLubyte); - static const unsigned int ColorByteSize = sizeof(VBO_VERTEX().r) + sizeof(VBO_VERTEX().g) + - sizeof(VBO_VERTEX().b) + sizeof(VBO_VERTEX().a); - static const unsigned int ColorStride = ColorByteSize / sizeof(GLubyte); - - // Shader attributes - static const unsigned int ShaderByteOffset = offsetof(VBO_VERTEX, shader); - static const unsigned int ShaderOffset = ShaderByteOffset / sizeof(GLfloat); - static const unsigned int ShaderByteSize = sizeof(VBO_VERTEX().shader); - static const unsigned int ShaderStride = ShaderByteSize / sizeof(GLfloat); - - static const unsigned int IndByteSize = sizeof(GLuint); - -protected: - ///< Offset and size of data stored in the VBO_CONTAINER. - unsigned int m_offset; - unsigned int m_size; - - ///< Storage for vertices. - VBO_CONTAINER* m_container; - - ///< Flag telling if the item should be recached in VBO or not. - bool m_isDirty; - - /** - * Function setSize() - * Sets data size in the VBO. - * @param aSize is the size expressed as a number of vertices. - */ - void setSize( unsigned int aSize ) - { - m_size = aSize; - } - - /** - * Function setOffset() - * Sets data offset in the VBO. - * @param aOffset is the offset expressed as a number of vertices. - */ - inline void setOffset( unsigned int aOffset ) - { - m_offset = aOffset; - } -}; -} // namespace KiGfx - -#endif /* VBO_ITEM_H_ */ diff --git a/include/gal/opengl/vertex_common.h b/include/gal/opengl/vertex_common.h new file mode 100644 index 0000000000..a718ef4ea8 --- /dev/null +++ b/include/gal/opengl/vertex_common.h @@ -0,0 +1,75 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Maciej Suminski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * @file vertex_common.h + * @brief Common defines and consts used in vertex related classes. + */ + +#ifndef VERTEX_COMMON_H_ +#define VERTEX_COMMON_H_ + +#include + +namespace KiGfx +{ +// Possible types of shaders +enum SHADER_TYPE +{ + SHADER_NONE = 0, + SHADER_LINE, + SHADER_FILLED_CIRCLE, + SHADER_STROKED_CIRCLE, +}; + +typedef struct VERTEX +{ + GLfloat x, y, z; // Coordinates + GLubyte r, g, b, a; // Color + GLfloat shader[4]; // Shader type & params +} VERTEX; + +///< Data structure for vertices {X,Y,Z,R,G,B,A,shader¶m} (@see VERTEX). +const unsigned int VertexSize = sizeof(VERTEX); +const unsigned int VertexStride = VertexSize / sizeof(GLfloat); + +const unsigned int CoordSize = sizeof(VERTEX().x) + sizeof(VERTEX().y) + sizeof(VERTEX().z); +const unsigned int CoordStride = CoordSize / sizeof(GLfloat); + +// Offset of color data from the beginning of each vertex data +const unsigned int ColorOffset = offsetof(VERTEX, r); +const unsigned int ColorSize = sizeof(VERTEX().r) + sizeof(VERTEX().g) + + sizeof(VERTEX().b) + sizeof(VERTEX().a); +const unsigned int ColorStride = ColorSize / sizeof(GLubyte); + +// Shader attributes +const unsigned int ShaderOffset = offsetof(VERTEX, shader); +const unsigned int ShaderSize = sizeof(VERTEX().shader); +const unsigned int ShaderStride = ShaderSize / sizeof(GLfloat); + +const unsigned int IndexSize = sizeof(GLuint); + +} // namespace KiGfx + +#endif /* VERTEX_COMMON_H_ */ diff --git a/include/gal/opengl/vertex_container.h b/include/gal/opengl/vertex_container.h new file mode 100644 index 0000000000..1714040022 --- /dev/null +++ b/include/gal/opengl/vertex_container.h @@ -0,0 +1,158 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Maciej Suminski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * @file vertex_container.h + * @brief Class to store vertices and handle transfers between system memory and GPU memory. + */ + +#ifndef VERTEX_CONTAINER_H_ +#define VERTEX_CONTAINER_H_ + +#include + +namespace KiGfx +{ +class VERTEX; +class VERTEX_ITEM; +class SHADER; + +class VERTEX_CONTAINER +{ +public: + /** + * Function MakeContainer() + * Returns a pointer to a new container of an appropriate type. + */ + static VERTEX_CONTAINER* MakeContainer( bool aCached ); + virtual ~VERTEX_CONTAINER(); + + /** + * Function SetItem() + * sets the item in order to modify or finishes its current modifications. + * @param aItem is the item or NULL in case of finishing the item. + */ + virtual void SetItem( VERTEX_ITEM* aItem ) = 0; + + /** + * Function Allocate() + * returns allocated space (possibly resizing the reserved memory chunk or allocating a new + * chunk if it was not stored before) for the given number of vertices associated with the + * current item (set by SetItem()). The newly allocated space is added at the end of the chunk + * used by the current item and may serve to store new vertices. + * @param aSize is the number of vertices to be allocated. + * @return Pointer to the allocated space or NULL in case of failure. + */ + virtual VERTEX* Allocate( unsigned int aSize ) = 0; + + /** + * Function Erase() + * erases all vertices associated with the current item (set by SetItem()). + */ + virtual void Erase() = 0; + + /** + * Function Clear() + * removes all the data stored in the container and restores its original state. + */ + virtual void Clear() = 0; + + /** + * Function GetAllVertices() + * returns all the vertices stored in the container. It is especially useful for transferring + * data to the GPU memory. + */ + inline virtual VERTEX* GetAllVertices() const + { + return m_vertices; + } + + /** + * Function GetVertices() + * returns vertices stored at the specific offset. + * @aOffset is the offset. + */ + virtual inline VERTEX* GetVertices( unsigned int aOffset ) const + { + return &m_vertices[aOffset]; + } + + /** + * Function GetSize() + * returns amount of vertices currently stored in the container. + */ + virtual inline unsigned int GetSize() const + { + return m_currentSize; + } + + /** + * Function IsDirty() + * returns information about container cache state. Clears the flag after calling the function. + * @return true in case the vertices have to be reuploaded. + */ + inline bool isDirty() + { + bool state = m_dirty; + + m_dirty = false; + + return state; + } + +protected: + VERTEX_CONTAINER( unsigned int aSize = defaultInitSize ); + + ///< How many vertices we can store in the container + unsigned int m_freeSpace; + + ///< How big is the current container, expressed in vertices + unsigned int m_currentSize; + + ///< Store the initial size, so it can be resized to this on Clear() + unsigned int m_initialSize; + + ///< Actual storage memory (should be handled using malloc/realloc/free to speed up resizing) + VERTEX* m_vertices; + + ///< State flags + bool m_failed; + bool m_dirty; + + /** + * Function reservedSpace() + * returns size of the reserved memory space. + * @return Size of the reserved memory space (expressed as a number of vertices). + */ + unsigned int reservedSpace() + { + return m_currentSize - m_freeSpace; + } + + ///< Default initial size of a container (expressed in vertices) + static const unsigned int defaultInitSize = 1048576; +}; +} // namespace KiGfx + +#endif /* VERTEX_CONTAINER_H_ */ diff --git a/include/gal/opengl/vertex_item.h b/include/gal/opengl/vertex_item.h new file mode 100644 index 0000000000..4dd6b084f2 --- /dev/null +++ b/include/gal/opengl/vertex_item.h @@ -0,0 +1,103 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Maciej Suminski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * @file vertex_item.h + * @brief Class to handle an item held in a container. + */ + +#ifndef VERTEX_ITEM_H_ +#define VERTEX_ITEM_H_ + +#include +#include +#include + +namespace KiGfx +{ +class VERTEX_MANAGER; + +class VERTEX_ITEM +{ +public: + friend class CACHED_CONTAINER; + friend class VERTEX_MANAGER; + + VERTEX_ITEM( const VERTEX_MANAGER& aManager ); + virtual ~VERTEX_ITEM(); + + /** + * Function GetSize() + * Returns information about number of vertices stored. + * @param Number of vertices. + */ + inline unsigned int GetSize() const + { + return m_size; + } + + /** + * Function GetOffset() + * Returns data offset in the container. + * @return Data offset expressed as a number of vertices. + */ + inline unsigned int GetOffset() const + { + return m_offset; + } + + /** + * Function GetVertices() + * Returns pointer to the data used by the VERTEX_ITEM. + */ + VERTEX* GetVertices() const; + +private: + const VERTEX_MANAGER& m_manager; + unsigned int m_offset; + unsigned int m_size; + + /** + * Function SetOffset() + * Sets data offset in the container. + * @param aOffset is the offset expressed as a number of vertices. + */ + inline void setOffset( unsigned int aOffset ) + { + m_offset = aOffset; + } + + /** + * Function SetSize() + * Sets data size in the container. + * @param aSize is the size expressed as a number of vertices. + */ + inline void setSize( unsigned int aSize ) + { + m_size = aSize; + } +}; +} // namespace KiGfx + +#endif /* VERTEX_ITEM_H_ */ diff --git a/include/gal/opengl/vertex_manager.h b/include/gal/opengl/vertex_manager.h new file mode 100644 index 0000000000..bacb99867e --- /dev/null +++ b/include/gal/opengl/vertex_manager.h @@ -0,0 +1,341 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2013 CERN + * @author Maciej Suminski + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/** + * @file vertex_manager.h + * @brief Class to control vertex container and GPU with possibility of emulating old-style OpenGL + * 1.0 state machine using modern OpenGL methods. + */ + +#ifndef VERTEX_MANAGER_H_ +#define VERTEX_MANAGER_H_ + +#define GLM_FORCE_RADIANS +#include +#include +#include +#include +#include +#include +#include + +namespace KiGfx +{ +class SHADER; +class VERTEX_ITEM; +class VERTEX_CONTAINER; +class GPU_MANAGER; + +class VERTEX_MANAGER +{ +public: + /** + * @brief Constructor. + * + * @param aCached says if vertices should be cached in GPU or system memory. For data that + * does not change every frame, it is better to store vertices in GPU memory. + */ + VERTEX_MANAGER( bool aCached ); + + /** + * Function Vertex() + * adds a vertex with the given coordinates to the currently set item. Color & shader + * parameters stored in aVertex are ignored, instead color & shader set by Color() and + * Shader() functions are used. Vertex coordinates will have the current transformation + * matrix applied. + * + * @param aVertex contains vertex coordinates. + */ + inline void Vertex( const VERTEX& aVertex ) const + { + Vertex( aVertex.x, aVertex.y, aVertex.z ); + } + + /** + * Function Vertex() + * adds a vertex with the given coordinates to the currently set item. Vertex coordinates will + * have the current transformation matrix applied. + * + * @param aX is the X coordinate of the new vertex. + * @param aY is the Y coordinate of the new vertex. + * @param aZ is the Z coordinate of the new vertex. + */ + void Vertex( GLfloat aX, GLfloat aY, GLfloat aZ ) const; + + /** + * Function Vertices() + * adds one or more vertices to the currently set item. It takes advantage of allocating memory + * in advance, so should be faster than adding vertices one by one. Color & shader + * parameters stored in aVertices are ignored, instead color & shader set by Color() and + * Shader() functions are used. All the vertex coordinates will have the current + * transformation matrix applied. + * + * @param aVertices contains vertices to be added + * @param aSize is the number of vertices to be added. + */ + void Vertices( const VERTEX aVertices[], unsigned int aSize ) const; + + /** + * Function Color() + * changes currently used color that will be applied to newly added vertices. + * + * @param aColor is the new color. + */ + inline void Color( const COLOR4D& aColor ) + { + m_color[0] = aColor.r * 255.0; + m_color[1] = aColor.g * 255.0; + m_color[2] = aColor.b * 255.0; + m_color[3] = aColor.a * 255.0; + } + + /** + * Function Color() + * changes currently used color that will be applied to newly added vertices. It is the + * equivalent of glColor4f() function. + * @param aRed is the red component of the new color. + * @param aGreen is the green component of the new color. + * @param aBlue is the blue component of the new color. + * @param aAlpha is the alpha component of the new color. + */ + inline void Color( GLfloat aRed, GLfloat aGreen, GLfloat aBlue, GLfloat aAlpha ) + { + m_color[0] = aRed * 255.0; + m_color[1] = aGreen * 255.0; + m_color[2] = aBlue * 255.0; + m_color[3] = aAlpha * 255.0; + } + + /** + * Function Shader() + * changes currently used shader and its parameters that will be applied to newly added + * vertices. Parameters depend on shader, for more information have a look at shaders source + * code. + * @see SHADER_TYPE + * + * @param aShaderType is the a shader type to be applied. + * @param aParam1 is the optional parameter for a shader. + * @param aParam2 is the optional parameter for a shader. + * @param aParam3 is the optional parameter for a shader. + */ + inline void Shader( GLfloat aShaderType, GLfloat aParam1 = 0.0f, + GLfloat aParam2 = 0.0f, GLfloat aParam3 = 0.0f ) + { + m_shader[0] = aShaderType; + m_shader[1] = aParam1; + m_shader[2] = aParam2; + m_shader[3] = aParam3; + } + + /** + * Function Translate() + * multiplies the current matrix by a translation matrix, so newly vertices will be + * translated by the given vector. It is the equivalent of the glTranslatef() function. + * + * @param aX is the X coordinate of a translation vector. + * @param aY is the X coordinate of a translation vector. + * @param aZ is the X coordinate of a translation vector. + */ + inline void Translate( GLfloat aX, GLfloat aY, GLfloat aZ ) + { + m_transform = glm::translate( m_transform, glm::vec3( aX, aY, aZ ) ); + } + + /** + * Function Rotate() + * multiplies the current matrix by a rotation matrix, so the newly vertices will be + * rotated by the given angles. It is the equivalent of the glRotatef() function. + * + * @param aAngle is the angle of rotation, in radians. + * @param aX is a multiplier for the X axis + * @param aY is a multiplier for the Y axis + * @param aZ is a multiplier for the Z axis. + */ + inline void Rotate( GLfloat aAngle, GLfloat aX, GLfloat aY, GLfloat aZ ) + { + m_transform = glm::rotate( m_transform, aAngle, glm::vec3( aX, aY, aZ ) ); + } + + /** + * Function Scale() + * multiplies the current matrix by a scaling matrix, so the newly vertices will be + * scaled by the given factors. It is the equivalent of the glScalef() function. + * + * @param aX is the X axis scaling factor. + * @param aY is the Y axis scaling factor. + * @param aZ is the Z axis scaling factor. + */ + inline void Scale( GLfloat aX, GLfloat aY, GLfloat aZ ) + { + m_transform = glm::scale( m_transform, glm::vec3( aX, aY, aZ ) ); + } + + /** + * Function PushMatrix() + * pushes the current transformation matrix stack. It is the equivalent of the glPushMatrix() + * function. + */ + inline void PushMatrix() + { + m_transformStack.push( m_transform ); + + // Every transformation starts with PushMatrix + m_noTransform = false; + } + + /** + * Function PopMatrix() + * pops the current transformation matrix stack. It is the equivalent of the glPopMatrix() + * function. + */ + void PopMatrix() + { + wxASSERT( !m_transformStack.empty() ); + + m_transform = m_transformStack.top(); + m_transformStack.pop(); + + if( m_transformStack.empty() ) + { + // We return back to the identity matrix, thus no vertex transformation is needed + m_noTransform = true; + } + } + + /** + * Function SetItem() + * sets an item to start its modifications. After calling the function it is possible to add + * vertices using function Add(). + * + * @param aItem is the item that is going to store vertices in the container. + */ + void SetItem( VERTEX_ITEM& aItem ) const; + + /** + * Function FreeItem() + * frees the memory occupied by the item, so it is no longer stored in the container. + * + * @param aItem is the item to be freed + */ + void FreeItem( VERTEX_ITEM& aItem ) const; + + /** + * Function ChangeItemColor() + * changes the color of all vertices owned by an item. + * + * @param aItem is the item to change. + * @param aColor is the new color to be applied. + */ + void ChangeItemColor( const VERTEX_ITEM& aItem, const COLOR4D& aColor ) const; + + /** + * Function ChangeItemDepth() + * changes the depth of all vertices owned by an item. + * + * @param aItem is the item to change. + * @param aDepth is the new color to be applied. + */ + void ChangeItemDepth( const VERTEX_ITEM& aItem, GLfloat aDepth ) const; + + /** + * Function GetVertices() + * returns a pointer to the vertices owned by an item. + * + * @param aItem is the owner of vertices that are going to be returned. + * @return Pointer to the vertices or NULL if the item is not stored at the container. + */ + VERTEX* GetVertices( const VERTEX_ITEM& aItem ) const; + + const glm::mat4& GetTransformation() const + { + return m_transform; + } + + /** + * Function SetShader() + * sets a shader program that is going to be used during rendering. + * @param aShader is the object containing compiled and linked shader program. + */ + void SetShader( SHADER& aShader ) const; + + /** + * Function Clear() + * removes all the stored vertices from the container. + */ + void Clear() const; + + /** + * Function BeginDrawing() + * prepares buffers and items to start drawing. + */ + void BeginDrawing() const; + + /** + * Function DrawItem() + * draws an item to the buffer. + * + * @param aItem is the item to be drawn. + */ + void DrawItem( const VERTEX_ITEM& aItem ) const; + + /** + * Function EndDrawing() + * finishes drawing operations. + */ + void EndDrawing() const; + +protected: + /** + * Function putVertex() + * applies all transformation to the given coordinates and store them at the specified target. + * + * @param aTarget is the place where the new vertex is going to be stored (it has to be + * allocated first). + * @param aX is the X coordinate of the new vertex. + * @param aY is the Y coordinate of the new vertex. + * @param aZ is the Z coordinate of the new vertex. + */ + void putVertex( VERTEX& aTarget, GLfloat aX, GLfloat aY, GLfloat aZ ) const; + + /// Container for vertices, may be cached or noncached + boost::shared_ptr m_container; + /// GPU manager for data transfers and drawing operations + boost::shared_ptr m_gpu; + + /// State machine variables + /// True in case there is no need to transform vertices + bool m_noTransform; + /// Currently used transform matrix + glm::mat4 m_transform; + /// Stack of transformation matrices, used for Push/PopMatrix + std::stack m_transformStack; + /// Currently used color + GLubyte m_color[ColorStride]; + /// Currently used shader and its parameters + GLfloat m_shader[ShaderStride]; +}; + +} // namespace KiGfx + +#endif /* VERTEX_MANAGER_H_ */