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
gal/color4d.cpp
gal/opengl/opengl_gal.cpp
gal/opengl/shader.cpp
gal/opengl/vbo_item.cpp
gal/opengl/vbo_container.cpp
gal/opengl/vertex_item.cpp
gal/opengl/vertex_container.cpp
gal/opengl/cached_container.cpp
gal/opengl/noncached_container.cpp
gal/opengl/vertex_manager.cpp
gal/opengl/gpu_manager.cpp
gal/cairo/cairo_gal.cpp
view/wx_view_controls.cpp
)
......
......@@ -132,7 +132,7 @@ void EDA_DRAW_PANEL_GAL::Refresh( bool eraseBackground, const wxRect* rect )
#endif /* __WXDEBUG__ */
m_gal->BeginDrawing();
m_gal->SetBackgroundColor( KiGfx::COLOR4D( 0, 0, 0, 1.0 ) );
m_gal->SetBackgroundColor( KiGfx::COLOR4D( 0.0, 0.0, 0.0, 1.0 ) );
m_gal->ClearScreen();
m_gal->DrawGrid();
......
......@@ -37,7 +37,7 @@ using namespace KiGfx;
CAIRO_GAL::CAIRO_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener,
wxEvtHandler* aPaintListener, const wxString& aName ) :
wxWindow( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxEXPAND, aName )
wxWindow( aParent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxEXPAND, aName )
{
// Default values
fillColor = COLOR4D( 0, 0, 0, 1 );
......@@ -141,7 +141,7 @@ void CAIRO_GAL::initSurface()
cairoSurface = cairo_image_surface_create_for_data( (unsigned char*) bitmapBuffer,
CAIRO_FORMAT_RGB24, clientRectangle.width,
clientRectangle.height, stride );
cairoImage = cairo_create ( cairoSurface );
cairoImage = cairo_create( cairoSurface );
#ifdef __WXDEBUG__
cairo_status_t status = cairo_status( cairoImage );
wxASSERT_MSG( status == CAIRO_STATUS_SUCCESS, "Cairo context creation error" );
......@@ -194,10 +194,10 @@ void CAIRO_GAL::deinitSurface()
}
unsigned int CAIRO_GAL::getGroupNumber()
unsigned int CAIRO_GAL::getNewGroupNumber()
{
wxASSERT_MSG( groups.size() < std::numeric_limits<unsigned int>::max(),
wxT( "There are no free slots to store a group" ) );
wxT( "There are no free slots to store a group" ) );
while( groups.find( groupCounter ) != groups.end() )
{
......@@ -230,6 +230,7 @@ void CAIRO_GAL::EndDrawing()
// Now translate the raw image data from the format stored
// by cairo into a format understood by wxImage.
unsigned char* wxOutputPtr = wxOutput;
for( size_t count = 0; count < bufferSize; count++ )
{
unsigned int value = bitmapBuffer[count];
......@@ -287,7 +288,8 @@ void CAIRO_GAL::DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint
}
void CAIRO_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, double aWidth )
void CAIRO_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint,
double aWidth )
{
if( isFillEnabled )
{
......@@ -317,7 +319,6 @@ void CAIRO_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPo
cairo_line_to( cairoImage, lineLength, -aWidth / 2.0 );
cairo_restore( cairoImage );
}
isElementAdded = true;
......@@ -351,7 +352,8 @@ void CAIRO_GAL::DrawPolyline( std::deque<VECTOR2D>& aPointList )
bool isFirstPoint = true;
// 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 )
{
......@@ -373,7 +375,8 @@ void CAIRO_GAL::DrawPolygon( const std::deque<VECTOR2D>& aPointList )
bool isFirstPoint = true;
// 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 )
{
......@@ -644,10 +647,10 @@ int CAIRO_GAL::BeginGroup()
storePath();
Group group;
int groupNumber = getGroupNumber();
int groupNumber = getNewGroupNumber();
groups.insert( std::make_pair( groupNumber, group ) );
currentGroup = &groups[groupNumber];
isGrouping = true;
isGrouping = true;
return groupNumber;
}
......@@ -677,6 +680,7 @@ void CAIRO_GAL::DeleteGroup( int aGroupNumber )
// Delete the Cairo paths
std::deque<GroupElement>::iterator it, end;
for( it = groups[aGroupNumber].begin(), end = groups[aGroupNumber].end(); it != end; ++it )
{
if( it->command == CMD_FILL_PATH || it->command == CMD_STROKE_PATH )
......
......@@ -23,203 +23,165 @@
*/
/**
* @file vbo_container.cpp
* @brief Class to store VBO_ITEMs.
* @file cached_container.cpp
* @brief Class to store instances of VERTEX with caching. It allows storing VERTEX objects and
* associates them with VERTEX_ITEMs. This leads to a possibility of caching vertices data in the
* GPU memory and a fast reuse of that data.
*/
#include <gal/opengl/vbo_container.h>
#include <algorithm>
#include <list>
#include <gal/opengl/cached_container.h>
#include <gal/opengl/vertex_manager.h>
#include <gal/opengl/vertex_item.h>
#include <gal/opengl/shader.h>
#include <wx/log.h>
#include <list>
#ifdef __WXDEBUG__
#include <profile.h>
#endif /* __WXDEBUG__ */
using namespace KiGfx;
VBO_CONTAINER::VBO_CONTAINER( unsigned int aSize ) :
m_freeSpace( aSize ), m_currentSize( aSize ), m_initialSize( aSize ), m_transform( NULL ),
m_failed( false )
CACHED_CONTAINER::CACHED_CONTAINER( unsigned int aSize ) :
VERTEX_CONTAINER( aSize )
{
// By default no shader is used
m_shader[0] = 0;
m_vertices = static_cast<VBO_VERTEX*>( malloc( aSize * sizeof( VBO_VERTEX ) ) );
// In the beginning there is only free space
m_freeChunks.insert( Chunk( aSize, 0 ) );
}
VBO_CONTAINER::~VBO_CONTAINER()
void CACHED_CONTAINER::SetItem( VERTEX_ITEM* aItem )
{
free( m_vertices );
}
if( aItem == NULL )
{
wxASSERT( m_item != NULL );
// Finishing the item
if( m_itemSize < m_chunkSize )
{
// There is some not used but reserved memory left, so we should return it to the pool
int itemOffset = m_item->GetOffset();
void VBO_CONTAINER::StartItem( VBO_ITEM* aItem )
{
m_item = aItem;
m_itemSize = aItem->GetSize();
m_chunkSize = m_itemSize;
// Add the not used memory back to the pool
m_freeChunks.insert( Chunk( m_chunkSize - m_itemSize, itemOffset + m_itemSize ) );
m_freeSpace += ( m_chunkSize - m_itemSize );
// mergeFreeChunks();
}
if( m_itemSize == 0 )
m_items.insert( m_item ); // The item was not stored before
m_item = NULL;
}
else
m_chunkOffset = m_item->GetOffset();
}
void VBO_CONTAINER::EndItem()
{
if( m_itemSize < m_chunkSize )
{
// Add the not used memory back to the pool
m_freeChunks.insert( Chunk( m_chunkSize - m_itemSize, m_chunkOffset + m_itemSize ) );
m_freeSpace += ( m_chunkSize - m_itemSize );
}
m_item = aItem;
m_itemSize = m_item->GetSize();
m_chunkSize = m_itemSize;
m_item = NULL;
if( m_itemSize == 0 )
m_items.insert( m_item ); // The item was not stored before
else
m_chunkOffset = m_item->GetOffset();
}
}
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
VBO_VERTEX* vertexPtr = allocate( aSize );
wxASSERT( m_item != NULL );
if( vertexPtr == NULL )
return;
if( m_failed )
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
vertexPtr->x = aVertex[i].x;
vertexPtr->y = aVertex[i].y;
vertexPtr->z = aVertex[i].z;
}
// There is not enough space in the currently reserved chunk, so we have to resize it
// Apply currently used color
vertexPtr->r = m_color[0];
vertexPtr->g = m_color[1];
vertexPtr->b = m_color[2];
vertexPtr->a = m_color[3];
// Reserve a bigger memory chunk for the current item and
// make it multiple of 3 to store triangles
m_chunkSize = ( 2 * m_itemSize ) + aSize + ( 3 - aSize % 3 );
// Save the current size before reallocating
m_chunkOffset = reallocate( m_chunkSize );
// Apply currently used shader
for( unsigned int j = 0; j < VBO_ITEM::ShaderStride; ++j )
if( m_chunkOffset > m_currentSize )
{
vertexPtr->shader[j] = m_shader[j];
m_failed = true;
return NULL;
}
vertexPtr++;
}
}
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();
VERTEX* reserved = &m_vertices[m_chunkOffset + m_itemSize];
m_itemSize += aSize;
m_item->setSize( m_itemSize );
// Reset state variables
m_transform = NULL;
m_failed = false;
// The content has to be updated
m_dirty = true;
// By default no shader is used
m_shader[0] = 0;
#if CACHED_CONTAINER_TEST > 1
test();
#endif
// In the beginning there is only free space
m_freeSpace = m_initialSize;
m_currentSize = m_initialSize;
m_freeChunks.clear();
m_freeChunks.insert( Chunk( m_freeSpace, 0 ) );
return reserved;
}
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
// 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 );
}
}
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 ) ) );
// Reset state variables
m_freeSpace = m_initialSize;
m_currentSize = m_initialSize;
m_failed = false;
VBO_VERTEX* VBO_CONTAINER::GetVertices( const VBO_ITEM* aItem ) const
{
int offset = aItem->GetOffset();
// 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;
return &m_vertices[offset];
}
for( it = m_items.begin(); it != m_items.end(); ++it )
{
( *it )->setSize( 0 );
}
VBO_VERTEX* VBO_CONTAINER::allocate( unsigned int aSize )
{
wxASSERT( m_item != NULL );
m_items.clear();
if( m_failed )
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
m_chunkSize = std::max( ( 2 * m_itemSize ) + aSize, (unsigned) 3 );
// Save the current size before reallocating
m_chunkOffset = reallocate( m_chunkSize );
// Now there is only free space left
m_freeChunks.clear();
m_freeChunks.insert( Chunk( m_freeSpace, 0 ) );
}
if( m_chunkOffset > m_currentSize )
{
m_failed = true;
return NULL;
}
}
VBO_VERTEX* reserved = &m_vertices[m_chunkOffset + m_itemSize];
m_itemSize += aSize;
m_item->setSize( m_itemSize );
VERTEX* CACHED_CONTAINER::GetVertices( const VERTEX_ITEM* aItem ) const
{
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?
if( m_freeSpace < aSize )
{
......@@ -260,7 +222,7 @@ unsigned int VBO_CONTAINER::reallocate( unsigned int aSize )
}
// Parameters of the allocated cuhnk
unsigned int chunkSize = newChunk->first;
unsigned int chunkSize = newChunk->first;
unsigned int chunkOffset = newChunk->second;
wxASSERT( chunkSize >= aSize );
......@@ -269,37 +231,57 @@ unsigned int VBO_CONTAINER::reallocate( unsigned int aSize )
// Check if the item was previously stored in the container
if( m_itemSize > 0 )
{
#if CACHED_CONTAINER_TEST > 3
wxLogDebug( wxT( "Moving 0x%08x from 0x%08x to 0x%08x" ),
(int) m_item, oldChunkOffset, chunkOffset );
#endif
// The item was reallocated, so we have to copy all the old data to the new place
memcpy( &m_vertices[chunkOffset], &m_vertices[m_chunkOffset],
m_itemSize * VBO_ITEM::VertByteSize );
m_itemSize * VertexSize );
// Free the space previously used by the chunk
m_freeChunks.insert( Chunk( m_itemSize, m_chunkOffset ) );
m_freeSpace += m_itemSize;
}
// Remove the allocated chunk from the free space pool
m_freeChunks.erase( newChunk );
m_freeSpace -= chunkSize;
// If there is some space left, return it to the pool - add an entry for it
if( chunkSize > aSize )
{
m_freeChunks.insert( Chunk( chunkSize - aSize, chunkOffset + aSize ) );
m_freeSpace += chunkSize - aSize;
}
m_freeSpace -= aSize;
// mergeFreeChunks();
m_item->setOffset( chunkOffset );
#if CACHED_CONTAINER_TEST > 2
showFreeChunks();
showReservedChunks();
#endif
return chunkOffset;
}
bool VBO_CONTAINER::defragment( VBO_VERTEX* aTarget )
bool CACHED_CONTAINER::defragment( VERTEX* aTarget )
{
#if CACHED_CONTAINER_TEST > 0
wxLogDebug( wxT( "Defragmenting" ) );
#endif
#ifdef __WXDEBUG__
prof_counter totalTime;
prof_start( &totalTime, false );
#endif /* __WXDEBUG__ */
if( aTarget == NULL )
{
// No target was specified, so we have to reallocate our own space
aTarget = static_cast<VBO_VERTEX*>( malloc( m_currentSize * sizeof( VBO_VERTEX ) ) );
aTarget = static_cast<VERTEX*>( malloc( m_currentSize * sizeof( VERTEX ) ) );
if( aTarget == NULL )
{
wxLogError( wxT( "Run out of memory" ) );
......@@ -309,16 +291,17 @@ bool VBO_CONTAINER::defragment( VBO_VERTEX* aTarget )
int newOffset = 0;
Items::iterator it, it_end;
for( it = m_items.begin(), it_end = m_items.end(); it != it_end; ++it )
{
VBO_ITEM* item = *it;
int itemOffset = item->GetOffset();
int itemSize = item->GetSize();
VERTEX_ITEM* item = *it;
int itemOffset = item->GetOffset();
int itemSize = item->GetSize();
// Move an item to the new container
memcpy( &aTarget[newOffset], &m_vertices[itemOffset], itemSize * VBO_ITEM::VertByteSize );
memcpy( &aTarget[newOffset], &m_vertices[itemOffset], itemSize * VertexSize );
// Update its offset
// Update new offset
item->setOffset( newOffset );
// Move to the next free space
......@@ -330,17 +313,29 @@ bool VBO_CONTAINER::defragment( VBO_VERTEX* aTarget )
// Now there is only one big chunk of free memory
m_freeChunks.clear();
m_freeChunks.insert( Chunk( m_freeSpace, reservedSpace() ) );
m_freeChunks.insert( Chunk( m_freeSpace, m_currentSize - m_freeSpace ) );
#ifdef __WXDEBUG__
prof_end( &totalTime );
wxLogDebug( wxT( "Defragmented the container storing %d vertices / %.1f ms" ),
m_currentSize - m_freeSpace, (double) totalTime.value / 1000.0 );
#endif /* __WXDEBUG__ */
return true;
}
void VBO_CONTAINER::mergeFreeChunks()
void CACHED_CONTAINER::mergeFreeChunks()
{
if( m_freeChunks.size() < 2 ) // There are no chunks that can be merged
if( m_freeChunks.size() <= 1 ) // There are no chunks that can be merged
return;
#ifdef __WXDEBUG__
prof_counter totalTime;
prof_start( &totalTime, false );
#endif /* __WXDEBUG__ */
// Reversed free chunks map - this one stores chunk size with its offset as the key
std::list<Chunk> freeChunks;
......@@ -349,6 +344,7 @@ void VBO_CONTAINER::mergeFreeChunks()
{
freeChunks.push_back( std::make_pair( it->second, it->first ) );
}
m_freeChunks.clear();
freeChunks.sort();
......@@ -356,6 +352,7 @@ void VBO_CONTAINER::mergeFreeChunks()
unsigned int offset = freeChunks.front().first;
unsigned int size = freeChunks.front().second;
freeChunks.pop_front();
for( itf = freeChunks.begin(), itf_end = freeChunks.end(); itf != itf_end; ++itf )
{
if( itf->first == offset + size )
......@@ -371,17 +368,30 @@ void VBO_CONTAINER::mergeFreeChunks()
// and let's check the next chunk
offset = itf->first;
size = itf->second;
}
}
// Add the last one
m_freeChunks.insert( std::make_pair( size, offset ) );
#ifdef __WXDEBUG__
prof_end( &totalTime );
wxLogDebug( wxT( "Merged free chunks / %.1f ms" ), (double) totalTime.value / 1000.0 );
#endif /* __WXDEBUG__ */
test();
}
bool VBO_CONTAINER::resizeContainer( unsigned int aNewSize )
bool CACHED_CONTAINER::resizeContainer( unsigned int aNewSize )
{
VBO_VERTEX* newContainer;
#if CACHED_CONTAINER_TEST > 0
wxLogDebug( wxT( "Resizing container from %d to %d" ), m_currentSize, aNewSize );
#endif
VERTEX* newContainer;
if( aNewSize < m_currentSize )
{
......@@ -390,7 +400,8 @@ bool VBO_CONTAINER::resizeContainer( unsigned int aNewSize )
if( reservedSpace() > aNewSize )
return false;
newContainer = static_cast<VBO_VERTEX*>( malloc( aNewSize * sizeof( VBO_VERTEX ) ) );
newContainer = static_cast<VERTEX*>( malloc( aNewSize * sizeof( VERTEX ) ) );
if( newContainer == NULL )
{
wxLogError( wxT( "Run out of memory" ) );
......@@ -407,7 +418,8 @@ bool VBO_CONTAINER::resizeContainer( unsigned int aNewSize )
else
{
// Enlarging container
newContainer = static_cast<VBO_VERTEX*>( realloc( m_vertices, aNewSize * sizeof( VBO_VERTEX ) ) );
newContainer = static_cast<VERTEX*>( realloc( m_vertices, aNewSize * sizeof( VERTEX ) ) );
if( newContainer == NULL )
{
wxLogError( wxT( "Run out of memory" ) );
......@@ -420,35 +432,94 @@ bool VBO_CONTAINER::resizeContainer( unsigned int aNewSize )
m_vertices = newContainer;
m_freeSpace += ( aNewSize - m_currentSize );
m_freeSpace += ( aNewSize - m_currentSize );
m_currentSize = aNewSize;
return true;
}
void VBO_CONTAINER::freeItem( VBO_ITEM* aItem )
void CACHED_CONTAINER::freeItem( VERTEX_ITEM* aItem )
{
int size = aItem->GetSize();
int offset = aItem->GetOffset();
int size = aItem->GetSize();
int offset = aItem->GetOffset();
// Insert a free memory chunk entry in the place where item was stored
m_freeChunks.insert( Chunk( size, offset ) );
m_freeSpace += size;
m_items.erase( aItem );
// Item size is set to 0, so it means that it is not stored in the container
// Indicate that the item is not stored in the container anymore
aItem->setSize( 0 );
}
void VBO_CONTAINER::test() const
unsigned int CACHED_CONTAINER::getPowerOf2( unsigned int aNumber ) const
{
unsigned int freeSpace = 0;
FreeChunkMap::const_iterator it, it_end;
unsigned int power = 1;
// Check if the amount of free memory stored as chunks is the same as reported by m_freeSpace
for( it = m_freeChunks.begin(), it_end = m_freeChunks.end(); it != it_end; ++it )
freeSpace += it->first;
while( power < aNumber && power != 0 )
power <<= 1;
return power;
}
#ifdef CACHED_CONTAINER_TEST
void CACHED_CONTAINER::showFreeChunks()
{
FreeChunkMap::iterator it;
wxLogDebug( wxT( "Free chunks:" ) );
for( it = m_freeChunks.begin(); it != m_freeChunks.end(); ++it )
{
unsigned int offset = getChunkOffset( *it );
unsigned int size = getChunkSize( *it );
wxLogDebug( wxT( "[0x%08x-0x%08x] (size %d)" ),
offset, offset + size - 1, size );
}
}
void CACHED_CONTAINER::showReservedChunks()
{
Items::iterator it;
wxLogDebug( wxT( "Reserved chunks:" ) );
for( it = m_items.begin(); it != m_items.end(); ++it )
{
VERTEX_ITEM* item = *it;
unsigned int offset = item->GetOffset();
unsigned int size = item->GetSize();
wxLogDebug( wxT( "[0x%08x-0x%08x] @ 0x%08x (size %d)" ),
offset, offset + size - 1, (int) item, size );
}
}
void CACHED_CONTAINER::test()
{
// Free space check
unsigned int freeSpace = 0;
FreeChunkMap::iterator itf;
for( itf = m_freeChunks.begin(); itf != m_freeChunks.end(); ++itf )
freeSpace += getChunkSize( *itf );
wxASSERT( freeSpace == m_freeSpace );
// Reserved space check
/*unsigned int reservedSpace = 0;
Items::iterator itr;
for( itr = m_items.begin(); itr != m_items.end(); ++itr )
reservedSpace += ( *itr )->GetSize();
reservedSpace += m_itemSize; // Add the current chunk size
wxASSERT( ( freeSpace + reservedSpace ) == m_currentSize );*/
// Overlapping check TBD
}
#endif /* CACHED_CONTAINER_TEST */
/*
* 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 @@
*/
/**
* @file vbo_item.cpp
* @brief Class to handle an item held in a Vertex Buffer Object.
* @file noncached_container.cpp
* @brief Class to store instances of VERTEX without caching. It allows a fast one-frame drawing
* and then clearing the buffer and starting from scratch.
*/
#include <gal/opengl/vbo_container.h>
#include <gal/opengl/vbo_item.h>
#include <cstring>
#include <gal/opengl/noncached_container.h>
#include <cstdlib>
using namespace KiGfx;
VBO_ITEM::VBO_ITEM( VBO_CONTAINER* aContainer ) :
m_offset( 0 ),
m_size( 0 ),
m_container( aContainer ),
m_isDirty( true )
NONCACHED_CONTAINER::NONCACHED_CONTAINER( unsigned int aSize ) :
VERTEX_CONTAINER( aSize ), m_freePtr( 0 )
{
// 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 );
m_isDirty = true;
// Nothing has to be done, as the noncached container
// does not care about VERTEX_ITEMs ownership
}
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) ) );
if( newVertices != NULL )
{
m_vertices = newVertices;
m_freeSpace += m_currentSize;
m_currentSize *= 2;
}
else
{
return NULL;
}
}
}
VBO_VERTEX* VBO_ITEM::GetVertices()
{
if( m_isDirty )
Finish();
return m_container->GetVertices( m_offset );
}
void VBO_ITEM::ChangeColor( const COLOR4D& aColor )
{
VBO_VERTEX* vertexPtr = GetVertices();
VERTEX* freeVertex = &m_vertices[m_freePtr];
for( unsigned int i = 0; i < m_size; ++i )
{
vertexPtr->r = aColor.r * 255;
vertexPtr->g = aColor.g * 255;
vertexPtr->b = aColor.b * 255;
vertexPtr->a = aColor.a * 255;
// Move to the next free chunk
m_freePtr += aSize;
m_freeSpace -= aSize;
// Move on to the next vertex
vertexPtr++;
}
return freeVertex;
}
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_container->EndItem();
m_isDirty = false;
m_freePtr = 0;
m_freeSpace = m_currentSize;
}
......@@ -53,7 +53,8 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener,
wxEvtHandler* aPaintListener, bool isUseShaders, const wxString& aName ) :
wxGLCanvas( aParent, wxID_ANY, (int*) glAttributes, wxDefaultPosition, wxDefaultSize,
wxEXPAND, aName ),
verticesCircle( &precomputedContainer )
cachedManager( true ),
nonCachedManager( false )
{
// Create the OpenGL-Context
glContext = new wxGLContext( this );
......@@ -73,13 +74,7 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener,
isShaderInitialized = false;
isGrouping = false;
wxSize parentSize = aParent->GetSize();
isVboInitialized = false;
vboNeedsUpdate = false;
currentItem = NULL;
groupCounter = 0;
transform = glm::mat4( 1.0f ); // Identity matrix
nonCachedItem = NULL;
SetSize( parentSize );
......@@ -112,11 +107,11 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener,
InitTesselatorCallbacks( tesselator );
gluTessProperty( tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE );
// Compute unit semicircle & circle vertices and store them in a buffer for faster drawing
computeCircleVbo();
// Compute the unit circle vertices and store them in a buffer for faster drawing
computeCircle();
// By default we draw non-cached objects, it changes on BeginGroup()/EndGroup()
currentContainer = &nonCachedVbo;
currentManager = &nonCachedManager;
}
......@@ -124,8 +119,6 @@ OPENGL_GAL::~OPENGL_GAL()
{
glFlush();
delete nonCachedItem;
// Delete the buffers
if( isFrameBufferInitialized )
{
......@@ -134,12 +127,7 @@ OPENGL_GAL::~OPENGL_GAL()
}
gluDeleteTess( tesselator );
if( isVboInitialized )
{
ClearCache();
deleteVertexBufferObjects();
}
ClearCache();
delete glContext;
}
......@@ -239,28 +227,6 @@ void OPENGL_GAL::initFrameBuffers()
}
void OPENGL_GAL::initVertexBufferObjects()
{
// Generate buffers for vertices and indices
glGenBuffers( 1, &cachedVerts );
glGenBuffers( 1, &cachedInds );
isVboInitialized = true;
}
void OPENGL_GAL::deleteVertexBufferObjects()
{
glBindBuffer( GL_ARRAY_BUFFER, 0 );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
glDeleteBuffers( 1, &cachedVerts );
glDeleteBuffers( 1, &cachedInds );
isVboInitialized = false;
}
void OPENGL_GAL::SaveScreen()
{
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, frameBufferBackup );
......@@ -323,8 +289,6 @@ void OPENGL_GAL::initGlew()
exit( 1 );
}
initVertexBufferObjects();
isGlewInitialized = true;
}
......@@ -337,38 +301,26 @@ void OPENGL_GAL::BeginDrawing()
// Initialize GLEW, FBOs & VBOs
if( !isGlewInitialized )
{
initGlew();
}
if( !isFrameBufferInitialized )
{
initFrameBuffers();
}
// Compile the shaders
if( !isShaderInitialized && isUseShader )
{
if( !shader.LoadBuiltinShader( 0, SHADER_TYPE_VERTEX ) )
{
wxLogFatalError( wxT( "Cannot compile vertex shader!" ) );
}
wxLogFatalError( wxT( "Cannot compile vertex shader!" ) );
if( !shader.LoadBuiltinShader( 1, SHADER_TYPE_FRAGMENT ) )
{
wxLogFatalError( wxT( "Cannot compile fragment shader!" ) );
}
wxLogFatalError( wxT( "Cannot compile fragment shader!" ) );
if( !shader.Link() )
{
wxLogFatalError( wxT( "Cannot link the shaders!" ) );
}
shaderAttrib = shader.GetAttribute( "attrShaderParams" );
if( shaderAttrib == -1 )
{
wxLogFatalError( wxT( "Could not get the shader attribute location" ) );
}
// Make VBOs use shaders
cachedManager.SetShader( shader );
nonCachedManager.SetShader( shader );
isShaderInitialized = true;
}
......@@ -418,29 +370,10 @@ void OPENGL_GAL::BeginDrawing()
SetStrokeColor( strokeColor );
isDeleteSavedPixels = true;
// If any of VBO items is dirty - recache everything
if( vboNeedsUpdate )
rebuildVbo();
// Number of vertices to be drawn
indicesSize = 0;
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, cachedInds );
// Discard old buffer, so we can use it again
glBufferData( GL_ELEMENT_ARRAY_BUFFER, cachedVbo.GetSize() * VBO_ITEM::IndByteSize,
NULL, GL_STREAM_DRAW );
// Map the GPU memory, so we can store indices that are going to be drawn
indicesPtr = static_cast<GLuint*>( glMapBuffer( GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY ) );
if( indicesPtr == NULL )
{
wxLogError( wxT( "Could not map GPU memory" ) );
}
nonCachedManager.Clear();
// Prepare buffer for non-cached items
delete nonCachedItem;
nonCachedItem = new VBO_ITEM( &nonCachedVbo );
currentItem = nonCachedItem;
cachedManager.BeginDrawing();
nonCachedManager.BeginDrawing();
}
......@@ -492,55 +425,8 @@ void OPENGL_GAL::blitMainTexture( bool aIsClearFrameBuffer )
void OPENGL_GAL::EndDrawing()
{
if( !glUnmapBuffer( GL_ELEMENT_ARRAY_BUFFER ) )
{
wxLogError( wxT( "Unmapping indices buffer failed" ) );
}
// Prepare buffers
glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_COLOR_ARRAY );
// Draw non-cached items
GLfloat* vertices = (GLfloat*)( nonCachedVbo.GetAllVertices() );
GLubyte* colors = (GLubyte*)( nonCachedVbo.GetAllVertices() ) + VBO_ITEM::ColorOffset;
GLfloat* shaders = (GLfloat*)( nonCachedVbo.GetAllVertices() ) + VBO_ITEM::ShaderOffset;
glVertexPointer( VBO_ITEM::CoordStride, GL_FLOAT, VBO_ITEM::VertByteSize, vertices );
glColorPointer( VBO_ITEM::ColorStride, GL_UNSIGNED_BYTE, VBO_ITEM::VertByteSize, colors );
if( isUseShader )
{
shader.Use();
glEnableVertexAttribArray( shaderAttrib );
glVertexAttribPointer( shaderAttrib, VBO_ITEM::ShaderStride, GL_FLOAT, GL_FALSE,
VBO_ITEM::VertByteSize, shaders );
}
glDrawArrays( GL_TRIANGLES, nonCachedItem->GetOffset(), nonCachedItem->GetSize() );
// Draw cached items
glBindBuffer( GL_ARRAY_BUFFER, cachedVerts );
glVertexPointer( VBO_ITEM::CoordStride, GL_FLOAT, VBO_ITEM::VertByteSize, 0 );
glColorPointer( VBO_ITEM::ColorStride, GL_UNSIGNED_BYTE, VBO_ITEM::VertByteSize,
(GLvoid*) VBO_ITEM::ColorByteOffset );
if( isUseShader )
{
glVertexAttribPointer( shaderAttrib, VBO_ITEM::ShaderStride, GL_FLOAT, GL_FALSE,
VBO_ITEM::VertByteSize, (GLvoid*) VBO_ITEM::ShaderByteOffset );
}
glDrawElements( GL_TRIANGLES, indicesSize, GL_UNSIGNED_INT, (GLvoid*) 0 );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
glBindBuffer( GL_ARRAY_BUFFER, 0 );
// Deactivate vertex array
glDisableClientState( GL_COLOR_ARRAY );
glDisableClientState( GL_VERTEX_ARRAY );
if( isUseShader )
{
glDisableVertexAttribArray( shaderAttrib );
shader.Deactivate();
}
cachedManager.EndDrawing();
nonCachedManager.EndDrawing();
// Draw the remaining contents, blit the main texture to the screen, swap the buffers
glFlush();
......@@ -551,38 +437,6 @@ void OPENGL_GAL::EndDrawing()
}
void OPENGL_GAL::rebuildVbo()
{
#ifdef __WXDEBUG__
prof_counter totalTime;
prof_start( &totalTime, false );
#endif /* __WXDEBUG__ */
GLfloat* data = (GLfloat*) cachedVbo.GetAllVertices();
// Upload vertices coordinates and shader types to GPU memory
glBindBuffer( GL_ARRAY_BUFFER, cachedVerts );
glBufferData( GL_ARRAY_BUFFER, cachedVbo.GetSize() * VBO_ITEM::VertByteSize,
data, GL_DYNAMIC_DRAW );
glBindBuffer( GL_ARRAY_BUFFER, 0 );
// Allocate the biggest possible buffer for indices
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, cachedInds );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, cachedVbo.GetSize() * VBO_ITEM::IndByteSize,
NULL, GL_STREAM_DRAW );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
vboNeedsUpdate = false;
#ifdef __WXDEBUG__
prof_end( &totalTime );
wxLogDebug( wxT( "Rebuilding VBO::%d vertices / %.1f ms" ),
cachedVbo.GetSize(), (double) totalTime.value / 1000.0 );
#endif /* __WXDEBUG__ */
}
inline void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
{
VECTOR2D startEndVector = aEndPoint - aStartPoint;
......@@ -598,29 +452,27 @@ inline void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2
{
glm::vec4 vector( perpendicularVector.x, perpendicularVector.y, 0.0, 0.0 );
// If transform stack is not empty, then it means that
// there is a transformation matrix that has to be applied
if( !transformStack.empty() )
vector = transform * vector;
// The perpendicular vector also needs transformations
vector = currentManager->GetTransformation() * vector;
// Line width is maintained by the vertex shader
setShader( SHADER_LINE, vector.x, vector.y, lineWidth );
vertex3( aStartPoint.x, aStartPoint.y, layerDepth ); // v0
currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth );
currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); // v0
setShader( SHADER_LINE, -vector.x, -vector.y, lineWidth );
vertex3( aStartPoint.x, aStartPoint.y, layerDepth ); // v1
currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth );
currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); // v1
setShader( SHADER_LINE, -vector.x, -vector.y, lineWidth );
vertex3( aEndPoint.x, aEndPoint.y, layerDepth ); // v3
currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth );
currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); // v3
setShader( SHADER_LINE, vector.x, vector.y, lineWidth );
vertex3( aStartPoint.x, aStartPoint.y, layerDepth ); // v0
currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth );
currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); // v0
setShader( SHADER_LINE, -vector.x, -vector.y, lineWidth );
vertex3( aEndPoint.x, aEndPoint.y, layerDepth ); // v3
currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth );
currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); // v3
setShader( SHADER_LINE, vector.x, vector.y, lineWidth );
vertex3( aEndPoint.x, aEndPoint.y, layerDepth ); // v2
currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth );
currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); // v2
}
else
{
......@@ -630,13 +482,13 @@ inline void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2
VECTOR2D v2 = aEndPoint + perpendicularVector;
VECTOR2D v3 = aEndPoint - perpendicularVector;
vertex3( v0.x, v0.y, layerDepth );
vertex3( v1.x, v1.y, layerDepth );
vertex3( v3.x, v3.y, layerDepth );
currentManager->Vertex( v0.x, v0.y, layerDepth );
currentManager->Vertex( v1.x, v1.y, layerDepth );
currentManager->Vertex( v3.x, v3.y, layerDepth );
vertex3( v0.x, v0.y, layerDepth );
vertex3( v3.x, v3.y, layerDepth );
vertex3( v2.x, v2.y, layerDepth );
currentManager->Vertex( v0.x, v0.y, layerDepth );
currentManager->Vertex( v3.x, v3.y, layerDepth );
currentManager->Vertex( v2.x, v2.y, layerDepth );
}
}
......@@ -650,7 +502,7 @@ void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndP
if( isFillEnabled )
{
// Filled tracks
color4( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
SetLineWidth( aWidth );
drawLineQuad( aStartPoint, aEndPoint );
......@@ -664,12 +516,12 @@ void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndP
// Outlined tracks
double lineLength = startEndVector.EuclideanNorm();
color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
Save();
translate3( aStartPoint.x, aStartPoint.y, 0.0 );
Rotate( lineAngle );
currentManager->Translate( aStartPoint.x, aStartPoint.y, 0.0 );
currentManager->Rotate( lineAngle, 0.0f, 0.0f, 1.0f );
drawLineQuad( VECTOR2D( 0.0, aWidth / 2.0 ),
VECTOR2D( lineLength, aWidth / 2.0 ) );
......@@ -686,7 +538,7 @@ void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndP
}
unsigned int OPENGL_GAL::getGroupNumber()
unsigned int OPENGL_GAL::getNewGroupNumber()
{
wxASSERT_MSG( groups.size() < std::numeric_limits<unsigned int>::max(),
wxT( "There are no free slots to store a group" ) );
......@@ -745,7 +597,7 @@ void OPENGL_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEn
// Stroke the outline
if( isStrokeEnabled )
{
color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
std::deque<VECTOR2D> pointList;
pointList.push_back( aStartPoint );
......@@ -759,16 +611,16 @@ void OPENGL_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEn
// Fill the rectangle
if( isFillEnabled )
{
setShader( SHADER_NONE );
color4( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
currentManager->Shader( SHADER_NONE );
currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
vertex3( aStartPoint.x, aStartPoint.y, layerDepth );
vertex3( diagonalPointA.x, diagonalPointA.y, layerDepth );
vertex3( aEndPoint.x, aEndPoint.y, layerDepth );
currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth );
currentManager->Vertex( diagonalPointA.x, diagonalPointA.y, layerDepth );
currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth );
vertex3( aStartPoint.x, aStartPoint.y, layerDepth );
vertex3( aEndPoint.x, aEndPoint.y, layerDepth );
vertex3( diagonalPointB.x, diagonalPointB.y, layerDepth );
currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth );
currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth );
currentManager->Vertex( diagonalPointB.x, diagonalPointB.y, layerDepth );
}
}
......@@ -779,7 +631,7 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )
{
if( isFillEnabled )
{
color4( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
/* Draw a triangle that contains the circle, then shade it leaving only the circle.
Parameters given to setShader are indices of the triangle's vertices
......@@ -790,21 +642,21 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )
//\\
v0 /_\/_\ v1
*/
setShader( SHADER_FILLED_CIRCLE, 1.0 );
vertex3( aCenterPoint.x - aRadius * sqrt( 3.0f ),
aCenterPoint.y - aRadius, layerDepth ); // v0
currentManager->Shader( SHADER_FILLED_CIRCLE, 1.0 );
currentManager->Vertex( aCenterPoint.x - aRadius * sqrt( 3.0f ),
aCenterPoint.y - aRadius, layerDepth ); // v0
setShader( SHADER_FILLED_CIRCLE, 2.0 );
vertex3( aCenterPoint.x + aRadius* sqrt( 3.0f ),
aCenterPoint.y - aRadius, layerDepth ); // v1
currentManager->Shader( SHADER_FILLED_CIRCLE, 2.0 );
currentManager->Vertex( aCenterPoint.x + aRadius* sqrt( 3.0f ),
aCenterPoint.y - aRadius, layerDepth ); // v1
setShader( SHADER_FILLED_CIRCLE, 3.0 );
vertex3( aCenterPoint.x, aCenterPoint.y + aRadius * 2.0f, layerDepth ); // v2
currentManager->Shader( SHADER_FILLED_CIRCLE, 3.0 );
currentManager->Vertex( aCenterPoint.x, aCenterPoint.y + aRadius * 2.0f, layerDepth ); // v2
}
if( isStrokeEnabled )
{
color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
/* Draw a triangle that contains the circle, then shade it leaving only the circle.
Parameters given to setShader are indices of the triangle's vertices
......@@ -817,114 +669,126 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )
v0 /_\/_\ v1
*/
double outerRadius = aRadius + ( lineWidth / 2 );
setShader( SHADER_STROKED_CIRCLE, 1.0, aRadius, lineWidth );
vertex3( aCenterPoint.x - outerRadius * sqrt( 3.0f ),
aCenterPoint.y - outerRadius, layerDepth ); // v0
currentManager->Shader( SHADER_STROKED_CIRCLE, 1.0, aRadius, lineWidth );
currentManager->Vertex( aCenterPoint.x - outerRadius * sqrt( 3.0f ),
aCenterPoint.y - outerRadius, layerDepth ); // v0
setShader( SHADER_STROKED_CIRCLE, 2.0, aRadius, lineWidth );
vertex3( aCenterPoint.x + outerRadius * sqrt( 3.0f ),
aCenterPoint.y - outerRadius, layerDepth ); // v1
currentManager->Shader( SHADER_STROKED_CIRCLE, 2.0, aRadius, lineWidth );
currentManager->Vertex( aCenterPoint.x + outerRadius * sqrt( 3.0f ),
aCenterPoint.y - outerRadius, layerDepth ); // v1
setShader( SHADER_STROKED_CIRCLE, 3.0, aRadius, lineWidth );
vertex3( aCenterPoint.x, aCenterPoint.y + outerRadius * 2.0f, layerDepth ); // v2
currentManager->Shader( SHADER_STROKED_CIRCLE, 3.0, aRadius, lineWidth );
currentManager->Vertex( aCenterPoint.x, aCenterPoint.y + outerRadius * 2.0f, layerDepth ); // v2
}
return;
}
if( isStrokeEnabled )
else
{
// Compute the factors for the unit circle
double outerScale = lineWidth / aRadius / 2;
double innerScale = -outerScale;
outerScale += 1.0;
innerScale += 1.0;
if( innerScale < outerScale )
if( isStrokeEnabled )
{
// Draw the outline
VBO_VERTEX* circle = verticesCircle.GetVertices();
int next;
// Compute the factors for the unit circle
double outerScale = lineWidth / aRadius / 2;
double innerScale = -outerScale;
outerScale += 1.0;
innerScale += 1.0;
color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
if( innerScale < outerScale )
{
// Draw the outline
VERTEX* circle = circleContainer.GetAllVertices();
int next;
Save();
currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b,
strokeColor.a );
translate3( aCenterPoint.x, aCenterPoint.y, 0.0 );
Scale( VECTOR2D( aRadius, aRadius ) );
Save();
for( int i = 0; i < 3 * CIRCLE_POINTS; ++i )
{
// verticesCircle contains precomputed circle points interleaved with vertex
// (0,0,0), so filled circles can be drawn as consecutive triangles, ie:
// { 0,a,b, 0,c,d, 0,e,f, 0,g,h, ... }
// where letters stand for consecutive circle points and 0 for (0,0,0) vertex.
currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0 );
currentManager->Scale( aRadius, aRadius, 0.0f );
// We have to skip all (0,0,0) vertices (every third vertex)
if( i % 3 == 0)
for( int i = 0; i < 3 * CIRCLE_POINTS; ++i )
{
i++;
// Depending on the vertex, next circle point may be stored in the next vertex..
next = i + 1;
// verticesCircle contains precomputed circle points interleaved with vertex
// (0,0,0), so filled circles can be drawn as consecutive triangles, ie:
// { 0,a,b, 0,c,d, 0,e,f, 0,g,h, ... }
// where letters stand for consecutive circle points and 0 for (0,0,0) vertex.
// We have to skip all (0,0,0) vertices (every third vertex)
if( i % 3 == 0 )
{
i++;
// Depending on the vertex, next circle point may be stored in the next vertex..
next = i + 1;
}
else
{
// ..or 2 vertices away (in case it is preceded by (0,0,0) vertex)
next = i + 2;
}
currentManager->Vertex( circle[i].x * innerScale,
circle[i].y * innerScale,
layerDepth );
currentManager->Vertex( circle[i].x * outerScale,
circle[i].y * outerScale,
layerDepth );
currentManager->Vertex( circle[next].x * innerScale,
circle[next].y * innerScale,
layerDepth );
currentManager->Vertex( circle[i].x * outerScale,
circle[i].y * outerScale,
layerDepth );
currentManager->Vertex( circle[next].x * outerScale,
circle[next].y * outerScale,
layerDepth );
currentManager->Vertex( circle[next].x * innerScale,
circle[next].y * innerScale,
layerDepth );
}
else
{
// ..or 2 vertices away (in case it is preceded by (0,0,0) vertex)
next = i + 2;
}
vertex3( circle[i].x * innerScale, circle[i].y * innerScale, layerDepth );
vertex3( circle[i].x * outerScale, circle[i].y * outerScale, layerDepth );
vertex3( circle[next].x * innerScale, circle[next].y * innerScale, layerDepth );
vertex3( circle[i].x * outerScale, circle[i].y * outerScale, layerDepth );
vertex3( circle[next].x * outerScale, circle[next].y * outerScale, layerDepth );
vertex3( circle[next].x * innerScale, circle[next].y * innerScale, layerDepth );
Restore();
}
Restore();
}
}
// Filled circles are easy to draw by using the stored display list, scaling and translating
if( isFillEnabled )
{
color4( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
Save();
translate3( aCenterPoint.x, aCenterPoint.y, layerDepth );
Scale( VECTOR2D( aRadius, aRadius ) );
currentItem->PushVertices( verticesCircle.GetVertices(), CIRCLE_POINTS * 3 );
// Filled circles are easy to draw by using the stored vertices list, scaling and translating
if( isFillEnabled )
{
currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
Restore();
Save();
currentManager->Translate( aCenterPoint.x, aCenterPoint.y, layerDepth );
currentManager->Scale( aRadius, aRadius, 0.0f );
currentManager->Vertices( circleContainer.GetAllVertices(), CIRCLE_POINTS * 3 );
Restore();
}
}
}
void OPENGL_GAL::drawSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle )
{
if( isFillEnabled )
{
color4( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
drawFilledSemiCircle( aCenterPoint, aRadius, aAngle );
}
if( isFillEnabled )
{
currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
drawFilledSemiCircle( aCenterPoint, aRadius, aAngle );
}
if( isStrokeEnabled )
{
color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
drawStrokedSemiCircle( aCenterPoint, aRadius, aAngle );
}
if( isStrokeEnabled )
{
currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
drawStrokedSemiCircle( aCenterPoint, aRadius, aAngle );
}
}
void OPENGL_GAL::drawFilledSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle )
void OPENGL_GAL::drawFilledSemiCircle( const VECTOR2D& aCenterPoint, double aRadius,
double aAngle )
{
if( isUseShader )
{
Save();
Translate( aCenterPoint );
Rotate( aAngle );
currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0f );
currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
/* Draw a triangle that contains the semicircle, then shade it to leave only the semicircle.
Parameters given to setShader are indices of the triangle's vertices
......@@ -935,41 +799,42 @@ void OPENGL_GAL::drawFilledSemiCircle( const VECTOR2D& aCenterPoint, double aRad
/__\
v0 //__\\ v1
*/
setShader( SHADER_FILLED_CIRCLE, 4.0f );
vertex3( -aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0
currentManager->Shader( SHADER_FILLED_CIRCLE, 4.0f );
currentManager->Vertex( -aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0
setShader( SHADER_FILLED_CIRCLE, 5.0f );
vertex3( aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1
currentManager->Shader( SHADER_FILLED_CIRCLE, 5.0f );
currentManager->Vertex( aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1
setShader( SHADER_FILLED_CIRCLE, 6.0f );
vertex3( 0.0f, aRadius * 2.0f, layerDepth ); // v2
currentManager->Shader( SHADER_FILLED_CIRCLE, 6.0f );
currentManager->Vertex( 0.0f, aRadius * 2.0f, layerDepth ); // v2
Restore();
}
else
{
Save();
translate3( aCenterPoint.x, aCenterPoint.y, layerDepth );
Scale( VECTOR2D( aRadius, aRadius ) );
Rotate( aAngle );
currentManager->Translate( aCenterPoint.x, aCenterPoint.y, layerDepth );
currentManager->Scale( aRadius, aRadius, 0.0f );
currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
// It is enough just to push just a half of the circle vertices to make a semicircle
currentItem->PushVertices( verticesCircle.GetVertices(), CIRCLE_POINTS / 2 * 3 );
// It is enough just to draw a half of the circle vertices to make a semicircle
currentManager->Vertices( circleContainer.GetAllVertices(), ( CIRCLE_POINTS * 3 ) / 2 );
Restore();
}
}
void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle )
void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRadius,
double aAngle )
{
if( isUseShader )
{
double outerRadius = aRadius + ( lineWidth / 2 );
Save();
Translate( aCenterPoint );
Rotate( aAngle );
currentManager->Translate( aCenterPoint.x, aCenterPoint.y, 0.0f );
currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
/* Draw a triangle that contains the semicircle, then shade it to leave only the semicircle.
Parameters given to setShader are indices of the triangle's vertices
......@@ -981,14 +846,14 @@ void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRa
/__\
v0 //__\\ v1
*/
setShader( SHADER_STROKED_CIRCLE, 4.0f, aRadius, lineWidth );
vertex3( -outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0
currentManager->Shader( SHADER_STROKED_CIRCLE, 4.0f, aRadius, lineWidth );
currentManager->Vertex( -outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0
setShader( SHADER_STROKED_CIRCLE, 5.0f, aRadius, lineWidth );
vertex3( outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1
currentManager->Shader( SHADER_STROKED_CIRCLE, 5.0f, aRadius, lineWidth );
currentManager->Vertex( outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1
setShader( SHADER_STROKED_CIRCLE, 6.0f, aRadius, lineWidth );
vertex3( 0.0f, outerRadius * 2.0f, layerDepth ); // v2
currentManager->Shader( SHADER_STROKED_CIRCLE, 6.0f, aRadius, lineWidth );
currentManager->Vertex( 0.0f, outerRadius * 2.0f, layerDepth ); // v2
Restore();
}
......@@ -998,13 +863,13 @@ void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRa
double innerScale = 1.0 - lineWidth / aRadius;
Save();
translate3( aCenterPoint.x, aCenterPoint.y, layerDepth );
Scale( VECTOR2D( aRadius, aRadius ) );
Rotate( aAngle );
currentManager->Translate( aCenterPoint.x, aCenterPoint.y, layerDepth );
currentManager->Scale( aRadius, aRadius, 0.0f );
currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
// Draw the outline
VBO_VERTEX* circle = verticesCircle.GetVertices();
int next;
VERTEX* circle = circleContainer.GetAllVertices();
int next;
for( int i = 0; i < ( 3 * CIRCLE_POINTS ) / 2; ++i )
{
......@@ -1026,13 +891,13 @@ void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRa
next = i + 2;
}
vertex3( circle[i].x * innerScale, circle[i].y * innerScale, 0.0 );
vertex3( circle[i].x, circle[i].y, 0.0 );
vertex3( circle[next].x * innerScale, circle[next].y * innerScale, 0.0 );
currentManager->Vertex( circle[i].x * innerScale, circle[i].y * innerScale, 0.0 );
currentManager->Vertex( circle[i].x, circle[i].y, 0.0 );
currentManager->Vertex( circle[next].x * innerScale, circle[next].y * innerScale, 0.0 );
vertex3( circle[i].x, circle[i].y, 0.0 );
vertex3( circle[next].x, circle[next].y, 0.0 );
vertex3( circle[next].x * innerScale, circle[next].y * innerScale, 0.0 );
currentManager->Vertex( circle[i].x, circle[i].y, 0.0 );
currentManager->Vertex( circle[next].x, circle[next].y, 0.0 );
currentManager->Vertex( circle[next].x * innerScale, circle[next].y * innerScale, 0.0 );
}
Restore();
......@@ -1045,9 +910,7 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double a
double aEndAngle )
{
if( aRadius <= 0 )
{
return;
}
// Swap the angles, if start angle is greater than end angle
SWAP( aStartAngle, >, aEndAngle );
......@@ -1058,17 +921,17 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double a
VECTOR2D middlePoint = 0.5 * startEndPoint;
Save();
translate3( aCenterPoint.x, aCenterPoint.y, layerDepth );
currentManager->Translate( aCenterPoint.x, aCenterPoint.y, layerDepth );
if( isStrokeEnabled )
{
if( isUseShader )
{
double alphaIncrement = 2.0 * M_PI / CIRCLE_POINTS;
color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
VECTOR2D p( cos( aStartAngle ) * aRadius, sin( aStartAngle ) * aRadius );
double alpha;
double alpha;
for( alpha = aStartAngle + alphaIncrement; alpha < aEndAngle; alpha += alphaIncrement )
{
VECTOR2D p_next( cos( alpha ) * aRadius, sin( alpha ) * aRadius );
......@@ -1095,7 +958,8 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double a
innerScale += 1.0;
double alphaIncrement = 2 * M_PI / CIRCLE_POINTS;
color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
for( double alpha = aStartAngle; alpha < aEndAngle; )
{
......@@ -1110,13 +974,13 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double a
double v2[] = { cos( alpha ) * innerScale, sin( alpha ) * innerScale };
double v3[] = { cos( alpha ) * outerScale, sin( alpha ) * outerScale };
vertex3( v0[0], v0[1], 0.0 );
vertex3( v1[0], v1[1], 0.0 );
vertex3( v2[0], v2[1], 0.0 );
currentManager->Vertex( v0[0], v0[1], 0.0 );
currentManager->Vertex( v1[0], v1[1], 0.0 );
currentManager->Vertex( v2[0], v2[1], 0.0 );
vertex3( v1[0], v1[1], 0.0 );
vertex3( v3[0], v3[1], 0.0 );
vertex3( v2[0], v2[1], 0.0 );
currentManager->Vertex( v1[0], v1[1], 0.0 );
currentManager->Vertex( v3[0], v3[1], 0.0 );
currentManager->Vertex( v2[0], v2[1], 0.0 );
}
// Draw line caps
......@@ -1129,19 +993,19 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double a
{
double alphaIncrement = 2 * M_PI / CIRCLE_POINTS;
double alpha;
color4( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
for( alpha = aStartAngle; ( alpha + alphaIncrement ) < aEndAngle; )
{
vertex3( middlePoint.x, middlePoint.y, 0.0 );
vertex3( cos( alpha ), sin( alpha ), 0.0 );
currentManager->Vertex( middlePoint.x, middlePoint.y, 0.0 );
currentManager->Vertex( cos( alpha ), sin( alpha ), 0.0 );
alpha += alphaIncrement;
vertex3( cos( alpha ), sin( alpha ), 0.0 );
currentManager->Vertex( cos( alpha ), sin( alpha ), 0.0 );
}
vertex3( middlePoint.x, middlePoint.y, 0.0 );
vertex3( cos( alpha ), sin( alpha ), 0.0 );
vertex3( endPoint.x, endPoint.y, 0.0 );
currentManager->Vertex( middlePoint.x, middlePoint.y, 0.0 );
currentManager->Vertex( cos( alpha ), sin( alpha ), 0.0 );
currentManager->Vertex( endPoint.x, endPoint.y, 0.0 );
}
Restore();
......@@ -1181,8 +1045,7 @@ void OPENGL_GAL::DrawPolygon( const std::deque<VECTOR2D>& aPointList )
{
// Any non convex polygon needs to be tesselated
// for this purpose the GLU standard functions are used
setShader( SHADER_NONE );
currentManager->Shader( SHADER_NONE );
typedef std::vector<OGLPOINT> OGLPOINTS;
......@@ -1191,11 +1054,11 @@ void OPENGL_GAL::DrawPolygon( const std::deque<VECTOR2D>& aPointList )
OGLPOINTS vertexList( aPointList.size(), OGLPOINT( "fastest" ) );
glNormal3d( 0.0, 0.0, 1.0 );
color4( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
glShadeModel( GL_FLAT );
TessParams params = { currentItem, tessIntersects };
TessParams params = { currentManager, tessIntersects };
gluTessBeginPolygon( tesselator, &params );
gluTessBeginContour( tesselator );
......@@ -1213,10 +1076,12 @@ void OPENGL_GAL::DrawPolygon( const std::deque<VECTOR2D>& aPointList )
// Free allocated intersecting points
std::vector<GLdouble*>::iterator it, it_end;
for( it = tessIntersects.begin(), it_end = tessIntersects.end(); it < it_end; ++it )
{
delete[] *it;
}
tessIntersects.clear();
// vertexList destroyed here
......@@ -1261,7 +1126,7 @@ void OPENGL_GAL::SetStrokeColor( const COLOR4D& aColor )
strokeColor = aColor;
// This is the default drawing color
color4( aColor.r, aColor.g, aColor.b, aColor.a );
currentManager->Color( aColor.r, aColor.g, aColor.b, aColor.a );
}
......@@ -1315,19 +1180,19 @@ void OPENGL_GAL::Transform( MATRIX3x3D aTransformation )
void OPENGL_GAL::Rotate( double aAngle )
{
transform = glm::rotate( transform, (float) aAngle, glm::vec3( 0, 0, 1 ) );
currentManager->Rotate( aAngle, 0.0f, 0.0f, 1.0f );
}
void OPENGL_GAL::Translate( const VECTOR2D& aVector )
{
transform = glm::translate( transform, glm::vec3( aVector.x, aVector.y, 0 ) );
currentManager->Translate( aVector.x, aVector.y, 0.0f );
}
void OPENGL_GAL::Scale( const VECTOR2D& aScale )
{
transform = glm::scale( transform, glm::vec3( aScale.x, aScale.y, 0 ) );
currentManager->Scale( aScale.x, aScale.y, 0.0f );
}
......@@ -1339,21 +1204,13 @@ void OPENGL_GAL::Flush()
void OPENGL_GAL::Save()
{
transformStack.push( transform );
currentContainer->SetTransformMatrix( &transform );
currentManager->PushMatrix();
}
void OPENGL_GAL::Restore()
{
transform = transformStack.top();
transformStack.pop();
if( transformStack.empty() )
{
// Disable transforming, as the selected matrix is identity
currentContainer->SetTransformMatrix( NULL );
}
currentManager->PopMatrix();
}
......@@ -1361,14 +1218,10 @@ int OPENGL_GAL::BeginGroup()
{
isGrouping = true;
// There is a new group that is not in VBO yet
vboNeedsUpdate = true;
// Save the pointer for caching the current item
currentItem = new VBO_ITEM( &cachedVbo );
currentContainer = &cachedVbo;
int groupNumber = getGroupNumber();
groups.insert( std::make_pair( groupNumber, currentItem ) );
boost::shared_ptr<VERTEX_ITEM> newItem( new VERTEX_ITEM( cachedManager ) );
currentManager = &cachedManager;
int groupNumber = getNewGroupNumber();
groups.insert( std::make_pair( groupNumber, newItem ) );
return groupNumber;
}
......@@ -1376,9 +1229,7 @@ int OPENGL_GAL::BeginGroup()
void OPENGL_GAL::EndGroup()
{
currentItem->Finish();
currentItem = nonCachedItem;
currentContainer = &nonCachedVbo;
currentManager = &nonCachedManager;
isGrouping = false;
}
......@@ -1386,75 +1237,57 @@ void OPENGL_GAL::EndGroup()
void OPENGL_GAL::ClearCache()
{
BOOST_FOREACH( GroupsMap::value_type it, groups )
{
delete it.second;
}
groups.clear();
cachedManager.Clear();
}
void OPENGL_GAL::DeleteGroup( int aGroupNumber )
{
delete groups[aGroupNumber];
groups.erase( aGroupNumber );
vboNeedsUpdate = true;
}
void OPENGL_GAL::DrawGroup( int aGroupNumber )
{
int size = groups[aGroupNumber]->GetSize();
int offset = groups[aGroupNumber]->GetOffset();
// Copy indices of items that should be drawn to GPU memory
for( int i = offset; i < offset + size; *indicesPtr++ = i++ );
indicesSize += size;
cachedManager.DrawItem( *groups[aGroupNumber] );
}
void OPENGL_GAL::ChangeGroupColor( int aGroupNumber, const COLOR4D& aNewColor )
{
groups[aGroupNumber]->ChangeColor( aNewColor );
vboNeedsUpdate = true;
cachedManager.ChangeItemColor( *groups[aGroupNumber], aNewColor );
}
void OPENGL_GAL::ChangeGroupDepth( int aGroupNumber, int aDepth )
{
groups[aGroupNumber]->ChangeDepth( aDepth );
vboNeedsUpdate = true;
cachedManager.ChangeItemDepth( *groups[aGroupNumber], aDepth );
}
void OPENGL_GAL::computeCircleVbo()
void OPENGL_GAL::computeCircle()
{
// Compute the circle points for a given number of segments
// Insert in a display list and a vector
const VBO_VERTEX v0 = { 0.0f, 0.0f, 0.0f };
VERTEX* vertex = circleContainer.Allocate( CIRCLE_POINTS );
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 = {
cos( 2.0 * M_PI / CIRCLE_POINTS * i ), // x
sin( 2.0 * M_PI / CIRCLE_POINTS * i ), // y
0.0f // z
};
const VBO_VERTEX v2 = {
cos( 2.0 * M_PI / CIRCLE_POINTS * ( i + 1 ) ), // x
sin( 2.0 * M_PI / CIRCLE_POINTS * ( i + 1 ) ), // y
0.0f // z
};
verticesCircle.PushVertex( &v0 );
verticesCircle.PushVertex( &v1 );
verticesCircle.PushVertex( &v2 );
vertex->x = 0.0f;
vertex->y = 0.0f;
vertex->z = 0.0f;
vertex++;
vertex->x = cos( 2.0 * M_PI / CIRCLE_POINTS * i );
vertex->y = sin( 2.0 * M_PI / CIRCLE_POINTS * i );
vertex->z = 0.0f;
vertex++;
vertex->x = cos( 2.0 * M_PI / CIRCLE_POINTS * ( i + 1 ) );
vertex->y = sin( 2.0 * M_PI / CIRCLE_POINTS * ( i + 1 ) );
vertex->z = 0.0f;
vertex++;
}
verticesCircle.Finish();
}
......@@ -1495,13 +1328,10 @@ void CALLBACK VertexCallback( GLvoid* aVertexPtr, void* aData )
{
GLdouble* vertex = static_cast<GLdouble*>( aVertexPtr );
OPENGL_GAL::TessParams* param = static_cast<OPENGL_GAL::TessParams*>( aData );
VBO_ITEM* vboItem = param->vboItem;
VERTEX_MANAGER* vboManager = param->vboManager;
if( vboItem )
{
VBO_VERTEX newVertex = { vertex[0], vertex[1], vertex[2] };
vboItem->PushVertex( &newVertex );
}
if( vboManager )
vboManager->Vertex( vertex[0], vertex[1], vertex[2] );
}
......@@ -1524,7 +1354,6 @@ void CALLBACK CombineCallback( GLdouble coords[3],
void CALLBACK EdgeCallback(void)
{
// This callback is needed to force GLU tesselator to use triangles only
return;
}
......@@ -1650,19 +1479,19 @@ void OPENGL_GAL::DrawGridLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEnd
VECTOR2D point4 = aEndPoint - perpendicularVector;
// Set color
color4( gridColor.r, gridColor.g, gridColor.b, gridColor.a );
currentManager->Color( gridColor.r, gridColor.g, gridColor.b, gridColor.a );
setShader( SHADER_NONE );
currentManager->Shader( SHADER_NONE );
// Draw the quad for the grid line
double gridDepth = depthRange.y * 0.75;
vertex3( point1.x, point1.y, gridDepth );
vertex3( point2.x, point2.y, gridDepth );
vertex3( point4.x, point4.y, gridDepth );
currentManager->Vertex( point1.x, point1.y, gridDepth );
currentManager->Vertex( point2.x, point2.y, gridDepth );
currentManager->Vertex( point4.x, point4.y, gridDepth );
vertex3( point1.x, point1.y, gridDepth );
vertex3( point4.x, point4.y, gridDepth );
vertex3( point3.x, point3.y, gridDepth );
currentManager->Vertex( point1.x, point1.y, gridDepth );
currentManager->Vertex( point4.x, point4.y, gridDepth );
currentManager->Vertex( point3.x, point3.y, gridDepth );
}
......
/*
* 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:
void deinitSurface();
/**
* @brief Returns a valid key that can be used as a group number.
* @brief Returns a valid key that can be used as a new group number.
*
* @return An unique group number that is not used by any other group.
*/
unsigned int getGroupNumber();
unsigned int getNewGroupNumber();
};
} // namespace KiGfx
......
/*
* 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 @@
// GAL imports
#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/vertex_manager.h>
#include <gal/opengl/vertex_item.h>
#include <gal/opengl/noncached_container.h>
// wxWidgets imports
#include <wx/wx.h>
#include <wx/glcanvas.h>
// STL imports
#include <cmath>
#include <iterator>
#include <vector>
#include <algorithm>
#include <boost/unordered_map.hpp>
#include <memory>
#include <map>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <stdlib.h>
#include <iostream>
......@@ -312,7 +308,7 @@ public:
///< Parameters passed to the GLU tesselator
typedef struct
{
VBO_ITEM* vboItem; ///< VBO_ITEM for storing new vertices
VERTEX_MANAGER* vboManager; ///< VERTEX_ITEM for storing new vertices
std::vector<GLdouble*>& intersectPoints; ///< Intersect points, that have to be freed
} TessParams;
......@@ -325,11 +321,6 @@ private:
static const int CIRCLE_POINTS = 64; ///< The number of points for circle approximation
static const int CURVE_POINTS = 32; ///< The number of points for curve approximation
static const double MITER_LIMIT = 1.5; ///< Limit for mitered edges ( * lineWidth )
/// This factor is used to for correct merging of antialiased edges,
/// a very small value is required
static const double DEPTH_ADJUST_FACTOR = ( 1.0 / (1 << 23) );
wxClientDC* clientDC; ///< Drawing context
wxGLContext* glContext; ///< OpenGL context of wxWidgets
......@@ -338,43 +329,22 @@ private:
wxEvtHandler* paintListener;
// VBO buffered vertices for faster circle & semicircle drawing
VBO_CONTAINER precomputedContainer; ///< Container for storing display lists
VBO_ITEM verticesCircle; ///< Buffer for circle & semicircle vertices
NONCACHED_CONTAINER circleContainer; ///< Container for storing circle vertices
// Vertex buffer objects related fields
typedef boost::unordered_map<unsigned int, VBO_ITEM*> GroupsMap;
typedef std::map< unsigned int, boost::shared_ptr<VERTEX_ITEM> > GroupsMap;
GroupsMap groups; ///< Stores informations about VBO objects (groups)
unsigned int groupCounter; ///< Counter used for generating keys for groups
VBO_ITEM* currentItem; ///< Currently used VBO_ITEM (for grouping)
VBO_CONTAINER* currentContainer; ///< Currently used VBO_CONTAINER (for storing VBO_ITEMs)
VBO_CONTAINER cachedVbo; ///< Container for storing VBO_ITEMs
GLuint cachedVerts; ///< Currently used vertices VBO handle
GLuint cachedInds; ///< Currently used indices VBO handle
bool vboNeedsUpdate; ///< Flag indicating if VBO should be rebuilt
VBO_CONTAINER nonCachedVbo; ///< Container for storing non-cached VBO_ITEMs
VBO_ITEM* nonCachedItem; ///< Item that is gathering non-cached vertices
glm::mat4 transform; ///< Current transformation matrix
std::stack<glm::mat4> transformStack; ///< Stack of transformation matrices
int indicesSize; ///< Number of indices to be drawn
GLuint* indicesPtr; ///< Pointer to mapped GPU memory
VERTEX_MANAGER* currentManager; ///< Currently used VERTEX_MANAGER (for storing VERTEX_ITEMs)
VERTEX_MANAGER cachedManager; ///< Container for storing cached VERTEX_ITEMs
VERTEX_MANAGER nonCachedManager; ///< Container for storing non-cached VERTEX_ITEMs
// Polygon tesselation
GLUtesselator* tesselator; ///< Pointer to the tesselator
GLUtesselator* tesselator; ///< Pointer to the tesselator
std::vector<GLdouble*> tessIntersects; ///< Storage of intersecting points
// Shader
// Possible types of shaders
typedef enum
{
SHADER_NONE = 0,
SHADER_LINE,
SHADER_FILLED_CIRCLE,
SHADER_STROKED_CIRCLE,
} SHADER_TYPE;
SHADER shader; ///< There is only one shader used for different objects
int shaderAttrib; ///< Location of shader attributes (for glVertexAttribPointer)
// Cursor
int cursorSize; ///< Size of the cursor in pixels
......@@ -394,7 +364,6 @@ private:
// Internal flags
bool isGlewInitialized; ///< Is GLEW initialized?
bool isFrameBufferInitialized; ///< Are the frame buffers initialized?
bool isVboInitialized;
bool isShaderInitialized; ///< Was the shader initialized?
bool isUseShader; ///< Should the shaders be used?
bool isGrouping; ///< Was a group started?
......@@ -430,8 +399,8 @@ private:
*/
void drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle );
/// Compute the points of an unit circle & semicircle and store them in VBO.
void computeCircleVbo();
/// Compute the points of the unit circle and store them in VBO.
void computeCircle();
// Event handling
/**
......@@ -493,22 +462,6 @@ private:
*/
void deleteFrameBuffer( GLuint* aFrameBuffer, GLuint* aDepthBuffer, GLuint* aTexture );
/**
* @brief Initializes everything needed to use vertex buffer objects.
*/
void initVertexBufferObjects();
/**
* @brief Deinitializes everything when vertex buffer objects are not used anymore.
*/
void deleteVertexBufferObjects();
/**
* @brief Rebuilds vertex buffer object using stored VBO_ITEMS and sends it to
* the graphics card memory.
*/
void rebuildVbo();
/**
* @brief Draw a quad for the line.
*
......@@ -518,76 +471,11 @@ private:
inline void drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint );
/**
* @brief Returns a valid key that can be used as a group number.
* @brief Returns a valid key that can be used as a new group number.
*
* @return An unique group number that is not used by any other group.
*/
unsigned int getGroupNumber();
/**
* @brief Adds vertex to the current item or draws it in immediate mode.
* @param aX is X coordinate.
* @param aY is Y coordinate.
* @param aZ is Z coordinate.
*/
inline void vertex3( double aX, double aY, double aZ )
{
// New vertex coordinates for VBO
const VBO_VERTEX vertex = { aX, aY, aZ };
currentItem->PushVertex( &vertex );
}
/**
* @brief Function that replaces glTranslate. It modifies transformation matrix.
*
* @param aX is translation in X axis direction.
* @param aY is translation in Y axis direction.
* @param aZ is translation in Z axis direction.
*/
inline void translate3( double aX, double aY, double aZ )
{
transform = glm::translate( transform, glm::vec3( aX, aY, aZ ) );
}
/**
* @brief Function that replaces glColor. It modifies color used by current VBO_ITEM.
*
* @param aR is red component.
* @param aG is green component.
* @param aB is blue component.
* @param aA is alpha component.
*/
inline void color4( double aRed, double aGreen, double aBlue, double aAlpha )
{
currentContainer->UseColor( aRed, aGreen, aBlue, aAlpha );
}
/**
* @brief Function that replaces glColor. It modifies color used by current VBO_ITEM.
*
* @param aColor is the new color.
*/
inline void color4( const COLOR4D& aColor )
{
currentContainer->UseColor( aColor );
}
/**
* @brief Function that sets shader and its parameters for the currently used VBO_ITEM.
* It should be used before adding any vertices that have to be shaded.
* @param aShader is the type of shader used for vertices.
* @param aParam[1..3] are shader's parameters. Their meaning depends on the type of used shader.
* For more information you may check shaders' source code.
*/
inline void setShader( SHADER_TYPE aShader, GLfloat aParam1 = 0.0f,
GLfloat aParam2 = 0.0f, GLfloat aParam3 = 0.0f )
{
if( isUseShader )
{
const GLfloat shader[] = { aShader, aParam1, aParam2, aParam3 };
currentContainer->UseShader( shader );
}
}
unsigned int getNewGroupNumber();
};
} // namespace KiGfx
......
/*
* 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 @@
*/
/**
* @file vbo_item.h
* @brief Class to handle an item held in a Vertex Buffer Object.
* @file vertex_item.h
* @brief Class to handle an item held in a container.
*/
#ifndef VBO_ITEM_H_
#define VBO_ITEM_H_
#ifndef VERTEX_ITEM_H_
#define VERTEX_ITEM_H_
#include <GL/gl.h>
#include <gal/opengl/vertex_common.h>
#include <gal/color4d.h>
#include <cstddef>
namespace KiGfx
{
typedef struct VBO_VERTEX
{
GLfloat x, y, z; // Coordinates
GLubyte r, g, b, a; // Color
GLfloat shader[4]; // Shader type & params
} VBO_VERTEX;
class VBO_CONTAINER;
class VERTEX_MANAGER;
class VBO_ITEM
class VERTEX_ITEM
{
friend class VBO_CONTAINER;
public:
VBO_ITEM( VBO_CONTAINER* aContainer );
~VBO_ITEM();
/**
* Function PushVertex()
* Adds a single vertex to the VBO_ITEM. Vertex contains information about coordinates and
* colors and has to follow the specified format {X,Y,Z,R,G,B,A}.
* @param aVertex is a vertex to be added.
* @param aShader is an attribute for shader.
*/
void PushVertex( const VBO_VERTEX* aVertex );
/**
* Function PushVertices()
* Adds multiple vertices to the VBO_ITEM. This function is recommended over multiple calls to
* PushVertex, as it does less memory reallocations. Vertices contain information about
* coordinates and colors and has to follow the specified format {X,Y,Z,R,G,B,A}.
* @param aVertices are vertices to be added.
* @param aSize is an amount of vertices to be added.
* @param aShader is an attribute for shader.
*/
void PushVertices( const VBO_VERTEX* aVertices, GLuint aSize );
/**
* Function GetVertices()
* Returns a pointer to the array containing all vertices.
* @return Pointer to vertices packed in format {X, Y, Z, R, G, B, A}.
*/
VBO_VERTEX* GetVertices();
friend class CACHED_CONTAINER;
friend class VERTEX_MANAGER;
VERTEX_ITEM( const VERTEX_MANAGER& aManager );
virtual ~VERTEX_ITEM();
/**
* Function GetSize()
* Returns information about number of vertices stored.
* @param Amount of vertices.
* @param Number of vertices.
*/
inline unsigned int GetSize() const
{
......@@ -93,7 +59,7 @@ public:
/**
* Function GetOffset()
* Returns data offset in the VBO.
* Returns data offset in the container.
* @return Data offset expressed as a number of vertices.
*/
inline unsigned int GetOffset() const
......@@ -102,76 +68,36 @@ public:
}
/**
* Function ChangeColor()
* Colors all vertices to the specified color.
* @param aColor is the new color for vertices.
*/
void ChangeColor( const COLOR4D& aColor );
/**
* Function ChangeDepth()
* Moves all vertices to the specified depth.
* @param aDepth is the new depth for vertices.
* Function GetVertices()
* Returns pointer to the data used by the VERTEX_ITEM.
*/
void ChangeDepth( int aDepth );
///< Informs the container that there will be no more vertices for the current VBO_ITEM
void Finish();
VERTEX* GetVertices() const;
///< Data structure for vertices {X,Y,Z,R,G,B,A,shader&param} (@see VBO_VERTEX).
static const unsigned int VertByteSize = sizeof(VBO_VERTEX);
static const unsigned int VertStride = VertByteSize / sizeof(GLfloat);
static const unsigned int CoordByteSize = sizeof(VBO_VERTEX().x) + sizeof(VBO_VERTEX().y) +
sizeof(VBO_VERTEX().z);
static const unsigned int CoordStride = CoordByteSize / sizeof(GLfloat);
// Offset of color data from the beginning of each vertex data
static const unsigned int ColorByteOffset = offsetof(VBO_VERTEX, r);
static const unsigned int ColorOffset = ColorByteOffset / sizeof(GLubyte);
static const unsigned int ColorByteSize = sizeof(VBO_VERTEX().r) + sizeof(VBO_VERTEX().g) +
sizeof(VBO_VERTEX().b) + sizeof(VBO_VERTEX().a);
static const unsigned int ColorStride = ColorByteSize / sizeof(GLubyte);
// Shader attributes
static const unsigned int ShaderByteOffset = offsetof(VBO_VERTEX, shader);
static const unsigned int ShaderOffset = ShaderByteOffset / sizeof(GLfloat);
static const unsigned int ShaderByteSize = sizeof(VBO_VERTEX().shader);
static const unsigned int ShaderStride = ShaderByteSize / sizeof(GLfloat);
static const unsigned int IndByteSize = sizeof(GLuint);
protected:
///< Offset and size of data stored in the VBO_CONTAINER.
unsigned int m_offset;
unsigned int m_size;
///< Storage for vertices.
VBO_CONTAINER* m_container;
///< Flag telling if the item should be recached in VBO or not.
bool m_isDirty;
private:
const VERTEX_MANAGER& m_manager;
unsigned int m_offset;
unsigned int m_size;
/**
* Function setSize()
* Sets data size in the VBO.
* @param aSize is the size expressed as a number of vertices.
* Function SetOffset()
* Sets data offset in the container.
* @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()
* Sets data offset in the VBO.
* @param aOffset is the offset expressed as a number of vertices.
* Function SetSize()
* Sets data size in the container.
* @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
#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