diff --git a/common/gal/opengl/gl_builtin_shaders.cpp b/common/gal/opengl/gl_builtin_shaders.cpp index c455a53d6e..a17bd42456 100644 --- a/common/gal/opengl/gl_builtin_shaders.cpp +++ b/common/gal/opengl/gl_builtin_shaders.cpp @@ -60,13 +60,18 @@ const char kicad_vertex_shader[] = R"SHADER_SOURCE( * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#version 120 +#version 130 // Shader types -const float SHADER_LINE = 1.0; -const float SHADER_FILLED_CIRCLE = 2.0; -const float SHADER_STROKED_CIRCLE = 3.0; -const float SHADER_FONT = 4.0; +const int SHADER_FILLED_CIRCLE = 2; +const int SHADER_STROKED_CIRCLE = 3; +const int SHADER_FONT = 4; +const int SHADER_LINE_A = 5; +const int SHADER_LINE_B = 6; +const int SHADER_LINE_C = 7; +const int SHADER_LINE_D = 8; +const int SHADER_LINE_E = 9; +const int SHADER_LINE_F = 10; // Minimum line width const float MIN_WIDTH = 1.0; @@ -74,58 +79,84 @@ const float MIN_WIDTH = 1.0; attribute vec4 attrShaderParams; varying vec4 shaderParams; varying vec2 circleCoords; +uniform float worldPixelSize; -void main() +void computeLineCoords( bool posture, vec2 offset, vec2 texcoord, vec2 dir ) { - // Pass attributes to the fragment shader - shaderParams = attrShaderParams; + float w = length(offset); - if( shaderParams[0] == SHADER_LINE ) + if( w > worldPixelSize ) { - float lineWidth = shaderParams[3]; - float worldScale = abs( gl_ModelViewMatrix[0][0] ); - - // Make lines appear to be at least 1 pixel wide - if( worldScale * lineWidth < MIN_WIDTH ) - gl_Position = gl_ModelViewProjectionMatrix * - ( gl_Vertex + vec4( shaderParams.yz * MIN_WIDTH / ( worldScale * lineWidth ), 0.0, 0.0 ) ); - else - gl_Position = gl_ModelViewProjectionMatrix * - ( gl_Vertex + vec4( shaderParams.yz, 0.0, 0.0 ) ); - } - else if( ( shaderParams[0] == SHADER_STROKED_CIRCLE ) || - ( shaderParams[0] == SHADER_FILLED_CIRCLE ) ) - { - // Compute relative circle coordinates basing on indices - // Circle - if( shaderParams[1] == 1.0 ) - circleCoords = vec2( -sqrt( 3.0 ), -1.0 ); - else if( shaderParams[1] == 2.0 ) - circleCoords = vec2( sqrt( 3.0 ), -1.0 ); - else if( shaderParams[1] == 3.0 ) - circleCoords = vec2( 0.0, 2.0 ); - - // Semicircle - else if( shaderParams[1] == 4.0 ) - circleCoords = vec2( -3.0 / sqrt( 3.0 ), 0.0 ); - else if( shaderParams[1] == 5.0 ) - circleCoords = vec2( 3.0 / sqrt( 3.0 ), 0.0 ); - else if( shaderParams[1] == 6.0 ) - circleCoords = vec2( 0.0, 2.0 ); - - // Make the line appear to be at least 1 pixel wide - float lineWidth = shaderParams[3]; - float worldScale = abs( gl_ModelViewMatrix[0][0] ); - - if( worldScale * lineWidth < MIN_WIDTH ) - shaderParams[3] = shaderParams[3] / ( worldScale * lineWidth ); - - gl_Position = ftransform(); + gl_Position = gl_ModelViewProjectionMatrix * vec4( gl_Vertex.x + offset.x, gl_Vertex.y + offset.y, gl_Vertex.z, gl_Vertex.w ); + shaderParams[0] = SHADER_LINE_A; + gl_TexCoord[0].st = texcoord; } else { - // Pass through the coordinates like in the fixed pipeline - gl_Position = ftransform(); + vec4 pos = gl_Vertex; + pos.xy += (posture ? dir : dir.yx ) * worldPixelSize / 2.0; + gl_Position = gl_ModelViewProjectionMatrix * pos; + shaderParams[0] = SHADER_LINE_B; + } +} + + +void main() +{ + int mode = int( attrShaderParams[0] ); + + // Pass attributes to the fragment shader + shaderParams = attrShaderParams; + + float aspect = shaderParams.y; + vec2 vs = shaderParams.zw; + vec2 vp = vec2(-vs.y, vs.x); + bool posture = abs( vs.x ) < abs(vs.y); + + switch( mode ) + { + case SHADER_LINE_A: computeLineCoords( posture, vp - vs, vec2( -aspect, -1 ), vec2(-1,0) ); break; + case SHADER_LINE_B: computeLineCoords( posture, -vp - vs, vec2( -aspect, 1 ), vec2(1,0) ); break; + case SHADER_LINE_C: computeLineCoords( posture, -vp + vs, vec2( aspect, 1 ), vec2(1,0) ); break; + case SHADER_LINE_D: computeLineCoords( posture, -vp + vs, vec2( -aspect, -1), vec2(1,0) ); break; + case SHADER_LINE_E: computeLineCoords( posture, vp + vs, vec2( -aspect, 1 ), vec2(-1,0) ); break; + case SHADER_LINE_F: computeLineCoords( posture, vp - vs, vec2( aspect, 1 ), vec2(-1,0) ); break; + case SHADER_STROKED_CIRCLE: + case SHADER_FILLED_CIRCLE: + { + // Compute relative circle coordinates basing on indices + // Circle + if( shaderParams[1] == 1.0 ) + circleCoords = vec2( -sqrt( 3.0 ), -1.0 ); + else if( shaderParams[1] == 2.0 ) + circleCoords = vec2( sqrt( 3.0 ), -1.0 ); + else if( shaderParams[1] == 3.0 ) + circleCoords = vec2( 0.0, 2.0 ); + + // Semicircle + else if( shaderParams[1] == 4.0 ) + circleCoords = vec2( -3.0 / sqrt( 3.0 ), 0.0 ); + else if( shaderParams[1] == 5.0 ) + circleCoords = vec2( 3.0 / sqrt( 3.0 ), 0.0 ); + else if( shaderParams[1] == 6.0 ) + circleCoords = vec2( 0.0, 2.0 ); + + // Make the line appear to be at least 1 pixel wide + float lineWidth = shaderParams[3]; + float worldScale = abs( gl_ModelViewMatrix[0][0] ); + + if( worldScale * lineWidth < MIN_WIDTH ) + shaderParams[3] = shaderParams[3] / ( worldScale * lineWidth ); + + gl_Position = ftransform(); + + break; + } + default: + { + gl_Position = ftransform(); + break; + } } gl_FrontColor = gl_Color; @@ -162,20 +193,22 @@ const char kicad_fragment_shader[] = R"SHADER_SOURCE( * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#version 120 +#version 130 // Multi-channel signed distance field #define USE_MSDF // Shader types -const float SHADER_LINE = 1.0; const float SHADER_FILLED_CIRCLE = 2.0; const float SHADER_STROKED_CIRCLE = 3.0; const float SHADER_FONT = 4.0; +const float SHADER_LINE_A = 5.0; +const float SHADER_LINE_B = 6.0; varying vec4 shaderParams; varying vec2 circleCoords; uniform sampler2D fontTexture; +uniform float worldPixelSize; // Needed to reconstruct the mipmap level / texel derivative uniform int fontTextureWidth; @@ -188,6 +221,36 @@ void filledCircle( vec2 aCoord ) discard; } +float pixelSegDistance( vec2 aCoord ) +{ + if (shaderParams[0] == SHADER_LINE_B) + { + gl_FragColor = gl_Color; + return 0.0; + } + + float aspect = shaderParams[1]; + float dist; + vec2 v = vec2( 1.0 - (aspect - abs(aCoord.s)), aCoord.t); + + if( v.x <= 0.0 ) + { + dist = abs(aCoord.t); + } + else + { + dist = length(v); + } + + return dist; +} + +int isPixelInSegment( vec2 aCoord ) +{ + return pixelSegDistance(aCoord) <= 1.0 ? 1 : 0; +} + + void strokedCircle( vec2 aCoord, float aRadius, float aWidth ) { @@ -202,6 +265,15 @@ void strokedCircle( vec2 aCoord, float aRadius, float aWidth ) discard; } + +void drawLine( vec2 aCoord ) +{ + if( isPixelInSegment( aCoord ) != 0) + gl_FragColor = gl_Color; + else + discard; +} + #ifdef USE_MSDF float median( vec3 v ) { @@ -211,7 +283,11 @@ float median( vec3 v ) void main() { - if( shaderParams[0] == SHADER_FILLED_CIRCLE ) + if( shaderParams[0] == SHADER_LINE_A ) + { + drawLine( gl_TexCoord[0].st ); + } + else if( shaderParams[0] == SHADER_FILLED_CIRCLE ) { filledCircle( circleCoords ); } diff --git a/common/gal/opengl/gpu_manager.cpp b/common/gal/opengl/gpu_manager.cpp index 374e31c074..921c0c3867 100644 --- a/common/gal/opengl/gpu_manager.cpp +++ b/common/gal/opengl/gpu_manager.cpp @@ -287,6 +287,8 @@ void GPU_NONCACHED_MANAGER::EndDrawing() m_shader->Deactivate(); } + m_container->Clear(); + #ifdef __WXDEBUG__ totalRealTime.Stop(); wxLogTrace( "GAL_PROFILE", diff --git a/common/gal/opengl/opengl_gal.cpp b/common/gal/opengl/opengl_gal.cpp index 34f18b5891..5a8ffca1a9 100644 --- a/common/gal/opengl/opengl_gal.cpp +++ b/common/gal/opengl/opengl_gal.cpp @@ -319,6 +319,11 @@ bool OPENGL_GAL::updatedGalDisplayOptions( const GAL_DISPLAY_OPTIONS& aOptions ) return refresh; } +double OPENGL_GAL::getWorldPixelSize() const +{ + auto matrix = GetScreenWorldMatrix(); + return std::min(std::abs(matrix.GetScale().x), std::abs(matrix.GetScale().y ) ); +} void OPENGL_GAL::BeginDrawing() { @@ -433,6 +438,8 @@ void OPENGL_GAL::BeginDrawing() // Set shader parameter GLint ufm_fontTexture = shader->AddParameter( "fontTexture" ); GLint ufm_fontTextureWidth = shader->AddParameter( "fontTextureWidth" ); + ufm_worldPixelSize = shader->AddParameter( "worldPixelSize" ); + shader->Use(); shader->SetParameter( ufm_fontTexture, (int) FONT_TEXTURE_UNIT ); shader->SetParameter( ufm_fontTextureWidth, (int) font_image.width ); @@ -442,6 +449,10 @@ void OPENGL_GAL::BeginDrawing() isBitmapFontInitialized = true; } + shader->Use(); + shader->SetParameter( ufm_worldPixelSize, (float) getWorldPixelSize() ); + shader->Deactivate(); + // Something betreen BeginDrawing and EndDrawing seems to depend on // this texture unit being active, but it does not assure it itself. glActiveTexture( GL_TEXTURE0 ); @@ -516,46 +527,26 @@ void OPENGL_GAL::EndUpdate() void OPENGL_GAL::DrawLine( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint ) { - const VECTOR2D startEndVector = aEndPoint - aStartPoint; - double lineAngle = startEndVector.Angle(); - currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a ); drawLineQuad( aStartPoint, aEndPoint ); - - // Line caps - if( lineWidth > 1.0 ) - { - drawFilledSemiCircle( aStartPoint, lineWidth / 2, lineAngle + M_PI / 2 ); - drawFilledSemiCircle( aEndPoint, lineWidth / 2, lineAngle - M_PI / 2 ); - } } void OPENGL_GAL::DrawSegment( const VECTOR2D& aStartPoint, const VECTOR2D& aEndPoint, double aWidth ) { - VECTOR2D startEndVector = aEndPoint - aStartPoint; - double lineAngle = startEndVector.Angle(); - - // Width must be nonzero for anything to appear - if( aWidth <= 0 ) - aWidth = 1.0; - - if( isFillEnabled ) + if( isFillEnabled || aWidth == 1.0 ) { - // Filled tracks currentManager->Color( fillColor.r, fillColor.g, fillColor.b, fillColor.a ); SetLineWidth( aWidth ); drawLineQuad( aStartPoint, aEndPoint ); - - // Draw line caps - drawFilledSemiCircle( aStartPoint, aWidth / 2, lineAngle + M_PI / 2 ); - drawFilledSemiCircle( aEndPoint, aWidth / 2, lineAngle - M_PI / 2 ); } else { + auto startEndVector = aEndPoint - aStartPoint; + auto lineAngle = startEndVector.Angle(); // Outlined tracks double lineLength = startEndVector.EuclideanNorm(); @@ -1161,7 +1152,7 @@ void OPENGL_GAL::DrawGrid() compositor->SetBuffer( mainBuffer ); // sub-pixel lines all render the same - double minorLineWidth = std::max( 1.0, gridLineWidth ); + double minorLineWidth = std::max(1.0, gridLineWidth) * getWorldPixelSize(); double majorLineWidth = minorLineWidth * 2.0; // Draw the axis and grid @@ -1173,20 +1164,16 @@ void OPENGL_GAL::DrawGrid() // Draw axes if desired if( axesEnabled ) { - glLineWidth( minorLineWidth ); - glColor4d( axesColor.r, axesColor.g, axesColor.b, axesColor.a ); + SetLineWidth( minorLineWidth ); + SetStrokeColor( axesColor ); - glBegin( GL_LINES ); - glVertex2d( worldStartPoint.x, 0 ); - glVertex2d( worldEndPoint.x, 0 ); - glEnd(); - - glBegin( GL_LINES ); - glVertex2d( 0, worldStartPoint.y ); - glVertex2d( 0, worldEndPoint.y ); - glEnd(); + DrawLine( VECTOR2D( worldStartPoint.x, 0 ), VECTOR2D( worldEndPoint.x, 0 ) ); + DrawLine( VECTOR2D( 0, worldStartPoint.y ), VECTOR2D( 0, worldEndPoint.y ) ); } + // force flush + nonCachedManager->EndDrawing(); + if( !gridVisibility ) return; @@ -1227,19 +1214,21 @@ void OPENGL_GAL::DrawGrid() glStencilFunc( GL_ALWAYS, 1, 1 ); glStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); glColor4d( 0.0, 0.0, 0.0, 0.0 ); + SetStrokeColor( COLOR4D(0.0, 0.0, 0.0, 0.0 ) ); } else { glColor4d( gridColor.r, gridColor.g, gridColor.b, gridColor.a ); + SetStrokeColor( gridColor ); } if( gridStyle == GRID_STYLE::SMALL_CROSS ) { - glLineWidth( minorLineWidth ); + SetLineWidth( minorLineWidth ); // calculate a line len = 2 minorLineWidth, in internal unit value // (in fact the size of cross is lineLen*2) - int lineLen = KiROUND( minorLineWidth / worldScale * 2 ); + int lineLen = KiROUND( minorLineWidth * 2.0 ); // Vertical positions for( int j = gridStartY; j <= gridEndY; j++ ) @@ -1257,12 +1246,8 @@ void OPENGL_GAL::DrawGrid() { int posX = i * gridSize.x + gridOrigin.x; - glBegin( GL_LINES ); - glVertex2d( posX -lineLen, posY ); - glVertex2d( posX + lineLen, posY ); - glVertex2d( posX, posY - lineLen ); - glVertex2d( posX, posY + lineLen ); - glEnd(); + DrawLine( VECTOR2D( posX - lineLen, posY ), VECTOR2D( posX + lineLen, posY ) ); + DrawLine( VECTOR2D( posX, posY - lineLen ), VECTOR2D( posX, posY + lineLen ) ); } } } @@ -1280,24 +1265,27 @@ void OPENGL_GAL::DrawGrid() continue; if( j % gridTick == 0 && gridScreenSizeDense > gridThreshold ) - glLineWidth( majorLineWidth ); + SetLineWidth( majorLineWidth ); else - glLineWidth( minorLineWidth ); + SetLineWidth( minorLineWidth ); if( ( j % gridTick == 0 && gridScreenSizeCoarse > gridThreshold ) || gridScreenSizeDense > gridThreshold ) { - glBegin( GL_LINES ); - glVertex2d( gridStartX * gridSize.x + gridOrigin.x, y ); - glVertex2d( gridEndX * gridSize.x + gridOrigin.x, y ); - glEnd(); + VECTOR2D a ( gridStartX * gridSize.x + gridOrigin.x, y ); + VECTOR2D b ( gridEndX * gridSize.x + gridOrigin.x, y ); + + DrawLine( a, b ); } } + nonCachedManager->EndDrawing(); + if( gridStyle == GRID_STYLE::DOTS ) { glStencilFunc( GL_NOTEQUAL, 0, 1 ); glColor4d( gridColor.r, gridColor.g, gridColor.b, gridColor.a ); + SetStrokeColor( gridColor ); } // Horizontal lines @@ -1310,20 +1298,21 @@ void OPENGL_GAL::DrawGrid() continue; if( i % gridTick == 0 && gridScreenSizeDense > gridThreshold ) - glLineWidth( majorLineWidth ); + SetLineWidth( majorLineWidth ); else - glLineWidth( minorLineWidth ); + SetLineWidth( minorLineWidth ); if( ( i % gridTick == 0 && gridScreenSizeCoarse > gridThreshold ) || gridScreenSizeDense > gridThreshold ) { - glBegin( GL_LINES ); - glVertex2d( x, gridStartY * gridSize.y + gridOrigin.y ); - glVertex2d( x, gridEndY * gridSize.y + gridOrigin.y ); - glEnd(); + VECTOR2D a ( x, gridStartY * gridSize.y + gridOrigin.y ); + VECTOR2D b ( x, gridEndY * gridSize.y + gridOrigin.y ); + DrawLine( a, b ); } } + nonCachedManager->EndDrawing(); + if( gridStyle == GRID_STYLE::DOTS ) glDisable( GL_STENCIL_TEST ); } @@ -1576,38 +1565,47 @@ void OPENGL_GAL::drawLineQuad( const VECTOR2D& aStartPoint, const VECTOR2D& aEnd * dots mark triangles' hypotenuses */ - VECTOR2D startEndVector = aEndPoint - aStartPoint; - double lineLength = startEndVector.EuclideanNorm(); + auto v1 = currentManager->GetTransformation() * glm::vec4( aStartPoint.x, aStartPoint.y, 0.0, 0.0 ); + auto v2 = currentManager->GetTransformation() * glm::vec4( aEndPoint.x, aEndPoint.y, 0.0, 0.0 ); - if( lineLength <= 0.0 ) - return; + VECTOR2D startEndVector( v2.x - v1.x, v2.y - v1.y ); - double scale = 0.5 * lineWidth / lineLength; + double lineLength = startEndVector.EuclideanNorm(); - // The perpendicular vector also needs transformations - glm::vec4 vector = currentManager->GetTransformation() * - glm::vec4( -startEndVector.y * scale, startEndVector.x * scale, 0.0, 0.0 ); + VECTOR2D vs ( startEndVector ); + float aspect; + + if ( lineWidth == 0.0 ) // pixel-width line + { + vs = vs.Resize( 0.5 ); + aspect = ( lineLength + 1.0 ); + } + else + { + vs = vs.Resize( 0.5 * lineWidth ); + aspect = ( lineLength + lineWidth ) / lineWidth; + } currentManager->Reserve( 6 ); // Line width is maintained by the vertex shader - currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth ); - currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); // v0 + currentManager->Shader( SHADER_LINE_A, aspect, vs.x, vs.y ); + currentManager->Vertex( aStartPoint, layerDepth ); - currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth ); - currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); // v1 + currentManager->Shader( SHADER_LINE_B, aspect, vs.x, vs.y ); + currentManager->Vertex( aStartPoint, layerDepth ); - currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth ); - currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); // v3 + currentManager->Shader( SHADER_LINE_C, aspect, vs.x, vs.y ); + currentManager->Vertex( aEndPoint, layerDepth ); - currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth ); - currentManager->Vertex( aStartPoint.x, aStartPoint.y, layerDepth ); // v0 + currentManager->Shader( SHADER_LINE_D, aspect, vs.x, vs.y ); + currentManager->Vertex( aEndPoint, layerDepth ); - currentManager->Shader( SHADER_LINE, -vector.x, -vector.y, lineWidth ); - currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); // v3 + currentManager->Shader( SHADER_LINE_E, aspect, vs.x, vs.y ); + currentManager->Vertex( aEndPoint, layerDepth ); - currentManager->Shader( SHADER_LINE, vector.x, vector.y, lineWidth ); - currentManager->Vertex( aEndPoint.x, aEndPoint.y, layerDepth ); // v2 + currentManager->Shader( SHADER_LINE_F, aspect, vs.x, vs.y ); + currentManager->Vertex( aStartPoint, layerDepth ); } diff --git a/include/gal/opengl/opengl_gal.h b/include/gal/opengl/opengl_gal.h index 96428b52e6..72a82d48d3 100644 --- a/include/gal/opengl/opengl_gal.h +++ b/include/gal/opengl/opengl_gal.h @@ -328,6 +328,7 @@ private: bool isInitialized; ///< Basic initialization flag, has to be done ///< when the window is visible bool isGrouping; ///< Was a group started? + GLint ufm_worldPixelSize; std::unique_ptr bitmapCache; @@ -465,6 +466,8 @@ private: return std::min( 1e6 / aRadius, 2.0 * M_PI / CIRCLE_POINTS ); } + double getWorldPixelSize() const; + /** * @brief Basic OpenGL initialization. */ diff --git a/include/gal/opengl/vertex_common.h b/include/gal/opengl/vertex_common.h index f255633c4b..017ac76799 100644 --- a/include/gal/opengl/vertex_common.h +++ b/include/gal/opengl/vertex_common.h @@ -30,20 +30,26 @@ #ifndef VERTEX_COMMON_H_ #define VERTEX_COMMON_H_ +#include #include #include namespace KIGFX { -///> Possible types of shaders +///> Possible types of shaders (keep consistent with the actual shader source in gl_builtin_shaders.cpp) enum SHADER_MODE { SHADER_NONE = 0, - SHADER_LINE, - SHADER_FILLED_CIRCLE, - SHADER_STROKED_CIRCLE, - SHADER_FONT + SHADER_FILLED_CIRCLE = 2, + SHADER_STROKED_CIRCLE = 3, + SHADER_FONT = 4, + SHADER_LINE_A = 5, + SHADER_LINE_B = 6, + SHADER_LINE_C = 7, + SHADER_LINE_D = 8, + SHADER_LINE_E = 9, + SHADER_LINE_F = 10 }; ///> Data structure for vertices {X,Y,Z,R,G,B,A,shader¶m} diff --git a/include/gal/opengl/vertex_manager.h b/include/gal/opengl/vertex_manager.h index 12bbaaea50..bb4d3711bd 100644 --- a/include/gal/opengl/vertex_manager.h +++ b/include/gal/opengl/vertex_manager.h @@ -106,6 +106,20 @@ public: */ bool Vertex( GLfloat aX, GLfloat aY, GLfloat aZ ); + /** + * Function Vertex() + * adds a vertex with the given coordinates to the currently set item. Vertex coordinates will + * have the current transformation matrix applied. + * + * @param aXY are the XY coordinates of the new vertex. + * @param aZ is the Z coordinate of the new vertex. + * @return True if successful, false otherwise. + */ + bool Vertex( const VECTOR2D& aXY, GLfloat aZ ) + { + return Vertex( aXY.x, aXY.y, aZ ); + } + /** * Function Vertices() * adds one or more vertices to the currently set item. It takes advantage of allocating memory @@ -163,10 +177,10 @@ public: * @param aParam2 is the optional parameter for a shader. * @param aParam3 is the optional parameter for a shader. */ - inline void Shader( GLfloat aShaderType, GLfloat aParam1 = 0.0f, + inline void Shader( int aShaderType, GLfloat aParam1 = 0.0f, GLfloat aParam2 = 0.0f, GLfloat aParam3 = 0.0f ) { - m_shader[0] = aShaderType; + m_shader[0] = (float) aShaderType; m_shader[1] = aParam1; m_shader[2] = aParam2; m_shader[3] = aParam3;