Commit 28511cf4 authored by Maciej Suminski's avatar Maciej Suminski

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.
parent ad5d10a8
......@@ -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
......
......@@ -26,8 +26,9 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <cmath>
#include <gal/opengl/opengl_gal.h>
#include <gal/opengl/shader.h>
#include <gal/definitions.h>
#include <gal/opengl/glm/gtc/matrix_transform.hpp>
......@@ -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() );
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 );
wxLogFatalError( wxT( "Cannot link the shaders!" ) );
}
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<GLuint*>( 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<VBO_ITEM*>::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 )
inline void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
{
if( currentShader != aIndex )
{
if( currentShader >= 0 )
shaderList[currentShader].Deactivate();
if( aIndex >= 0 )
shaderList[aIndex].Use();
VECTOR2D startEndVector = aEndPoint - aStartPoint;
double lineLength = startEndVector.EuclideanNorm();
double scale = 0.5 * lineWidth / lineLength;
currentShader = aIndex;
#ifdef __WXDEBUG__
if( lineLength > 0.0 )
{
wxLogDebug( wxT( "Tried to draw line with length <= 0" ) );
}
}
#endif /* __WXDEBUG__ */
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( lineLength <= 0.0 )
return;
if( l.x == 0 && l.y == 0 )
{
l = VECTOR2D( aWidth / 2.0, 0.0 );
aspect = 0.0;
}
else
if( lineWidth * worldScale < 1.0002 && !isGrouping && !isUseShader )
{
l = l.Resize( aWidth / 2.0 );
aspect = lnorm / (lnorm + aWidth);
// Limit the width of the line to a minimum of one pixel
// this looks best without anti-aliasing
scale = 0.5001 / worldScale / lineLength;
}
VECTOR2D p = l.Perpendicular();
VECTOR2D corners[4] = { aStartPoint - l - p, aEndPoint + l - p,
aEndPoint + l + p, aStartPoint - l + p };
VECTOR2D perpendicularVector( -startEndVector.y * scale, startEndVector.x * scale );
if( aStroke )
{
color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
}
else
begin( GL_TRIANGLES );
if( isUseShader )
{
color4( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
}
glm::vec4 vector( perpendicularVector.x, perpendicularVector.y, 0.0, 0.0 );
selectShader( 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 );
}
if( aGlBegin )
glBegin( GL_QUADS ); // shader
// Line width is maintained by the vertex shader
setShader( SHADER_LINE, vector.x, vector.y, lineWidth );
vertex3( aStartPoint.x, aStartPoint.y, layerDepth ); // v0
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 );
setShader( SHADER_LINE, -vector.x, -vector.y, lineWidth );
vertex3( aStartPoint.x, aStartPoint.y, layerDepth ); // v1
if( aGlBegin )
glEnd();
}
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
inline void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint )
{
VECTOR2D startEndVector = aEndPoint - aStartPoint;
double lineLength = startEndVector.EuclideanNorm();
setShader( SHADER_LINE, -vector.x, -vector.y, lineWidth );
vertex3( aEndPoint.x, aEndPoint.y, layerDepth ); // v3
// 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 )
{
scale = scale1pix;
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;
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;
vertex3( v0.x, v0.y, layerDepth );
vertex3( v1.x, v1.y, layerDepth );
vertex3( v3.x, v3.y, layerDepth );
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 );
}
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 );
color4( fillColor.r, fillColor.g, fillColor.b, fillColor.a );
drawLineCap( aStartPoint, aEndPoint );
drawLineCap( aEndPoint, aStartPoint );
drawLineQuad( aStartPoint, aEndPoint );
}
else
if( isStrokeEnabled )
{
VECTOR2D startEndVector = aEndPoint - aStartPoint;
double lineLength = startEndVector.EuclideanNorm();
if( lineLength > 0.0 )
{
color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
// TODO outline mode
color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
drawLineCap( aStartPoint, aEndPoint, layerDepth );
drawLineCap( aEndPoint, aStartPoint, layerDepth );
drawLineQuad( aStartPoint, aEndPoint );
}
drawLineCap( aStartPoint, aEndPoint );
drawLineCap( aEndPoint, aStartPoint );
drawLineQuad( aStartPoint, aEndPoint );
}
}
void OPENGL_GAL::DrawPolyline( std::deque<VECTOR2D>& aPointList )
{
LineCap savedLineCap = lineCap;
bool isFirstPoint = true;
if( isUseShader )
{
// This method reduces amount of triangles used for drawing
std::deque<VECTOR2D>::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<VECTOR2D>& aPointList )
if( isFirstLine )
{
drawLineCap( lastPoint, actualPoint, layerDepth );
drawLineCap( lastPoint, actualPoint );
isFirstLine = false;
}
else
......@@ -1029,7 +1048,7 @@ void OPENGL_GAL::DrawPolyline( std::deque<VECTOR2D>& 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<VECTOR2D> 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 ) );
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
double alphaIncrement = 2.0 * M_PI / CIRCLE_POINTS;
color4( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
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<VECTOR2D>& 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<OGLPOINT> 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<VBO_ITEM*>::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 );
......
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2013 Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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( dot( aCoord, aCoord ) < 1.0 )
gl_FragColor = gl_Color;
else
discard;
}
if( v.x <= 0.0 || (dot( d, d ) < 1.0 ) )
void strokedCircle( vec2 aCoord, float aWidth )
{
if( ( dot( aCoord, aCoord ) < 1.0 ) &&
( dot( aCoord, aCoord ) > aWidth * aWidth ) )
gl_FragColor = gl_Color;
else
discard;
}
// gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
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;
}
}
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> gmx.de
* Copyright (C) 2012 Kicad Developers, see change_log.txt for contributors.
* Copyright (C) 2013 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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;
}
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> 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;
}
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> 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();
}
}
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> 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;
}
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> 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 ) );
}
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2012 Torsten Hueter, torstenhtr <at> 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();
}
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2013 Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* 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;
}
......@@ -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<GLfloat*>::const_iterator v_it, v_end;
std::list<VBO_VERTEX*>::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<GLfloat*>::const_iterator v_it;
std::list<VBO_VERTEX*>::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<GLuint*>::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;
}
......@@ -36,6 +36,7 @@
// OpenGL mathematics library
#define GLM_FORCE_RADIANS
#include <gal/opengl/vbo_item.h>
#include <gal/opengl/shader.h>
// wxWidgets imports
#include <wx/wx.h>
......@@ -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<SHADER> 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
......
......@@ -34,10 +34,31 @@
#include <gal/opengl/glm/glm.hpp>
#include <gal/color4d.h>
#include <cstddef>
#include <list>
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<GLfloat*> m_vertBlocks;
std::list<GLuint*> 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<VBO_VERTEX*> m_vertBlocks;
std::list<GLuint*> 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;
......
......@@ -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;
}
......
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