Commit 5242fff9 authored by Maciej Suminski's avatar Maciej Suminski

Code refactorization. VBO_CONTAINER is split to [NON]CACHED_MANAGER,...

Code refactorization. VBO_CONTAINER is split to [NON]CACHED_MANAGER, GPU_MANAGER and VERTEX_MANAGER.
parent 4d7db717
...@@ -36,8 +36,12 @@ set(GAL_SRCS ...@@ -36,8 +36,12 @@ set(GAL_SRCS
gal/color4d.cpp gal/color4d.cpp
gal/opengl/opengl_gal.cpp gal/opengl/opengl_gal.cpp
gal/opengl/shader.cpp gal/opengl/shader.cpp
gal/opengl/vbo_item.cpp gal/opengl/vertex_item.cpp
gal/opengl/vbo_container.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 gal/cairo/cairo_gal.cpp
view/wx_view_controls.cpp view/wx_view_controls.cpp
) )
......
...@@ -132,7 +132,7 @@ void EDA_DRAW_PANEL_GAL::Refresh( bool eraseBackground, const wxRect* rect ) ...@@ -132,7 +132,7 @@ void EDA_DRAW_PANEL_GAL::Refresh( bool eraseBackground, const wxRect* rect )
#endif /* __WXDEBUG__ */ #endif /* __WXDEBUG__ */
m_gal->BeginDrawing(); 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->ClearScreen();
m_gal->DrawGrid(); m_gal->DrawGrid();
......
...@@ -141,7 +141,7 @@ void CAIRO_GAL::initSurface() ...@@ -141,7 +141,7 @@ void CAIRO_GAL::initSurface()
cairoSurface = cairo_image_surface_create_for_data( (unsigned char*) bitmapBuffer, cairoSurface = cairo_image_surface_create_for_data( (unsigned char*) bitmapBuffer,
CAIRO_FORMAT_RGB24, clientRectangle.width, CAIRO_FORMAT_RGB24, clientRectangle.width,
clientRectangle.height, stride ); clientRectangle.height, stride );
cairoImage = cairo_create ( cairoSurface ); cairoImage = cairo_create( cairoSurface );
#ifdef __WXDEBUG__ #ifdef __WXDEBUG__
cairo_status_t status = cairo_status( cairoImage ); cairo_status_t status = cairo_status( cairoImage );
wxASSERT_MSG( status == CAIRO_STATUS_SUCCESS, "Cairo context creation error" ); wxASSERT_MSG( status == CAIRO_STATUS_SUCCESS, "Cairo context creation error" );
...@@ -194,7 +194,7 @@ void CAIRO_GAL::deinitSurface() ...@@ -194,7 +194,7 @@ void CAIRO_GAL::deinitSurface()
} }
unsigned int CAIRO_GAL::getGroupNumber() unsigned int CAIRO_GAL::getNewGroupNumber()
{ {
wxASSERT_MSG( groups.size() < std::numeric_limits<unsigned int>::max(), wxASSERT_MSG( groups.size() < std::numeric_limits<unsigned int>::max(),
wxT( "There are no free slots to store a group" ) ); wxT( "There are no free slots to store a group" ) );
...@@ -230,6 +230,7 @@ void CAIRO_GAL::EndDrawing() ...@@ -230,6 +230,7 @@ void CAIRO_GAL::EndDrawing()
// Now translate the raw image data from the format stored // Now translate the raw image data from the format stored
// by cairo into a format understood by wxImage. // by cairo into a format understood by wxImage.
unsigned char* wxOutputPtr = wxOutput; unsigned char* wxOutputPtr = wxOutput;
for( size_t count = 0; count < bufferSize; count++ ) for( size_t count = 0; count < bufferSize; count++ )
{ {
unsigned int value = bitmapBuffer[count]; unsigned int value = bitmapBuffer[count];
...@@ -287,7 +288,8 @@ void CAIRO_GAL::DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ...@@ -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 ) if( isFillEnabled )
{ {
...@@ -317,7 +319,6 @@ void CAIRO_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPo ...@@ -317,7 +319,6 @@ void CAIRO_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPo
cairo_line_to( cairoImage, lineLength, -aWidth / 2.0 ); cairo_line_to( cairoImage, lineLength, -aWidth / 2.0 );
cairo_restore( cairoImage ); cairo_restore( cairoImage );
} }
isElementAdded = true; isElementAdded = true;
...@@ -351,7 +352,8 @@ void CAIRO_GAL::DrawPolyline( std::deque<VECTOR2D>& aPointList ) ...@@ -351,7 +352,8 @@ void CAIRO_GAL::DrawPolyline( std::deque<VECTOR2D>& aPointList )
bool isFirstPoint = true; bool isFirstPoint = true;
// Iterate over the point list and draw the segments // Iterate over the point list and draw the segments
for( std::deque<VECTOR2D>::const_iterator it = aPointList.begin(); it != aPointList.end(); ++it ) std::deque<VECTOR2D>::const_iterator it;
for( it = aPointList.begin(); it != aPointList.end(); ++it )
{ {
if( isFirstPoint ) if( isFirstPoint )
{ {
...@@ -373,7 +375,8 @@ void CAIRO_GAL::DrawPolygon( const std::deque<VECTOR2D>& aPointList ) ...@@ -373,7 +375,8 @@ void CAIRO_GAL::DrawPolygon( const std::deque<VECTOR2D>& aPointList )
bool isFirstPoint = true; bool isFirstPoint = true;
// Iterate over the point list and draw the polygon // Iterate over the point list and draw the polygon
for( std::deque<VECTOR2D>::const_iterator it = aPointList.begin(); it != aPointList.end(); ++it ) std::deque<VECTOR2D>::const_iterator it;
for( it = aPointList.begin(); it != aPointList.end(); ++it )
{ {
if( isFirstPoint ) if( isFirstPoint )
{ {
...@@ -644,7 +647,7 @@ int CAIRO_GAL::BeginGroup() ...@@ -644,7 +647,7 @@ int CAIRO_GAL::BeginGroup()
storePath(); storePath();
Group group; Group group;
int groupNumber = getGroupNumber(); int groupNumber = getNewGroupNumber();
groups.insert( std::make_pair( groupNumber, group ) ); groups.insert( std::make_pair( groupNumber, group ) );
currentGroup = &groups[groupNumber]; currentGroup = &groups[groupNumber];
isGrouping = true; isGrouping = true;
...@@ -677,6 +680,7 @@ void CAIRO_GAL::DeleteGroup( int aGroupNumber ) ...@@ -677,6 +680,7 @@ void CAIRO_GAL::DeleteGroup( int aGroupNumber )
// Delete the Cairo paths // Delete the Cairo paths
std::deque<GroupElement>::iterator it, end; std::deque<GroupElement>::iterator it, end;
for( it = groups[aGroupNumber].begin(), end = groups[aGroupNumber].end(); it != end; ++it ) for( it = groups[aGroupNumber].begin(), end = groups[aGroupNumber].end(); it != end; ++it )
{ {
if( it->command == CMD_FILL_PATH || it->command == CMD_STROKE_PATH ) if( it->command == CMD_FILL_PATH || it->command == CMD_STROKE_PATH )
......
...@@ -23,203 +23,165 @@ ...@@ -23,203 +23,165 @@
*/ */
/** /**
* @file vbo_container.cpp * @file cached_container.cpp
* @brief Class to store VBO_ITEMs. * @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 <gal/opengl/vbo_container.h> #include <gal/opengl/cached_container.h>
#include <algorithm> #include <gal/opengl/vertex_manager.h>
#include <list> #include <gal/opengl/vertex_item.h>
#include <gal/opengl/shader.h>
#include <wx/log.h> #include <wx/log.h>
#include <list>
#ifdef __WXDEBUG__ #ifdef __WXDEBUG__
#include <profile.h> #include <profile.h>
#endif /* __WXDEBUG__ */ #endif /* __WXDEBUG__ */
using namespace KiGfx; using namespace KiGfx;
VBO_CONTAINER::VBO_CONTAINER( unsigned int aSize ) : CACHED_CONTAINER::CACHED_CONTAINER( unsigned int aSize ) :
m_freeSpace( aSize ), m_currentSize( aSize ), m_initialSize( aSize ), m_transform( NULL ), VERTEX_CONTAINER( aSize )
m_failed( false )
{ {
// By default no shader is used
m_shader[0] = 0;
m_vertices = static_cast<VBO_VERTEX*>( malloc( aSize * sizeof( VBO_VERTEX ) ) );
// In the beginning there is only free space // In the beginning there is only free space
m_freeChunks.insert( Chunk( aSize, 0 ) ); 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 ) // 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();
}
m_item = NULL;
}
else
{
m_item = aItem; m_item = aItem;
m_itemSize = aItem->GetSize(); m_itemSize = m_item->GetSize();
m_chunkSize = m_itemSize; m_chunkSize = m_itemSize;
if( m_itemSize == 0 ) if( m_itemSize == 0 )
m_items.insert( m_item ); // The item was not stored before m_items.insert( m_item ); // The item was not stored before
else else
m_chunkOffset = m_item->GetOffset(); 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 = NULL;
} }
void VBO_CONTAINER::Add( const VBO_VERTEX* aVertex, unsigned int aSize ) VERTEX* CACHED_CONTAINER::Allocate( unsigned int aSize )
{ {
// Pointer to the vertex that we are currently adding wxASSERT( m_item != NULL );
VBO_VERTEX* vertexPtr = allocate( aSize );
if( vertexPtr == NULL ) if( m_failed )
return; return NULL;
for( unsigned int i = 0; i < aSize; ++i ) if( m_itemSize + aSize > m_chunkSize )
{
// 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;
}
else
{ {
// Simply copy coordinates // There is not enough space in the currently reserved chunk, so we have to resize it
vertexPtr->x = aVertex[i].x;
vertexPtr->y = aVertex[i].y;
vertexPtr->z = aVertex[i].z;
}
// Apply currently used color // Reserve a bigger memory chunk for the current item and
vertexPtr->r = m_color[0]; // make it multiple of 3 to store triangles
vertexPtr->g = m_color[1]; m_chunkSize = ( 2 * m_itemSize ) + aSize + ( 3 - aSize % 3 );
vertexPtr->b = m_color[2]; // Save the current size before reallocating
vertexPtr->a = m_color[3]; m_chunkOffset = reallocate( m_chunkSize );
// Apply currently used shader if( m_chunkOffset > m_currentSize )
for( unsigned int j = 0; j < VBO_ITEM::ShaderStride; ++j )
{ {
vertexPtr->shader[j] = m_shader[j]; m_failed = true;
return NULL;
} }
vertexPtr++;
} }
} VERTEX* reserved = &m_vertices[m_chunkOffset + m_itemSize];
m_itemSize += aSize;
m_item->setSize( m_itemSize );
void VBO_CONTAINER::Clear()
{
// Change size to the default one
m_vertices = static_cast<VBO_VERTEX*>( 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 // The content has to be updated
m_transform = NULL; m_dirty = true;
m_failed = false;
// By default no shader is used #if CACHED_CONTAINER_TEST > 1
m_shader[0] = 0; test();
#endif
// In the beginning there is only free space return reserved;
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 ) void CACHED_CONTAINER::Erase()
{ {
freeItem( aItem ); wxASSERT( m_item != NULL );
freeItem( m_item );
// Dynamic memory freeing, there is no point in holding // Dynamic memory freeing, there is no point in holding
// a large amount of memory when there is no use for it // a large amount of memory when there is no use for it
if( m_freeSpace > ( m_currentSize / 2 ) && m_currentSize > defaultInitSize ) if( m_freeSpace > ( m_currentSize / 2 ) && m_currentSize > m_initialSize )
{ {
resizeContainer( m_currentSize / 2 ); resizeContainer( m_currentSize / 2 );
} }
} }
VBO_VERTEX* VBO_CONTAINER::GetAllVertices() const void CACHED_CONTAINER::Clear()
{ {
return m_vertices; // Change size to the default one
} m_vertices = static_cast<VERTEX*>( realloc( m_vertices,
m_initialSize * sizeof( VERTEX ) ) );
VBO_VERTEX* VBO_CONTAINER::GetVertices( const VBO_ITEM* aItem ) const // Reset state variables
{ m_freeSpace = m_initialSize;
int offset = aItem->GetOffset(); m_currentSize = m_initialSize;
m_failed = false;
return &m_vertices[offset]; // 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;
VBO_VERTEX* VBO_CONTAINER::allocate( unsigned int aSize ) for( it = m_items.begin(); it != m_items.end(); ++it )
{ {
wxASSERT( m_item != NULL ); ( *it )->setSize( 0 );
}
if( m_failed ) m_items.clear();
return NULL;
if( m_itemSize + aSize > m_chunkSize )
{
// 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 // Now there is only free space left
m_chunkSize = std::max( ( 2 * m_itemSize ) + aSize, (unsigned) 3 ); m_freeChunks.clear();
// Save the current size before reallocating m_freeChunks.insert( Chunk( m_freeSpace, 0 ) );
m_chunkOffset = reallocate( m_chunkSize ); }
if( m_chunkOffset > m_currentSize )
{
m_failed = true;
return NULL;
}
}
VBO_VERTEX* reserved = &m_vertices[m_chunkOffset + m_itemSize]; VERTEX* CACHED_CONTAINER::GetVertices( const VERTEX_ITEM* aItem ) const
m_itemSize += aSize; {
m_item->setSize( m_itemSize ); int offset = aItem->GetOffset();
return reserved; return &m_vertices[offset];
} }
unsigned int VBO_CONTAINER::reallocate( unsigned int aSize ) 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? // Is there enough space to store vertices?
if( m_freeSpace < aSize ) if( m_freeSpace < aSize )
{ {
...@@ -269,37 +231,57 @@ unsigned int VBO_CONTAINER::reallocate( unsigned int aSize ) ...@@ -269,37 +231,57 @@ unsigned int VBO_CONTAINER::reallocate( unsigned int aSize )
// Check if the item was previously stored in the container // Check if the item was previously stored in the container
if( m_itemSize > 0 ) 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 // 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], memcpy( &m_vertices[chunkOffset], &m_vertices[m_chunkOffset],
m_itemSize * VBO_ITEM::VertByteSize ); m_itemSize * VertexSize );
// Free the space previously used by the chunk // Free the space previously used by the chunk
m_freeChunks.insert( Chunk( m_itemSize, m_chunkOffset ) ); m_freeChunks.insert( Chunk( m_itemSize, m_chunkOffset ) );
m_freeSpace += m_itemSize; m_freeSpace += m_itemSize;
} }
// Remove the allocated chunk from the free space pool // Remove the allocated chunk from the free space pool
m_freeChunks.erase( newChunk ); m_freeChunks.erase( newChunk );
m_freeSpace -= chunkSize;
// If there is some space left, return it to the pool - add an entry for it // If there is some space left, return it to the pool - add an entry for it
if( chunkSize > aSize ) if( chunkSize > aSize )
{ {
m_freeChunks.insert( Chunk( chunkSize - aSize, chunkOffset + aSize ) ); m_freeChunks.insert( Chunk( chunkSize - aSize, chunkOffset + aSize ) );
m_freeSpace += chunkSize - aSize;
} }
m_freeSpace -= aSize;
// mergeFreeChunks();
m_item->setOffset( chunkOffset ); m_item->setOffset( chunkOffset );
#if CACHED_CONTAINER_TEST > 2
showFreeChunks();
showReservedChunks();
#endif
return chunkOffset; 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 ) if( aTarget == NULL )
{ {
// No target was specified, so we have to reallocate our own space // No target was specified, so we have to reallocate our own space
aTarget = static_cast<VBO_VERTEX*>( malloc( m_currentSize * sizeof( VBO_VERTEX ) ) ); aTarget = static_cast<VERTEX*>( malloc( m_currentSize * sizeof( VERTEX ) ) );
if( aTarget == NULL ) if( aTarget == NULL )
{ {
wxLogError( wxT( "Run out of memory" ) ); wxLogError( wxT( "Run out of memory" ) );
...@@ -309,16 +291,17 @@ bool VBO_CONTAINER::defragment( VBO_VERTEX* aTarget ) ...@@ -309,16 +291,17 @@ bool VBO_CONTAINER::defragment( VBO_VERTEX* aTarget )
int newOffset = 0; int newOffset = 0;
Items::iterator it, it_end; Items::iterator it, it_end;
for( it = m_items.begin(), it_end = m_items.end(); it != it_end; ++it ) for( it = m_items.begin(), it_end = m_items.end(); it != it_end; ++it )
{ {
VBO_ITEM* item = *it; VERTEX_ITEM* item = *it;
int itemOffset = item->GetOffset(); int itemOffset = item->GetOffset();
int itemSize = item->GetSize(); int itemSize = item->GetSize();
// Move an item to the new container // 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 ); item->setOffset( newOffset );
// Move to the next free space // Move to the next free space
...@@ -330,17 +313,29 @@ bool VBO_CONTAINER::defragment( VBO_VERTEX* aTarget ) ...@@ -330,17 +313,29 @@ bool VBO_CONTAINER::defragment( VBO_VERTEX* aTarget )
// Now there is only one big chunk of free memory // Now there is only one big chunk of free memory
m_freeChunks.clear(); 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; 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; 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 // Reversed free chunks map - this one stores chunk size with its offset as the key
std::list<Chunk> freeChunks; std::list<Chunk> freeChunks;
...@@ -349,6 +344,7 @@ void VBO_CONTAINER::mergeFreeChunks() ...@@ -349,6 +344,7 @@ void VBO_CONTAINER::mergeFreeChunks()
{ {
freeChunks.push_back( std::make_pair( it->second, it->first ) ); freeChunks.push_back( std::make_pair( it->second, it->first ) );
} }
m_freeChunks.clear(); m_freeChunks.clear();
freeChunks.sort(); freeChunks.sort();
...@@ -356,6 +352,7 @@ void VBO_CONTAINER::mergeFreeChunks() ...@@ -356,6 +352,7 @@ void VBO_CONTAINER::mergeFreeChunks()
unsigned int offset = freeChunks.front().first; unsigned int offset = freeChunks.front().first;
unsigned int size = freeChunks.front().second; unsigned int size = freeChunks.front().second;
freeChunks.pop_front(); freeChunks.pop_front();
for( itf = freeChunks.begin(), itf_end = freeChunks.end(); itf != itf_end; ++itf ) for( itf = freeChunks.begin(), itf_end = freeChunks.end(); itf != itf_end; ++itf )
{ {
if( itf->first == offset + size ) if( itf->first == offset + size )
...@@ -371,17 +368,30 @@ void VBO_CONTAINER::mergeFreeChunks() ...@@ -371,17 +368,30 @@ void VBO_CONTAINER::mergeFreeChunks()
// and let's check the next chunk // and let's check the next chunk
offset = itf->first; offset = itf->first;
size = itf->second; size = itf->second;
} }
} }
// Add the last one // Add the last one
m_freeChunks.insert( std::make_pair( size, offset ) ); 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 ) if( aNewSize < m_currentSize )
{ {
...@@ -390,7 +400,8 @@ bool VBO_CONTAINER::resizeContainer( unsigned int aNewSize ) ...@@ -390,7 +400,8 @@ bool VBO_CONTAINER::resizeContainer( unsigned int aNewSize )
if( reservedSpace() > aNewSize ) if( reservedSpace() > aNewSize )
return false; return false;
newContainer = static_cast<VBO_VERTEX*>( malloc( aNewSize * sizeof( VBO_VERTEX ) ) ); newContainer = static_cast<VERTEX*>( malloc( aNewSize * sizeof( VERTEX ) ) );
if( newContainer == NULL ) if( newContainer == NULL )
{ {
wxLogError( wxT( "Run out of memory" ) ); wxLogError( wxT( "Run out of memory" ) );
...@@ -407,7 +418,8 @@ bool VBO_CONTAINER::resizeContainer( unsigned int aNewSize ) ...@@ -407,7 +418,8 @@ bool VBO_CONTAINER::resizeContainer( unsigned int aNewSize )
else else
{ {
// Enlarging container // Enlarging container
newContainer = static_cast<VBO_VERTEX*>( realloc( m_vertices, aNewSize * sizeof( VBO_VERTEX ) ) ); newContainer = static_cast<VERTEX*>( realloc( m_vertices, aNewSize * sizeof( VERTEX ) ) );
if( newContainer == NULL ) if( newContainer == NULL )
{ {
wxLogError( wxT( "Run out of memory" ) ); wxLogError( wxT( "Run out of memory" ) );
...@@ -427,28 +439,87 @@ bool VBO_CONTAINER::resizeContainer( unsigned int aNewSize ) ...@@ -427,28 +439,87 @@ bool VBO_CONTAINER::resizeContainer( unsigned int aNewSize )
} }
void VBO_CONTAINER::freeItem( VBO_ITEM* aItem ) void CACHED_CONTAINER::freeItem( VERTEX_ITEM* aItem )
{ {
int size = aItem->GetSize(); int size = aItem->GetSize();
int offset = aItem->GetOffset(); int offset = aItem->GetOffset();
// Insert a free memory chunk entry in the place where item was stored
m_freeChunks.insert( Chunk( size, offset ) ); m_freeChunks.insert( Chunk( size, offset ) );
m_freeSpace += size; m_freeSpace += size;
m_items.erase( aItem ); 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 ); aItem->setSize( 0 );
} }
void VBO_CONTAINER::test() const unsigned int CACHED_CONTAINER::getPowerOf2( unsigned int aNumber ) const
{ {
unsigned int freeSpace = 0; unsigned int power = 1;
FreeChunkMap::const_iterator it, it_end;
// Check if the amount of free memory stored as chunks is the same as reported by m_freeSpace while( power < aNumber && power != 0 )
for( it = m_freeChunks.begin(), it_end = m_freeChunks.end(); it != it_end; ++it ) power <<= 1;
freeSpace += it->first;
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 ); 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 */
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 <gal/opengl/gpu_manager.h>
#include <gal/opengl/cached_container.h>
#include <gal/opengl/noncached_container.h>
#include <gal/opengl/shader.h>
#include <typeinfo>
#include <wx/log.h>
#ifdef __WXDEBUG__
#include <profile.h>
#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();
}
}
...@@ -23,94 +23,72 @@ ...@@ -23,94 +23,72 @@
*/ */
/** /**
* @file vbo_item.cpp * @file noncached_container.cpp
* @brief Class to handle an item held in a Vertex Buffer Object. * @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 <gal/opengl/vbo_container.h> #include <gal/opengl/noncached_container.h>
#include <gal/opengl/vbo_item.h> #include <cstdlib>
#include <cstring>
using namespace KiGfx; using namespace KiGfx;
VBO_ITEM::VBO_ITEM( VBO_CONTAINER* aContainer ) : NONCACHED_CONTAINER::NONCACHED_CONTAINER( unsigned int aSize ) :
m_offset( 0 ), VERTEX_CONTAINER( aSize ), m_freePtr( 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() NONCACHED_CONTAINER::~NONCACHED_CONTAINER()
{ {
m_container->Free( this );
} }
void VBO_ITEM::PushVertex( const VBO_VERTEX* aVertex ) void NONCACHED_CONTAINER::SetItem( VERTEX_ITEM* aItem )
{ {
m_container->Add( aVertex ); // Nothing has to be done, as the noncached container
// does not care about VERTEX_ITEMs ownership
m_isDirty = true;
} }
void VBO_ITEM::PushVertices( const VBO_VERTEX* aVertices, GLuint aSize ) VERTEX* NONCACHED_CONTAINER::Allocate( unsigned int aSize )
{ {
for( unsigned int i = 0; i < aSize; ++i ) if( m_freeSpace < aSize )
{ {
PushVertex( &aVertices[i] ); // Double the space
} VERTEX* newVertices = static_cast<VERTEX*>( realloc( m_vertices,
} m_currentSize * 2 *
sizeof(VERTEX) ) );
VBO_VERTEX* VBO_ITEM::GetVertices()
{
if( m_isDirty )
Finish();
return m_container->GetVertices( m_offset );
}
if( newVertices != NULL )
{
m_vertices = newVertices;
m_freeSpace += m_currentSize;
m_currentSize *= 2;
}
else
{
return NULL;
}
}
void VBO_ITEM::ChangeColor( const COLOR4D& aColor ) VERTEX* freeVertex = &m_vertices[m_freePtr];
{
VBO_VERTEX* vertexPtr = GetVertices();
for( unsigned int i = 0; i < m_size; ++i ) // Move to the next free chunk
{ m_freePtr += aSize;
vertexPtr->r = aColor.r * 255; m_freeSpace -= aSize;
vertexPtr->g = aColor.g * 255;
vertexPtr->b = aColor.b * 255;
vertexPtr->a = aColor.a * 255;
// Move on to the next vertex return freeVertex;
vertexPtr++;
}
} }
void VBO_ITEM::ChangeDepth( int aDepth ) void NONCACHED_CONTAINER::Erase()
{ {
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() void NONCACHED_CONTAINER::Clear()
{ {
// The unknown-sized item has just ended, so we need to inform the container about it m_freePtr = 0;
m_container->EndItem(); m_freeSpace = m_currentSize;
m_isDirty = false;
} }
...@@ -53,7 +53,8 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener, ...@@ -53,7 +53,8 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener,
wxEvtHandler* aPaintListener, bool isUseShaders, const wxString& aName ) : wxEvtHandler* aPaintListener, bool isUseShaders, const wxString& aName ) :
wxGLCanvas( aParent, wxID_ANY, (int*) glAttributes, wxDefaultPosition, wxDefaultSize, wxGLCanvas( aParent, wxID_ANY, (int*) glAttributes, wxDefaultPosition, wxDefaultSize,
wxEXPAND, aName ), wxEXPAND, aName ),
verticesCircle( &precomputedContainer ) cachedManager( true ),
nonCachedManager( false )
{ {
// Create the OpenGL-Context // Create the OpenGL-Context
glContext = new wxGLContext( this ); glContext = new wxGLContext( this );
...@@ -73,13 +74,7 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener, ...@@ -73,13 +74,7 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener,
isShaderInitialized = false; isShaderInitialized = false;
isGrouping = false; isGrouping = false;
wxSize parentSize = aParent->GetSize(); wxSize parentSize = aParent->GetSize();
isVboInitialized = false;
vboNeedsUpdate = false;
currentItem = NULL;
groupCounter = 0; groupCounter = 0;
transform = glm::mat4( 1.0f ); // Identity matrix
nonCachedItem = NULL;
SetSize( parentSize ); SetSize( parentSize );
...@@ -112,11 +107,11 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener, ...@@ -112,11 +107,11 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener,
InitTesselatorCallbacks( tesselator ); InitTesselatorCallbacks( tesselator );
gluTessProperty( tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE ); gluTessProperty( tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE );
// Compute unit semicircle & circle vertices and store them in a buffer for faster drawing // Compute the unit circle vertices and store them in a buffer for faster drawing
computeCircleVbo(); computeCircle();
// By default we draw non-cached objects, it changes on BeginGroup()/EndGroup() // By default we draw non-cached objects, it changes on BeginGroup()/EndGroup()
currentContainer = &nonCachedVbo; currentManager = &nonCachedManager;
} }
...@@ -124,8 +119,6 @@ OPENGL_GAL::~OPENGL_GAL() ...@@ -124,8 +119,6 @@ OPENGL_GAL::~OPENGL_GAL()
{ {
glFlush(); glFlush();
delete nonCachedItem;
// Delete the buffers // Delete the buffers
if( isFrameBufferInitialized ) if( isFrameBufferInitialized )
{ {
...@@ -134,12 +127,7 @@ OPENGL_GAL::~OPENGL_GAL() ...@@ -134,12 +127,7 @@ OPENGL_GAL::~OPENGL_GAL()
} }
gluDeleteTess( tesselator ); gluDeleteTess( tesselator );
if( isVboInitialized )
{
ClearCache(); ClearCache();
deleteVertexBufferObjects();
}
delete glContext; delete glContext;
} }
...@@ -239,28 +227,6 @@ void OPENGL_GAL::initFrameBuffers() ...@@ -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() void OPENGL_GAL::SaveScreen()
{ {
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, frameBufferBackup ); glBindFramebuffer( GL_DRAW_FRAMEBUFFER, frameBufferBackup );
...@@ -323,8 +289,6 @@ void OPENGL_GAL::initGlew() ...@@ -323,8 +289,6 @@ void OPENGL_GAL::initGlew()
exit( 1 ); exit( 1 );
} }
initVertexBufferObjects();
isGlewInitialized = true; isGlewInitialized = true;
} }
...@@ -337,38 +301,26 @@ void OPENGL_GAL::BeginDrawing() ...@@ -337,38 +301,26 @@ void OPENGL_GAL::BeginDrawing()
// Initialize GLEW, FBOs & VBOs // Initialize GLEW, FBOs & VBOs
if( !isGlewInitialized ) if( !isGlewInitialized )
{
initGlew(); initGlew();
}
if( !isFrameBufferInitialized ) if( !isFrameBufferInitialized )
{
initFrameBuffers(); initFrameBuffers();
}
// Compile the shaders // Compile the shaders
if( !isShaderInitialized && isUseShader ) if( !isShaderInitialized && isUseShader )
{ {
if( !shader.LoadBuiltinShader( 0, SHADER_TYPE_VERTEX ) ) 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 ) ) if( !shader.LoadBuiltinShader( 1, SHADER_TYPE_FRAGMENT ) )
{
wxLogFatalError( wxT( "Cannot compile fragment shader!" ) ); wxLogFatalError( wxT( "Cannot compile fragment shader!" ) );
}
if( !shader.Link() ) if( !shader.Link() )
{
wxLogFatalError( wxT( "Cannot link the shaders!" ) ); wxLogFatalError( wxT( "Cannot link the shaders!" ) );
}
shaderAttrib = shader.GetAttribute( "attrShaderParams" ); // Make VBOs use shaders
if( shaderAttrib == -1 ) cachedManager.SetShader( shader );
{ nonCachedManager.SetShader( shader );
wxLogFatalError( wxT( "Could not get the shader attribute location" ) );
}
isShaderInitialized = true; isShaderInitialized = true;
} }
...@@ -418,29 +370,10 @@ void OPENGL_GAL::BeginDrawing() ...@@ -418,29 +370,10 @@ void OPENGL_GAL::BeginDrawing()
SetStrokeColor( strokeColor ); SetStrokeColor( strokeColor );
isDeleteSavedPixels = true; isDeleteSavedPixels = true;
// If any of VBO items is dirty - recache everything nonCachedManager.Clear();
if( vboNeedsUpdate )
rebuildVbo();
// Number of vertices to be drawn
indicesSize = 0;
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, cachedInds ); cachedManager.BeginDrawing();
// Discard old buffer, so we can use it again nonCachedManager.BeginDrawing();
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<GLuint*>( 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;
} }
...@@ -492,55 +425,8 @@ void OPENGL_GAL::blitMainTexture( bool aIsClearFrameBuffer ) ...@@ -492,55 +425,8 @@ void OPENGL_GAL::blitMainTexture( bool aIsClearFrameBuffer )
void OPENGL_GAL::EndDrawing() void OPENGL_GAL::EndDrawing()
{ {
if( !glUnmapBuffer( GL_ELEMENT_ARRAY_BUFFER ) ) cachedManager.EndDrawing();
{ nonCachedManager.EndDrawing();
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();
}
// Draw the remaining contents, blit the main texture to the screen, swap the buffers // Draw the remaining contents, blit the main texture to the screen, swap the buffers
glFlush(); glFlush();
...@@ -551,38 +437,6 @@ void OPENGL_GAL::EndDrawing() ...@@ -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 ) inline void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
{ {
VECTOR2D startEndVector = aEndPoint - aStartPoint; VECTOR2D startEndVector = aEndPoint - aStartPoint;
...@@ -598,29 +452,27 @@ inline void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2 ...@@ -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 ); glm::vec4 vector( perpendicularVector.x, perpendicularVector.y, 0.0, 0.0 );
// If transform stack is not empty, then it means that // The perpendicular vector also needs transformations
// there is a transformation matrix that has to be applied vector = currentManager->GetTransformation() * vector;
if( !transformStack.empty() )
vector = transform * vector;
// Line width is maintained by the vertex shader // Line width is maintained by the vertex shader
setShader( SHADER_LINE, vector.x, vector.y, lineWidth ); currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth );
vertex3( aStartPoint.x, aStartPoint.y, layerDepth ); // v0 currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); // v0
setShader( SHADER_LINE, -vector.x, -vector.y, lineWidth ); currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth );
vertex3( aStartPoint.x, aStartPoint.y, layerDepth ); // v1 currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); // v1
setShader( SHADER_LINE, -vector.x, -vector.y, lineWidth ); currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth );
vertex3( aEndPoint.x, aEndPoint.y, layerDepth ); // v3 currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); // v3
setShader( SHADER_LINE, vector.x, vector.y, lineWidth ); currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth );
vertex3( aStartPoint.x, aStartPoint.y, layerDepth ); // v0 currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); // v0
setShader( SHADER_LINE, -vector.x, -vector.y, lineWidth ); currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth );
vertex3( aEndPoint.x, aEndPoint.y, layerDepth ); // v3 currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); // v3
setShader( SHADER_LINE, vector.x, vector.y, lineWidth ); currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth );
vertex3( aEndPoint.x, aEndPoint.y, layerDepth ); // v2 currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); // v2
} }
else else
{ {
...@@ -630,13 +482,13 @@ inline void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2 ...@@ -630,13 +482,13 @@ inline void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2
VECTOR2D v2 = aEndPoint + perpendicularVector; VECTOR2D v2 = aEndPoint + perpendicularVector;
VECTOR2D v3 = aEndPoint - perpendicularVector; VECTOR2D v3 = aEndPoint - perpendicularVector;
vertex3( v0.x, v0.y, layerDepth ); currentManager->Vertex( v0.x, v0.y, layerDepth );
vertex3( v1.x, v1.y, layerDepth ); currentManager->Vertex( v1.x, v1.y, layerDepth );
vertex3( v3.x, v3.y, layerDepth ); currentManager->Vertex( v3.x, v3.y, layerDepth );
vertex3( v0.x, v0.y, layerDepth ); currentManager->Vertex( v0.x, v0.y, layerDepth );
vertex3( v3.x, v3.y, layerDepth ); currentManager->Vertex( v3.x, v3.y, layerDepth );
vertex3( v2.x, v2.y, layerDepth ); currentManager->Vertex( v2.x, v2.y, layerDepth );
} }
} }
...@@ -650,7 +502,7 @@ void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndP ...@@ -650,7 +502,7 @@ void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndP
if( isFillEnabled ) if( isFillEnabled )
{ {
// Filled tracks // Filled tracks
color4( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
SetLineWidth( aWidth ); SetLineWidth( aWidth );
drawLineQuad( aStartPoint, aEndPoint ); drawLineQuad( aStartPoint, aEndPoint );
...@@ -664,12 +516,12 @@ void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndP ...@@ -664,12 +516,12 @@ void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndP
// Outlined tracks // Outlined tracks
double lineLength = startEndVector.EuclideanNorm(); double lineLength = startEndVector.EuclideanNorm();
color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
Save(); Save();
translate3( aStartPoint.x, aStartPoint.y, 0.0 ); currentManager->Translate( aStartPoint.x, aStartPoint.y, 0.0 );
Rotate( lineAngle ); currentManager->Rotate( lineAngle, 0.0f, 0.0f, 1.0f );
drawLineQuad( VECTOR2D( 0.0, aWidth / 2.0 ), drawLineQuad( VECTOR2D( 0.0, aWidth / 2.0 ),
VECTOR2D( lineLength, aWidth / 2.0 ) ); VECTOR2D( lineLength, aWidth / 2.0 ) );
...@@ -686,7 +538,7 @@ void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndP ...@@ -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<unsigned int>::max(), wxASSERT_MSG( groups.size() < std::numeric_limits<unsigned int>::max(),
wxT( "There are no free slots to store a group" ) ); wxT( "There are no free slots to store a group" ) );
...@@ -745,7 +597,7 @@ void OPENGL_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEn ...@@ -745,7 +597,7 @@ void OPENGL_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEn
// Stroke the outline // Stroke the outline
if( isStrokeEnabled ) if( isStrokeEnabled )
{ {
color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
std::deque<VECTOR2D> pointList; std::deque<VECTOR2D> pointList;
pointList.push_back( aStartPoint ); pointList.push_back( aStartPoint );
...@@ -759,16 +611,16 @@ void OPENGL_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEn ...@@ -759,16 +611,16 @@ void OPENGL_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEn
// Fill the rectangle // Fill the rectangle
if( isFillEnabled ) if( isFillEnabled )
{ {
setShader( SHADER_NONE ); currentManager->Shader( SHADER_NONE );
color4( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
vertex3( aStartPoint.x, aStartPoint.y, layerDepth ); currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth );
vertex3( diagonalPointA.x, diagonalPointA.y, layerDepth ); currentManager->Vertex( diagonalPointA.x, diagonalPointA.y, layerDepth );
vertex3( aEndPoint.x, aEndPoint.y, layerDepth ); currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth );
vertex3( aStartPoint.x, aStartPoint.y, layerDepth ); currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth );
vertex3( aEndPoint.x, aEndPoint.y, layerDepth ); currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth );
vertex3( diagonalPointB.x, diagonalPointB.y, layerDepth ); currentManager->Vertex( diagonalPointB.x, diagonalPointB.y, layerDepth );
} }
} }
...@@ -779,7 +631,7 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius ) ...@@ -779,7 +631,7 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )
{ {
if( isFillEnabled ) 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. /* 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 Parameters given to setShader are indices of the triangle's vertices
...@@ -790,21 +642,21 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius ) ...@@ -790,21 +642,21 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )
//\\ //\\
v0 /_\/_\ v1 v0 /_\/_\ v1
*/ */
setShader( SHADER_FILLED_CIRCLE, 1.0 ); currentManager->Shader( SHADER_FILLED_CIRCLE, 1.0 );
vertex3( aCenterPoint.x - aRadius * sqrt( 3.0f ), currentManager->Vertex( aCenterPoint.x - aRadius * sqrt( 3.0f ),
aCenterPoint.y - aRadius, layerDepth ); // v0 aCenterPoint.y - aRadius, layerDepth ); // v0
setShader( SHADER_FILLED_CIRCLE, 2.0 ); currentManager->Shader( SHADER_FILLED_CIRCLE, 2.0 );
vertex3( aCenterPoint.x + aRadius* sqrt( 3.0f ), currentManager->Vertex( aCenterPoint.x + aRadius* sqrt( 3.0f ),
aCenterPoint.y - aRadius, layerDepth ); // v1 aCenterPoint.y - aRadius, layerDepth ); // v1
setShader( SHADER_FILLED_CIRCLE, 3.0 ); currentManager->Shader( SHADER_FILLED_CIRCLE, 3.0 );
vertex3( aCenterPoint.x, aCenterPoint.y + aRadius * 2.0f, layerDepth ); // v2 currentManager->Vertex( aCenterPoint.x, aCenterPoint.y + aRadius * 2.0f, layerDepth ); // v2
} }
if( isStrokeEnabled ) 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. /* 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 Parameters given to setShader are indices of the triangle's vertices
...@@ -817,21 +669,20 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius ) ...@@ -817,21 +669,20 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )
v0 /_\/_\ v1 v0 /_\/_\ v1
*/ */
double outerRadius = aRadius + ( lineWidth / 2 ); double outerRadius = aRadius + ( lineWidth / 2 );
setShader( SHADER_STROKED_CIRCLE, 1.0, aRadius, lineWidth ); currentManager->Shader( SHADER_STROKED_CIRCLE, 1.0, aRadius, lineWidth );
vertex3( aCenterPoint.x - outerRadius * sqrt( 3.0f ), currentManager->Vertex( aCenterPoint.x - outerRadius * sqrt( 3.0f ),
aCenterPoint.y - outerRadius, layerDepth ); // v0 aCenterPoint.y - outerRadius, layerDepth ); // v0
setShader( SHADER_STROKED_CIRCLE, 2.0, aRadius, lineWidth ); currentManager->Shader( SHADER_STROKED_CIRCLE, 2.0, aRadius, lineWidth );
vertex3( aCenterPoint.x + outerRadius * sqrt( 3.0f ), currentManager->Vertex( aCenterPoint.x + outerRadius * sqrt( 3.0f ),
aCenterPoint.y - outerRadius, layerDepth ); // v1 aCenterPoint.y - outerRadius, layerDepth ); // v1
setShader( SHADER_STROKED_CIRCLE, 3.0, aRadius, lineWidth ); currentManager->Shader( SHADER_STROKED_CIRCLE, 3.0, aRadius, lineWidth );
vertex3( aCenterPoint.x, aCenterPoint.y + outerRadius * 2.0f, layerDepth ); // v2 currentManager->Vertex( aCenterPoint.x, aCenterPoint.y + outerRadius * 2.0f, layerDepth ); // v2
} }
return;
} }
else
{
if( isStrokeEnabled ) if( isStrokeEnabled )
{ {
// Compute the factors for the unit circle // Compute the factors for the unit circle
...@@ -843,15 +694,16 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius ) ...@@ -843,15 +694,16 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )
if( innerScale < outerScale ) if( innerScale < outerScale )
{ {
// Draw the outline // Draw the outline
VBO_VERTEX* circle = verticesCircle.GetVertices(); VERTEX* circle = circleContainer.GetAllVertices();
int next; int next;
color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b,
strokeColor.a );
Save(); Save();
translate3( aCenterPoint.x, aCenterPoint.y, 0.0 ); currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0 );
Scale( VECTOR2D( aRadius, aRadius ) ); currentManager->Scale( aRadius, aRadius, 0.0f );
for( int i = 0; i < 3 * CIRCLE_POINTS; ++i ) for( int i = 0; i < 3 * CIRCLE_POINTS; ++i )
{ {
...@@ -861,7 +713,7 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius ) ...@@ -861,7 +713,7 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )
// where letters stand for consecutive circle points and 0 for (0,0,0) vertex. // 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) // We have to skip all (0,0,0) vertices (every third vertex)
if( i % 3 == 0) if( i % 3 == 0 )
{ {
i++; i++;
// Depending on the vertex, next circle point may be stored in the next vertex.. // Depending on the vertex, next circle point may be stored in the next vertex..
...@@ -873,32 +725,43 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius ) ...@@ -873,32 +725,43 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )
next = i + 2; next = i + 2;
} }
vertex3( circle[i].x * innerScale, circle[i].y * innerScale, layerDepth ); currentManager->Vertex( circle[i].x * innerScale,
vertex3( circle[i].x * outerScale, circle[i].y * outerScale, layerDepth ); circle[i].y * innerScale,
vertex3( circle[next].x * innerScale, circle[next].y * innerScale, layerDepth ); layerDepth );
currentManager->Vertex( circle[i].x * outerScale,
circle[i].y * outerScale,
layerDepth );
currentManager->Vertex( circle[next].x * innerScale,
circle[next].y * innerScale,
layerDepth );
vertex3( circle[i].x * outerScale, circle[i].y * outerScale, layerDepth ); currentManager->Vertex( circle[i].x * outerScale,
vertex3( circle[next].x * outerScale, circle[next].y * outerScale, layerDepth ); circle[i].y * outerScale,
vertex3( circle[next].x * innerScale, circle[next].y * innerScale, layerDepth ); layerDepth );
currentManager->Vertex( circle[next].x * outerScale,
circle[next].y * outerScale,
layerDepth );
currentManager->Vertex( circle[next].x * innerScale,
circle[next].y * innerScale,
layerDepth );
} }
Restore(); Restore();
} }
} }
// Filled circles are easy to draw by using the stored display list, scaling and translating // Filled circles are easy to draw by using the stored vertices list, scaling and translating
if( isFillEnabled ) if( isFillEnabled )
{ {
color4( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
Save(); Save();
translate3( aCenterPoint.x, aCenterPoint.y, layerDepth ); currentManager->Translate( aCenterPoint.x, aCenterPoint.y, layerDepth );
Scale( VECTOR2D( aRadius, aRadius ) ); currentManager->Scale( aRadius, aRadius, 0.0f );
currentManager->Vertices( circleContainer.GetAllVertices(), CIRCLE_POINTS * 3 );
currentItem->PushVertices( verticesCircle.GetVertices(), CIRCLE_POINTS * 3 );
Restore(); Restore();
} }
}
} }
...@@ -906,25 +769,26 @@ void OPENGL_GAL::drawSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, d ...@@ -906,25 +769,26 @@ void OPENGL_GAL::drawSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, d
{ {
if( isFillEnabled ) if( isFillEnabled )
{ {
color4( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
drawFilledSemiCircle( aCenterPoint, aRadius, aAngle ); drawFilledSemiCircle( aCenterPoint, aRadius, aAngle );
} }
if( isStrokeEnabled ) if( isStrokeEnabled )
{ {
color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
drawStrokedSemiCircle( aCenterPoint, aRadius, aAngle ); 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 ) if( isUseShader )
{ {
Save(); Save();
Translate( aCenterPoint ); currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0f );
Rotate( aAngle ); currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
/* Draw a triangle that contains the semicircle, then shade it to leave only the semicircle. /* 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 Parameters given to setShader are indices of the triangle's vertices
...@@ -935,41 +799,42 @@ void OPENGL_GAL::drawFilledSemiCircle( const VECTOR2D& aCenterPoint, double aRad ...@@ -935,41 +799,42 @@ void OPENGL_GAL::drawFilledSemiCircle( const VECTOR2D& aCenterPoint, double aRad
/__\ /__\
v0 //__\\ v1 v0 //__\\ v1
*/ */
setShader( SHADER_FILLED_CIRCLE, 4.0f ); currentManager->Shader( SHADER_FILLED_CIRCLE, 4.0f );
vertex3( -aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0 currentManager->Vertex( -aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0
setShader( SHADER_FILLED_CIRCLE, 5.0f ); currentManager->Shader( SHADER_FILLED_CIRCLE, 5.0f );
vertex3( aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1 currentManager->Vertex( aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1
setShader( SHADER_FILLED_CIRCLE, 6.0f ); currentManager->Shader( SHADER_FILLED_CIRCLE, 6.0f );
vertex3( 0.0f, aRadius * 2.0f, layerDepth ); // v2 currentManager->Vertex( 0.0f, aRadius * 2.0f, layerDepth ); // v2
Restore(); Restore();
} }
else else
{ {
Save(); Save();
translate3( aCenterPoint.x, aCenterPoint.y, layerDepth ); currentManager->Translate( aCenterPoint.x, aCenterPoint.y, layerDepth );
Scale( VECTOR2D( aRadius, aRadius ) ); currentManager->Scale( aRadius, aRadius, 0.0f );
Rotate( aAngle ); 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 // It is enough just to draw a half of the circle vertices to make a semicircle
currentItem->PushVertices( verticesCircle.GetVertices(), CIRCLE_POINTS / 2 * 3 ); currentManager->Vertices( circleContainer.GetAllVertices(), ( CIRCLE_POINTS * 3 ) / 2 );
Restore(); 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 ) if( isUseShader )
{ {
double outerRadius = aRadius + ( lineWidth / 2 ); double outerRadius = aRadius + ( lineWidth / 2 );
Save(); Save();
Translate( aCenterPoint ); currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0f );
Rotate( aAngle ); currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
/* Draw a triangle that contains the semicircle, then shade it to leave only the semicircle. /* 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 Parameters given to setShader are indices of the triangle's vertices
...@@ -981,14 +846,14 @@ void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRa ...@@ -981,14 +846,14 @@ void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRa
/__\ /__\
v0 //__\\ v1 v0 //__\\ v1
*/ */
setShader( SHADER_STROKED_CIRCLE, 4.0f, aRadius, lineWidth ); currentManager->Shader( SHADER_STROKED_CIRCLE, 4.0f, aRadius, lineWidth );
vertex3( -outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0 currentManager->Vertex( -outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0
setShader( SHADER_STROKED_CIRCLE, 5.0f, aRadius, lineWidth ); currentManager->Shader( SHADER_STROKED_CIRCLE, 5.0f, aRadius, lineWidth );
vertex3( outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1 currentManager->Vertex( outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1
setShader( SHADER_STROKED_CIRCLE, 6.0f, aRadius, lineWidth ); currentManager->Shader( SHADER_STROKED_CIRCLE, 6.0f, aRadius, lineWidth );
vertex3( 0.0f, outerRadius * 2.0f, layerDepth ); // v2 currentManager->Vertex( 0.0f, outerRadius * 2.0f, layerDepth ); // v2
Restore(); Restore();
} }
...@@ -998,12 +863,12 @@ void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRa ...@@ -998,12 +863,12 @@ void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRa
double innerScale = 1.0 - lineWidth / aRadius; double innerScale = 1.0 - lineWidth / aRadius;
Save(); Save();
translate3( aCenterPoint.x, aCenterPoint.y, layerDepth ); currentManager->Translate( aCenterPoint.x, aCenterPoint.y, layerDepth );
Scale( VECTOR2D( aRadius, aRadius ) ); currentManager->Scale( aRadius, aRadius, 0.0f );
Rotate( aAngle ); currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
// Draw the outline // Draw the outline
VBO_VERTEX* circle = verticesCircle.GetVertices(); VERTEX* circle = circleContainer.GetAllVertices();
int next; int next;
for( int i = 0; i < ( 3 * CIRCLE_POINTS ) / 2; ++i ) for( int i = 0; i < ( 3 * CIRCLE_POINTS ) / 2; ++i )
...@@ -1026,13 +891,13 @@ void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRa ...@@ -1026,13 +891,13 @@ void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRa
next = i + 2; next = i + 2;
} }
vertex3( circle[i].x * innerScale, circle[i].y * innerScale, 0.0 ); currentManager->Vertex( circle[i].x * innerScale, circle[i].y * innerScale, 0.0 );
vertex3( circle[i].x, circle[i].y, 0.0 ); currentManager->Vertex( circle[i].x, circle[i].y, 0.0 );
vertex3( circle[next].x * innerScale, circle[next].y * innerScale, 0.0 ); currentManager->Vertex( circle[next].x * innerScale, circle[next].y * innerScale, 0.0 );
vertex3( circle[i].x, circle[i].y, 0.0 ); currentManager->Vertex( circle[i].x, circle[i].y, 0.0 );
vertex3( circle[next].x, circle[next].y, 0.0 ); currentManager->Vertex( circle[next].x, circle[next].y, 0.0 );
vertex3( circle[next].x * innerScale, circle[next].y * innerScale, 0.0 ); currentManager->Vertex( circle[next].x * innerScale, circle[next].y * innerScale, 0.0 );
} }
Restore(); Restore();
...@@ -1045,9 +910,7 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double a ...@@ -1045,9 +910,7 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double a
double aEndAngle ) double aEndAngle )
{ {
if( aRadius <= 0 ) if( aRadius <= 0 )
{
return; return;
}
// Swap the angles, if start angle is greater than end angle // Swap the angles, if start angle is greater than end angle
SWAP( aStartAngle, >, aEndAngle ); SWAP( aStartAngle, >, aEndAngle );
...@@ -1058,14 +921,14 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double a ...@@ -1058,14 +921,14 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double a
VECTOR2D middlePoint = 0.5 * startEndPoint; VECTOR2D middlePoint = 0.5 * startEndPoint;
Save(); Save();
translate3( aCenterPoint.x, aCenterPoint.y, layerDepth ); currentManager->Translate( aCenterPoint.x, aCenterPoint.y, layerDepth );
if( isStrokeEnabled ) if( isStrokeEnabled )
{ {
if( isUseShader ) if( isUseShader )
{ {
double alphaIncrement = 2.0 * M_PI / CIRCLE_POINTS; 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 ); VECTOR2D p( cos( aStartAngle ) * aRadius, sin( aStartAngle ) * aRadius );
double alpha; double alpha;
...@@ -1095,7 +958,8 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double a ...@@ -1095,7 +958,8 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double a
innerScale += 1.0; innerScale += 1.0;
double alphaIncrement = 2 * M_PI / CIRCLE_POINTS; 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; ) for( double alpha = aStartAngle; alpha < aEndAngle; )
{ {
...@@ -1110,13 +974,13 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double a ...@@ -1110,13 +974,13 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double a
double v2[] = { cos( alpha ) * innerScale, sin( alpha ) * innerScale }; double v2[] = { cos( alpha ) * innerScale, sin( alpha ) * innerScale };
double v3[] = { cos( alpha ) * outerScale, sin( alpha ) * outerScale }; double v3[] = { cos( alpha ) * outerScale, sin( alpha ) * outerScale };
vertex3( v0[0], v0[1], 0.0 ); currentManager->Vertex( v0[0], v0[1], 0.0 );
vertex3( v1[0], v1[1], 0.0 ); currentManager->Vertex( v1[0], v1[1], 0.0 );
vertex3( v2[0], v2[1], 0.0 ); currentManager->Vertex( v2[0], v2[1], 0.0 );
vertex3( v1[0], v1[1], 0.0 ); currentManager->Vertex( v1[0], v1[1], 0.0 );
vertex3( v3[0], v3[1], 0.0 ); currentManager->Vertex( v3[0], v3[1], 0.0 );
vertex3( v2[0], v2[1], 0.0 ); currentManager->Vertex( v2[0], v2[1], 0.0 );
} }
// Draw line caps // Draw line caps
...@@ -1129,19 +993,19 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double a ...@@ -1129,19 +993,19 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double a
{ {
double alphaIncrement = 2 * M_PI / CIRCLE_POINTS; double alphaIncrement = 2 * M_PI / CIRCLE_POINTS;
double alpha; 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; ) for( alpha = aStartAngle; ( alpha + alphaIncrement ) < aEndAngle; )
{ {
vertex3( middlePoint.x, middlePoint.y, 0.0 ); currentManager->Vertex( middlePoint.x, middlePoint.y, 0.0 );
vertex3( cos( alpha ), sin( alpha ), 0.0 ); currentManager->Vertex( cos( alpha ), sin( alpha ), 0.0 );
alpha += alphaIncrement; alpha += alphaIncrement;
vertex3( cos( alpha ), sin( alpha ), 0.0 ); currentManager->Vertex( cos( alpha ), sin( alpha ), 0.0 );
} }
vertex3( middlePoint.x, middlePoint.y, 0.0 ); currentManager->Vertex( middlePoint.x, middlePoint.y, 0.0 );
vertex3( cos( alpha ), sin( alpha ), 0.0 ); currentManager->Vertex( cos( alpha ), sin( alpha ), 0.0 );
vertex3( endPoint.x, endPoint.y, 0.0 ); currentManager->Vertex( endPoint.x, endPoint.y, 0.0 );
} }
Restore(); Restore();
...@@ -1181,8 +1045,7 @@ void OPENGL_GAL::DrawPolygon( const std::deque<VECTOR2D>& aPointList ) ...@@ -1181,8 +1045,7 @@ void OPENGL_GAL::DrawPolygon( const std::deque<VECTOR2D>& aPointList )
{ {
// Any non convex polygon needs to be tesselated // Any non convex polygon needs to be tesselated
// for this purpose the GLU standard functions are used // for this purpose the GLU standard functions are used
currentManager->Shader( SHADER_NONE );
setShader( SHADER_NONE );
typedef std::vector<OGLPOINT> OGLPOINTS; typedef std::vector<OGLPOINT> OGLPOINTS;
...@@ -1191,11 +1054,11 @@ void OPENGL_GAL::DrawPolygon( const std::deque<VECTOR2D>& aPointList ) ...@@ -1191,11 +1054,11 @@ void OPENGL_GAL::DrawPolygon( const std::deque<VECTOR2D>& aPointList )
OGLPOINTS vertexList( aPointList.size(), OGLPOINT( "fastest" ) ); OGLPOINTS vertexList( aPointList.size(), OGLPOINT( "fastest" ) );
glNormal3d( 0.0, 0.0, 1.0 ); 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 ); glShadeModel( GL_FLAT );
TessParams params = { currentItem, tessIntersects }; TessParams params = { currentManager, tessIntersects };
gluTessBeginPolygon( tesselator, &params ); gluTessBeginPolygon( tesselator, &params );
gluTessBeginContour( tesselator ); gluTessBeginContour( tesselator );
...@@ -1213,10 +1076,12 @@ void OPENGL_GAL::DrawPolygon( const std::deque<VECTOR2D>& aPointList ) ...@@ -1213,10 +1076,12 @@ void OPENGL_GAL::DrawPolygon( const std::deque<VECTOR2D>& aPointList )
// Free allocated intersecting points // Free allocated intersecting points
std::vector<GLdouble*>::iterator it, it_end; std::vector<GLdouble*>::iterator it, it_end;
for( it = tessIntersects.begin(), it_end = tessIntersects.end(); it < it_end; ++it ) for( it = tessIntersects.begin(), it_end = tessIntersects.end(); it < it_end; ++it )
{ {
delete[] *it; delete[] *it;
} }
tessIntersects.clear(); tessIntersects.clear();
// vertexList destroyed here // vertexList destroyed here
...@@ -1261,7 +1126,7 @@ void OPENGL_GAL::SetStrokeColor( const COLOR4D& aColor ) ...@@ -1261,7 +1126,7 @@ void OPENGL_GAL::SetStrokeColor( const COLOR4D& aColor )
strokeColor = aColor; strokeColor = aColor;
// This is the default drawing color // 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 ) ...@@ -1315,19 +1180,19 @@ void OPENGL_GAL::Transform( MATRIX3x3D aTransformation )
void OPENGL_GAL::Rotate( double aAngle ) 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 ) 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 ) 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() ...@@ -1339,21 +1204,13 @@ void OPENGL_GAL::Flush()
void OPENGL_GAL::Save() void OPENGL_GAL::Save()
{ {
transformStack.push( transform ); currentManager->PushMatrix();
currentContainer->SetTransformMatrix( &transform );
} }
void OPENGL_GAL::Restore() void OPENGL_GAL::Restore()
{ {
transform = transformStack.top(); currentManager->PopMatrix();
transformStack.pop();
if( transformStack.empty() )
{
// Disable transforming, as the selected matrix is identity
currentContainer->SetTransformMatrix( NULL );
}
} }
...@@ -1361,14 +1218,10 @@ int OPENGL_GAL::BeginGroup() ...@@ -1361,14 +1218,10 @@ int OPENGL_GAL::BeginGroup()
{ {
isGrouping = true; isGrouping = true;
// There is a new group that is not in VBO yet boost::shared_ptr<VERTEX_ITEM> newItem( new VERTEX_ITEM( cachedManager ) );
vboNeedsUpdate = true; currentManager = &cachedManager;
int groupNumber = getNewGroupNumber();
// Save the pointer for caching the current item groups.insert( std::make_pair( groupNumber, newItem ) );
currentItem = new VBO_ITEM( &cachedVbo );
currentContainer = &cachedVbo;
int groupNumber = getGroupNumber();
groups.insert( std::make_pair( groupNumber, currentItem ) );
return groupNumber; return groupNumber;
} }
...@@ -1376,9 +1229,7 @@ int OPENGL_GAL::BeginGroup() ...@@ -1376,9 +1229,7 @@ int OPENGL_GAL::BeginGroup()
void OPENGL_GAL::EndGroup() void OPENGL_GAL::EndGroup()
{ {
currentItem->Finish(); currentManager = &nonCachedManager;
currentItem = nonCachedItem;
currentContainer = &nonCachedVbo;
isGrouping = false; isGrouping = false;
} }
...@@ -1386,75 +1237,57 @@ void OPENGL_GAL::EndGroup() ...@@ -1386,75 +1237,57 @@ void OPENGL_GAL::EndGroup()
void OPENGL_GAL::ClearCache() void OPENGL_GAL::ClearCache()
{ {
BOOST_FOREACH( GroupsMap::value_type it, groups )
{
delete it.second;
}
groups.clear(); groups.clear();
cachedManager.Clear();
} }
void OPENGL_GAL::DeleteGroup( int aGroupNumber ) void OPENGL_GAL::DeleteGroup( int aGroupNumber )
{ {
delete groups[aGroupNumber];
groups.erase( aGroupNumber ); groups.erase( aGroupNumber );
vboNeedsUpdate = true;
} }
void OPENGL_GAL::DrawGroup( int aGroupNumber ) void OPENGL_GAL::DrawGroup( int aGroupNumber )
{ {
int size = groups[aGroupNumber]->GetSize(); cachedManager.DrawItem( *groups[aGroupNumber] );
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;
} }
void OPENGL_GAL::ChangeGroupColor( int aGroupNumber, const COLOR4D& aNewColor ) void OPENGL_GAL::ChangeGroupColor( int aGroupNumber, const COLOR4D& aNewColor )
{ {
groups[aGroupNumber]->ChangeColor( aNewColor ); cachedManager.ChangeItemColor( *groups[aGroupNumber], aNewColor );
vboNeedsUpdate = true;
} }
void OPENGL_GAL::ChangeGroupDepth( int aGroupNumber, int aDepth ) void OPENGL_GAL::ChangeGroupDepth( int aGroupNumber, int aDepth )
{ {
groups[aGroupNumber]->ChangeDepth( aDepth ); cachedManager.ChangeItemDepth( *groups[aGroupNumber], aDepth );
vboNeedsUpdate = true;
} }
void OPENGL_GAL::computeCircleVbo() void OPENGL_GAL::computeCircle()
{ {
// Compute the circle points for a given number of segments VERTEX* vertex = circleContainer.Allocate( CIRCLE_POINTS );
// 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++ ) // Compute the circle points for a given number of segments
for( int i = 0; i < CIRCLE_POINTS; ++i )
{ {
const VBO_VERTEX v1 = { vertex->x = 0.0f;
cos( 2.0 * M_PI / CIRCLE_POINTS * i ), // x vertex->y = 0.0f;
sin( 2.0 * M_PI / CIRCLE_POINTS * i ), // y vertex->z = 0.0f;
0.0f // z vertex++;
};
const VBO_VERTEX v2 = { vertex->x = cos( 2.0 * M_PI / CIRCLE_POINTS * i );
cos( 2.0 * M_PI / CIRCLE_POINTS * ( i + 1 ) ), // x vertex->y = sin( 2.0 * M_PI / CIRCLE_POINTS * i );
sin( 2.0 * M_PI / CIRCLE_POINTS * ( i + 1 ) ), // y vertex->z = 0.0f;
0.0f // z vertex++;
};
verticesCircle.PushVertex( &v0 );
verticesCircle.PushVertex( &v1 );
verticesCircle.PushVertex( &v2 );
}
verticesCircle.Finish(); 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++;
}
} }
...@@ -1495,13 +1328,10 @@ void CALLBACK VertexCallback( GLvoid* aVertexPtr, void* aData ) ...@@ -1495,13 +1328,10 @@ void CALLBACK VertexCallback( GLvoid* aVertexPtr, void* aData )
{ {
GLdouble* vertex = static_cast<GLdouble*>( aVertexPtr ); GLdouble* vertex = static_cast<GLdouble*>( aVertexPtr );
OPENGL_GAL::TessParams* param = static_cast<OPENGL_GAL::TessParams*>( aData ); OPENGL_GAL::TessParams* param = static_cast<OPENGL_GAL::TessParams*>( aData );
VBO_ITEM* vboItem = param->vboItem; VERTEX_MANAGER* vboManager = param->vboManager;
if( vboItem ) if( vboManager )
{ vboManager->Vertex( vertex[0], vertex[1], vertex[2] );
VBO_VERTEX newVertex = { vertex[0], vertex[1], vertex[2] };
vboItem->PushVertex( &newVertex );
}
} }
...@@ -1524,7 +1354,6 @@ void CALLBACK CombineCallback( GLdouble coords[3], ...@@ -1524,7 +1354,6 @@ void CALLBACK CombineCallback( GLdouble coords[3],
void CALLBACK EdgeCallback(void) void CALLBACK EdgeCallback(void)
{ {
// This callback is needed to force GLU tesselator to use triangles only // 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 ...@@ -1650,19 +1479,19 @@ void OPENGL_GAL::DrawGridLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEnd
VECTOR2D point4 = aEndPoint - perpendicularVector; VECTOR2D point4 = aEndPoint - perpendicularVector;
// Set color // 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 // Draw the quad for the grid line
double gridDepth = depthRange.y * 0.75; double gridDepth = depthRange.y * 0.75;
vertex3( point1.x, point1.y, gridDepth ); currentManager->Vertex( point1.x, point1.y, gridDepth );
vertex3( point2.x, point2.y, gridDepth ); currentManager->Vertex( point2.x, point2.y, gridDepth );
vertex3( point4.x, point4.y, gridDepth ); currentManager->Vertex( point4.x, point4.y, gridDepth );
vertex3( point1.x, point1.y, gridDepth ); currentManager->Vertex( point1.x, point1.y, gridDepth );
vertex3( point4.x, point4.y, gridDepth ); currentManager->Vertex( point4.x, point4.y, gridDepth );
vertex3( point3.x, point3.y, gridDepth ); currentManager->Vertex( point3.x, point3.y, gridDepth );
} }
......
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 <gal/opengl/vertex_container.h>
#include <gal/opengl/cached_container.h>
#include <gal/opengl/noncached_container.h>
#include <gal/opengl/shader.h>
#include <wx/log.h>
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<VERTEX*>( malloc( aSize * sizeof( VERTEX ) ) );
}
VERTEX_CONTAINER::~VERTEX_CONTAINER()
{
free( m_vertices );
}
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 <gal/opengl/vertex_item.h>
#include <gal/opengl/vertex_manager.h>
#include <cstring>
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 );
}
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 <gal/opengl/vertex_manager.h>
#include <gal/opengl/cached_container.h>
#include <gal/opengl/noncached_container.h>
#include <gal/opengl/gpu_manager.h>
#include <gal/opengl/vertex_item.h>
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];
}
}
...@@ -401,11 +401,11 @@ private: ...@@ -401,11 +401,11 @@ private:
void deinitSurface(); 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. * @return An unique group number that is not used by any other group.
*/ */
unsigned int getGroupNumber(); unsigned int getNewGroupNumber();
}; };
} // namespace KiGfx } // namespace KiGfx
......
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 <gal/opengl/vertex_container.h>
#include <map>
#include <set>
#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<unsigned int, unsigned int> Chunk;
typedef std::multimap<unsigned int, unsigned int> FreeChunkMap;
/// List of all the stored items
typedef std::set<VERTEX_ITEM*> 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_ */
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 <gal/opengl/vertex_common.h>
#include <boost/scoped_array.hpp>
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<GLuint> 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_ */
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 <gal/opengl/vertex_container.h>
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_ */
...@@ -31,25 +31,21 @@ ...@@ -31,25 +31,21 @@
// GAL imports // GAL imports
#include <gal/graphics_abstraction_layer.h> #include <gal/graphics_abstraction_layer.h>
#include <GL/glew.h>
// OpenGL mathematics library
#define GLM_FORCE_RADIANS
#include <gal/opengl/glm/gtc/matrix_transform.hpp>
#include <gal/opengl/vbo_container.h>
#include <gal/opengl/shader.h> #include <gal/opengl/shader.h>
#include <gal/opengl/vertex_manager.h>
#include <gal/opengl/vertex_item.h>
#include <gal/opengl/noncached_container.h>
// wxWidgets imports
#include <wx/wx.h> #include <wx/wx.h>
#include <wx/glcanvas.h> #include <wx/glcanvas.h>
// STL imports
#include <cmath> #include <cmath>
#include <iterator> #include <iterator>
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
#include <boost/unordered_map.hpp> #include <memory>
#include <map>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <stdlib.h> #include <stdlib.h>
#include <iostream> #include <iostream>
...@@ -312,7 +308,7 @@ public: ...@@ -312,7 +308,7 @@ public:
///< Parameters passed to the GLU tesselator ///< Parameters passed to the GLU tesselator
typedef struct typedef struct
{ {
VBO_ITEM* vboItem; ///< VBO_ITEM for storing new vertices VERTEX_MANAGER* vboManager; ///< VERTEX_ITEM for storing new vertices
std::vector<GLdouble*>& intersectPoints; ///< Intersect points, that have to be freed std::vector<GLdouble*>& intersectPoints; ///< Intersect points, that have to be freed
} TessParams; } TessParams;
...@@ -325,11 +321,6 @@ private: ...@@ -325,11 +321,6 @@ private:
static const int CIRCLE_POINTS = 64; ///< The number of points for circle approximation 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 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 wxClientDC* clientDC; ///< Drawing context
wxGLContext* glContext; ///< OpenGL context of wxWidgets wxGLContext* glContext; ///< OpenGL context of wxWidgets
...@@ -338,43 +329,22 @@ private: ...@@ -338,43 +329,22 @@ private:
wxEvtHandler* paintListener; wxEvtHandler* paintListener;
// VBO buffered vertices for faster circle & semicircle drawing // VBO buffered vertices for faster circle & semicircle drawing
VBO_CONTAINER precomputedContainer; ///< Container for storing display lists NONCACHED_CONTAINER circleContainer; ///< Container for storing circle vertices
VBO_ITEM verticesCircle; ///< Buffer for circle & semicircle vertices
// Vertex buffer objects related fields // Vertex buffer objects related fields
typedef boost::unordered_map<unsigned int, VBO_ITEM*> GroupsMap; typedef std::map< unsigned int, boost::shared_ptr<VERTEX_ITEM> > GroupsMap;
GroupsMap groups; ///< Stores informations about VBO objects (groups) GroupsMap groups; ///< Stores informations about VBO objects (groups)
unsigned int groupCounter; ///< Counter used for generating keys for groups unsigned int groupCounter; ///< Counter used for generating keys for groups
VBO_ITEM* currentItem; ///< Currently used VBO_ITEM (for grouping) VERTEX_MANAGER* currentManager; ///< Currently used VERTEX_MANAGER (for storing VERTEX_ITEMs)
VBO_CONTAINER* currentContainer; ///< Currently used VBO_CONTAINER (for storing VBO_ITEMs) VERTEX_MANAGER cachedManager; ///< Container for storing cached VERTEX_ITEMs
VBO_CONTAINER cachedVbo; ///< Container for storing VBO_ITEMs VERTEX_MANAGER nonCachedManager; ///< Container for storing non-cached VERTEX_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<glm::mat4> transformStack; ///< Stack of transformation matrices
int indicesSize; ///< Number of indices to be drawn
GLuint* indicesPtr; ///< Pointer to mapped GPU memory
// Polygon tesselation // Polygon tesselation
GLUtesselator* tesselator; ///< Pointer to the tesselator GLUtesselator* tesselator; ///< Pointer to the tesselator
std::vector<GLdouble*> tessIntersects; ///< Storage of intersecting points std::vector<GLdouble*> tessIntersects; ///< Storage of intersecting points
// Shader // 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 SHADER shader; ///< There is only one shader used for different objects
int shaderAttrib; ///< Location of shader attributes (for glVertexAttribPointer)
// Cursor // Cursor
int cursorSize; ///< Size of the cursor in pixels int cursorSize; ///< Size of the cursor in pixels
...@@ -394,7 +364,6 @@ private: ...@@ -394,7 +364,6 @@ private:
// Internal flags // Internal flags
bool isGlewInitialized; ///< Is GLEW initialized? bool isGlewInitialized; ///< Is GLEW initialized?
bool isFrameBufferInitialized; ///< Are the frame buffers initialized? bool isFrameBufferInitialized; ///< Are the frame buffers initialized?
bool isVboInitialized;
bool isShaderInitialized; ///< Was the shader initialized? bool isShaderInitialized; ///< Was the shader initialized?
bool isUseShader; ///< Should the shaders be used? bool isUseShader; ///< Should the shaders be used?
bool isGrouping; ///< Was a group started? bool isGrouping; ///< Was a group started?
...@@ -430,8 +399,8 @@ private: ...@@ -430,8 +399,8 @@ private:
*/ */
void drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle ); void drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle );
/// Compute the points of an unit circle & semicircle and store them in VBO. /// Compute the points of the unit circle and store them in VBO.
void computeCircleVbo(); void computeCircle();
// Event handling // Event handling
/** /**
...@@ -493,22 +462,6 @@ private: ...@@ -493,22 +462,6 @@ private:
*/ */
void deleteFrameBuffer( GLuint* aFrameBuffer, GLuint* aDepthBuffer, GLuint* aTexture ); 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. * @brief Draw a quad for the line.
* *
...@@ -518,76 +471,11 @@ private: ...@@ -518,76 +471,11 @@ private:
inline void drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ); 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. * @return An unique group number that is not used by any other group.
*/ */
unsigned int getGroupNumber(); unsigned int getNewGroupNumber();
/**
* @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 );
}
}
}; };
} // namespace KiGfx } // namespace KiGfx
......
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 <GL/gl.h>
#include <gal/opengl/glm/glm.hpp>
#include <gal/opengl/vbo_item.h>
#include <gal/color4d.h>
#include <map>
#include <set>
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<const unsigned int, unsigned int> Chunk;
typedef std::multimap<const unsigned int, unsigned int> FreeChunkMap;
/// List of all the stored items
typedef std::set<VBO_ITEM*> 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_ */
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 <GL/glew.h>
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&param} (@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_ */
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 <gal/opengl/vertex_common.h>
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_ */
...@@ -23,68 +23,34 @@ ...@@ -23,68 +23,34 @@
*/ */
/** /**
* @file vbo_item.h * @file vertex_item.h
* @brief Class to handle an item held in a Vertex Buffer Object. * @brief Class to handle an item held in a container.
*/ */
#ifndef VBO_ITEM_H_ #ifndef VERTEX_ITEM_H_
#define VBO_ITEM_H_ #define VERTEX_ITEM_H_
#include <GL/gl.h> #include <gal/opengl/vertex_common.h>
#include <gal/color4d.h> #include <gal/color4d.h>
#include <cstddef> #include <cstddef>
namespace KiGfx namespace KiGfx
{ {
typedef struct VBO_VERTEX class VERTEX_MANAGER;
{
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 class VERTEX_ITEM
{ {
friend class VBO_CONTAINER;
public: public:
VBO_ITEM( VBO_CONTAINER* aContainer ); friend class CACHED_CONTAINER;
~VBO_ITEM(); friend class VERTEX_MANAGER;
/**
* 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();
VERTEX_ITEM( const VERTEX_MANAGER& aManager );
virtual ~VERTEX_ITEM();
/** /**
* Function GetSize() * Function GetSize()
* Returns information about number of vertices stored. * Returns information about number of vertices stored.
* @param Amount of vertices. * @param Number of vertices.
*/ */
inline unsigned int GetSize() const inline unsigned int GetSize() const
{ {
...@@ -93,7 +59,7 @@ public: ...@@ -93,7 +59,7 @@ public:
/** /**
* Function GetOffset() * Function GetOffset()
* Returns data offset in the VBO. * Returns data offset in the container.
* @return Data offset expressed as a number of vertices. * @return Data offset expressed as a number of vertices.
*/ */
inline unsigned int GetOffset() const inline unsigned int GetOffset() const
...@@ -102,76 +68,36 @@ public: ...@@ -102,76 +68,36 @@ public:
} }
/** /**
* Function ChangeColor() * Function GetVertices()
* Colors all vertices to the specified color. * Returns pointer to the data used by the VERTEX_ITEM.
* @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 ); VERTEX* GetVertices() const;
///< 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&param} (@see VBO_VERTEX). private:
static const unsigned int VertByteSize = sizeof(VBO_VERTEX); const VERTEX_MANAGER& m_manager;
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_offset;
unsigned int m_size; 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() * Function SetOffset()
* Sets data size in the VBO. * Sets data offset in the container.
* @param aSize is the size expressed as a number of vertices. * @param aOffset is the offset expressed as a number of vertices.
*/ */
void setSize( unsigned int aSize ) inline void setOffset( unsigned int aOffset )
{ {
m_size = aSize; m_offset = aOffset;
} }
/** /**
* Function setOffset() * Function SetSize()
* Sets data offset in the VBO. * Sets data size in the container.
* @param aOffset is the offset expressed as a number of vertices. * @param aSize is the size expressed as a number of vertices.
*/ */
inline void setOffset( unsigned int aOffset ) inline void setSize( unsigned int aSize )
{ {
m_offset = aOffset; m_size = aSize;
} }
}; };
} // namespace KiGfx } // namespace KiGfx
#endif /* VBO_ITEM_H_ */ #endif /* VERTEX_ITEM_H_ */
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 <gal/opengl/glm/gtc/matrix_transform.hpp>
#include <gal/opengl/glm/glm.hpp>
#include <gal/opengl/vertex_common.h>
#include <gal/color4d.h>
#include <stack>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <wx/log.h>
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<VERTEX_CONTAINER> m_container;
/// GPU manager for data transfers and drawing operations
boost::shared_ptr<GPU_MANAGER> 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<glm::mat4> 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_ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment