From 28511cf4fe47e76ea02abc79f2a495ba4a689649 Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Tue, 4 Jun 2013 15:58:53 +0200 Subject: [PATCH] Introducing shaders. Shader's parameters are stored in VBO_ITEM. Changed VBO_ITEM data structure. Added UseShader() function for selecting shader for a given VBO_ITEM. Added one main vertex & fragment shader program to be used for with all kinds of items (type of shader is selected using attributes that are stored in VBO). Currently available shaders are: at-least-1px-width line, filled circle and stroked circle. Removed unnecessary param (aDepthOffset) from a few functions (OPENGL_GAL::drawSemiCircle(), OPENGL_GAL::drawLineCap()). Removed function OPENGL_GAL::DrawRoundedSegment(). Changed some asserts to debug info or error log. --- common/drawpanel_gal.cpp | 4 +- common/gal/opengl/opengl_gal.cpp | 574 ++++++++++-------- .../opengl/{shader/round.frag => shader.frag} | 49 +- .../opengl/{shader/line.vert => shader.vert} | 40 +- common/gal/opengl/shader/circle.frag | 60 -- common/gal/opengl/shader/circle.geom | 115 ---- common/gal/opengl/shader/circle.vert | 35 -- common/gal/opengl/shader/line.frag | 37 -- common/gal/opengl/shader/line.geom | 123 ---- common/gal/opengl/shader/round.vert | 37 -- common/gal/opengl/vbo_item.cpp | 46 +- include/gal/opengl/opengl_gal.h | 46 +- include/gal/opengl/vbo_item.h | 86 ++- pcbnew/pcbframe.cpp | 4 +- 14 files changed, 513 insertions(+), 743 deletions(-) rename common/gal/opengl/{shader/round.frag => shader.frag} (53%) rename common/gal/opengl/{shader/line.vert => shader.vert} (50%) delete mode 100644 common/gal/opengl/shader/circle.frag delete mode 100644 common/gal/opengl/shader/circle.geom delete mode 100644 common/gal/opengl/shader/circle.vert delete mode 100644 common/gal/opengl/shader/line.frag delete mode 100644 common/gal/opengl/shader/line.geom delete mode 100644 common/gal/opengl/shader/round.vert diff --git a/common/drawpanel_gal.cpp b/common/drawpanel_gal.cpp index e82f5f3553..390f919c1b 100644 --- a/common/drawpanel_gal.cpp +++ b/common/drawpanel_gal.cpp @@ -58,9 +58,9 @@ EDA_DRAW_PANEL_GAL::EDA_DRAW_PANEL_GAL( wxWindow* aParentWindow, wxWindowID aWin wxStandardPaths paths; wxFileName executableFile( paths.GetExecutablePath() ); m_galShaderPath = std::string( ( executableFile.GetPath() + - wxT( "/../../common/gal/opengl/shader/" ) ).mb_str() ); + wxT( "/../../common/gal/opengl/" ) ).mb_str() ); - SwitchBackend( aGalType, false ); + SwitchBackend( aGalType, true ); SetBackgroundStyle( wxBG_STYLE_CUSTOM ); // Initial display settings diff --git a/common/gal/opengl/opengl_gal.cpp b/common/gal/opengl/opengl_gal.cpp index 9c67bc22e3..c9d3987402 100644 --- a/common/gal/opengl/opengl_gal.cpp +++ b/common/gal/opengl/opengl_gal.cpp @@ -26,8 +26,9 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +#include + #include -#include #include #include @@ -71,22 +72,20 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener, isUseShader = isUseShaders; isShaderInitialized = false; isGrouping = false; - shaderPath = "../../common/gal/opengl/shader/"; + shaderPath = "../../common/gal/opengl"; wxSize parentSize = aParent->GetSize(); isVboInitialized = false; vboNeedsUpdate = false; curVboItem = NULL; vboSize = 0; - transform = glm::mat4( 1.0f ); + transform = glm::mat4( 1.0f ); // Identity matrix SetSize( parentSize ); screenSize.x = parentSize.x; screenSize.y = parentSize.y; - currentShader = -1; - // Set grid defaults SetGridColor( COLOR4D( 0.3, 0.3, 0.3, 0.3 ) ); SetCoarseGrid( 10 ); @@ -108,10 +107,13 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener, Connect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( OPENGL_GAL::skipMouseEvent ) ); #endif - // Compute the unit circles, used for speed up of the circle drawing - computeUnitCircle(); - computeUnitSemiCircle(); - // computeUnitArcs(); // TODO it is not used anywhere + if( !isUseShader ) + { + // Compute the unit circles, used for speed up of the circle drawing + computeUnitCircle(); + computeUnitSemiCircle(); + //computeUnitArcs(); // TODO remove? it is not used anywhere + } } @@ -346,18 +348,18 @@ void OPENGL_GAL::BeginDrawing() // Compile the shaders if( !isShaderInitialized && isUseShader ) { - std::string shaderNames[SHADER_NUMBER] = { std::string( "round" ) }; - - for( int i = 0; i < 1; i++ ) + shader.ConfigureGeometryShader( 3, GL_TRIANGLES, GL_TRIANGLES ); + shader.AddSource( shaderPath + std::string( "/shader.vert" ), SHADER_TYPE_VERTEX ); + shader.AddSource( shaderPath + std::string( "/shader.frag" ), SHADER_TYPE_FRAGMENT ); + if( !shader.Link() ) { - shaderList.push_back( SHADER() ); + wxLogFatalError( wxT( "Cannot link the shaders!" ) ); + } - shaderList[i].AddSource( shaderPath + std::string( "/" ) + shaderNames[i] + - std::string( ".frag" ), SHADER_TYPE_FRAGMENT ); - shaderList[i].AddSource( shaderPath + std::string( "/" ) + shaderNames[i] + - std::string( ".vert" ), SHADER_TYPE_VERTEX ); - - shaderList[i].Link(); + shaderAttrib = shader.GetAttribute( "attrShaderParams" ); + if( shaderAttrib == -1 ) + { + wxLogFatalError( wxT( "Could not get the shader attribute location" ) ); } isShaderInitialized = true; @@ -420,7 +422,8 @@ void OPENGL_GAL::BeginDrawing() void OPENGL_GAL::blitMainTexture( bool aIsClearFrameBuffer ) { - selectShader( -1 ); + shader.Deactivate(); + // Don't use blending for the final blitting glDisable( GL_BLEND ); @@ -474,25 +477,41 @@ void OPENGL_GAL::EndDrawing() glEnableClientState( GL_VERTEX_ARRAY ); glEnableClientState( GL_COLOR_ARRAY ); - // Bind vertices data buffer and point to the data + // Bind vertices data buffers glBindBuffer( GL_ARRAY_BUFFER, curVboVertId ); - glVertexPointer( 3, GL_FLOAT, VBO_ITEM::VertSize, 0 ); - glColorPointer( 4, GL_FLOAT, VBO_ITEM::VertSize, (GLvoid*) VBO_ITEM::ColorByteOffset ); + glVertexPointer( VBO_ITEM::CoordStride, GL_FLOAT, VBO_ITEM::VertByteSize, 0 ); + glColorPointer( VBO_ITEM::ColorStride, GL_FLOAT, VBO_ITEM::VertByteSize, + (GLvoid*) VBO_ITEM::ColorByteOffset ); + + // Shader parameters + if( isUseShader ) + { + shader.Use(); + glEnableVertexAttribArray( shaderAttrib ); + glVertexAttribPointer( shaderAttrib, VBO_ITEM::ShaderStride, GL_FLOAT, GL_FALSE, + VBO_ITEM::VertByteSize, (GLvoid*) VBO_ITEM::ShaderByteOffset ); + } glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, curVboIndId ); GLuint* indicesPtr = static_cast( glMapBuffer( GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY ) ); - wxASSERT_MSG( indicesPtr != NULL, "OPENGL_GAL::EndDrawing: Could not map GPU memory" ); + if( indicesPtr == NULL ) + { + wxLogError( wxT( "Could not map GPU memory" ) ); + } + // Copy indices of items that should be drawn to GPU memory std::list::const_iterator it, end; for( it = itemsToDraw.begin(), end = itemsToDraw.end(); it != end; ++it ) { - memcpy( indicesPtr, (*it)->GetIndices(), (*it)->GetSize() * VBO_ITEM::IndSize ); + memcpy( indicesPtr, (*it)->GetIndices(), (*it)->GetSize() * VBO_ITEM::IndByteSize ); indicesPtr += (*it)->GetSize() * VBO_ITEM::IndStride; } - bool result = glUnmapBuffer( GL_ELEMENT_ARRAY_BUFFER ); - wxASSERT_MSG( result == TRUE, "OPENGL_GAL::EndDrawing: Unmapping indices buffer failed" ); + if( !glUnmapBuffer( GL_ELEMENT_ARRAY_BUFFER ) ) + { + wxLogError( wxT( "Unmapping indices buffer failed" ) ); + } glDrawElements( GL_TRIANGLES, itemsToDrawSize, GL_UNSIGNED_INT, (GLvoid*) 0 ); glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); @@ -501,6 +520,11 @@ void OPENGL_GAL::EndDrawing() // Deactivate vertex array glDisableClientState( GL_COLOR_ARRAY ); glDisableClientState( GL_VERTEX_ARRAY ); + if( isUseShader ) + { + glDisableVertexAttribArray( shaderAttrib ); + shader.Deactivate(); + } // Draw the remaining contents, blit the main texture to the screen, swap the buffers glFlush(); @@ -538,18 +562,18 @@ void OPENGL_GAL::rebuildVbo() { int size = (*vboItem)->GetSize(); - memcpy( verticesBufferPtr, (*vboItem)->GetVertices(), size * VBO_ITEM::VertSize ); + memcpy( verticesBufferPtr, (*vboItem)->GetVertices(), size * VBO_ITEM::VertByteSize ); verticesBufferPtr += size * VBO_ITEM::VertStride; } - // Upload vertices coordinates and indices to GPU memory + // Upload vertices coordinates, shader types and indices to GPU memory glBindBuffer( GL_ARRAY_BUFFER, curVboVertId ); - glBufferData( GL_ARRAY_BUFFER, vboSize * VBO_ITEM::VertSize, verticesBuffer, GL_DYNAMIC_DRAW ); + glBufferData( GL_ARRAY_BUFFER, vboSize * VBO_ITEM::VertByteSize, verticesBuffer, GL_DYNAMIC_DRAW ); glBindBuffer( GL_ARRAY_BUFFER, 0 ); // Allocate the biggest possible buffer for indices glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, curVboIndId ); - glBufferData( GL_ELEMENT_ARRAY_BUFFER, vboSize * VBO_ITEM::IndSize, NULL, GL_STREAM_DRAW ); + glBufferData( GL_ELEMENT_ARRAY_BUFFER, vboSize * VBO_ITEM::IndByteSize, NULL, GL_STREAM_DRAW ); glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); delete[] verticesBuffer; @@ -558,112 +582,90 @@ void OPENGL_GAL::rebuildVbo() #ifdef __WXDEBUG__ prof_end( &totalTime ); - wxLogDebug( wxT( "Rebuilding VBO::items %d / %.1f ms" ), + wxLogDebug( wxT( "Rebuilding VBO::%d vertices / %.1f ms" ), vboSize, (double) totalTime.value / 1000.0 ); #endif /* __WXDEBUG__ */ } -inline void OPENGL_GAL::selectShader( int aIndex ) -{ - if( currentShader != aIndex ) - { - if( currentShader >= 0 ) - shaderList[currentShader].Deactivate(); - - if( aIndex >= 0 ) - shaderList[aIndex].Use(); - - currentShader = aIndex; - } -} - - -void OPENGL_GAL::drawRoundedSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, - double aWidth, bool aStroke, bool aGlBegin ) -{ - VECTOR2D l = ( aEndPoint - aStartPoint ); - double lnorm = l.EuclideanNorm(); - double aspect; - - if( l.x == 0 && l.y == 0 ) - { - l = VECTOR2D( aWidth / 2.0, 0.0 ); - aspect = 0.0; - } - else - { - l = l.Resize( aWidth / 2.0 ); - aspect = lnorm / (lnorm + aWidth); - } - - VECTOR2D p = l.Perpendicular(); - VECTOR2D corners[4] = { aStartPoint - l - p, aEndPoint + l - p, - aEndPoint + l + p, aStartPoint - l + p }; - - if( aStroke ) - { - color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); - } - else - { - color4( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); - } - - selectShader( 0 ); - - if( aGlBegin ) - glBegin( GL_QUADS ); // shader - - glNormal3d( aspect, 0, 0 ); - glTexCoord2f( 0.0, 0.0 ); - glVertex3d( corners[0].x, corners[0].y, layerDepth ); - glNormal3d( aspect, 0, 0 ); - glTexCoord2f( 1.0, 0.0 ); - glVertex3d( corners[1].x, corners[1].y, layerDepth ); - glNormal3d( aspect, 0, 0 ); - glTexCoord2f( 1.0, 1.0 ); - glVertex3d( corners[2].x, corners[2].y, layerDepth ); - glNormal3d( aspect, 0, 0 ); - glTexCoord2f( 0.0, 1.0 ); - glVertex3d( corners[3].x, corners[3].y, layerDepth ); - - if( aGlBegin ) - glEnd(); -} - - inline void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) { VECTOR2D startEndVector = aEndPoint - aStartPoint; double lineLength = startEndVector.EuclideanNorm(); + double scale = 0.5 * lineWidth / lineLength; - // Limit the width of the line to a minimum of one pixel - // this looks best without anti-aliasing - // XXX Should be improved later. - double scale = 0.5 * lineWidth / lineLength; - double scale1pix = 0.5001 / worldScale / lineLength; - if( lineWidth * worldScale < 1.0002 && !isGrouping ) +#ifdef __WXDEBUG__ + if( lineLength > 0.0 ) { - scale = scale1pix; + wxLogDebug( wxT( "Tried to draw line with length <= 0" ) ); + } +#endif /* __WXDEBUG__ */ + + if( lineLength <= 0.0 ) + return; + + if( lineWidth * worldScale < 1.0002 && !isGrouping && !isUseShader ) + { + // Limit the width of the line to a minimum of one pixel + // this looks best without anti-aliasing + scale = 0.5001 / worldScale / lineLength; } VECTOR2D perpendicularVector( -startEndVector.y * scale, startEndVector.x * scale ); - // Compute the edge points of the line - VECTOR2D v0 = aStartPoint + perpendicularVector; - VECTOR2D v1 = aStartPoint - perpendicularVector; - VECTOR2D v2 = aEndPoint + perpendicularVector; - VECTOR2D v3 = aEndPoint - perpendicularVector; - begin( GL_TRIANGLES ); - vertex3( v0.x, v0.y, layerDepth ); - vertex3( v1.x, v1.y, layerDepth ); - vertex3( v3.x, v3.y, layerDepth ); - vertex3( v0.x, v0.y, layerDepth ); - vertex3( v3.x, v3.y, layerDepth ); - vertex3( v2.x, v2.y, layerDepth ); + if( isUseShader ) + { + 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; + } + else + { + glm::vec4 vector( perpendicularVector.x, perpendicularVector.y, 0.0, 0.0 ); + } + + // Line width is maintained by the vertex shader + setShader( SHADER_LINE, vector.x, vector.y, lineWidth ); + vertex3( aStartPoint.x, aStartPoint.y, layerDepth ); // v0 + + setShader( SHADER_LINE, -vector.x, -vector.y, lineWidth ); + vertex3( aStartPoint.x, aStartPoint.y, layerDepth ); // v1 + + setShader( SHADER_LINE, -vector.x, -vector.y, lineWidth ); + vertex3( aEndPoint.x, aEndPoint.y, layerDepth ); // v3 + + setShader( SHADER_LINE, vector.x, vector.y, lineWidth ); + vertex3( aStartPoint.x, aStartPoint.y, layerDepth ); // v0 + + setShader( SHADER_LINE, -vector.x, -vector.y, lineWidth ); + vertex3( aEndPoint.x, aEndPoint.y, layerDepth ); // v3 + + setShader( SHADER_LINE, vector.x, vector.y, lineWidth ); + vertex3( aEndPoint.x, aEndPoint.y, layerDepth ); // v2 + } + else + { + // Compute the edge points of the line + VECTOR2D v0 = aStartPoint + perpendicularVector; + VECTOR2D v1 = aStartPoint - perpendicularVector; + 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 ); + + vertex3( v0.x, v0.y, layerDepth ); + vertex3( v3.x, v3.y, layerDepth ); + vertex3( v2.x, v2.y, layerDepth ); + } + end(); } @@ -676,15 +678,17 @@ void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndP if( isFillEnabled ) { + // Filled tracks color4( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); SetLineWidth( aWidth ); - drawSemiCircle( aStartPoint, aWidth / 2, lineAngle + M_PI / 2, layerDepth ); - drawSemiCircle( aEndPoint, aWidth / 2, lineAngle - M_PI / 2, layerDepth ); + drawSemiCircle( aStartPoint, aWidth / 2, lineAngle + M_PI / 2 ); + drawSemiCircle( aEndPoint, aWidth / 2, lineAngle - M_PI / 2 ); drawLineQuad( aStartPoint, aEndPoint ); } else { + // Outlined tracks double lineLength = startEndVector.EuclideanNorm(); color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); @@ -700,16 +704,15 @@ void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndP drawLineQuad( VECTOR2D( 0.0, -aWidth / 2.0 ), VECTOR2D( lineLength, -aWidth / 2.0 ) ); - DrawArc( VECTOR2D( 0.0, 0.0 ), aWidth / 2.0, M_PI / 2.0, 3.0 * M_PI / 2.0 ); - DrawArc( VECTOR2D( lineLength, 0.0 ), aWidth / 2.0, M_PI / 2.0, -M_PI / 2.0 ); + drawSemiCircle( VECTOR2D( 0.0, 0.0 ), aWidth / 2, M_PI / 2 ); + drawSemiCircle( VECTOR2D( lineLength, 0.0 ), aWidth / 2, -M_PI / 2 ); Restore(); } } -inline void OPENGL_GAL::drawLineCap( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, - double aDepthOffset ) +inline void OPENGL_GAL::drawLineCap( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) { VECTOR2D startEndVector = aEndPoint - aStartPoint; // double lineLength = startEndVector.EuclideanNorm(); @@ -723,7 +726,7 @@ inline void OPENGL_GAL::drawLineCap( const VECTOR2D& aStartPoint, const VECTOR2D case LINE_CAP_ROUND: // Add a semicircle at the line end - drawSemiCircle( aStartPoint, lineWidth / 2, lineAngle + M_PI / 2, aDepthOffset ); + drawSemiCircle( aStartPoint, lineWidth / 2, lineAngle + M_PI / 2 ); break; case LINE_CAP_SQUARED: @@ -754,6 +757,7 @@ void OPENGL_GAL::vertex3( double aX, double aY, double aZ ) { if( isGrouping ) { + // New vertex coordinates for VBO const GLfloat vertex[] = { aX, aY, aZ }; curVboItem->PushVertex( vertex ); } @@ -805,31 +809,46 @@ void OPENGL_GAL::color4( const COLOR4D& aColor ) void OPENGL_GAL::DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) { - if( isUseShader ) + if( isFillEnabled ) { - drawRoundedSegment( aStartPoint, aEndPoint, lineWidth, true, true ); - } - else - { - VECTOR2D startEndVector = aEndPoint - aStartPoint; - double lineLength = startEndVector.EuclideanNorm(); - if( lineLength > 0.0 ) - { - color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); + color4( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); - drawLineCap( aStartPoint, aEndPoint, layerDepth ); - drawLineCap( aEndPoint, aStartPoint, layerDepth ); - drawLineQuad( aStartPoint, aEndPoint ); - } + drawLineCap( aStartPoint, aEndPoint ); + drawLineCap( aEndPoint, aStartPoint ); + drawLineQuad( aStartPoint, aEndPoint ); + } + + if( isStrokeEnabled ) + { + // TODO outline mode + color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); + + drawLineCap( aStartPoint, aEndPoint ); + drawLineCap( aEndPoint, aStartPoint ); + drawLineQuad( aStartPoint, aEndPoint ); } } void OPENGL_GAL::DrawPolyline( std::deque& aPointList ) { - LineCap savedLineCap = lineCap; - bool isFirstPoint = true; + + if( isUseShader ) + { + // This method reduces amount of triangles used for drawing + std::deque::const_iterator it = aPointList.begin(); + + // Start from the second point + for( it++; it != aPointList.end(); it++ ) + { + DrawLine( *( it - 1 ), *it ); + } + + return; + } + + LineCap savedLineCap = lineCap; bool isFirstLine = true; VECTOR2D startEndVector; VECTOR2D lastStartEndVector; @@ -854,7 +873,7 @@ void OPENGL_GAL::DrawPolyline( std::deque& aPointList ) if( isFirstLine ) { - drawLineCap( lastPoint, actualPoint, layerDepth ); + drawLineCap( lastPoint, actualPoint ); isFirstLine = false; } else @@ -1029,7 +1048,7 @@ void OPENGL_GAL::DrawPolyline( std::deque& aPointList ) if( it == aPointList.end() - 1 ) { - drawLineCap( actualPoint, lastPoint, layerDepth ); + drawLineCap( actualPoint, lastPoint ); } drawLineQuad( lastPoint, *it ); @@ -1050,47 +1069,11 @@ void OPENGL_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEn VECTOR2D diagonalPointA( aEndPoint.x, aStartPoint.y ); VECTOR2D diagonalPointB( aStartPoint.x, aEndPoint.y ); - if( isUseShader ) - { - if( isFillEnabled ) - { - selectShader( 0 ); - glColor4d( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); - glBegin( GL_QUADS ); // shader - glNormal3d( 1.0, 0, 0 ); - glTexCoord2f( 0.0, 0.0 ); - glVertex3d( aStartPoint.x, aStartPoint.y, layerDepth ); - glNormal3d( 1.0, 0, 0 ); - glTexCoord2f( 1.0, 0.0 ); - glVertex3d( diagonalPointA.x, diagonalPointA.y, layerDepth ); - glNormal3d( 1.0, 0, 0 ); - glTexCoord2f( 1.0, 1.0 ); - glVertex3d( aEndPoint.x, aEndPoint.y, layerDepth ); - glNormal3d( 1.0, 0, 0 ); - glTexCoord2f( 0.0, 1.0 ); - glVertex3d( diagonalPointB.x, diagonalPointB.y, layerDepth ); - glEnd(); - } - - if( isStrokeEnabled ) - { - glBegin( GL_QUADS ); // shader - drawRoundedSegment( aStartPoint, diagonalPointA, lineWidth, true, false ); - drawRoundedSegment( aEndPoint, diagonalPointA, lineWidth, true, false ); - drawRoundedSegment( aStartPoint, diagonalPointB, lineWidth, true, false ); - drawRoundedSegment( aEndPoint, diagonalPointB, lineWidth, true, false ); - glEnd(); - } - - return; - } - - selectShader( -1 ); - // Stroke the outline if( isStrokeEnabled ) { color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); + std::deque pointList; pointList.push_back( aStartPoint ); pointList.push_back( diagonalPointA ); @@ -1103,6 +1086,7 @@ 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 ); begin( GL_TRIANGLES ); @@ -1115,23 +1099,74 @@ void OPENGL_GAL::DrawRectangle( const VECTOR2D& aStartPoint, const VECTOR2D& aEn vertex3( diagonalPointB.x, diagonalPointB.y, layerDepth ); end(); } - - // Restore the stroke color - color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); } void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius ) { - // We need a minimum radius, else simply don't draw the circle - if( aRadius <= 0.0 ) +#ifdef __WXDEBUG__ + if( aRadius > 0.0 ) { - return; + wxLogDebug( wxT( "Tried to draw circle with radius <= 0" ) ); } +#endif /* __WXDEBUG__ */ if( isUseShader ) { - drawRoundedSegment( aCenterPoint, aCenterPoint, aRadius * 2.0, false, true ); + if( isFillEnabled ) + { + color4( 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 relative coordinates of the triangle's vertices. + Shader uses this coordinates to determine if fragments are inside the circle or not. + v2 + /\ + //\\ + v0 /_\/_\ v1 + */ + setShader( SHADER_FILLED_CIRCLE, -sqrt( 3.0f ), -1.0f ); + vertex3( aCenterPoint.x - aRadius * sqrt( 3.0f ), // v0 + aCenterPoint.y - aRadius, layerDepth ); + + setShader( SHADER_FILLED_CIRCLE, sqrt( 3.0f ), -1.0f ); + vertex3( aCenterPoint.x + aRadius * sqrt( 3.0f ), // v1 + aCenterPoint.y - aRadius, layerDepth ); + + setShader( SHADER_FILLED_CIRCLE, 0.0f, 2.0f ); + vertex3( aCenterPoint.x, aCenterPoint.y + aRadius * 2.0f, layerDepth ); // v2 + } + + if( isStrokeEnabled ) + { + color4( 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 relative coordinates of the triangle's vertices + and the line width. Shader uses this coordinates to determine if fragments are inside + the circle or not. Width parameter has to be passed as a relative value. + v2 + /\ + //\\ + v0 /_\/_\ v1 + */ + float outerRadius = aRadius + ( lineWidth / 2.0f ); + float innerRadius = aRadius - ( lineWidth / 2.0f ); + float relWidth = innerRadius / outerRadius; + + setShader( SHADER_STROKED_CIRCLE, -sqrt( 3.0f ), -1.0f, relWidth ); + vertex3( aCenterPoint.x - outerRadius * sqrt( 3.0f ), // v0 + aCenterPoint.y - outerRadius, layerDepth ); + + setShader( SHADER_STROKED_CIRCLE, sqrt( 3.0f ), -1.0f, relWidth ); + vertex3( aCenterPoint.x + outerRadius * sqrt( 3.0f ), // v1 + aCenterPoint.y - outerRadius, layerDepth ); + + setShader( SHADER_STROKED_CIRCLE, 0.0f, 2.0f, relWidth ); + vertex3( aCenterPoint.x, // v2 + aCenterPoint.y + outerRadius * 2.0f, layerDepth ); + } + return; } @@ -1142,12 +1177,6 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius ) outerScale += 1.0; innerScale += 1.0; - if( isUseShader ) - { - // TODO is it ever reached? - innerScale *= 1.0 / cos( M_PI / CIRCLE_POINTS ); - } - if( isStrokeEnabled ) { if( innerScale < outerScale ) @@ -1209,24 +1238,53 @@ void OPENGL_GAL::DrawCircle( const VECTOR2D& aCenterPoint, double aRadius ) } -void OPENGL_GAL::drawSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle, - double aDepthOffset ) +void OPENGL_GAL::drawSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle ) { - Save(); - translate3( aCenterPoint.x, aCenterPoint.y, aDepthOffset ); - Scale( VECTOR2D( aRadius, aRadius ) ); - Rotate( aAngle ); - - if( isGrouping ) + if( isUseShader ) { - curVboItem->PushVertices( verticesSemiCircle.GetVertices(), verticesSemiCircle.GetSize() ); + Save(); + Translate( aCenterPoint ); + Rotate( aAngle ); + + color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); + + /* Draw a triangle that contains the semicircle, then shade it to leave only the semicircle. + Parameters given to setShader are relative coordinates of the triangle's vertices. + Shader uses this coordinates to determine if fragments are inside the semicircle or not. + v2 + /\ + /__\ + v0 //__\\ v1 + */ + setShader( SHADER_FILLED_CIRCLE, -3.0f / sqrt( 3.0f ), 0.0f, lineWidth ); + vertex3( -aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v0 + + setShader( SHADER_FILLED_CIRCLE, 3.0f / sqrt( 3.0f ), 0.0f, lineWidth ); + vertex3( aRadius * 3.0f / sqrt( 3.0f ), 0.0f, layerDepth ); // v1 + + setShader( SHADER_FILLED_CIRCLE, 0.0f, 2.0f, lineWidth ); + vertex3( 0.0f, aRadius * 2.0f, layerDepth ); // v2 + + Restore(); } else { - glCallList( displayListSemiCircle ); - } + Save(); + translate3( aCenterPoint.x, aCenterPoint.y, layerDepth ); + Scale( VECTOR2D( aRadius, aRadius ) ); + Rotate( aAngle ); - Restore(); + if( isGrouping ) + { + curVboItem->PushVertices( verticesSemiCircle.GetVertices(), verticesSemiCircle.GetSize() ); + } + else + { + glCallList( displayListSemiCircle ); + } + + Restore(); + } } @@ -1239,12 +1297,6 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double a return; } - double outerScale = lineWidth / aRadius / 2; - double innerScale = -outerScale; - - outerScale += 1.0; - innerScale += 1.0; - // Swap the angles, if start angle is greater than end angle SWAP( aStartAngle, >, aEndAngle ); @@ -1254,46 +1306,37 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double a VECTOR2D middlePoint = 0.5 * startEndPoint; Save(); - translate3( aCenterPoint.x, aCenterPoint.y, layerDepth ); - Scale( VECTOR2D( aRadius, aRadius ) ); + translate3( aCenterPoint.x, aCenterPoint.y, 0.0 ); if( isStrokeEnabled ) { if( isUseShader ) { - int n_points_s = (int) ( aRadius * worldScale ); - int n_points_a = (int) ( ( aEndAngle - aStartAngle ) / - (double) ( 2.0 * M_PI / CIRCLE_POINTS ) ); + double alphaIncrement = 2.0 * M_PI / CIRCLE_POINTS; + color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); - if( n_points_s < 4 ) - n_points_s = 4; - - int n_points = std::min( n_points_s, n_points_a ); - - if( n_points > CIRCLE_POINTS ) - n_points = CIRCLE_POINTS; - - double alphaIncrement = ( aEndAngle - aStartAngle ) / n_points; - - double cosI = cos( alphaIncrement ); - double sinI = sin( alphaIncrement ); - - VECTOR2D p( cos( aStartAngle ), sin( aStartAngle ) ); - - glBegin( GL_QUADS ); // shader - - for( int i = 0; i < n_points; i++ ) + VECTOR2D p( cos( aStartAngle ) * aRadius, sin( aStartAngle ) * aRadius ); + for( double alpha = aStartAngle; alpha < aEndAngle; alpha += alphaIncrement ) { - VECTOR2D p_next( p.x * cosI - p.y * sinI, p.x * sinI + p.y * cosI ); + if( alpha > aEndAngle ) + alpha = aEndAngle; + + VECTOR2D p_next( cos( alpha ) * aRadius, sin( alpha ) * aRadius ); + DrawLine( p, p_next ); - drawRoundedSegment( p, p_next, lineWidth / aRadius, true, false ); p = p_next; } - - glEnd(); } else { + Scale( VECTOR2D( aRadius, aRadius ) ); + + double outerScale = lineWidth / aRadius / 2; + double innerScale = -outerScale; + + outerScale += 1.0; + innerScale += 1.0; + double alphaIncrement = 2 * M_PI / CIRCLE_POINTS; color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); @@ -1312,21 +1355,21 @@ 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 ); + vertex3( v0[0], v0[1], layerDepth ); + vertex3( v1[0], v1[1], layerDepth ); + vertex3( v2[0], v2[1], layerDepth ); - vertex3( v1[0], v1[1], 0.0 ); - vertex3( v3[0], v3[1], 0.0 ); - vertex3( v2[0], v2[1], 0.0 ); + vertex3( v1[0], v1[1], layerDepth ); + vertex3( v3[0], v3[1], layerDepth ); + vertex3( v2[0], v2[1], layerDepth ); } end(); if( lineCap == LINE_CAP_ROUND ) { - drawSemiCircle( startPoint, lineWidth / aRadius / 2.0, aStartAngle + M_PI, 0 ); - drawSemiCircle( endPoint, lineWidth / aRadius / 2.0, aEndAngle, 0 ); + drawSemiCircle( startPoint, lineWidth / aRadius / 2.0, aStartAngle + M_PI ); + drawSemiCircle( endPoint, lineWidth / aRadius / 2.0, aEndAngle ); } } } @@ -1341,15 +1384,15 @@ void OPENGL_GAL::DrawArc( const VECTOR2D& aCenterPoint, double aRadius, double a for( alpha = aStartAngle; ( alpha + alphaIncrement ) < aEndAngle; ) { - vertex3( middlePoint.x, middlePoint.y, 0.0 ); - vertex3( cos( alpha ), sin( alpha ), 0.0 ); + vertex3( middlePoint.x, middlePoint.y, layerDepth ); + vertex3( cos( alpha ), sin( alpha ), layerDepth ); alpha += alphaIncrement; - vertex3( cos( alpha ), sin( alpha ), 0.0 ); + vertex3( cos( alpha ), sin( alpha ), layerDepth ); } - vertex3( middlePoint.x, middlePoint.y, 0.0 ); - vertex3( cos( alpha ), sin( alpha ), 0.0 ); - vertex3( endPoint.x, endPoint.y, 0.0 ); + vertex3( middlePoint.x, middlePoint.y, layerDepth ); + vertex3( cos( alpha ), sin( alpha ), layerDepth ); + vertex3( endPoint.x, endPoint.y, layerDepth ); end(); } @@ -1391,6 +1434,8 @@ void OPENGL_GAL::DrawPolygon( const std::deque& aPointList ) // Any non convex polygon needs to be tesselated // for this purpose the GLU standard functions are used + setShader( SHADER_NONE ); + GLUtesselator* tesselator = gluNewTess(); typedef std::vector OGLPOINTS; @@ -1624,18 +1669,27 @@ int OPENGL_GAL::BeginGroup() void OPENGL_GAL::EndGroup() { - wxASSERT_MSG( curVboItem->GetSize() != 0, - "OPENGL_GAL::EndGroup: Tried to add group that contains nothing" ); +#ifdef __WXDEBUG__ + if( curVboItem->GetSize() != 0 ) + { + wxLogDebug( wxT( "Tried to add group that contains nothing" ) ); + } +#endif /* __WXDEBUG__ */ - vboSize += curVboItem->GetSize(); + vboSize += curVboItem->GetSize(); + curVboItem = NULL; isGrouping = false; } void OPENGL_GAL::DeleteGroup( int aGroupNumber ) { - wxASSERT_MSG( aGroupNumber < vboItems.size(), - "OPENGL_GAL::DeleteGroup: Tried to delete not existing group" ); +#ifdef __WXDEBUG__ + if( (unsigned) aGroupNumber < vboItems.size() ) + { + wxLogDebug( wxT( "Tried to delete not existing group" ) ); + } +#endif /* __WXDEBUG__ */ std::deque::iterator it = vboItems.begin(); std::advance( it, aGroupNumber ); @@ -1962,7 +2016,7 @@ void OPENGL_GAL::DrawGridLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEnd VECTOR2D point4 = aEndPoint - perpendicularVector; if( isUseShader ) - selectShader( -1 ); + shader.Deactivate(); // Set color glColor4d( gridColor.r, gridColor.g, gridColor.b, gridColor.a ); diff --git a/common/gal/opengl/shader/round.frag b/common/gal/opengl/shader.frag similarity index 53% rename from common/gal/opengl/shader/round.frag rename to common/gal/opengl/shader.frag index 3d615db8c0..16ceb949ef 100644 --- a/common/gal/opengl/shader/round.frag +++ b/common/gal/opengl/shader.frag @@ -1,7 +1,8 @@ /* * This program source code file is part of KICAD, a free EDA CAD application. * - * Copyright (C) 2013 Tomasz Wlostowski + * Copyright (C) 2013 CERN + * @author Maciej Suminski * * Fragment shader * @@ -24,18 +25,48 @@ */ #version 120 +//#pragma debug(on) -varying float aspect; +// Shader types +const float SHADER_LINE = 1.0; +const float SHADER_FILLED_CIRCLE = 2.0; +const float SHADER_STROKED_CIRCLE = 3.0; -void main() +varying in vec4 shaderParams; + +void filledCircle( vec2 aCoord ) { - vec2 v = abs( gl_TexCoord[0].xy - vec2( 0.5, 0.5 ) ) * 2.0 - vec2( aspect, 0.0 ); - vec2 d = vec2( v.x / ( 1.0 - aspect ), v.y ); - - if( v.x <= 0.0 || (dot( d, d ) < 1.0 ) ) + if( dot( aCoord, aCoord ) < 1.0 ) gl_FragColor = gl_Color; else discard; - - // gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); } + + +void strokedCircle( vec2 aCoord, float aWidth ) +{ + if( ( dot( aCoord, aCoord ) < 1.0 ) && + ( dot( aCoord, aCoord ) > aWidth * aWidth ) ) + gl_FragColor = gl_Color; + else + discard; +} + + +void main() +{ + if( shaderParams[0] == SHADER_FILLED_CIRCLE ) + { + filledCircle( vec2( shaderParams[1], shaderParams[2] ) ); + } + else if( shaderParams[0] == SHADER_STROKED_CIRCLE ) + { + strokedCircle( vec2( shaderParams[1], shaderParams[2] ), shaderParams[3] ); + } + else + { + // Simple pass-through + gl_FragColor = gl_Color; + } +} + diff --git a/common/gal/opengl/shader/line.vert b/common/gal/opengl/shader.vert similarity index 50% rename from common/gal/opengl/shader/line.vert rename to common/gal/opengl/shader.vert index 2e16c5d08f..a272982119 100644 --- a/common/gal/opengl/shader/line.vert +++ b/common/gal/opengl/shader.vert @@ -1,8 +1,8 @@ /* * This program source code file is part of KICAD, a free EDA CAD application. * - * Copyright (C) 2012 Torsten Hueter, torstenhtr gmx.de - * Copyright (C) 2012 Kicad Developers, see change_log.txt for contributors. + * Copyright (C) 2013 CERN + * @author Maciej Suminski * * Vertex shader * @@ -24,12 +24,42 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -// This shader requires GLSL 1.2 #version 120 +// Shader types +const float SHADER_LINE = 1.0; +const float SHADER_FILLED_CIRCLE = 2.0; +const float SHADER_STROKED_CIRCLE = 3.0; + +attribute vec4 attrShaderParams; +varying out vec4 shaderParams; + void main() { - // Simple pass-through - gl_Position = gl_Vertex; + // Pass attributes to the fragment shader + shaderParams = attrShaderParams; + + if( shaderParams[0] == SHADER_LINE ) + { + float lineWidth = shaderParams[3]; + float worldScale = gl_ModelViewMatrix[0][0]; + float scale; + + // Make lines appear to be at least 1 pixel width + if( worldScale * lineWidth < 1.0 ) + scale = 1.0 / ( worldScale * lineWidth ); + else + scale = 1.0; + + gl_Position = gl_ModelViewProjectionMatrix * + ( gl_Vertex + vec4( shaderParams.yz * scale, 0.0, 0.0 ) ); + } + else + { + // Pass through the coordinates like in the fixed pipeline + gl_Position = ftransform(); + } + gl_FrontColor = gl_Color; } + diff --git a/common/gal/opengl/shader/circle.frag b/common/gal/opengl/shader/circle.frag deleted file mode 100644 index 142952c878..0000000000 --- a/common/gal/opengl/shader/circle.frag +++ /dev/null @@ -1,60 +0,0 @@ -/* - * This program source code file is part of KICAD, a free EDA CAD application. - * - * Copyright (C) 2012 Torsten Hueter, torstenhtr gmx.de - * Copyright (C) 2012 Kicad Developers, see change_log.txt for contributors. - * - * Fragment shader - * - * 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 - */ - -// This shader requires GLSL 1.2 -#version 120 - -// Input variables -flat varying vec4 center_; -flat varying vec2 radius_; -flat varying vec4 colorA_; -flat varying vec4 colorB_; - -void main( void ) -{ - // Compute the distance from the circle edge - float distA = distance( center_, gl_FragCoord ) - radius_.y; - float distB = radius_.x - distance( center_, gl_FragCoord ); - - // Limit the range to [ 0 .. 1 ] - if( distA < 0 ) distA = 0; - if( distA > 1 ) distA = 1; - if( distB < 0 ) distB = 0; - if( distB > 1 ) distB = 1; - - // Points with a larger distance from the edge are set deeper - gl_FragDepth = gl_FragCoord.z + distA * 0.001 + distB * 0.001; - - // Compute the color - vec4 color; - color.r = colorA_.r; - color.g = colorA_.g; - color.b = colorA_.b; - color.a = colorA_.a * ( 1 - distA ) * ( 1 - distB ); - - // Now output the edge fragment color - gl_FragColor = color; -} diff --git a/common/gal/opengl/shader/circle.geom b/common/gal/opengl/shader/circle.geom deleted file mode 100644 index e908e458b6..0000000000 --- a/common/gal/opengl/shader/circle.geom +++ /dev/null @@ -1,115 +0,0 @@ -/* - * This program source code file is part of KICAD, a free EDA CAD application. - * - * Copyright (C) 2012 Torsten Hueter, torstenhtr gmx.de - * Copyright (C) 2012 Kicad Developers, see change_log.txt for contributors. - * - * Geometry shader - * - * 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 - */ - -// This shader requires GLSL 1.2 -#version 120 -#extension GL_EXT_geometry_shader4: enable -#extension GL_EXT_gpu_shader4: enable - -uniform float viewPortX2; -uniform float viewPortY2; - -flat varying vec4 center_; -flat varying vec2 radius_; -flat varying vec4 colorA_; - -const float PI = 3.141592654; -const float EPSILON = 0.01; -const float smallestValue = 1.175494351e-38; -const int SEGMENTS = 16; - -const float PIXEL_EXTEND = 1.5; - -void main() -{ - vec4 center = gl_PositionIn[0]; - vec4 radius = gl_PositionIn[1]; - - center_ = gl_ModelViewProjectionMatrix * center; - - // Compute the outer and inner radius in screen coordinates - // This could be further optimized - radius_.x = ( gl_ModelViewProjectionMatrix * vec4(radius.x, 0, 0, 1) ).x; - radius_.x = abs( radius_.x - (gl_ModelViewProjectionMatrix * vec4(0, 0, 0, 1) ).x ) * viewPortX2; - radius_.y = ( gl_ModelViewProjectionMatrix * vec4(radius.y, 0, 0, 1) ).x; - radius_.y = abs( radius_.y - (gl_ModelViewProjectionMatrix * vec4(0, 0, 0, 1) ).x ) * viewPortX2; - - // Compute the center point in screen coordinates - center_.x = center_.x * viewPortX2 + viewPortX2; - center_.y = center_.y * viewPortY2 + viewPortY2; - - // Compute the extend value, first make sure that the outline is inside the triangles and second add - // a margin for one pixel for smooth edges - float extendInner = 1.0; - float extendOuter = 0; - if( radius_.y > smallestValue ) - { - extendOuter += PIXEL_EXTEND / radius_.y; - } - extendOuter += 1.0 / cos( PI / SEGMENTS ); - - colorA_ = gl_FrontColorIn[0]; - - // Create a quad strip for the outer circle edge - for( float alpha = 0, inc = 2 * PI / SEGMENTS, limit = 2 * PI + EPSILON; - alpha < limit; alpha += inc ) - { - gl_Position = gl_ModelViewProjectionMatrix * - vec4( center.x + extendInner * radius.y * cos( alpha ), - center.y + extendInner * radius.y * sin( alpha ), center.zw ); - EmitVertex(); - gl_Position = gl_ModelViewProjectionMatrix * - vec4( center.x + extendOuter * radius.y * cos( alpha ), - center.y + extendOuter * radius.y * sin( alpha ), center.zw ); - EmitVertex(); - } - EndPrimitive(); - - if( radius.x > 0 ) - { - extendInner = cos( PI / SEGMENTS ) - PIXEL_EXTEND / radius_.x; - if( extendInner < 0.0 ) - { - extendInner = 0; - } - extendOuter = 1.0 / cos( PI / SEGMENTS); - - // Create a quad strip for the inner circle edge - for( float alpha = 0, inc = 2 * PI / SEGMENTS, limit = 2 * PI + EPSILON; - alpha < limit; alpha += inc ) - { - gl_Position = gl_ModelViewProjectionMatrix * - vec4( center.x + extendOuter * radius.x * cos( alpha ), - center.y + extendOuter * radius.x * sin( alpha ), center.zw ); - EmitVertex(); - gl_Position = gl_ModelViewProjectionMatrix * - vec4( center.x + extendInner * radius.x * cos( alpha ), - center.y + extendInner * radius.x * sin( alpha ), center.zw ); - EmitVertex(); - } - EndPrimitive(); - } -} diff --git a/common/gal/opengl/shader/circle.vert b/common/gal/opengl/shader/circle.vert deleted file mode 100644 index 2e16c5d08f..0000000000 --- a/common/gal/opengl/shader/circle.vert +++ /dev/null @@ -1,35 +0,0 @@ -/* - * This program source code file is part of KICAD, a free EDA CAD application. - * - * Copyright (C) 2012 Torsten Hueter, torstenhtr gmx.de - * Copyright (C) 2012 Kicad Developers, see change_log.txt for contributors. - * - * Vertex shader - * - * 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 - */ - -// This shader requires GLSL 1.2 -#version 120 - -void main() -{ - // Simple pass-through - gl_Position = gl_Vertex; - gl_FrontColor = gl_Color; -} diff --git a/common/gal/opengl/shader/line.frag b/common/gal/opengl/shader/line.frag deleted file mode 100644 index 63d0f0bf2c..0000000000 --- a/common/gal/opengl/shader/line.frag +++ /dev/null @@ -1,37 +0,0 @@ -/* - * This program source code file is part of KICAD, a free EDA CAD application. - * - * Copyright (C) 2012 Torsten Hueter, torstenhtr gmx.de - * Copyright (C) 2012 Kicad Developers, see change_log.txt for contributors. - * - * Fragment shader - * - * 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 - */ - -#version 120 -#extension GL_EXT_gpu_shader4: enable - -varying float dist; - -void main() -{ - float d = dist; - gl_FragDepth = gl_FragCoord.z + d * 0.001; - gl_FragColor = vec4( gl_Color.rgb, gl_Color.a * ( 1 - d ) ); -} diff --git a/common/gal/opengl/shader/line.geom b/common/gal/opengl/shader/line.geom deleted file mode 100644 index 8000a791cd..0000000000 --- a/common/gal/opengl/shader/line.geom +++ /dev/null @@ -1,123 +0,0 @@ -/* - * This program source code file is part of KICAD, a free EDA CAD application. - * - * Copyright (C) 2012 Torsten Hueter, torstenhtr gmx.de - * Copyright (C) 2012 Kicad Developers, see change_log.txt for contributors. - * - * Geometry shader - * - * 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 - */ - -#version 120 -#extension GL_EXT_geometry_shader4: enable -#extension GL_EXT_gpu_shader4: enable - -uniform float viewPortX2; -uniform float viewPortY2; -varying float dist; - -void main() -{ - // Compute the transformed start and end points - vec2 startPoint = gl_PositionIn[0].xy; - vec2 endPoint = gl_PositionIn[1].xy; - float lineWidth = gl_PositionIn[1].z; - - // Compute vector start -> end - vec2 startEndVector = endPoint.xy - startPoint.xy; - float lineLength = distance( startPoint, endPoint ); - float scale = 0.0; - - if( lineLength > 0.0 ) - { - scale = 0.5 * lineWidth / lineLength; - } - else - { - scale = 0.0; - } - - // Compute the edge points of the line - vec2 perpendicularVector = scale * vec2( -startEndVector.y, startEndVector.x ); - vec2 point1 = startPoint + perpendicularVector; - vec2 point2 = startPoint - perpendicularVector; - vec2 point3 = endPoint + perpendicularVector; - vec2 point4 = endPoint - perpendicularVector; - - vec4 point1T = gl_ModelViewProjectionMatrix * vec4( point1, gl_PositionIn[0].zw ); - vec4 point2T = gl_ModelViewProjectionMatrix * vec4( point2, gl_PositionIn[0].zw ); - vec4 point3T = gl_ModelViewProjectionMatrix * vec4( point3, gl_PositionIn[0].zw ); - vec4 point4T = gl_ModelViewProjectionMatrix * vec4( point4, gl_PositionIn[0].zw ); - - // Construct the quad for the middle - gl_FrontColor = gl_FrontColorIn[0]; - dist = 0; - gl_Position = point1T; - EmitVertex(); - dist = 0; - gl_Position = point2T; - EmitVertex(); - dist = 0; - gl_Position = point3T; - EmitVertex(); - dist = 0; - gl_Position = point4T; - EmitVertex(); - - EndPrimitive(); - - // Compute the perpendicular vector with 1 pixel width - vec2 v = point1T.xy - point3T.xy; - vec4 onePix = 0.5 * vec4( -v.y, v.x, 0, 0 ); - onePix *= 1.0 / sqrt( dot( onePix, onePix ) ); - onePix.x *= 1.0 / viewPortX2; - onePix.y *= 1.0 / viewPortY2; - - gl_FrontColor = gl_FrontColorIn[0]; - - dist = 1; - gl_Position = point1T + onePix; - EmitVertex(); - dist = 1; - gl_Position = point3T + onePix; - EmitVertex(); - dist = 0; - gl_Position = point1T; - EmitVertex(); - dist = 0; - gl_Position = point3T; - EmitVertex(); - - EndPrimitive(); - - dist = 1; - gl_Position = point2T - onePix; - EmitVertex(); - dist = 1; - gl_Position = point4T - onePix; - EmitVertex(); - dist = 0; - gl_Position = point2T; - EmitVertex(); - dist = 0; - gl_Position = point4T; - EmitVertex(); - - EndPrimitive(); -} diff --git a/common/gal/opengl/shader/round.vert b/common/gal/opengl/shader/round.vert deleted file mode 100644 index c42f2be8f5..0000000000 --- a/common/gal/opengl/shader/round.vert +++ /dev/null @@ -1,37 +0,0 @@ -/* - * This program source code file is part of KICAD, a free EDA CAD application. - * - * Copyright (C) 2013 Tomasz Wlostowski - * - * Vertex shader - * - * 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 - */ - -#version 120 - -varying float aspect; - -void main() -{ - gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; - gl_FrontColor = gl_Color; - gl_TexCoord[0] = gl_MultiTexCoord0; - - aspect = gl_Normal.x; -} diff --git a/common/gal/opengl/vbo_item.cpp b/common/gal/opengl/vbo_item.cpp index c458dffccf..ce254d40e9 100644 --- a/common/gal/opengl/vbo_item.cpp +++ b/common/gal/opengl/vbo_item.cpp @@ -40,6 +40,9 @@ VBO_ITEM::VBO_ITEM() : m_isDirty( true ), m_transform( NULL ) { + // By default no shader is used + m_shader[0] = 0; + // Prepare a block for storing vertices & indices useNewBlock(); } @@ -50,7 +53,7 @@ VBO_ITEM::~VBO_ITEM() if( m_isDirty ) { // Data is still stored in blocks - std::list::const_iterator v_it, v_end; + std::list::const_iterator v_it, v_end; for( v_it = m_vertBlocks.begin(), v_end = m_vertBlocks.end(); v_it != v_end; ++v_it ) delete[] *v_it; @@ -75,24 +78,27 @@ void VBO_ITEM::PushVertex( const GLfloat* aVertex ) if( m_transform != NULL ) { // Apply transformations - // X, Y, Z coordinates - glm::vec4 origVertex( aVertex[0], aVertex[1], aVertex[2], 1.0f ); - glm::vec4 transVertex = *m_transform * origVertex; + // X, Y, Z coordinates + glm::vec4 vertex( aVertex[0], aVertex[1], aVertex[2], 1.0f ); + vertex = *m_transform * vertex; // Replace only coordinates, leave color as it is - memcpy( m_vertPtr, &transVertex[0], CoordSize ); + memcpy( &m_vertPtr->struc.coord, &vertex[0], CoordByteSize ); } else { // Add the new vertex - memcpy( m_vertPtr, aVertex, CoordSize ); + memcpy( &m_vertPtr->struc.coord, aVertex, CoordByteSize ); } // Apply currently used color - memcpy( m_vertPtr + ColorOffset, m_color, ColorSize ); + memcpy( &m_vertPtr->struc.color, m_color, ColorByteSize ); + + // Apply currently used shader + memcpy( &m_vertPtr->struc.shader, m_shader, ShaderByteSize ); // Move to the next free space - m_vertPtr += VertStride; + m_vertPtr++; // Add the new index *m_indPtr = m_offset + m_size; @@ -177,10 +183,10 @@ void VBO_ITEM::ChangeColor( const COLOR4D& aColor ) for( int i = 0; i < m_size; ++i ) { - memcpy( vertexPtr, newColor, ColorSize ); + memcpy( vertexPtr, newColor, ColorByteSize ); // Move on to the next vertex - vertexPtr += VertStride; + vertexPtr++; } } @@ -194,6 +200,12 @@ void VBO_ITEM::UseColor( const COLOR4D& aColor ) } +void VBO_ITEM::UseShader( const GLfloat* aShader ) +{ + memcpy( m_shader, aShader, ShaderByteSize ); +} + + /* // TODO void SetVbo( int aVboId ) @@ -209,8 +221,8 @@ int GetVbo() const void VBO_ITEM::useNewBlock() { - GLfloat* newVertBlock = new GLfloat[BLOCK_SIZE * VertStride]; - GLuint* newIndBlock = new GLuint[BLOCK_SIZE]; + VBO_VERTEX* newVertBlock = new VBO_VERTEX[BLOCK_SIZE]; + GLuint* newIndBlock = new GLuint[BLOCK_SIZE]; m_vertPtr = newVertBlock; m_indPtr = newIndBlock; @@ -233,16 +245,16 @@ void VBO_ITEM::prepareFinal() GLfloat* vertPtr = m_vertices; // Copy blocks of vertices one after another to m_vertices - std::list::const_iterator v_it; + std::list::const_iterator v_it; for( v_it = m_vertBlocks.begin(); *v_it != m_vertBlocks.back(); ++v_it ) { - memcpy( vertPtr, *v_it, BLOCK_SIZE * VertSize ); + memcpy( vertPtr, *v_it, BLOCK_SIZE * VertByteSize ); delete[] *v_it; vertPtr += ( BLOCK_SIZE * VertStride ); } // In the last block we need to copy only used vertices - memcpy( vertPtr, *v_it, ( BLOCK_SIZE - m_spaceLeft ) * VertSize ); + memcpy( vertPtr, *v_it, ( BLOCK_SIZE - m_spaceLeft ) * VertByteSize ); if( m_indices ) delete m_indices; @@ -256,13 +268,13 @@ void VBO_ITEM::prepareFinal() std::list::const_iterator i_it; for( i_it = m_indBlocks.begin(); *i_it != m_indBlocks.back(); ++i_it ) { - memcpy( indPtr, *i_it, BLOCK_SIZE * IndSize ); + memcpy( indPtr, *i_it, BLOCK_SIZE * IndByteSize ); delete[] *i_it; indPtr += ( BLOCK_SIZE * IndStride ); } // In the last block we need to copy only used indices - memcpy( indPtr, *i_it, ( BLOCK_SIZE - m_spaceLeft ) * IndSize ); + memcpy( indPtr, *i_it, ( BLOCK_SIZE - m_spaceLeft ) * IndByteSize ); m_isDirty = false; } diff --git a/include/gal/opengl/opengl_gal.h b/include/gal/opengl/opengl_gal.h index 22bd697d28..56a2c38911 100644 --- a/include/gal/opengl/opengl_gal.h +++ b/include/gal/opengl/opengl_gal.h @@ -36,6 +36,7 @@ // OpenGL mathematics library #define GLM_FORCE_RADIANS #include +#include // wxWidgets imports #include @@ -323,7 +324,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 int SHADER_NUMBER = 2; ///< Number of the used shaders static const double MITER_LIMIT = 1.5; ///< Limit for mitered edges ( * lineWidth ) /// This factor is used to for correct merging of antialiased edges, @@ -365,7 +365,18 @@ private: GLUtesselator* tesselator; ///< Pointer to the tesselator // Shader - std::deque shaderList; ///< List of the shaders + // 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) + std::string shaderPath; ///< Location of shader files // Cursor int cursorSize; ///< Size of the cursor in pixels @@ -391,8 +402,6 @@ private: bool isShaderEnabled; ///< Are the shaders enabled? bool isUseShader; ///< Should the shaders be used? bool isGrouping; ///< Was a group started? - int currentShader; ///< ID of the shader currently in use - std::string shaderPath; /** * @brief Draw a semi circle (used for line caps). @@ -400,11 +409,9 @@ private: * @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 ADepthOffset is the relative depth of the semi-circle. * */ - void drawSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle, - double aDepthOffset ); + void drawSemiCircle( const VECTOR2D& aCenterPoint, double aRadius, double aAngle ); /// Compute the points of a unit circle. void computeUnitCircle(); @@ -506,8 +513,7 @@ private: * @param aEndPoint is the end point of the line. * @param aDepthOffset is the relative depth of the line cap. */ - inline void drawLineCap( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, - double aDepthOffset ); + inline void drawLineCap( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ); ///< OpenGL replacement functions (that are working both in immediate and VBO modes) /** @@ -561,13 +567,23 @@ private: */ inline void color4( const COLOR4D& aColor ); - inline void selectShader( int aIndex ); - - /// @copydoc GAL::DrawRoundedSegment() - void drawRoundedSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, double aWidth, - bool aStroke = false, bool aGlBegin = false ); - + /** + * @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 && isGrouping ) + { + const GLfloat shader[] = { aShader, aParam1, aParam2, aParam3 }; + curVboItem->UseShader( shader ); + } + } }; } // namespace KiGfx diff --git a/include/gal/opengl/vbo_item.h b/include/gal/opengl/vbo_item.h index bbc8919a57..95e556eb9b 100644 --- a/include/gal/opengl/vbo_item.h +++ b/include/gal/opengl/vbo_item.h @@ -34,10 +34,31 @@ #include #include +#include + #include namespace KiGfx { +typedef struct VBO_VERTEX_DATA +{ + GLfloat x, y, z; // Coordinates + GLfloat r, g, b, a; // Color + GLfloat shader[4]; // Shader type & params +} VBO_VERTEX_DATA; + +typedef struct VBO_VERTEX_STRUCT +{ + GLfloat coord[3]; // Coordinates + GLfloat color[4]; // Color + GLfloat shader[4]; // Shader type & params +} VBO_VERTEX_STRUCT; + +typedef union VBO_VERTEX +{ + VBO_VERTEX_DATA data; + VBO_VERTEX_STRUCT struc; +} VBO_VERTEX; class VBO_ITEM { @@ -50,6 +71,7 @@ public: * 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 GLfloat* aVertex ); @@ -60,6 +82,7 @@ public: * 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 GLfloat* aVertices, GLuint aSize ); @@ -121,26 +144,38 @@ public: */ void UseColor( const COLOR4D& aColor ); + /** + * 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. + */ + void UseShader( const GLfloat* aShader ); + ///< Functions for getting VBO ids. //void SetVbo( int aVboId ); //int GetVbo() const; - ///< Data organization information for vertices {X,Y,Z,R,G,B,A}. - // Each vertex consists of 7 floats, but it is padded to 8 - static const int VertStride = 8; - static const int VertSize = VertStride * sizeof(GLfloat); + ///< Data organization information for vertices {X,Y,Z,R,G,B,A} (@see VBO_VERTEX). + static const int VertByteSize = sizeof(VBO_VERTEX); + static const int VertStride = VertByteSize / sizeof(GLfloat); - static const int CoordStride = 3; - static const int CoordSize = CoordStride * sizeof(GLfloat); + static const int CoordStride = sizeof(VBO_VERTEX_STRUCT().coord) / sizeof(GLfloat); + static const int CoordByteSize = sizeof(VBO_VERTEX_STRUCT().coord); // Offset of color data from the beginning of each vertex data - static const int ColorOffset = 3; - static const int ColorByteOffset = ColorOffset * sizeof(GLfloat); - static const int ColorStride = 4; - static const int ColorSize = ColorStride * sizeof(GLfloat); + static const int ColorByteOffset = offsetof( VBO_VERTEX_STRUCT, color ); + static const int ColorOffset = ColorByteOffset / sizeof(GLfloat); + static const int ColorStride = sizeof(VBO_VERTEX_STRUCT().color) / sizeof(GLfloat); + static const int ColorByteSize = sizeof(VBO_VERTEX_STRUCT().color); + + // Shader attributes + static const int ShaderByteOffset = offsetof( VBO_VERTEX_STRUCT, shader ); + static const int ShaderOffset = ShaderByteOffset / sizeof(GLfloat); + static const int ShaderStride = sizeof(VBO_VERTEX_STRUCT().shader) / sizeof(GLfloat); + static const int ShaderByteSize = sizeof(VBO_VERTEX_STRUCT().shader); static const int IndStride = 1; - static const int IndSize = IndStride * sizeof(GLuint); + static const int IndByteSize = IndStride * sizeof(GLuint); private: ///< VBO ids in which the item is stored. @@ -153,31 +188,30 @@ private: ///< Indices of vertices GLuint* m_indices; - ///< Lists of blocks - std::list m_vertBlocks; - std::list m_indBlocks; - ///< Pointers to current blocks that can be used for storing data - GLfloat* m_vertPtr; - GLuint* m_indPtr; + ///< Lists of data blocks storing vertices + std::list m_vertBlocks; + std::list m_indBlocks; + ///< Pointers to current blocks that should be used for storing data + VBO_VERTEX* m_vertPtr; + GLuint* m_indPtr; ///< How many vertices can be stored in the current buffer - int m_spaceLeft; + int m_spaceLeft; ///< Number of vertices & indices stored in a single block - static const int BLOCK_SIZE = 8; + static const int BLOCK_SIZE = 256; ///< Creates a new block for storing vertices data - void useNewBlock(); + void useNewBlock(); ///< Prepares a continuous block of data that can be copied to graphics card buffer. - void prepareFinal(); + void prepareFinal(); ///< Offset and size of data in VBO. int m_offset; int m_size; - ///< Shader data used for rendering. - int m_shader; - int m_shaderAttrib; - ///< Color used for new vertices pushed. - GLfloat m_color[4]; + GLfloat m_color[ColorStride]; + + ///< Shader and its parameters used for new vertices pushed + GLfloat m_shader[ShaderStride]; ///< Flag telling if the item should be recached in VBO or not. bool m_isDirty; diff --git a/pcbnew/pcbframe.cpp b/pcbnew/pcbframe.cpp index 58aeaf1724..c4fca25758 100644 --- a/pcbnew/pcbframe.cpp +++ b/pcbnew/pcbframe.cpp @@ -582,12 +582,12 @@ void PCB_EDIT_FRAME::SwitchCanvas( wxCommandEvent& aEvent ) break; case ID_MENU_CANVAS_CAIRO: - m_galCanvas->SwitchBackend( EDA_DRAW_PANEL_GAL::GAL_TYPE_CAIRO, false ); + m_galCanvas->SwitchBackend( EDA_DRAW_PANEL_GAL::GAL_TYPE_CAIRO ); UseGalCanvas( true ); break; case ID_MENU_CANVAS_OPENGL: - m_galCanvas->SwitchBackend( EDA_DRAW_PANEL_GAL::GAL_TYPE_OPENGL, false ); + m_galCanvas->SwitchBackend( EDA_DRAW_PANEL_GAL::GAL_TYPE_OPENGL, true ); UseGalCanvas( true ); break; }