Commit 190ed585 authored by Maciej Suminski's avatar Maciej Suminski

Code refactoring.

parent 790a1f85
......@@ -34,7 +34,7 @@
using namespace KiGfx;
CAIRO_COMPOSITOR::CAIRO_COMPOSITOR( cairo_t** aMainContext ) :
m_current( 0 ), m_currentContext( aMainContext ), m_mainContext( *aMainContext )
m_current( 0 ), m_currentContext( aMainContext ), m_mainContext( *aMainContext )
{
// Obtain the transformation matrix used in the main context
cairo_get_matrix( m_mainContext, &m_matrix );
......@@ -69,6 +69,7 @@ unsigned int CAIRO_COMPOSITOR::GetBuffer()
{
// Pixel storage
BitmapPtr bitmap( new unsigned int[m_bufferSize] );
memset( bitmap.get(), 0x00, m_bufferSize * sizeof(int) );
// Create the Cairo surface
......@@ -105,6 +106,7 @@ void CAIRO_COMPOSITOR::SetBuffer( unsigned int aBufferHandle )
m_current = aBufferHandle - 1;
*m_currentContext = m_buffers[m_current].context;
}
#ifdef __WXDEBUG__
else
wxLogDebug( wxT( "Tried to use a not existing buffer" ) );
......@@ -141,6 +143,7 @@ void CAIRO_COMPOSITOR::DrawBuffer( unsigned int aBufferHandle )
// Restore the transformation matrix
cairo_set_matrix( m_mainContext, &m_matrix );
}
#ifdef __WXDEBUG__
else
wxLogDebug( wxT( "Tried to use a not existing buffer" ) );
......
......@@ -87,117 +87,7 @@ CAIRO_GAL::~CAIRO_GAL()
}
void CAIRO_GAL::onPaint( wxPaintEvent& aEvent )
{
PostPaint();
}
void CAIRO_GAL::ResizeScreen( int aWidth, int aHeight )
{
screenSize = VECTOR2D( aWidth, aHeight );
// Recreate the bitmaps
deleteBitmaps();
allocateBitmaps();
SetSize( wxSize( aWidth, aHeight ) );
}
void CAIRO_GAL::skipMouseEvent( wxMouseEvent& aEvent )
{
// Post the mouse event to the event listener registered in constructor, if any
if( mouseListener )
wxPostEvent( mouseListener, aEvent );
}
void CAIRO_GAL::initSurface()
{
wxASSERT( !isInitialized );
// Create the Cairo surface
surface = cairo_image_surface_create_for_data( (unsigned char*) bitmapBuffer, GAL_FORMAT,
screenSize.x, screenSize.y, stride );
context = cairo_create( surface );
#ifdef __WXDEBUG__
cairo_status_t status = cairo_status( context );
wxASSERT_MSG( status == CAIRO_STATUS_SUCCESS, "Cairo context creation error" );
#endif /* __WXDEBUG__ */
currentContext = context;
cairo_set_antialias( context, CAIRO_ANTIALIAS_SUBPIXEL );
// Clear the screen
ClearScreen();
// Compute the world <-> screen transformations
ComputeWorldScreenMatrix();
cairo_matrix_init( &cairoWorldScreenMatrix, worldScreenMatrix.m_data[0][0],
worldScreenMatrix.m_data[1][0], worldScreenMatrix.m_data[0][1],
worldScreenMatrix.m_data[1][1], worldScreenMatrix.m_data[0][2],
worldScreenMatrix.m_data[1][2] );
cairo_set_matrix( context, &cairoWorldScreenMatrix );
isSetAttributes = false;
// Start drawing with a new path
cairo_new_path( context );
isElementAdded = true;
cairo_set_line_join( context, CAIRO_LINE_JOIN_ROUND );
cairo_set_line_cap( context, CAIRO_LINE_CAP_ROUND );
lineWidth = 0;
isDeleteSavedPixels = true;
isInitialized = true;
}
void CAIRO_GAL::deinitSurface()
{
if( !isInitialized )
return;
// Destroy Cairo objects
cairo_destroy( context );
cairo_surface_destroy( surface );
isInitialized = false;
}
void CAIRO_GAL::setCompositor()
{
// Recreate the compositor with the new Cairo context
compositor.reset( new CAIRO_COMPOSITOR( &currentContext ) );
compositor->Resize( screenSize.x, screenSize.y );
// Prepare buffers
mainBuffer = compositor->GetBuffer();
overlayBuffer = compositor->GetBuffer();
}
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" ) );
while( groups.find( groupCounter ) != groups.end() )
{
groupCounter++;
}
return groupCounter++;
}
void CAIRO_GAL::BeginDrawing() throw( int )
void CAIRO_GAL::BeginDrawing()
{
initSurface();
setCompositor();
......@@ -245,65 +135,6 @@ void CAIRO_GAL::EndDrawing()
}
void CAIRO_GAL::SaveScreen()
{
// Copy the current bitmap to the backup buffer
int offset = 0;
for( int j = 0; j < screenSize.y; j++ )
{
for( int i = 0; i < stride; i++ )
{
bitmapBufferBackup[offset + i] = bitmapBuffer[offset + i];
offset += stride;
}
}
}
void CAIRO_GAL::RestoreScreen()
{
int offset = 0;
for( int j = 0; j < screenSize.y; j++ )
{
for( int i = 0; i < stride; i++ )
{
bitmapBuffer[offset + i] = bitmapBufferBackup[offset + i];
offset += stride;
}
}
}
void CAIRO_GAL::SetTarget( RenderTarget aTarget )
{
// If the compositor is not set, that means that there is a recaching process going on
// and we do not need the compositor now
if( !compositor )
return;
// Cairo grouping prevents display of overlapping items on the same layer in the lighter color
cairo_pop_group_to_source( currentContext );
cairo_paint_with_alpha( currentContext, fillColor.a );
switch( aTarget )
{
default:
case TARGET_CACHED:
case TARGET_NONCACHED:
compositor->SetBuffer( mainBuffer );
break;
case TARGET_OVERLAY:
compositor->SetBuffer( overlayBuffer );
break;
}
cairo_push_group( currentContext );
}
void CAIRO_GAL::DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
{
cairo_move_to( currentContext, aStartPoint.x, aStartPoint.y );
......@@ -335,7 +166,7 @@ void CAIRO_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPo
cairo_translate( currentContext, aStartPoint.x, aStartPoint.y );
cairo_rotate( currentContext, lineAngle );
cairo_arc( currentContext, 0.0, 0.0, aWidth / 2.0, M_PI / 2.0, 3.0 * M_PI / 2.0 );
cairo_arc( currentContext, 0.0, 0.0, aWidth / 2.0, M_PI / 2.0, 3.0 * M_PI / 2.0 );
cairo_arc( currentContext, lineLength, 0.0, aWidth / 2.0, -M_PI / 2.0, M_PI / 2.0 );
cairo_move_to( currentContext, 0.0, aWidth / 2.0 );
......@@ -373,12 +204,30 @@ void CAIRO_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double aS
}
void CAIRO_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
{
// Calculate the diagonal points
VECTOR2D diagonalPointA( aEndPoint.x, aStartPoint.y );
VECTOR2D diagonalPointB( aStartPoint.x, aEndPoint.y );
// The path is composed from 4 segments
cairo_move_to( currentContext, aStartPoint.x, aStartPoint.y );
cairo_line_to( currentContext, diagonalPointA.x, diagonalPointA.y );
cairo_line_to( currentContext, aEndPoint.x, aEndPoint.y );
cairo_line_to( currentContext, diagonalPointB.x, diagonalPointB.y );
cairo_close_path( currentContext );
isElementAdded = true;
}
void CAIRO_GAL::DrawPolyline( std::deque<VECTOR2D>& aPointList )
{
// Iterate over the point list and draw the segments
std::deque<VECTOR2D>::const_iterator it = aPointList.begin();
cairo_move_to( currentContext, it->x, it->y );
for( ++it; it != aPointList.end(); ++it )
{
cairo_line_to( currentContext, it->x, it->y );
......@@ -394,6 +243,7 @@ void CAIRO_GAL::DrawPolygon( const std::deque<VECTOR2D>& aPointList )
std::deque<VECTOR2D>::const_iterator it = aPointList.begin();
cairo_move_to( currentContext, it->x, it->y );
for( ++it; it != aPointList.end(); ++it )
{
cairo_line_to( currentContext, it->x, it->y );
......@@ -403,38 +253,53 @@ void CAIRO_GAL::DrawPolygon( const std::deque<VECTOR2D>& aPointList )
}
void CAIRO_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
void CAIRO_GAL::DrawCurve( const VECTOR2D& aStartPoint, const VECTOR2D& aControlPointA,
const VECTOR2D& aControlPointB, const VECTOR2D& aEndPoint )
{
// Calculate the diagonal points
VECTOR2D diagonalPointA( aEndPoint.x, aStartPoint.y );
VECTOR2D diagonalPointB( aStartPoint.x, aEndPoint.y );
// The path is composed from 4 segments
cairo_move_to( currentContext, aStartPoint.x, aStartPoint.y );
cairo_line_to( currentContext, diagonalPointA.x, diagonalPointA.y );
cairo_curve_to( currentContext, aControlPointA.x, aControlPointA.y, aControlPointB.x,
aControlPointB.y, aEndPoint.x, aEndPoint.y );
cairo_line_to( currentContext, aEndPoint.x, aEndPoint.y );
cairo_line_to( currentContext, diagonalPointB.x, diagonalPointB.y );
cairo_close_path( currentContext );
isElementAdded = true;
}
void CAIRO_GAL::DrawCurve( const VECTOR2D& aStartPoint, const VECTOR2D& aControlPointA,
const VECTOR2D& aControlPointB, const VECTOR2D& aEndPoint )
void CAIRO_GAL::ResizeScreen( int aWidth, int aHeight )
{
cairo_move_to( currentContext, aStartPoint.x, aStartPoint.y );
cairo_curve_to( currentContext, aControlPointA.x, aControlPointA.y, aControlPointB.x,
aControlPointB.y, aEndPoint.x, aEndPoint.y );
cairo_line_to( currentContext, aEndPoint.x, aEndPoint.y );
screenSize = VECTOR2D( aWidth, aHeight );
isElementAdded = true;
// Recreate the bitmaps
deleteBitmaps();
allocateBitmaps();
SetSize( wxSize( aWidth, aHeight ) );
}
bool CAIRO_GAL::Show( bool aShow )
{
bool s = wxWindow::Show( aShow );
if( aShow )
wxWindow::Raise();
return s;
}
void CAIRO_GAL::Flush()
{
storePath();
}
void CAIRO_GAL::SetBackgroundColor( const COLOR4D& aColor )
void CAIRO_GAL::ClearScreen()
{
backgroundColor = aColor;
cairo_set_source_rgb( currentContext,
backgroundColor.r, backgroundColor.g, backgroundColor.b );
cairo_rectangle( currentContext, 0.0, 0.0, screenSize.x, screenSize.y );
cairo_fill( currentContext );
}
......@@ -528,15 +393,6 @@ void CAIRO_GAL::SetLineWidth( double aLineWidth )
}
void CAIRO_GAL::ClearScreen()
{
cairo_set_source_rgb( currentContext,
backgroundColor.r, backgroundColor.g, backgroundColor.b );
cairo_rectangle( currentContext, 0.0, 0.0, screenSize.x, screenSize.y );
cairo_fill( currentContext );
}
void CAIRO_GAL::SetLayerDepth( double aLayerDepth )
{
super::SetLayerDepth( aLayerDepth );
......@@ -686,39 +542,10 @@ void CAIRO_GAL::EndGroup()
}
void CAIRO_GAL::ClearCache()
void CAIRO_GAL::DrawGroup( int aGroupNumber )
{
for( int i = groups.size() - 1; i >= 0; --i )
{
DeleteGroup( i );
}
}
void CAIRO_GAL::DeleteGroup( int aGroupNumber )
{
storePath();
// 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 )
{
cairo_path_destroy( it->cairoPath );
}
}
// Delete the group
groups.erase( aGroupNumber );
}
void CAIRO_GAL::DrawGroup( int aGroupNumber )
{
// This method implements a small Virtual Machine - all stored commands
// are executed; nested calling is also possible
// This method implements a small Virtual Machine - all stored commands
// are executed; nested calling is also possible
storePath();
......@@ -828,31 +655,147 @@ void CAIRO_GAL::ChangeGroupDepth( int aGroupNumber, int aDepth )
}
void CAIRO_GAL::Flush()
void CAIRO_GAL::DeleteGroup( int aGroupNumber )
{
storePath();
// 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 )
{
cairo_path_destroy( it->cairoPath );
}
}
// Delete the group
groups.erase( aGroupNumber );
}
void CAIRO_GAL::ClearCache()
{
for( int i = groups.size() - 1; i >= 0; --i )
{
DeleteGroup( i );
}
}
void CAIRO_GAL::SaveScreen()
{
// Copy the current bitmap to the backup buffer
int offset = 0;
for( int j = 0; j < screenSize.y; j++ )
{
for( int i = 0; i < stride; i++ )
{
bitmapBufferBackup[offset + i] = bitmapBuffer[offset + i];
offset += stride;
}
}
}
void CAIRO_GAL::RestoreScreen()
{
int offset = 0;
for( int j = 0; j < screenSize.y; j++ )
{
for( int i = 0; i < stride; i++ )
{
bitmapBuffer[offset + i] = bitmapBufferBackup[offset + i];
offset += stride;
}
}
}
void CAIRO_GAL::SetTarget( RenderTarget aTarget )
{
// If the compositor is not set, that means that there is a recaching process going on
// and we do not need the compositor now
if( !compositor )
return;
// Cairo grouping prevents display of overlapping items on the same layer in the lighter color
cairo_pop_group_to_source( currentContext );
cairo_paint_with_alpha( currentContext, fillColor.a );
switch( aTarget )
{
default:
case TARGET_CACHED:
case TARGET_NONCACHED:
compositor->SetBuffer( mainBuffer );
break;
case TARGET_OVERLAY:
compositor->SetBuffer( overlayBuffer );
break;
}
cairo_push_group( currentContext );
}
VECTOR2D CAIRO_GAL::ComputeCursorToWorld( const VECTOR2D& aCursorPosition )
{
MATRIX3x3D inverseMatrix = worldScreenMatrix.Inverse();
VECTOR2D cursorPositionWorld = inverseMatrix * aCursorPosition;
return cursorPositionWorld;
}
void CAIRO_GAL::ComputeWorldScreenMatrix()
void CAIRO_GAL::DrawCursor( VECTOR2D aCursorPosition )
{
ComputeWorldScale();
if( !IsShownOnScreen() )
return;
wxClientDC clientDC( this );
wxMemoryDC cursorSave( *cursorPixelsSaved );
wxMemoryDC cursorShape( *cursorPixels );
// Snap to grid
VECTOR2D cursorPositionWorld = ComputeCursorToWorld( aCursorPosition );
worldScreenMatrix.SetIdentity();
cursorPositionWorld.x = round( cursorPositionWorld.x / gridSize.x ) * gridSize.x;
cursorPositionWorld.y = round( cursorPositionWorld.y / gridSize.y ) * gridSize.y;
aCursorPosition = worldScreenMatrix * cursorPositionWorld;
aCursorPosition = aCursorPosition - VECTOR2D( cursorSize / 2, cursorSize / 2 );
if( !isDeleteSavedPixels )
{
clientDC.Blit( savedCursorPosition.x, savedCursorPosition.y, cursorSize, cursorSize,
&cursorSave, 0, 0 );
}
else
{
isDeleteSavedPixels = false;
}
cursorSave.Blit( 0, 0, cursorSize, cursorSize, &clientDC, aCursorPosition.x,
aCursorPosition.y );
MATRIX3x3D translation;
translation.SetIdentity();
translation.SetTranslation( 0.5 * screenSize );
clientDC.Blit( aCursorPosition.x, aCursorPosition.y, cursorSize, cursorSize, &cursorShape, 0,
0, wxOR );
MATRIX3x3D scale;
scale.SetIdentity();
scale.SetScale( VECTOR2D( worldScale, worldScale ) );
savedCursorPosition.x = (wxCoord) aCursorPosition.x;
savedCursorPosition.y = (wxCoord) aCursorPosition.y;
}
MATRIX3x3D lookat;
lookat.SetIdentity();
lookat.SetTranslation( -lookAtPoint );
worldScreenMatrix = translation * scale * lookat * worldScreenMatrix;
void CAIRO_GAL::drawGridLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
{
cairo_move_to( currentContext, aStartPoint.x, aStartPoint.y );
cairo_line_to( currentContext, aEndPoint.x, aEndPoint.y );
cairo_set_source_rgb( currentContext, gridColor.r, gridColor.g, gridColor.b );
cairo_stroke( currentContext );
}
......@@ -872,7 +815,8 @@ void CAIRO_GAL::storePath()
if( isStrokeEnabled )
{
cairo_set_source_rgb( currentContext, strokeColor.r, strokeColor.g, strokeColor.b );
cairo_set_source_rgb( currentContext, strokeColor.r, strokeColor.g,
strokeColor.b );
cairo_stroke_preserve( currentContext );
}
}
......@@ -903,9 +847,18 @@ void CAIRO_GAL::storePath()
}
// ---------------
// Cursor handling
// ---------------
void CAIRO_GAL::onPaint( wxPaintEvent& aEvent )
{
PostPaint();
}
void CAIRO_GAL::skipMouseEvent( wxMouseEvent& aEvent )
{
// Post the mouse event to the event listener registered in constructor, if any
if( mouseListener )
wxPostEvent( mouseListener, aEvent );
}
void CAIRO_GAL::initCursor( int aCursorSize )
......@@ -919,7 +872,7 @@ void CAIRO_GAL::initCursor( int aCursorSize )
cursorShape.SetBackground( *wxTRANSPARENT_BRUSH );
wxColour color( cursorColor.r * cursorColor.a * 255, cursorColor.g * cursorColor.a * 255,
cursorColor.b * cursorColor.a * 255, 255 );
wxPen pen = wxPen( color );
wxPen pen = wxPen( color );
cursorShape.SetPen( pen );
cursorShape.Clear();
......@@ -928,88 +881,103 @@ void CAIRO_GAL::initCursor( int aCursorSize )
}
VECTOR2D CAIRO_GAL::ComputeCursorToWorld( const VECTOR2D& aCursorPosition )
void CAIRO_GAL::allocateBitmaps()
{
MATRIX3x3D inverseMatrix = worldScreenMatrix.Inverse();
VECTOR2D cursorPositionWorld = inverseMatrix * aCursorPosition;
// Create buffer, use the system independent Cairo context backend
stride = cairo_format_stride_for_width( GAL_FORMAT, screenSize.x );
bufferSize = stride * screenSize.y;
return cursorPositionWorld;
bitmapBuffer = new unsigned int[bufferSize];
bitmapBufferBackup = new unsigned int[bufferSize];
wxOutput = new unsigned char[bufferSize * 3];
}
void CAIRO_GAL::DrawCursor( VECTOR2D aCursorPosition )
void CAIRO_GAL::deleteBitmaps()
{
if( !IsShownOnScreen() )
return;
delete[] bitmapBuffer;
delete[] bitmapBufferBackup;
delete[] wxOutput;
}
wxClientDC clientDC( this );
wxMemoryDC cursorSave( *cursorPixelsSaved );
wxMemoryDC cursorShape( *cursorPixels );
// Snap to grid
VECTOR2D cursorPositionWorld = ComputeCursorToWorld( aCursorPosition );
void CAIRO_GAL::initSurface()
{
wxASSERT( !isInitialized );
cursorPositionWorld.x = round( cursorPositionWorld.x / gridSize.x ) * gridSize.x;
cursorPositionWorld.y = round( cursorPositionWorld.y / gridSize.y ) * gridSize.y;
aCursorPosition = worldScreenMatrix * cursorPositionWorld;
aCursorPosition = aCursorPosition - VECTOR2D( cursorSize / 2, cursorSize / 2 );
// Create the Cairo surface
surface = cairo_image_surface_create_for_data( (unsigned char*) bitmapBuffer, GAL_FORMAT,
screenSize.x, screenSize.y, stride );
context = cairo_create( surface );
#ifdef __WXDEBUG__
cairo_status_t status = cairo_status( context );
wxASSERT_MSG( status == CAIRO_STATUS_SUCCESS, "Cairo context creation error" );
#endif /* __WXDEBUG__ */
currentContext = context;
if( !isDeleteSavedPixels )
{
clientDC.Blit( savedCursorPosition.x, savedCursorPosition.y, cursorSize, cursorSize,
&cursorSave, 0, 0 );
}
else
{
isDeleteSavedPixels = false;
}
cairo_set_antialias( context, CAIRO_ANTIALIAS_SUBPIXEL );
cursorSave.Blit( 0, 0, cursorSize, cursorSize, &clientDC, aCursorPosition.x,
aCursorPosition.y );
// Clear the screen
ClearScreen();
clientDC.Blit( aCursorPosition.x, aCursorPosition.y, cursorSize, cursorSize, &cursorShape, 0,
0, wxOR );
// Compute the world <-> screen transformations
ComputeWorldScreenMatrix();
savedCursorPosition.x = (wxCoord) aCursorPosition.x;
savedCursorPosition.y = (wxCoord) aCursorPosition.y;
}
cairo_matrix_init( &cairoWorldScreenMatrix, worldScreenMatrix.m_data[0][0],
worldScreenMatrix.m_data[1][0], worldScreenMatrix.m_data[0][1],
worldScreenMatrix.m_data[1][1], worldScreenMatrix.m_data[0][2],
worldScreenMatrix.m_data[1][2] );
cairo_set_matrix( context, &cairoWorldScreenMatrix );
void CAIRO_GAL::DrawGridLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
{
cairo_move_to( currentContext, aStartPoint.x, aStartPoint.y );
cairo_line_to( currentContext, aEndPoint.x, aEndPoint.y );
cairo_set_source_rgb( currentContext, gridColor.r, gridColor.g, gridColor.b );
cairo_stroke( currentContext );
// Start drawing with a new path
cairo_new_path( context );
isElementAdded = true;
cairo_set_line_join( context, CAIRO_LINE_JOIN_ROUND );
cairo_set_line_cap( context, CAIRO_LINE_CAP_ROUND );
lineWidth = 0;
isDeleteSavedPixels = true;
isInitialized = true;
}
void CAIRO_GAL::allocateBitmaps()
void CAIRO_GAL::deinitSurface()
{
// Create buffer, use the system independent Cairo context backend
stride = cairo_format_stride_for_width( GAL_FORMAT, screenSize.x );
bufferSize = stride * screenSize.y;
if( !isInitialized )
return;
bitmapBuffer = new unsigned int[bufferSize];
bitmapBufferBackup = new unsigned int[bufferSize];
wxOutput = new unsigned char[bufferSize * 3];
// Destroy Cairo objects
cairo_destroy( context );
cairo_surface_destroy( surface );
isInitialized = false;
}
void CAIRO_GAL::deleteBitmaps()
void CAIRO_GAL::setCompositor()
{
delete[] bitmapBuffer;
delete[] bitmapBufferBackup;
delete[] wxOutput;
// Recreate the compositor with the new Cairo context
compositor.reset( new CAIRO_COMPOSITOR( &currentContext ) );
compositor->Resize( screenSize.x, screenSize.y );
// Prepare buffers
mainBuffer = compositor->GetBuffer();
overlayBuffer = compositor->GetBuffer();
}
bool CAIRO_GAL::Show( bool aShow )
unsigned int CAIRO_GAL::getNewGroupNumber()
{
bool s = wxWindow::Show( aShow );
wxASSERT_MSG( groups.size() < std::numeric_limits<unsigned int>::max(),
wxT( "There are no free slots to store a group" ) );
if( aShow )
wxWindow::Raise();
while( groups.find( groupCounter ) != groups.end() )
{
groupCounter++;
}
return s;
return groupCounter++;
}
......@@ -63,6 +63,33 @@ GAL::~GAL()
}
void GAL::ComputeWorldScreenMatrix()
{
ComputeWorldScale();
worldScreenMatrix.SetIdentity();
MATRIX3x3D translation;
translation.SetIdentity();
translation.SetTranslation( 0.5 * screenSize );
MATRIX3x3D scale;
scale.SetIdentity();
scale.SetScale( VECTOR2D( worldScale, worldScale ) );
MATRIX3x3D flip;
flip.SetIdentity();
flip.SetScale( VECTOR2D( 1.0, 1.0 ) );
MATRIX3x3D lookat;
lookat.SetIdentity();
lookat.SetTranslation( -lookAtPoint );
worldScreenMatrix = translation * flip * scale * lookat * worldScreenMatrix;
}
void GAL::DrawGrid()
{
if( !gridVisibility )
......@@ -136,7 +163,7 @@ void GAL::DrawGrid()
if( ( j % gridTick == 0 && gridScreenSizeCoarse > gridDrawThreshold )
|| gridScreenSizeDense > gridDrawThreshold )
{
DrawGridLine( VECTOR2D( gridStartX * gridSize.x, j * gridSize.y ),
drawGridLine( VECTOR2D( gridStartX * gridSize.x, j * gridSize.y ),
VECTOR2D( gridEndX * gridSize.x, j * gridSize.y ) );
}
}
......@@ -155,7 +182,7 @@ void GAL::DrawGrid()
if( ( i % gridTick == 0 && gridScreenSizeCoarse > gridDrawThreshold )
|| gridScreenSizeDense > gridDrawThreshold )
{
DrawGridLine( VECTOR2D( i * gridSize.x, gridStartY * gridSize.y ),
drawGridLine( VECTOR2D( i * gridSize.x, gridStartY * gridSize.y ),
VECTOR2D( i * gridSize.x, gridEndY * gridSize.y ) );
}
}
......
......@@ -52,7 +52,7 @@ GPU_MANAGER* GPU_MANAGER::MakeManager( VERTEX_CONTAINER* aContainer )
GPU_MANAGER::GPU_MANAGER( VERTEX_CONTAINER* aContainer ) :
m_isDrawing( false ), m_container( aContainer ), m_shader( NULL )
m_isDrawing( false ), m_container( aContainer ), m_shader( NULL )
{
}
......
......@@ -104,7 +104,7 @@ unsigned int OPENGL_COMPOSITOR::GetBuffer()
wxASSERT( m_initialized );
if( m_buffers.size() >= m_maxBuffers )
return 0; // Unfortunately we have no more free buffers left
return 0; // Unfortunately we have no more free buffers left
// GL_COLOR_ATTACHMENTn are consecutive integers
GLuint attachmentPoint = GL_COLOR_ATTACHMENT0 + usedBuffers();
......@@ -229,9 +229,11 @@ void OPENGL_COMPOSITOR::clean()
{
glDeleteTextures( 1, &it->textureTarget );
}
m_buffers.clear();
m_initialized = false;
}
GLuint OPENGL_COMPOSITOR::m_currentFbo = 0;
......@@ -36,7 +36,6 @@
#endif /* __WXDEBUG__ */
#include <limits>
#include <boost/foreach.hpp>
#ifndef CALLBACK
#define CALLBACK
......@@ -94,9 +93,6 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener,
tesselator = gluNewTess();
InitTesselatorCallbacks( tesselator );
gluTessProperty( tesselator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_POSITIVE );
// Compute the unit circle vertices and store them in a buffer for faster drawing
computeCircle();
}
......@@ -111,109 +107,6 @@ OPENGL_GAL::~OPENGL_GAL()
}
void OPENGL_GAL::onPaint( wxPaintEvent& aEvent )
{
PostPaint();
}
void OPENGL_GAL::ResizeScreen( int aWidth, int aHeight )
{
screenSize = VECTOR2D( aWidth, aHeight );
// Resize framebuffers
compositor.Resize( aWidth, aHeight );
isFramebufferInitialized = false;
wxGLCanvas::SetSize( aWidth, aHeight );
}
void OPENGL_GAL::skipMouseEvent( wxMouseEvent& aEvent )
{
// Post the mouse event to the event listener registered in constructor, if any
if( mouseListener )
wxPostEvent( mouseListener, aEvent );
}
void OPENGL_GAL::SaveScreen()
{
wxASSERT_MSG( false, wxT( "Not implemented yet" ) );
}
void OPENGL_GAL::RestoreScreen()
{
wxASSERT_MSG( false, wxT( "Not implemented yet" ) );
}
void OPENGL_GAL::SetTarget( RenderTarget aTarget )
{
switch( aTarget )
{
default:
case TARGET_CACHED:
currentManager = &cachedManager;
break;
case TARGET_NONCACHED:
currentManager = &nonCachedManager;
break;
case TARGET_OVERLAY:
currentManager = &overlayManager;
break;
}
}
void OPENGL_GAL::initGlew()
{
// Initialize GLEW library
GLenum err = glewInit();
if( GLEW_OK != err )
{
wxLogError( wxString::FromUTF8( (char*) glewGetErrorString( err ) ) );
exit( 1 );
}
else
{
wxLogDebug( wxString( wxT( "Status: Using GLEW " ) ) +
FROM_UTF8( (char*) glewGetString( GLEW_VERSION ) ) );
}
// Check the OpenGL version (minimum 2.1 is required)
if( GLEW_VERSION_2_1 )
{
wxLogInfo( wxT( "OpenGL Version 2.1 supported." ) );
}
else
{
wxLogError( wxT( "OpenGL Version 2.1 is not supported!" ) );
exit( 1 );
}
// Framebuffers have to be supported
if( !GLEW_ARB_framebuffer_object )
{
wxLogError( wxT( "Framebuffer objects are not supported!" ) );
exit( 1 );
}
// Vertex buffer have to be supported
if( !GLEW_ARB_vertex_buffer_object )
{
wxLogError( wxT( "Vertex buffer objects are not supported!" ) );
exit( 1 );
}
isGlewInitialized = true;
}
void OPENGL_GAL::BeginDrawing()
{
SetCurrent( *glContext );
......@@ -232,7 +125,8 @@ void OPENGL_GAL::BeginDrawing()
glViewport( 0, 0, (GLsizei) screenSize.x, (GLsizei) screenSize.y );
// Create the screen transformation
glOrtho( 0, (GLint) screenSize.x, 0, (GLsizei) screenSize.y, -depthRange.x, -depthRange.y );
glOrtho( 0, (GLint) screenSize.x, 0, (GLsizei) screenSize.y,
-depthRange.x, -depthRange.y );
// Prepare rendering target buffers
compositor.Initialize();
......@@ -301,7 +195,7 @@ void OPENGL_GAL::BeginDrawing()
compositor.ClearBuffer();
compositor.SetBuffer( overlayBuffer );
compositor.ClearBuffer();
compositor.SetBuffer( 0 ); // Unbind buffers
compositor.SetBuffer( 0 ); // Unbind buffers
nonCachedManager.Clear();
overlayManager.Clear();
......@@ -333,37 +227,16 @@ void OPENGL_GAL::EndDrawing()
}
inline void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
void OPENGL_GAL::DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
{
VECTOR2D startEndVector = aEndPoint - aStartPoint;
double lineLength = startEndVector.EuclideanNorm();
double scale = 0.5 * lineWidth / lineLength;
if( lineLength <= 0.0 )
return;
// The perpendicular vector also needs transformations
glm::vec4 vector = currentManager->GetTransformation() *
glm::vec4( -startEndVector.y * scale, startEndVector.x * scale, 0.0, 0.0 );
// Line width is maintained by the vertex shader
currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth );
currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); // v0
currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth );
currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); // v1
currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth );
currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); // v3
currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth );
currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); // v0
const VECTOR2D startEndVector = aEndPoint - aStartPoint;
double lineAngle = startEndVector.Angle();
currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth );
currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); // v3
drawLineQuad( aStartPoint, aEndPoint );
currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth );
currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); // v2
// Line caps
drawFilledSemiCircle( aStartPoint, lineWidth / 2, lineAngle + M_PI / 2 );
drawFilledSemiCircle( aEndPoint, lineWidth / 2, lineAngle - M_PI / 2 );
}
......@@ -414,53 +287,124 @@ void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndP
}
unsigned int OPENGL_GAL::getNewGroupNumber()
void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )
{
wxASSERT_MSG( groups.size() < std::numeric_limits<unsigned int>::max(),
wxT( "There are no free slots to store a group" ) );
while( groups.find( groupCounter ) != groups.end() )
if( isFillEnabled )
{
groupCounter++;
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
* (if you want to understand more, check the vertex shader source [shader.vert]).
* Shader uses this coordinates to determine if fragments are inside the circle or not.
* v2
* /\
* //\\
* v0 /_\/_\ v1
*/
currentManager->Shader( SHADER_FILLED_CIRCLE, 1.0 );
currentManager->Vertex( aCenterPoint.x - aRadius * sqrt( 3.0f ), // v0
aCenterPoint.y - aRadius, layerDepth );
currentManager->Shader( SHADER_FILLED_CIRCLE, 2.0 );
currentManager->Vertex( aCenterPoint.x + aRadius * sqrt( 3.0f ), // v1
aCenterPoint.y - aRadius, layerDepth );
currentManager->Shader( SHADER_FILLED_CIRCLE, 3.0 );
currentManager->Vertex( aCenterPoint.x, aCenterPoint.y + aRadius * 2.0f, // v2
layerDepth );
}
return groupCounter++;
if( isStrokeEnabled )
{
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
* (if you want to understand more, check the vertex shader source [shader.vert]).
* and the line width. Shader uses this coordinates to determine if fragments are
* inside the circle or not.
* v2
* /\
* //\\
* v0 /_\/_\ v1
*/
double outerRadius = aRadius + ( lineWidth / 2 );
currentManager->Shader( SHADER_STROKED_CIRCLE, 1.0, aRadius, lineWidth );
currentManager->Vertex( aCenterPoint.x - outerRadius * sqrt( 3.0f ), // v0
aCenterPoint.y - outerRadius, layerDepth );
currentManager->Shader( SHADER_STROKED_CIRCLE, 2.0, aRadius, lineWidth );
currentManager->Vertex( aCenterPoint.x + outerRadius * sqrt( 3.0f ), // v1
aCenterPoint.y - outerRadius, layerDepth );
currentManager->Shader( SHADER_STROKED_CIRCLE, 3.0, aRadius, lineWidth );
currentManager->Vertex( aCenterPoint.x, aCenterPoint.y + outerRadius * 2.0f, // v2
layerDepth );
}
}
void OPENGL_GAL::DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle,
double aEndAngle )
{
const VECTOR2D startEndVector = aEndPoint - aStartPoint;
double lineAngle = startEndVector.Angle();
if( aRadius <= 0 )
return;
drawLineQuad( aStartPoint, aEndPoint );
// Swap the angles, if start angle is greater than end angle
SWAP( aStartAngle, >, aEndAngle );
// Line caps
drawFilledSemiCircle( aStartPoint, lineWidth / 2, lineAngle + M_PI / 2 );
drawFilledSemiCircle( aEndPoint, lineWidth / 2, lineAngle - M_PI / 2 );
}
VECTOR2D startPoint( cos( aStartAngle ), sin( aStartAngle ) );
VECTOR2D endPoint( cos( aEndAngle ), sin( aEndAngle ) );
VECTOR2D startEndPoint = startPoint + endPoint;
VECTOR2D middlePoint = 0.5 * startEndPoint;
Save();
currentManager->Translate( aCenterPoint.x, aCenterPoint.y, layerDepth );
void OPENGL_GAL::DrawPolyline( std::deque<VECTOR2D>& aPointList )
{
std::deque<VECTOR2D>::const_iterator it = aPointList.begin();
if( isStrokeEnabled )
{
double alphaIncrement = 2.0 * M_PI / CIRCLE_POINTS;
currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
// Start from the second point
for( it++; it != aPointList.end(); it++ )
VECTOR2D p( cos( aStartAngle ) * aRadius, sin( aStartAngle ) * aRadius );
double alpha;
for( alpha = aStartAngle + alphaIncrement; alpha < aEndAngle; alpha += alphaIncrement )
{
VECTOR2D p_next( cos( alpha ) * aRadius, sin( alpha ) * aRadius );
DrawLine( p, p_next );
p = p_next;
}
// Draw the last missing part
if( alpha != aEndAngle )
{
VECTOR2D p_last( cos( aEndAngle ) * aRadius, sin( aEndAngle ) * aRadius );
DrawLine( p, p_last );
}
}
if( isFillEnabled )
{
const VECTOR2D startEndVector = ( *it - *( it - 1 ) );
double lineAngle = startEndVector.Angle();
double alphaIncrement = 2 * M_PI / CIRCLE_POINTS;
double alpha;
currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
drawLineQuad( *( it - 1 ), *it );
for( alpha = aStartAngle; ( alpha + alphaIncrement ) < aEndAngle; )
{
currentManager->Vertex( middlePoint.x, middlePoint.y, 0.0 );
currentManager->Vertex( cos( alpha ), sin( alpha ), 0.0 );
alpha += alphaIncrement;
currentManager->Vertex( cos( alpha ), sin( alpha ), 0.0 );
}
// There is no need to draw line caps on both ends of polyline's segments
drawFilledSemiCircle( *( it - 1 ), lineWidth / 2, lineAngle + M_PI / 2 );
currentManager->Vertex( middlePoint.x, middlePoint.y, 0.0 );
currentManager->Vertex( cos( alpha ), sin( alpha ), 0.0 );
currentManager->Vertex( endPoint.x, endPoint.y, 0.0 );
}
// ..and now - draw the ending cap
const VECTOR2D startEndVector = ( *( it - 1 ) - *( it - 2 ) );
double lineAngle = startEndVector.Angle();
drawFilledSemiCircle( *( it - 1 ), lineWidth / 2, lineAngle - M_PI / 2 );
Restore();
}
......@@ -501,234 +445,29 @@ void OPENGL_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEn
}
void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius )
void OPENGL_GAL::DrawPolyline( std::deque<VECTOR2D>& aPointList )
{
if( isFillEnabled )
std::deque<VECTOR2D>::const_iterator it = aPointList.begin();
// Start from the second point
for( it++; it != aPointList.end(); it++ )
{
currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
const VECTOR2D startEndVector = ( *it - *( it - 1 ) );
double lineAngle = startEndVector.Angle();
/* 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
(if you want to understand more, check the vertex shader source [shader.vert]).
Shader uses this coordinates to determine if fragments are inside the circle or not.
v2
/\
//\\
v0 /_\/_\ v1
*/
currentManager->Shader( SHADER_FILLED_CIRCLE, 1.0 );
currentManager->Vertex( aCenterPoint.x - aRadius * sqrt( 3.0f ), // v0
aCenterPoint.y - aRadius, layerDepth );
drawLineQuad( *( it - 1 ), *it );
currentManager->Shader( SHADER_FILLED_CIRCLE, 2.0 );
currentManager->Vertex( aCenterPoint.x + aRadius* sqrt( 3.0f ), // v1
aCenterPoint.y - aRadius, layerDepth );
currentManager->Shader( SHADER_FILLED_CIRCLE, 3.0 );
currentManager->Vertex( aCenterPoint.x, aCenterPoint.y + aRadius * 2.0f, // v2
layerDepth );
}
if( isStrokeEnabled )
{
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
(if you want to understand more, check the vertex shader source [shader.vert]).
and the line width. Shader uses this coordinates to determine if fragments are
inside the circle or not.
v2
/\
//\\
v0 /_\/_\ v1
*/
double outerRadius = aRadius + ( lineWidth / 2 );
currentManager->Shader( SHADER_STROKED_CIRCLE, 1.0, aRadius, lineWidth );
currentManager->Vertex( aCenterPoint.x - outerRadius * sqrt( 3.0f ), // v0
aCenterPoint.y - outerRadius, layerDepth );
currentManager->Shader( SHADER_STROKED_CIRCLE, 2.0, aRadius, lineWidth );
currentManager->Vertex( aCenterPoint.x + outerRadius * sqrt( 3.0f ), // v1
aCenterPoint.y - outerRadius, layerDepth );
currentManager->Shader( SHADER_STROKED_CIRCLE, 3.0, aRadius, lineWidth );
currentManager->Vertex( aCenterPoint.x, aCenterPoint.y + outerRadius * 2.0f, // v2
layerDepth );
}
}
void OPENGL_GAL::drawSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle )
{
if( isFillEnabled )
{
currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
drawFilledSemiCircle( 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 )
{
Save();
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
(if you want to understand more, check the vertex shader source [shader.vert]).
Shader uses this coordinates to determine if fragments are inside the semicircle or not.
v2
/\
/__\
v0 //__\\ v1
*/
currentManager->Shader( SHADER_FILLED_CIRCLE, 4.0f );
currentManager->Vertex( -aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0
currentManager->Shader( SHADER_FILLED_CIRCLE, 5.0f );
currentManager->Vertex( aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1
currentManager->Shader( SHADER_FILLED_CIRCLE, 6.0f );
currentManager->Vertex( 0.0f, aRadius * 2.0f, layerDepth ); // v2
Restore();
}
void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRadius,
double aAngle )
{
double outerRadius = aRadius + ( lineWidth / 2 );
Save();
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
(if you want to understand more, check the vertex shader source [shader.vert]), the
radius and the line width. Shader uses this coordinates to determine if fragments are
inside the semicircle or not.
v2
/\
/__\
v0 //__\\ v1
*/
currentManager->Shader( SHADER_STROKED_CIRCLE, 4.0f, aRadius, lineWidth );
currentManager->Vertex( -outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0
currentManager->Shader( SHADER_STROKED_CIRCLE, 5.0f, aRadius, lineWidth );
currentManager->Vertex( outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1
currentManager->Shader( SHADER_STROKED_CIRCLE, 6.0f, aRadius, lineWidth );
currentManager->Vertex( 0.0f, outerRadius * 2.0f, layerDepth ); // v2
Restore();
}
// FIXME Optimize
void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle,
double aEndAngle )
{
if( aRadius <= 0 )
return;
// Swap the angles, if start angle is greater than end angle
SWAP( aStartAngle, >, aEndAngle );
VECTOR2D startPoint( cos( aStartAngle ), sin( aStartAngle ) );
VECTOR2D endPoint( cos( aEndAngle ), sin( aEndAngle ) );
VECTOR2D startEndPoint = startPoint + endPoint;
VECTOR2D middlePoint = 0.5 * startEndPoint;
Save();
currentManager->Translate( aCenterPoint.x, aCenterPoint.y, layerDepth );
if( isStrokeEnabled )
{
double alphaIncrement = 2.0 * M_PI / CIRCLE_POINTS;
currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
VECTOR2D p( cos( aStartAngle ) * aRadius, sin( aStartAngle ) * aRadius );
double alpha;
for( alpha = aStartAngle + alphaIncrement; alpha < aEndAngle; alpha += alphaIncrement )
{
VECTOR2D p_next( cos( alpha ) * aRadius, sin( alpha ) * aRadius );
DrawLine( p, p_next );
p = p_next;
}
// Draw the last missing part
if( alpha != aEndAngle )
{
VECTOR2D p_last( cos( aEndAngle ) * aRadius, sin( aEndAngle ) * aRadius );
DrawLine( p, p_last );
}
}
if( isFillEnabled )
{
double alphaIncrement = 2 * M_PI / CIRCLE_POINTS;
double alpha;
currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
for( alpha = aStartAngle; ( alpha + alphaIncrement ) < aEndAngle; )
{
currentManager->Vertex( middlePoint.x, middlePoint.y, 0.0 );
currentManager->Vertex( cos( alpha ), sin( alpha ), 0.0 );
alpha += alphaIncrement;
currentManager->Vertex( cos( alpha ), sin( alpha ), 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 );
// There is no need to draw line caps on both ends of polyline's segments
drawFilledSemiCircle( *( it - 1 ), lineWidth / 2, lineAngle + M_PI / 2 );
}
Restore();
// ..and now - draw the ending cap
const VECTOR2D startEndVector = ( *( it - 1 ) - *( it - 2 ) );
double lineAngle = startEndVector.Angle();
drawFilledSemiCircle( *( it - 1 ), lineWidth / 2, lineAngle - M_PI / 2 );
}
struct OGLPOINT
{
OGLPOINT() :
x( 0.0 ), y( 0.0 ), z( 0.0 )
{}
OGLPOINT( const char* fastest )
{
// do nothing for fastest speed, and keep inline
}
OGLPOINT( const VECTOR2D& aPoint ) :
x( aPoint.x ), y( aPoint.y ), z( 0.0 )
{}
OGLPOINT& operator=( const VECTOR2D& aPoint )
{
x = aPoint.x;
y = aPoint.y;
z = 0.0;
return *this;
}
GLdouble x;
GLdouble y;
GLdouble z;
};
void OPENGL_GAL::DrawPolygon( const std::deque<VECTOR2D>& aPointList )
{
// Any non convex polygon needs to be tesselated
......@@ -808,34 +547,32 @@ void OPENGL_GAL::DrawCurve( const VECTOR2D& aStartPoint, const VECTOR2D& aContro
}
void OPENGL_GAL::SetStrokeColor( const COLOR4D& aColor )
void OPENGL_GAL::ResizeScreen( int aWidth, int aHeight )
{
isSetAttributes = true;
strokeColor = aColor;
screenSize = VECTOR2D( aWidth, aHeight );
// This is the default drawing color
currentManager->Color( aColor.r, aColor.g, aColor.b, aColor.a );
// Resize framebuffers
compositor.Resize( aWidth, aHeight );
isFramebufferInitialized = false;
wxGLCanvas::SetSize( aWidth, aHeight );
}
void OPENGL_GAL::SetFillColor( const COLOR4D& aColor )
bool OPENGL_GAL::Show( bool aShow )
{
isSetAttributes = true;
fillColor = aColor;
}
bool s = wxGLCanvas::Show( aShow );
if( aShow )
wxGLCanvas::Raise();
void OPENGL_GAL::SetBackgroundColor( const COLOR4D& aColor )
{
isSetAttributes = true;
backgroundColor = aColor;
return s;
}
void OPENGL_GAL::SetLineWidth( double aLineWidth )
void OPENGL_GAL::Flush()
{
isSetAttributes = true;
lineWidth = aLineWidth;
glFlush();
}
......@@ -847,6 +584,15 @@ void OPENGL_GAL::ClearScreen()
}
void OPENGL_GAL::SetStrokeColor( const COLOR4D& aColor )
{
strokeColor = aColor;
// This is the default drawing color
currentManager->Color( aColor.r, aColor.g, aColor.b, aColor.a );
}
void OPENGL_GAL::Transform( MATRIX3x3D aTransformation )
{
GLdouble matrixData[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
......@@ -883,12 +629,6 @@ void OPENGL_GAL::Scale( const VECTOR2D& aScale )
}
void OPENGL_GAL::Flush()
{
glFlush();
}
void OPENGL_GAL::Save()
{
currentManager->PushMatrix();
......@@ -919,19 +659,6 @@ void OPENGL_GAL::EndGroup()
}
void OPENGL_GAL::ClearCache()
{
groups.clear();
cachedManager.Clear();
}
void OPENGL_GAL::DeleteGroup( int aGroupNumber )
{
groups.erase( aGroupNumber );
}
void OPENGL_GAL::DrawGroup( int aGroupNumber )
{
cachedManager.DrawItem( *groups[aGroupNumber] );
......@@ -950,140 +677,65 @@ void OPENGL_GAL::ChangeGroupDepth( int aGroupNumber, int aDepth )
}
void OPENGL_GAL::computeCircle()
void OPENGL_GAL::DeleteGroup( int aGroupNumber )
{
VERTEX* vertex = circleContainer.Allocate( CIRCLE_POINTS );
groups.erase( aGroupNumber );
}
// Compute the circle points for a given number of segments
for( int i = 0; i < CIRCLE_POINTS; ++i )
{
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++;
}
void OPENGL_GAL::ClearCache()
{
groups.clear();
cachedManager.Clear();
}
void OPENGL_GAL::ComputeWorldScreenMatrix()
void OPENGL_GAL::SaveScreen()
{
ComputeWorldScale();
wxASSERT_MSG( false, wxT( "Not implemented yet" ) );
}
worldScreenMatrix.SetIdentity();
MATRIX3x3D translation;
translation.SetIdentity();
translation.SetTranslation( 0.5 * screenSize );
void OPENGL_GAL::RestoreScreen()
{
wxASSERT_MSG( false, wxT( "Not implemented yet" ) );
}
MATRIX3x3D scale;
scale.SetIdentity();
scale.SetScale( VECTOR2D( worldScale, worldScale ) );
MATRIX3x3D flip;
flip.SetIdentity();
flip.SetScale( VECTOR2D( 1.0, 1.0 ) );
void OPENGL_GAL::SetTarget( RenderTarget aTarget )
{
switch( aTarget )
{
default:
case TARGET_CACHED:
currentManager = &cachedManager;
break;
MATRIX3x3D lookat;
lookat.SetIdentity();
lookat.SetTranslation( -lookAtPoint );
case TARGET_NONCACHED:
currentManager = &nonCachedManager;
break;
worldScreenMatrix = translation * flip * scale * lookat * worldScreenMatrix;
case TARGET_OVERLAY:
currentManager = &overlayManager;
break;
}
}
// -------------------------------------
// Callback functions for the tesselator
// -------------------------------------
VECTOR2D OPENGL_GAL::ComputeCursorToWorld( const VECTOR2D& aCursorPosition )
{
VECTOR2D cursorPosition = aCursorPosition;
cursorPosition.y = screenSize.y - aCursorPosition.y;
MATRIX3x3D inverseMatrix = worldScreenMatrix.Inverse();
VECTOR2D cursorPositionWorld = inverseMatrix * cursorPosition;
// Compare Redbook Chapter 11
void CALLBACK VertexCallback( GLvoid* aVertexPtr, void* aData )
{
GLdouble* vertex = static_cast<GLdouble*>( aVertexPtr );
OPENGL_GAL::TessParams* param = static_cast<OPENGL_GAL::TessParams*>( aData );
VERTEX_MANAGER* vboManager = param->vboManager;
if( vboManager )
vboManager->Vertex( vertex[0], vertex[1], vertex[2] );
}
void CALLBACK CombineCallback( GLdouble coords[3],
GLdouble* vertex_data[4],
GLfloat weight[4], GLdouble** dataOut, void* aData )
{
GLdouble* vertex = new GLdouble[3];
OPENGL_GAL::TessParams* param = static_cast<OPENGL_GAL::TessParams*>( aData );
// Save the pointer so we can delete it later
param->intersectPoints.push_back( vertex );
memcpy( vertex, coords, 3 * sizeof(GLdouble) );
*dataOut = vertex;
}
void CALLBACK EdgeCallback(void)
{
// This callback is needed to force GLU tesselator to use triangles only
}
void CALLBACK ErrorCallback( GLenum aErrorCode )
{
const GLubyte* estring;
estring = gluErrorString( aErrorCode );
wxLogError( wxT( "Tessellation Error: %s" ), (char*) estring );
}
void InitTesselatorCallbacks( GLUtesselator* aTesselator )
{
gluTessCallback( aTesselator, GLU_TESS_VERTEX_DATA, ( void (CALLBACK*)() )VertexCallback );
gluTessCallback( aTesselator, GLU_TESS_COMBINE_DATA, ( void (CALLBACK*)() )CombineCallback );
gluTessCallback( aTesselator, GLU_TESS_EDGE_FLAG, ( void (CALLBACK*)() )EdgeCallback );
gluTessCallback( aTesselator, GLU_TESS_ERROR_DATA, ( void (CALLBACK*)() )ErrorCallback );
}
// ---------------
// Cursor handling
// ---------------
void OPENGL_GAL::initCursor( int aCursorSize )
{
cursorSize = aCursorSize;
}
VECTOR2D OPENGL_GAL::ComputeCursorToWorld( const VECTOR2D& aCursorPosition )
{
VECTOR2D cursorPosition = aCursorPosition;
cursorPosition.y = screenSize.y - aCursorPosition.y;
MATRIX3x3D inverseMatrix = worldScreenMatrix.Inverse();
VECTOR2D cursorPositionWorld = inverseMatrix * cursorPosition;
return cursorPositionWorld;
}
return cursorPositionWorld;
}
void OPENGL_GAL::DrawCursor( VECTOR2D aCursorPosition )
{
wxLogWarning( wxT( "Not tested ") );
wxLogWarning( wxT( "Not tested" ) );
SetCurrent( *glContext );
......@@ -1096,8 +748,8 @@ void OPENGL_GAL::DrawCursor( VECTOR2D aCursorPosition )
aCursorPosition = worldScreenMatrix * cursorPositionWorld;
// Switch to the main framebuffer and blit the scene
//glBindFramebuffer( GL_FRAMEBUFFER, 0 );
//glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
// glBindFramebuffer( GL_FRAMEBUFFER, 0 );
// glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glLoadIdentity();
......@@ -1140,7 +792,7 @@ void OPENGL_GAL::DrawCursor( VECTOR2D aCursorPosition )
}
void OPENGL_GAL::DrawGridLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
void OPENGL_GAL::drawGridLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
{
compositor.SetBuffer( mainBuffer );
......@@ -1165,12 +817,247 @@ void OPENGL_GAL::DrawGridLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEnd
}
bool OPENGL_GAL::Show( bool aShow )
inline void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
{
bool s = wxGLCanvas::Show( aShow );
VECTOR2D startEndVector = aEndPoint - aStartPoint;
double lineLength = startEndVector.EuclideanNorm();
double scale = 0.5 * lineWidth / lineLength;
if( aShow )
wxGLCanvas::Raise();
if( lineLength <= 0.0 )
return;
return s;
// The perpendicular vector also needs transformations
glm::vec4 vector = currentManager->GetTransformation() *
glm::vec4( -startEndVector.y * scale, startEndVector.x * scale, 0.0, 0.0 );
// Line width is maintained by the vertex shader
currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth );
currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); // v0
currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth );
currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); // v1
currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth );
currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); // v3
currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth );
currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); // v0
currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth );
currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); // v3
currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth );
currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); // v2
}
void OPENGL_GAL::drawSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle )
{
if( isFillEnabled )
{
currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
drawFilledSemiCircle( 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 )
{
Save();
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
* (if you want to understand more, check the vertex shader source [shader.vert]).
* Shader uses this coordinates to determine if fragments are inside the semicircle or not.
* v2
* /\
* /__\
* v0 //__\\ v1
*/
currentManager->Shader( SHADER_FILLED_CIRCLE, 4.0f );
currentManager->Vertex( -aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0
currentManager->Shader( SHADER_FILLED_CIRCLE, 5.0f );
currentManager->Vertex( aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1
currentManager->Shader( SHADER_FILLED_CIRCLE, 6.0f );
currentManager->Vertex( 0.0f, aRadius * 2.0f, layerDepth ); // v2
Restore();
}
void OPENGL_GAL::drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRadius,
double aAngle )
{
double outerRadius = aRadius + ( lineWidth / 2 );
Save();
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
* (if you want to understand more, check the vertex shader source [shader.vert]), the
* radius and the line width. Shader uses this coordinates to determine if fragments are
* inside the semicircle or not.
* v2
* /\
* /__\
* v0 //__\\ v1
*/
currentManager->Shader( SHADER_STROKED_CIRCLE, 4.0f, aRadius, lineWidth );
currentManager->Vertex( -outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0
currentManager->Shader( SHADER_STROKED_CIRCLE, 5.0f, aRadius, lineWidth );
currentManager->Vertex( outerRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1
currentManager->Shader( SHADER_STROKED_CIRCLE, 6.0f, aRadius, lineWidth );
currentManager->Vertex( 0.0f, outerRadius * 2.0f, layerDepth ); // v2
Restore();
}
void OPENGL_GAL::onPaint( wxPaintEvent& aEvent )
{
PostPaint();
}
void OPENGL_GAL::skipMouseEvent( wxMouseEvent& aEvent )
{
// Post the mouse event to the event listener registered in constructor, if any
if( mouseListener )
wxPostEvent( mouseListener, aEvent );
}
void OPENGL_GAL::initGlew()
{
// Initialize GLEW library
GLenum err = glewInit();
if( GLEW_OK != err )
{
wxLogError( wxString::FromUTF8( (char*) glewGetErrorString( err ) ) );
exit( 1 );
}
else
{
wxLogDebug( wxString( wxT( "Status: Using GLEW " ) ) +
FROM_UTF8( (char*) glewGetString( GLEW_VERSION ) ) );
}
// Check the OpenGL version (minimum 2.1 is required)
if( GLEW_VERSION_2_1 )
{
wxLogInfo( wxT( "OpenGL Version 2.1 supported." ) );
}
else
{
wxLogError( wxT( "OpenGL Version 2.1 is not supported!" ) );
exit( 1 );
}
// Framebuffers have to be supported
if( !GLEW_ARB_framebuffer_object )
{
wxLogError( wxT( "Framebuffer objects are not supported!" ) );
exit( 1 );
}
// Vertex buffer have to be supported
if( !GLEW_ARB_vertex_buffer_object )
{
wxLogError( wxT( "Vertex buffer objects are not supported!" ) );
exit( 1 );
}
isGlewInitialized = true;
}
void OPENGL_GAL::initCursor( int aCursorSize )
{
cursorSize = aCursorSize;
}
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" ) );
while( groups.find( groupCounter ) != groups.end() )
{
groupCounter++;
}
return groupCounter++;
}
// -------------------------------------
// Callback functions for the tesselator
// -------------------------------------
// Compare Redbook Chapter 11
void CALLBACK VertexCallback( GLvoid* aVertexPtr, void* aData )
{
GLdouble* vertex = static_cast<GLdouble*>( aVertexPtr );
OPENGL_GAL::TessParams* param = static_cast<OPENGL_GAL::TessParams*>( aData );
VERTEX_MANAGER* vboManager = param->vboManager;
if( vboManager )
vboManager->Vertex( vertex[0], vertex[1], vertex[2] );
}
void CALLBACK CombineCallback( GLdouble coords[3],
GLdouble* vertex_data[4],
GLfloat weight[4], GLdouble** dataOut, void* aData )
{
GLdouble* vertex = new GLdouble[3];
OPENGL_GAL::TessParams* param = static_cast<OPENGL_GAL::TessParams*>( aData );
// Save the pointer so we can delete it later
param->intersectPoints.push_back( vertex );
memcpy( vertex, coords, 3 * sizeof(GLdouble) );
*dataOut = vertex;
}
void CALLBACK EdgeCallback()
{
// This callback is needed to force GLU tesselator to use triangles only
}
void CALLBACK ErrorCallback( GLenum aErrorCode )
{
const GLubyte* estring;
estring = gluErrorString( aErrorCode );
wxLogError( wxT( "Tessellation Error: %s" ), (char*) estring );
}
void InitTesselatorCallbacks( GLUtesselator* aTesselator )
{
gluTessCallback( aTesselator, GLU_TESS_VERTEX_DATA, ( void (CALLBACK*)() )VertexCallback );
gluTessCallback( aTesselator, GLU_TESS_COMBINE_DATA, ( void (CALLBACK*)() )CombineCallback );
gluTessCallback( aTesselator, GLU_TESS_EDGE_FLAG, ( void (CALLBACK*)() )EdgeCallback );
gluTessCallback( aTesselator, GLU_TESS_ERROR_DATA, ( void (CALLBACK*)() )ErrorCallback );
}
......@@ -37,12 +37,12 @@
using namespace KiGfx;
SHADER::SHADER() :
isProgramCreated( false ),
isShaderLinked( false ),
active( false ),
maximumVertices( 4 ),
geomInputType( GL_LINES ),
geomOutputType( GL_LINES )
isProgramCreated( false ),
isShaderLinked( false ),
active( false ),
maximumVertices( 4 ),
geomInputType( GL_LINES ),
geomOutputType( GL_LINES )
{
}
......@@ -97,7 +97,8 @@ bool SHADER::Link()
programInfo( programNumber );
// Check the Link state
glGetObjectParameterivARB( programNumber, GL_OBJECT_LINK_STATUS_ARB, (GLint*) &isShaderLinked );
glGetObjectParameterivARB( programNumber, GL_OBJECT_LINK_STATUS_ARB,
(GLint*) &isShaderLinked );
#ifdef __WXDEBUG__
if( !isShaderLinked )
......@@ -253,6 +254,7 @@ bool SHADER::addSource( const std::string& aShaderSource, ShaderType aShaderType
glCompileShader( shaderNumber );
GLint status;
glGetShaderiv( shaderNumber, GL_COMPILE_STATUS, &status );
if( status != GL_TRUE )
{
wxLogError( wxT( "Shader compilation error" ) );
......@@ -275,4 +277,3 @@ bool SHADER::addSource( const std::string& aShaderSource, ShaderType aShaderType
return true;
}
......@@ -37,7 +37,7 @@
using namespace KiGfx;
VERTEX_MANAGER::VERTEX_MANAGER( bool aCached ) :
m_noTransform( true ), m_transform( 1.0f )
m_noTransform( true ), m_transform( 1.0f )
{
m_container.reset( VERTEX_CONTAINER::MakeContainer( aCached ) );
m_gpu.reset( GPU_MANAGER::MakeManager( m_container.get() ) );
......@@ -52,6 +52,7 @@ 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" ) );
......@@ -66,6 +67,7 @@ void VERTEX_MANAGER::Vertices( const VERTEX aVertices[], unsigned int aSize ) co
{
// Obtain pointer to the vertex in currently used container
VERTEX* newVertex = m_container->Allocate( aSize );
if( newVertex == NULL )
{
wxLogError( wxT( "Vertex allocation error" ) );
......@@ -95,7 +97,7 @@ void VERTEX_MANAGER::FreeItem( VERTEX_ITEM& aItem ) const
void VERTEX_MANAGER::ChangeItemColor( const VERTEX_ITEM& aItem, const COLOR4D& aColor ) const
{
unsigned int size = aItem.GetSize();
unsigned int size = aItem.GetSize();
unsigned int offset = aItem.GetOffset();
VERTEX* vertex = m_container->GetVertices( offset );
......@@ -114,7 +116,7 @@ void VERTEX_MANAGER::ChangeItemColor( const VERTEX_ITEM& aItem, const COLOR4D& a
void VERTEX_MANAGER::ChangeItemDepth( const VERTEX_ITEM& aItem, GLfloat aDepth ) const
{
unsigned int size = aItem.GetSize();
unsigned int size = aItem.GetSize();
unsigned int offset = aItem.GetOffset();
VERTEX* vertex = m_container->GetVertices( offset );
......@@ -131,7 +133,7 @@ void VERTEX_MANAGER::ChangeItemDepth( const VERTEX_ITEM& aItem, GLfloat aDepth )
VERTEX* VERTEX_MANAGER::GetVertices( const VERTEX_ITEM& aItem ) const
{
if( aItem.GetSize() == 0 )
return NULL; // The item is not stored in the container
return NULL; // The item is not stored in the container
return m_container->GetVertices( aItem.GetOffset() );
}
......@@ -158,6 +160,7 @@ void VERTEX_MANAGER::BeginDrawing() const
void VERTEX_MANAGER::DrawItem( const VERTEX_ITEM& aItem ) const
{
int size = aItem.GetSize();
if( size > 0 )
{
int offset = aItem.GetOffset();
......
......@@ -85,7 +85,6 @@ void WX_VIEW_CONTROLS::onWheel( wxMouseEvent& event )
else
scrollSpeed = scrollVec.y;
VECTOR2D t = m_view->GetScreenPixelSize();
VECTOR2D delta( event.ControlDown() ? -scrollSpeed : 0.0,
event.ShiftDown() ? -scrollSpeed : 0.0 );
......
......@@ -38,7 +38,6 @@
namespace KiGfx
{
class CAIRO_COMPOSITOR : public COMPOSITOR
{
public:
......@@ -67,25 +66,25 @@ protected:
typedef boost::shared_array<unsigned int> BitmapPtr;
typedef struct
{
cairo_t* context; ///< Main texture handle
cairo_surface_t* surface; ///< Point to which an image from texture is attached
BitmapPtr bitmap; ///< Pixel storage
cairo_t* context; ///< Main texture handle
cairo_surface_t* surface; ///< Point to which an image from texture is attached
BitmapPtr bitmap; ///< Pixel storage
} CAIRO_BUFFER;
unsigned int m_current; ///< Currently used buffer handle
unsigned int m_current; ///< Currently used buffer handle
typedef std::deque<CAIRO_BUFFER> CAIRO_BUFFERS;
/// Pointer to the current context, so it can be changed
cairo_t** m_currentContext;
cairo_t** m_currentContext;
/// Rendering target used for compositing (the main display)
cairo_t* m_mainContext;
cairo_t* m_mainContext;
/// Transformation matrix
cairo_matrix_t m_matrix;
cairo_matrix_t m_matrix;
/// Stores information about initialized buffers
CAIRO_BUFFERS m_buffers;
CAIRO_BUFFERS m_buffers;
unsigned int m_stride; ///< Stride to use given the desired format and width
unsigned int m_bufferSize; ///< Amount of memory needed to store a buffer
......@@ -102,7 +101,6 @@ protected:
return m_buffers.size();
}
};
} // namespace KiGfx
#endif /* COMPOSITOR_H_ */
......@@ -45,9 +45,6 @@
#endif
#endif
#define EXCEPTION_ZERO_CLIENT_RECTANGLE 0
#define EXCEPTION_ZERO_CONTEXT 1
/**
* @brief Class CAIRO_GAL is the cairo implementation of the graphics abstraction layer.
*
......@@ -92,7 +89,7 @@ public:
// ---------------
/// @copydoc GAL::BeginDrawing()
virtual void BeginDrawing() throw (int);
virtual void BeginDrawing();
/// @copydoc GAL::EndDrawing()
virtual void EndDrawing();
......@@ -103,19 +100,19 @@ public:
/// @copydoc GAL::DrawSegment()
virtual void DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, double aWidth );
/// @copydoc GAL::DrawPolyline()
virtual void DrawPolyline( std::deque<VECTOR2D>& aPointList );
/// @copydoc GAL::DrawCircle()
virtual void DrawCircle( const VECTOR2D& aCenterPoint, double aRadius );
/// @copydoc GAL::DrawArc()
virtual void
DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle, double aEndAngle );
virtual void DrawArc( const VECTOR2D& aCenterPoint, double aRadius,
double aStartAngle, double aEndAngle );
/// @copydoc GAL::DrawRectangle()
virtual void DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint );
/// @copydoc GAL::DrawPolyline()
virtual void DrawPolyline( std::deque<VECTOR2D>& aPointList );
/// @copydoc GAL::DrawPolygon()
virtual void DrawPolygon( const std::deque<VECTOR2D>& aPointList );
......@@ -149,24 +146,15 @@ public:
/// @copydoc GAL::SetIsStroke()
virtual void SetIsStroke( bool aIsStrokeEnabled );
/// @copydoc GAL::SetFillColor()
virtual void SetFillColor( const COLOR4D& aColor );
/// @copydoc GAL::SetStrokeColor()
virtual void SetStrokeColor( const COLOR4D& aColor );
/// @copydoc GAL::GetStrokeColor()
COLOR4D GetStrokeColor();
/// @copydoc GAL::SetBackgroundColor()
virtual void SetBackgroundColor( const COLOR4D& aColor );
/// @copydoc GAL::SetFillColor()
virtual void SetFillColor( const COLOR4D& aColor );
/// @copydoc GAL::SetLineWidth()
virtual void SetLineWidth( double aLineWidth );
/// @copydoc GAL::GetLineWidth()
double GetLineWidth();
/// @copydoc GAL::SetLayerDepth()
virtual void SetLayerDepth( double aLayerDepth );
......@@ -221,33 +209,6 @@ public:
// Handling the world <-> screen transformation
// --------------------------------------------------------
/// @copydoc GAL::ComputeWorldScreenMatrix()
virtual void ComputeWorldScreenMatrix();
/// @copydoc GAL::GetWorldScreenMatrix()
MATRIX3x3D GetWorldScreenMatrix();
/// @copydoc GAL::SetWorldScreenMatrix()
void SetWorldScreenMatrix( MATRIX3x3D aMatrix );
/// @copydoc GAL::SetWorldUnitLength()
void SetWorldUnitLength( double aWorldUnitLength );
/// @copydoc GAL::SetScreenDPI()
void SetScreenDPI( double aScreenDPI );
/// @copydoc GAL::SetLookAtPoint()
void SetLookAtPoint( const VECTOR2D& aPoint );
/// @copydoc GAL::GetLookAtPoint()
VECTOR2D GetLookAtPoint();
/// @copydoc GAL::SetZoomFactor()
void SetZoomFactor( double aZoomFactor );
/// @copydoc GAL::GetZoomFactor()
double GetZoomFactor();
/// @copydoc GAL::SaveScreen()
virtual void SaveScreen();
......@@ -264,9 +225,6 @@ public:
/// @copydoc GAL::ComputeCursorToWorld()
virtual VECTOR2D ComputeCursorToWorld( const VECTOR2D& aCursorPosition );
/// @copydoc GAL::SetIsCursorEnabled()
void SetIsCursorEnabled( bool aIsCursorEnabled );
/// @copydoc GAL::DrawCursor()
virtual void DrawCursor( VECTOR2D aCursorPosition );
......@@ -295,7 +253,7 @@ public:
}
protected:
virtual void DrawGridLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint );
virtual void drawGridLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint );
private:
/// Super class definition
......@@ -303,30 +261,29 @@ private:
// Compositing variables
boost::shared_ptr<CAIRO_COMPOSITOR> compositor; ///< Object for layers compositing
unsigned int mainBuffer; ///< Handle to the main buffer
unsigned int overlayBuffer; ///< Handle to the overlay buffer
unsigned int mainBuffer; ///< Handle to the main buffer
unsigned int overlayBuffer; ///< Handle to the overlay buffer
// Variables related to wxWidgets
wxWindow* parentWindow; ///< Parent window
wxEvtHandler* mouseListener; ///< Mouse listener
wxEvtHandler* paintListener; ///< Paint listener
unsigned int bufferSize; ///< Size of buffers cairoOutput, bitmapBuffers
unsigned char* wxOutput; ///< wxImage comaptible buffer
wxWindow* parentWindow; ///< Parent window
wxEvtHandler* mouseListener; ///< Mouse listener
wxEvtHandler* paintListener; ///< Paint listener
unsigned int bufferSize; ///< Size of buffers cairoOutput, bitmapBuffers
unsigned char* wxOutput; ///< wxImage comaptible buffer
// Cursor variables
std::deque<wxColour> savedCursorPixels; ///< Saved pixels of the cursor
bool isDeleteSavedPixels; ///< True, if the saved pixels can be discarded
wxPoint savedCursorPosition; ///< The last cursor position
wxBitmap* cursorPixels; ///< Cursor pixels
wxBitmap* cursorPixelsSaved; ///< Saved cursor pixels
int cursorSize; ///< Cursor size
std::deque<wxColour> savedCursorPixels; ///< Saved pixels of the cursor
bool isDeleteSavedPixels; ///< True, if the saved pixels can be discarded
wxPoint savedCursorPosition; ///< The last cursor position
wxBitmap* cursorPixels; ///< Cursor pixels
wxBitmap* cursorPixelsSaved; ///< Saved cursor pixels
int cursorSize; ///< Cursor size
/// Maximum number of arguments for one command
static const int MAX_CAIRO_ARGUMENTS = 6;
/// Definitions for the command recorder
enum GraphicsCommand
{
enum GraphicsCommand {
CMD_SET_FILL, ///< Enable/disable filling
CMD_SET_STROKE, ///< Enable/disable stroking
CMD_SET_FILLCOLOR, ///< Set the fill color
......@@ -392,18 +349,18 @@ private:
/// @copydoc GAL::initCursor()
virtual void initCursor( int aCursorSize );
/// Allocate the bitmaps for drawing
void allocateBitmaps();
/// Allocate the bitmaps for drawing
void deleteBitmaps();
/// Prepare Cairo surfaces for drawing
void initSurface();
/// Destroy Cairo surfaces when are not needed anymore
void deinitSurface();
/// Allocate the bitmaps for drawing
void allocateBitmaps();
/// Allocate the bitmaps for drawing
void deleteBitmaps();
/// Prepare the compositor
void setCompositor();
......
......@@ -231,7 +231,10 @@ public:
*
* @param aColor is the color for background filling.
*/
virtual void SetBackgroundColor( const COLOR4D& aColor ) = 0;
inline virtual void SetBackgroundColor( const COLOR4D& aColor )
{
backgroundColor = aColor;
}
/**
* @brief Set the line width.
......@@ -417,7 +420,7 @@ public:
// --------------------------------------------------------
/// @brief Compute the world <-> screen transformation matrix
virtual void ComputeWorldScreenMatrix() = 0;
virtual void ComputeWorldScreenMatrix();
/**
* @brief Get the world <-> screen transformation matrix.
......@@ -745,7 +748,6 @@ protected:
bool isFillEnabled; ///< Is filling of graphic objects enabled ?
bool isStrokeEnabled; ///< Are the outlines stroked ?
bool isSetAttributes; ///< True, if the attributes have been set
COLOR4D backgroundColor; ///< The background color
COLOR4D fillColor; ///< The fill color
......@@ -784,7 +786,7 @@ protected:
* @param aStartPoint is the start point of the line.
* @param aEndPoint is the end point of the line.
*/
virtual void DrawGridLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) = 0;
virtual void drawGridLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) = 0;
/**
* @brief Initialize the cursor.
......
......@@ -94,12 +94,12 @@ protected:
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.
*/
* 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 );
/**
......
......@@ -37,7 +37,6 @@
namespace KiGfx
{
class OPENGL_COMPOSITOR : public COMPOSITOR
{
public:
......@@ -94,7 +93,6 @@ protected:
return m_buffers.size();
}
};
} // namespace KiGfx
#endif /* COMPOSITOR_H_ */
......@@ -104,19 +104,19 @@ public:
/// @copydoc GAL::DrawSegment()
virtual void DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, double aWidth );
/// @copydoc GAL::DrawPolyline()
virtual void DrawPolyline( std::deque<VECTOR2D>& aPointList );
/// @copydoc GAL::DrawCircle()
virtual void DrawCircle( const VECTOR2D& aCenterPoint, double aRadius );
/// @copydoc GAL::DrawArc()
virtual void
DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double aStartAngle, double aEndAngle );
virtual void DrawArc( const VECTOR2D& aCenterPoint, double aRadius,
double aStartAngle, double aEndAngle );
/// @copydoc GAL::DrawRectangle()
virtual void DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint );
/// @copydoc GAL::DrawPolyline()
virtual void DrawPolyline( std::deque<VECTOR2D>& aPointList );
/// @copydoc GAL::DrawPolygon()
virtual void DrawPolygon( const std::deque<VECTOR2D>& aPointList );
......@@ -129,7 +129,7 @@ public:
// --------------
/// @brief Resizes the canvas.
virtual void ResizeScreen ( int aWidth, int aHeight );
virtual void ResizeScreen( int aWidth, int aHeight );
/// @brief Shows/hides the GAL canvas
virtual bool Show( bool aShow );
......@@ -144,42 +144,9 @@ public:
// Attribute setting
// -----------------
/// @copydoc GAL::SetIsFill()
virtual void SetIsFill( bool aIsFillEnabled )
{
isFillEnabled = aIsFillEnabled;
}
/// @copydoc GAL::SetIsStroke()
virtual void SetIsStroke( bool aIsStrokeEnabled )
{
isStrokeEnabled = aIsStrokeEnabled;
}
/// @copydoc GAL::SetFillColor()
virtual void SetFillColor( const COLOR4D& aColor );
/// @copydoc GAL::SetStrokeColor()
virtual void SetStrokeColor( const COLOR4D& aColor );
/// @copydoc GAL::GetStrokeColor()
COLOR4D GetStrokeColor();
/// @copydoc GAL::SetBackgroundColor()
virtual void SetBackgroundColor( const COLOR4D& aColor );
/// @copydoc GAL::SetLineWidth()
virtual void SetLineWidth( double aLineWidth );
/// @copydoc GAL::GetLineWidth()
double GetLineWidth();
/// @copydoc GAL::SetLayerDepth()
virtual void SetLayerDepth( double aLayerDepth )
{
super::SetLayerDepth( aLayerDepth );
}
// --------------
// Transformation
// --------------
......@@ -231,33 +198,6 @@ public:
// Handling the world <-> screen transformation
// --------------------------------------------------------
/// @copydoc GAL::ComputeWorldScreenMatrix()
virtual void ComputeWorldScreenMatrix();
/// @copydoc GAL::GetWorldScreenMatrix()
MATRIX3x3D GetWorldScreenMatrix();
/// @copydoc GAL::SetWorldScreenMatrix()
void SetWorldScreenMatrix( MATRIX3x3D aMatrix );
/// @copydoc GAL::SetWorldUnitLength()
void SetWorldUnitLength( double aWorldUnitLength );
/// @copydoc GAL::SetScreenDPI()
void SetScreenDPI( double aScreenDPI );
/// @copydoc GAL::SetLookAtPoint()
void SetLookAtPoint( const VECTOR2D& aPoint );
/// @copydoc GAL::GetLookAtPoint()
VECTOR2D GetLookAtPoint();
/// @copydoc GAL::SetZoomFactor()
void SetZoomFactor( double aZoomFactor );
/// @copydoc GAL::GetZoomFactor()
double GetZoomFactor();
/// @copydoc GAL::SaveScreen()
virtual void SaveScreen();
......@@ -274,9 +214,6 @@ public:
/// @copydoc GAL::ComputeCursorToWorld()
virtual VECTOR2D ComputeCursorToWorld( const VECTOR2D& aCursorPosition );
/// @copydoc GAL::SetIsCursorEnabled()
void SetIsCursorEnabled( bool aIsCursorEnabled );
/// @copydoc GAL::DrawCursor()
virtual void DrawCursor( VECTOR2D aCursorPosition );
......@@ -312,7 +249,7 @@ public:
} TessParams;
protected:
virtual void DrawGridLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint );
virtual void drawGridLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint );
private:
/// Super class definition
......@@ -321,90 +258,114 @@ 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
wxClientDC* clientDC; ///< Drawing context
wxGLContext* glContext; ///< OpenGL context of wxWidgets
wxWindow* parentWindow; ///< Parent window
wxEvtHandler* mouseListener;
wxEvtHandler* paintListener;
// Precomputed vertices for faster circle & semicircle drawing
NONCACHED_CONTAINER circleContainer; ///< Container for storing circle vertices
wxClientDC* clientDC; ///< Drawing context
wxGLContext* glContext; ///< OpenGL context of wxWidgets
wxWindow* parentWindow; ///< Parent window
wxEvtHandler* mouseListener;
wxEvtHandler* paintListener;
// Vertex buffer objects related fields
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
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
VERTEX_MANAGER overlayManager; ///< Container for storing overlaid VERTEX_ITEMs
GroupsMap groups; ///< Stores informations about VBO objects (groups)
unsigned int groupCounter; ///< Counter used for generating keys for groups
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
VERTEX_MANAGER overlayManager; ///< Container for storing overlaid VERTEX_ITEMs
// Framebuffer & compositing
OPENGL_COMPOSITOR compositor; ///< Handles multiple rendering targets
unsigned int mainBuffer; ///< Main rendering target
unsigned int overlayBuffer; ///< Auxiliary rendering target (for menus etc.)
// Polygon tesselation
GLUtesselator* tesselator; ///< Pointer to the tesselator
std::vector<GLdouble*> tessIntersects; ///< Storage of intersecting points
OPENGL_COMPOSITOR compositor; ///< Handles multiple rendering targets
unsigned int mainBuffer; ///< Main rendering target
unsigned int overlayBuffer; ///< Auxiliary rendering target (for menus etc.)
// Shader
SHADER shader; ///< There is only one shader used for different objects
SHADER shader; ///< There is only one shader used for different objects
// Cursor
int cursorSize; ///< Size of the cursor in pixels
GLubyte* cursorShape; ///< Cursor pixel storage
GLubyte* cursorSave; ///< Saved cursor pixels
VECTOR2D savedCursorPosition; ///< Last saved cursor position
int cursorSize; ///< Size of the cursor in pixels
GLubyte* cursorShape; ///< Cursor pixel storage
GLubyte* cursorSave; ///< Saved cursor pixels
VECTOR2D savedCursorPosition; ///< Last saved cursor position
// Internal flags
bool isGlewInitialized; ///< Is GLEW initialized?
bool isFramebufferInitialized; ///< Are the framebuffers initialized?
bool isShaderInitialized; ///< Was the shader initialized?
bool isGrouping; ///< Was a group started?
bool isGlewInitialized; ///< Is GLEW initialized?
bool isFramebufferInitialized; ///< Are the framebuffers initialized?
bool isShaderInitialized; ///< Was the shader initialized?
bool isGrouping; ///< Was a group started?
// Polygon tesselation
GLUtesselator* tesselator; ///< Pointer to the tesselator
std::vector<GLdouble*> tessIntersects; ///< Storage of intersecting points
// Structure used for tesselation of polygons
struct OGLPOINT
{
OGLPOINT() :
x( 0.0 ), y( 0.0 ), z( 0.0 )
{}
OGLPOINT( const char* fastest )
{
// do nothing for fastest speed, and keep inline
}
OGLPOINT( const VECTOR2D& aPoint ) :
x( aPoint.x ), y( aPoint.y ), z( 0.0 )
{}
OGLPOINT& operator=( const VECTOR2D& aPoint )
{
x = aPoint.x;
y = aPoint.y;
z = 0.0;
return *this;
}
GLdouble x;
GLdouble y;
GLdouble z;
};
/**
* @brief Draw a semi circle. Depending on settings (isStrokeEnabled & isFilledEnabled) it runs
* @brief Draw a quad for the line.
*
* @param aStartPoint is the start point of the line.
* @param aEndPoint is the end point of the line.
*/
inline void drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint );
/**
* @brief Draw a semicircle. Depending on settings (isStrokeEnabled & isFilledEnabled) it runs
* the proper function (drawStrokedSemiCircle or drawFilledSemiCircle).
*
* @param aCenterPoint is the center point.
* @param aRadius is the radius of the semi-circle.
* @param aAngle is the angle of the semi-circle.
* @param aRadius is the radius of the semicircle.
* @param aAngle is the angle of the semicircle.
*
*/
void drawSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle );
/**
* @brief Draw a filled semi circle.
* @brief Draw a filled semicircle.
*
* @param aCenterPoint is the center point.
* @param aRadius is the radius of the semi-circle.
* @param aAngle is the angle of the semi-circle.
* @param aRadius is the radius of the semicircle.
* @param aAngle is the angle of the semicircle.
*
*/
void drawFilledSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle );
/**
* @brief Draw a stroked semi circle.
* @brief Draw a stroked semicircle.
*
* @param aCenterPoint is the center point.
* @param aRadius is the radius of the semi-circle.
* @param aAngle is the angle of the semi-circle.
* @param aRadius is the radius of the semicircle.
* @param aAngle is the angle of the semicircle.
*
*/
void drawStrokedSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle );
/// Compute the points of the unit circle and store them in VBO.
void computeCircle();
// Event handling
/**
* @brief This is the window creation event handler.
*
* @param aEvent is the window creation event.
*/
void onCreate( wxWindowCreateEvent& aEvent );
/**
* @brief This is the OnPaint event handler.
*
......@@ -419,20 +380,12 @@ private:
*/
void skipMouseEvent( wxMouseEvent& aEvent );
/// Initialize GLEW.
/// Initialize GLEW
void initGlew();
/// @copydoc GAL::initCursor()
virtual void initCursor( int aCursorSize );
/**
* @brief Draw a quad for the line.
*
* @param aStartPoint is the start point of the line.
* @param aEndPoint is the end point of the line.
*/
inline void drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint );
/**
* @brief Returns a valid key that can be used as a new group number.
*
......
......@@ -35,9 +35,8 @@
namespace KiGfx
{
// Possible types of shaders
enum SHADER_TYPE
{
SHADER_NONE = 0,
enum SHADER_TYPE {
SHADER_NONE = 0,
SHADER_LINE,
SHADER_FILLED_CIRCLE,
SHADER_STROKED_CIRCLE,
......@@ -60,7 +59,7 @@ 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);
sizeof(VERTEX().b) + sizeof(VERTEX().a);
const unsigned int ColorStride = ColorSize / sizeof(GLubyte);
// Shader attributes
......
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