diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 4a173cf3fa..67bacb0530 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -12,6 +12,20 @@ include_directories( ) if(KICAD_GAL) +# Generate files containing shader programs +add_custom_command ( + OUTPUT gal/opengl/shader_src.h + DEPENDS gal/opengl/make_shader_src_h.sh + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/common/gal/opengl + COMMAND ${SHELL} + ARGS ${PROJECT_SOURCE_DIR}/common/gal/opengl/make_shader_src_h.sh +) + +add_custom_target ( + ShaderHeader ALL + DEPENDS gal/opengl/shader_src.h +) + set(GAL_SRCS drawpanel_gal.cpp painter.cpp @@ -27,6 +41,7 @@ set(GAL_SRCS ) add_library(gal STATIC ${GAL_SRCS}) +add_dependencies(gal ShaderHeader) if(WIN32) add_definitions(-DGLEW_STATIC) diff --git a/common/drawpanel_gal.cpp b/common/drawpanel_gal.cpp index 2896be651f..77719d093b 100644 --- a/common/drawpanel_gal.cpp +++ b/common/drawpanel_gal.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -56,11 +55,6 @@ EDA_DRAW_PANEL_GAL::EDA_DRAW_PANEL_GAL( wxWindow* aParentWindow, wxWindowID aWin m_view = NULL; m_painter = NULL; - wxStandardPaths paths; - wxFileName executableFile( paths.GetExecutablePath() ); - m_galShaderPath = std::string( ( executableFile.GetPath() + - wxT( "/../../common/gal/opengl" ) ).mb_str() ); - SwitchBackend( aGalType, true ); SetBackgroundStyle( wxBG_STYLE_CUSTOM ); @@ -170,7 +164,6 @@ void EDA_DRAW_PANEL_GAL::SwitchBackend( GalType aGalType, bool aUseShaders ) { case GAL_TYPE_OPENGL: m_gal = new KiGfx::OPENGL_GAL( this, this, this, aUseShaders ); - static_cast (m_gal)->SetShaderPath( m_galShaderPath ); break; case GAL_TYPE_CAIRO: diff --git a/common/gal/opengl/make_shader_src_h.sh b/common/gal/opengl/make_shader_src_h.sh new file mode 100755 index 0000000000..19f6a410f2 --- /dev/null +++ b/common/gal/opengl/make_shader_src_h.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +# Make a header file containing GLSL source code +echo "Generating headers containing GLSL source code.." + +# Source files to be included +SHADER_SRC=( "shader.vert" "shader.frag" ) +# Number of shaders +SHADERS_NUMBER=${#SHADER_SRC[@]} +OUTPUT="shader_src.h" + +# Prepare GLSL source to be included in C array +function processSrc { + # 1st part: remove /* */ comments + # 2nd part: remove // comments + # 3rd part: remove blank lines (or containing only whitespaces) + # 4th & 5th part: wrap every line in quotation marks + sed '/\/\*/,/\*\//d; s/[ \t]*\/\/.*$//; /^[ \t]*$/d; s/^[ \t]*/"/; s/[ \t]*$/\\n"/' $1 >> $OUTPUT + echo "," >> $OUTPUT +} + +# Header +echo "#ifndef SHADER_SRC_H +#define SHADER_SRC_H + +const unsigned int shaders_number = $SHADERS_NUMBER; +const char *shaders_src[] = {" > $OUTPUT + +# Main contents +for filename in "${SHADER_SRC[@]}" +do + processSrc $filename +done + +# Footer +echo "}; +#endif /* SHADER_SRC_H */" >> $OUTPUT + +echo "Done." diff --git a/common/gal/opengl/opengl_gal.cpp b/common/gal/opengl/opengl_gal.cpp index b984655e13..dde0ff9c6d 100644 --- a/common/gal/opengl/opengl_gal.cpp +++ b/common/gal/opengl/opengl_gal.cpp @@ -74,7 +74,6 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener, isUseShader = isUseShaders; isShaderInitialized = false; isGrouping = false; - shaderPath = "../../common/gal/opengl"; wxSize parentSize = aParent->GetSize(); isVboInitialized = false; @@ -359,12 +358,12 @@ void OPENGL_GAL::BeginDrawing() // Compile the shaders if( !isShaderInitialized && isUseShader ) { - if( !shader.AddSource( shaderPath + std::string( "/shader.vert" ), SHADER_TYPE_VERTEX ) ) + if( !shader.LoadBuiltinShader( 0, SHADER_TYPE_VERTEX ) ) { wxLogFatalError( wxT( "Cannot compile vertex shader!" ) ); } - if( !shader.AddSource( shaderPath + std::string( "/shader.frag" ), SHADER_TYPE_FRAGMENT ) ) + if( !shader.LoadBuiltinShader( 1, SHADER_TYPE_FRAGMENT ) ) { wxLogFatalError( wxT( "Cannot compile fragment shader!" ) ); } diff --git a/common/gal/opengl/shader.cpp b/common/gal/opengl/shader.cpp index 8baf9f68c1..693e0596ac 100644 --- a/common/gal/opengl/shader.cpp +++ b/common/gal/opengl/shader.cpp @@ -32,14 +32,15 @@ #include #include +#include "shader_src.h" using namespace KiGfx; SHADER::SHADER() : isProgramCreated( false ), isShaderLinked( false ), - maximumVertices( 4 ), active( false ), + maximumVertices( 4 ), geomInputType( GL_LINES ), geomOutputType( GL_LINES ) { @@ -62,135 +63,21 @@ SHADER::~SHADER() } -void SHADER::ProgramInfo( GLuint aProgram ) +bool SHADER::LoadBuiltinShader( unsigned int aShaderNumber, ShaderType aShaderType ) { - GLint glInfoLogLength = 0; - GLint writtenChars = 0; + if( aShaderNumber >= shaders_number ) + return false; - // Get the length of the info string - glGetProgramiv( aProgram, GL_INFO_LOG_LENGTH, &glInfoLogLength ); - - // Print the information - if( glInfoLogLength > 2 ) - { - GLchar* glInfoLog = new GLchar[glInfoLogLength]; - glGetProgramInfoLog( aProgram, glInfoLogLength, &writtenChars, glInfoLog ); - - wxLogInfo( wxString::FromUTF8( (char*) glInfoLog ) ); - - delete glInfoLog; - } + return addSource( std::string( shaders_src[aShaderNumber] ), aShaderType ); } -void SHADER::ShaderInfo( GLuint aShader ) +bool SHADER::LoadShaderFromFile( const std::string& aShaderSourceName, ShaderType aShaderType ) { - GLint glInfoLogLength = 0; - GLint writtenChars = 0; - - // Get the length of the info string - glGetShaderiv( aShader, GL_INFO_LOG_LENGTH, &glInfoLogLength ); - - // Print the information - if( glInfoLogLength > 2 ) - { - GLchar* glInfoLog = new GLchar[glInfoLogLength]; - glGetShaderInfoLog( aShader, glInfoLogLength, &writtenChars, glInfoLog ); - - wxLogInfo( wxString::FromUTF8( (char*) glInfoLog ) ); - - delete glInfoLog; - } -} - - -std::string SHADER::ReadSource( std::string aShaderSourceName ) -{ - // Open the shader source for reading - std::ifstream inputFile( aShaderSourceName.c_str(), std::ifstream::in ); - std::string shaderSource; - - if( !inputFile ) - { - wxLogError( wxString::FromUTF8( "Can't read the shader source: " ) + - wxString( aShaderSourceName.c_str(), wxConvUTF8 ) ); - exit( 1 ); - } - - std::string shaderSourceLine; - - // Read all lines from the text file - while( getline( inputFile, shaderSourceLine ) ) - { - shaderSource += shaderSourceLine; - shaderSource += "\n"; - } - - return shaderSource; -} - - -bool SHADER::AddSource( const std::string& aShaderSourceName, ShaderType aShaderType ) -{ - if( isShaderLinked ) - { - wxLogError( wxString::FromUTF8( "Shader is already linked!" ) ); - } - - // Create the program - if( !isProgramCreated ) - { - programNumber = glCreateProgram(); - isProgramCreated = true; - } - // Load shader sources - std::string shaderSource = ReadSource( aShaderSourceName ); + const std::string shaderSource = readSource( aShaderSourceName ); - // Create a shader - GLuint shaderNumber = glCreateShader( aShaderType ); - shaderNumbers.push_back( shaderNumber ); - - // Get the program info - ProgramInfo( programNumber ); - - // Copy to char array - char* source = new char[shaderSource.size() + 1]; - strcpy( source, shaderSource.c_str() ); - const char** source_ = (const char**) ( &source ); - - // Attach the source - glShaderSource( shaderNumber, 1, source_, NULL ); - ProgramInfo( programNumber ); - - // Compile and attach shader to the program - glCompileShader( shaderNumber ); - GLint status; - glGetShaderiv( shaderNumber, GL_COMPILE_STATUS, &status ); - if( status != GL_TRUE ) - { - wxLogError( wxT( "Shader compilation error" ) ); - - ShaderInfo( shaderNumber ); - - return false; - } - - glAttachShader( programNumber, shaderNumber ); - ProgramInfo( programNumber ); - - // Special handling for the geometry shader - if( aShaderType == SHADER_TYPE_GEOMETRY ) - { - glProgramParameteriEXT( programNumber, GL_GEOMETRY_VERTICES_OUT_EXT, maximumVertices ); - glProgramParameteriEXT( programNumber, GL_GEOMETRY_INPUT_TYPE_EXT, geomInputType ); - glProgramParameteriEXT( programNumber, GL_GEOMETRY_OUTPUT_TYPE_EXT, geomOutputType ); - } - - // Delete the allocated char array - delete[] source; - - return true; + return addSource( shaderSource, aShaderType ); } @@ -207,7 +94,7 @@ bool SHADER::Link() { // Shader linking glLinkProgram( programNumber ); - ProgramInfo( programNumber ); + programInfo( programNumber ); // Check the Link state glGetObjectParameterivARB( programNumber, GL_OBJECT_LINK_STATUS_ARB, (GLint*) &isShaderLinked ); @@ -251,3 +138,133 @@ int SHADER::GetAttribute( std::string aAttributeName ) const { return glGetAttribLocation( programNumber, aAttributeName.c_str() ); } + + +void SHADER::programInfo( GLuint aProgram ) +{ + GLint glInfoLogLength = 0; + GLint writtenChars = 0; + + // Get the length of the info string + glGetProgramiv( aProgram, GL_INFO_LOG_LENGTH, &glInfoLogLength ); + + // Print the information + if( glInfoLogLength > 2 ) + { + GLchar* glInfoLog = new GLchar[glInfoLogLength]; + glGetProgramInfoLog( aProgram, glInfoLogLength, &writtenChars, glInfoLog ); + + wxLogInfo( wxString::FromUTF8( (char*) glInfoLog ) ); + + delete glInfoLog; + } +} + + +void SHADER::shaderInfo( GLuint aShader ) +{ + GLint glInfoLogLength = 0; + GLint writtenChars = 0; + + // Get the length of the info string + glGetShaderiv( aShader, GL_INFO_LOG_LENGTH, &glInfoLogLength ); + + // Print the information + if( glInfoLogLength > 2 ) + { + GLchar* glInfoLog = new GLchar[glInfoLogLength]; + glGetShaderInfoLog( aShader, glInfoLogLength, &writtenChars, glInfoLog ); + + wxLogInfo( wxString::FromUTF8( (char*) glInfoLog ) ); + + delete glInfoLog; + } +} + + +std::string SHADER::readSource( std::string aShaderSourceName ) +{ + // Open the shader source for reading + std::ifstream inputFile( aShaderSourceName.c_str(), std::ifstream::in ); + std::string shaderSource; + + if( !inputFile ) + { + wxLogError( wxString::FromUTF8( "Can't read the shader source: " ) + + wxString( aShaderSourceName.c_str(), wxConvUTF8 ) ); + exit( 1 ); + } + + std::string shaderSourceLine; + + // Read all lines from the text file + while( getline( inputFile, shaderSourceLine ) ) + { + shaderSource += shaderSourceLine; + shaderSource += "\n"; + } + + return shaderSource; +} + + +bool SHADER::addSource( const std::string& aShaderSource, ShaderType aShaderType ) +{ + if( isShaderLinked ) + { + wxLogError( wxString::FromUTF8( "Shader is already linked!" ) ); + } + + // Create the program + if( !isProgramCreated ) + { + programNumber = glCreateProgram(); + isProgramCreated = true; + } + + // Create a shader + GLuint shaderNumber = glCreateShader( aShaderType ); + shaderNumbers.push_back( shaderNumber ); + + // Get the program info + programInfo( programNumber ); + + // Copy to char array + char* source = new char[aShaderSource.size() + 1]; + strcpy( source, aShaderSource.c_str() ); + const char** source_ = (const char**) ( &source ); + + // Attach the source + glShaderSource( shaderNumber, 1, source_, NULL ); + programInfo( programNumber ); + + // Compile and attach shader to the program + glCompileShader( shaderNumber ); + GLint status; + glGetShaderiv( shaderNumber, GL_COMPILE_STATUS, &status ); + if( status != GL_TRUE ) + { + wxLogError( wxT( "Shader compilation error" ) ); + + shaderInfo( shaderNumber ); + + return false; + } + + glAttachShader( programNumber, shaderNumber ); + programInfo( programNumber ); + + // Special handling for the geometry shader + if( aShaderType == SHADER_TYPE_GEOMETRY ) + { + glProgramParameteriEXT( programNumber, GL_GEOMETRY_VERTICES_OUT_EXT, maximumVertices ); + glProgramParameteriEXT( programNumber, GL_GEOMETRY_INPUT_TYPE_EXT, geomInputType ); + glProgramParameteriEXT( programNumber, GL_GEOMETRY_OUTPUT_TYPE_EXT, geomOutputType ); + } + + // Delete the allocated char array + delete[] source; + + return true; +} + diff --git a/include/class_drawpanel_gal.h b/include/class_drawpanel_gal.h index 35c7488d52..b6a63306f9 100644 --- a/include/class_drawpanel_gal.h +++ b/include/class_drawpanel_gal.h @@ -91,8 +91,6 @@ protected: GalType m_currentGal; ///< Currently used GAL bool m_useShaders; ///< Are shaders used? (only for OpenGL GAL) wxLongLong m_timeStamp; - - std::string m_galShaderPath; ///< Path to shader files, used in OpenGL mode }; #endif diff --git a/include/gal/opengl/opengl_gal.h b/include/gal/opengl/opengl_gal.h index 8b098440cf..663bb29d6b 100644 --- a/include/gal/opengl/opengl_gal.h +++ b/include/gal/opengl/opengl_gal.h @@ -320,11 +320,6 @@ public: paintListener = aPaintListener; } - void SetShaderPath( const std::string& aPath ) - { - shaderPath = aPath; - } - ///< Parameters passed to the GLU tesselator typedef struct { @@ -389,7 +384,6 @@ private: 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 diff --git a/include/gal/opengl/shader.h b/include/gal/opengl/shader.h index f4804c3b66..9e94d9b406 100644 --- a/include/gal/opengl/shader.h +++ b/include/gal/opengl/shader.h @@ -71,12 +71,22 @@ public: virtual ~SHADER(); /** - * @brief Add a shader and compile the shader sources. + * @brief Loads one of the built-in shaders and compiles it. + * + * @param aShaderNumber is the shader number (indexing from 0). + * @param aShaderType is the type of the shader. + * @return True in case of success, false otherwise. + */ + bool LoadBuiltinShader( unsigned int aShaderNumber, ShaderType aShaderType ); + + /** + * @brief Loads one of the built-in shaders and compiles it. * * @param aShaderSourceName is the shader source file name. * @param aShaderType is the type of the shader. + * @return True in case of success, false otherwise. */ - bool AddSource( const std::string& aShaderSourceName, ShaderType aShaderType ); + bool LoadShaderFromFile( const std::string& aShaderSourceName, ShaderType aShaderType ); /** * @brief Link the shaders. @@ -157,14 +167,14 @@ private: * * @param aProgram is the program number. */ - void ProgramInfo( GLuint aProgram ); + void programInfo( GLuint aProgram ); /** * @brief Get the shader information. * * @param aShader is the shader number. */ - void ShaderInfo( GLuint aShader ); + void shaderInfo( GLuint aShader ); /** * @brief Read the shader source file @@ -172,7 +182,16 @@ private: * @param aShaderSourceName is the shader source file name. * @return the source as string */ - std::string ReadSource( std::string aShaderSourceName ); + std::string readSource( std::string aShaderSourceName ); + + /** + * @brief Add a shader and compile the shader sources. + * + * @param aShaderSource is the shader source content. + * @param aShaderType is the type of the shader. + * @return True in case of success, false otherwise. + */ + bool addSource( const std::string& aShaderSource, ShaderType aShaderType ); std::deque shaderNumbers; ///< Shader number list GLuint programNumber; ///< Shader program number