From 1763861b260787e52e530999318191eb23bcefd0 Mon Sep 17 00:00:00 2001 From: Mrowqa Date: Thu, 18 Jul 2013 18:47:41 +0200 Subject: [PATCH] Added support for geometry shaders --- include/SFML/Graphics/Shader.hpp | 127 ++++++++++++++++--- src/SFML/Graphics/GLExtensions.hpp | 4 + src/SFML/Graphics/GLExtensions.txt | 1 + src/SFML/Graphics/GLLoader.cpp | 37 +++++- src/SFML/Graphics/GLLoader.hpp | 34 ++++++ src/SFML/Graphics/Shader.cpp | 189 +++++++++++++++++++++++++++-- 6 files changed, 359 insertions(+), 33 deletions(-) diff --git a/include/SFML/Graphics/Shader.hpp b/include/SFML/Graphics/Shader.hpp index fbd473c6..9f7e5f99 100644 --- a/include/SFML/Graphics/Shader.hpp +++ b/include/SFML/Graphics/Shader.hpp @@ -46,7 +46,7 @@ class Texture; class Transform; //////////////////////////////////////////////////////////// -/// \brief Shader class (vertex and fragment) +/// \brief Shader class (vertex, geometry and fragment) /// //////////////////////////////////////////////////////////// class SFML_GRAPHICS_API Shader : GlResource, NonCopyable @@ -59,8 +59,9 @@ public: //////////////////////////////////////////////////////////// enum Type { - Vertex, ///< %Vertex shader - Fragment ///< Fragment (pixel) shader + Vertex, ///< %Vertex shader + Geometry, ///< Geometry shader + Fragment ///< Fragment (pixel) shader }; //////////////////////////////////////////////////////////// @@ -97,9 +98,9 @@ public: ~Shader(); //////////////////////////////////////////////////////////// - /// \brief Load either the vertex or fragment shader from a file + /// \brief Load the vertex, geometry or fragment shader from a file /// - /// This function loads a single shader, either vertex or + /// This function loads a single shader, vertex, geometry or /// fragment, identified by the second argument. /// The source must be a text file containing a valid /// shader in GLSL language. GLSL is a C-like language @@ -107,8 +108,8 @@ public: /// read a good documentation for it before writing your /// own shaders. /// - /// \param filename Path of the vertex or fragment shader file to load - /// \param type Type of shader (vertex or fragment) + /// \param filename Path of the vertex, geometry or fragment shader file to load + /// \param type Type of shader (vertex, geometry or fragment) /// /// \return True if loading succeeded, false if it failed /// @@ -139,17 +140,39 @@ public: bool loadFromFile(const std::string& vertexShaderFilename, const std::string& fragmentShaderFilename); //////////////////////////////////////////////////////////// - /// \brief Load either the vertex or fragment shader from a source code in memory + /// \brief Load the vertex, geometry and fragment shaders from files /// - /// This function loads a single shader, either vertex or - /// fragment, identified by the second argument. + /// This function loads the vertex, geometry and fragment + /// shaders. If one of them fails to load, the shader is left + /// empty (the valid shader is unloaded). + /// The sources must be text files containing valid shaders + /// in GLSL language. GLSL is a C-like language dedicated to + /// OpenGL shaders; you'll probably need to read a good documentation + /// for it before writing your own shaders. + /// + /// \param vertexShaderFilename Path of the vertex shader file to load + /// \param geometryShaderFilename Path of the geometry shader file to load + /// \param fragmentShaderFilename Path of the fragment shader file to load + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see loadFromMemory, loadFromStream + /// + //////////////////////////////////////////////////////////// + bool loadFromFile(const std::string& vertexShaderFilename, const std::string& geometryShaderFilename, const std::string& fragmentShaderFilename); + + //////////////////////////////////////////////////////////// + /// \brief Load the vertex, geometry or fragment shader from a source code in memory + /// + /// This function loads a single shader, vertex, geometry + /// or fragment, identified by the second argument. /// The source code must be a valid shader in GLSL language. /// GLSL is a C-like language dedicated to OpenGL shaders; /// you'll probably need to read a good documentation for /// it before writing your own shaders. /// /// \param shader String containing the source code of the shader - /// \param type Type of shader (vertex or fragment) + /// \param type Type of shader (vertex, geometry or fragment) /// /// \return True if loading succeeded, false if it failed /// @@ -180,17 +203,39 @@ public: bool loadFromMemory(const std::string& vertexShader, const std::string& fragmentShader); //////////////////////////////////////////////////////////// - /// \brief Load either the vertex or fragment shader from a custom stream + /// \brief Load the vertex, geometry and fragment shaders from source codes in memory /// - /// This function loads a single shader, either vertex or - /// fragment, identified by the second argument. + /// This function loads the vertex, geometry and fragment + /// shaders. If one of them fails to load, the shader is left + /// empty (the valid shader is unloaded). + /// The sources must be valid shaders in GLSL language. GLSL is + /// a C-like language dedicated to OpenGL shaders; you'll + /// probably need to read a good documentation for it before + /// writing your own shaders. + /// + /// \param vertexShader String containing the source code of the vertex shader + /// \param geometryShader String containing the source code of the geometry shader + /// \param fragmentShader String containing the source code of the fragment shader + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see loadFromFile, loadFromStream + /// + //////////////////////////////////////////////////////////// + bool loadFromMemory(const std::string& vertexShader, const std::string& geometryShader, const std::string& fragmentShader); + + //////////////////////////////////////////////////////////// + /// \brief Load the vertex, geometry or fragment shader from a custom stream + /// + /// This function loads a single shader, vertex, geometry + /// or fragment, identified by the second argument. /// The source code must be a valid shader in GLSL language. /// GLSL is a C-like language dedicated to OpenGL shaders; /// you'll probably need to read a good documentation for it /// before writing your own shaders. /// /// \param stream Source stream to read from - /// \param type Type of shader (vertex or fragment) + /// \param type Type of shader (vertex, geometry or fragment) /// /// \return True if loading succeeded, false if it failed /// @@ -220,6 +265,28 @@ public: //////////////////////////////////////////////////////////// bool loadFromStream(InputStream& vertexShaderStream, InputStream& fragmentShaderStream); + //////////////////////////////////////////////////////////// + /// \brief Load the vertex, geometry and fragment shaders from custom streams + /// + /// This function loads the vertex, geometry and fragment + /// shaders. If one of them fails to load, the shader is left + /// empty (the valid shader is unloaded). + /// The source codes must be valid shaders in GLSL language. + /// GLSL is a C-like language dedicated to OpenGL shaders; + /// you'll probably need to read a good documentation for + /// it before writing your own shaders. + /// + /// \param vertexShaderStream Source stream to read the vertex shader from + /// \param geometryShaderStream Source stream to read the geometry shader from + /// \param fragmentShaderStream Source stream to read the fragment shader from + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see loadFromFile, loadFromMemory + /// + //////////////////////////////////////////////////////////// + bool loadFromStream(InputStream& vertexShaderStream, InputStream& geometryShaderStream, InputStream& fragmentShaderStream); + //////////////////////////////////////////////////////////// /// \brief Specify value for \p float uniform /// @@ -605,6 +672,25 @@ public: //////////////////////////////////////////////////////////// static bool isAvailable(); + //////////////////////////////////////////////////////////// + /// \brief Tell whether or not the system supports geometry shaders + /// + /// This function should always be called before using + /// the geometry shader features. If it returns false, then + /// any attempt to use sf::Shader geometry shader features will fail. + /// + /// This function can only return true if isAvailable() would also + /// return true, since shaders in general have to be supported in + /// order for geometry shaders to be supported as well. + /// + /// Note: The first call to this function, whether by your + /// code or SFML will result in a context switch. + /// + /// \return True if geometry shaders are supported, false otherwise + /// + //////////////////////////////////////////////////////////// + static bool isGeometryAvailable(); + private: //////////////////////////////////////////////////////////// @@ -614,12 +700,13 @@ private: /// is not created. /// /// \param vertexShaderCode Source code of the vertex shader + /// \param geometryShaderCode Source code of the geometry shader /// \param fragmentShaderCode Source code of the fragment shader /// /// \return True on success, false if any error happened /// //////////////////////////////////////////////////////////// - bool compile(const char* vertexShaderCode, const char* fragmentShaderCode); + bool compile(const char* vertexShaderCode, const char* geometryShaderCode, const char* fragmentShaderCode); //////////////////////////////////////////////////////////// /// \brief Bind all the textures used by the shader @@ -678,13 +765,15 @@ private: /// executed directly by the graphics card and allowing /// to apply real-time operations to the rendered entities. /// -/// There are two kinds of shaders: +/// There are three kinds of shaders: /// \li %Vertex shaders, that process vertices +/// \li Geometry shaders, that process primitives /// \li Fragment (pixel) shaders, that process pixels /// /// A sf::Shader can be composed of either a vertex shader -/// alone, a fragment shader alone, or both combined -/// (see the variants of the load functions). +/// alone, a geometry shader alone, a fragment shader alone, +/// or any combination of them. (see the variants of the +/// load functions). /// /// Shaders are written in GLSL, which is a C-like /// language dedicated to OpenGL shaders. You'll probably diff --git a/src/SFML/Graphics/GLExtensions.hpp b/src/SFML/Graphics/GLExtensions.hpp index bcc5d7e6..9dfa8d7f 100644 --- a/src/SFML/Graphics/GLExtensions.hpp +++ b/src/SFML/Graphics/GLExtensions.hpp @@ -228,6 +228,10 @@ #define GLEXT_GL_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING_EXT #define GLEXT_GL_INVALID_FRAMEBUFFER_OPERATION GL_INVALID_FRAMEBUFFER_OPERATION_EXT + // Core since 3.2 - ARB_geometry_shader4 + #define GLEXT_geometry_shader4 sfogl_ext_ARB_geometry_shader4 + #define GLEXT_GL_GEOMETRY_SHADER GL_GEOMETRY_SHADER_ARB + #endif namespace sf diff --git a/src/SFML/Graphics/GLExtensions.txt b/src/SFML/Graphics/GLExtensions.txt index 7e84e830..a2447cbe 100644 --- a/src/SFML/Graphics/GLExtensions.txt +++ b/src/SFML/Graphics/GLExtensions.txt @@ -14,3 +14,4 @@ ARB_fragment_shader ARB_texture_non_power_of_two EXT_blend_equation_separate EXT_framebuffer_object +ARB_geometry_shader4 diff --git a/src/SFML/Graphics/GLLoader.cpp b/src/SFML/Graphics/GLLoader.cpp index 025a038b..d7635920 100644 --- a/src/SFML/Graphics/GLLoader.cpp +++ b/src/SFML/Graphics/GLLoader.cpp @@ -46,6 +46,7 @@ int sfogl_ext_ARB_fragment_shader = sfogl_LOAD_FAILED; int sfogl_ext_ARB_texture_non_power_of_two = sfogl_LOAD_FAILED; int sfogl_ext_EXT_blend_equation_separate = sfogl_LOAD_FAILED; int sfogl_ext_EXT_framebuffer_object = sfogl_LOAD_FAILED; +int sfogl_ext_ARB_geometry_shader4 = sfogl_LOAD_FAILED; void (GL_FUNCPTR *sf_ptrc_glBlendEquationEXT)(GLenum) = NULL; @@ -798,6 +799,34 @@ static int Load_EXT_framebuffer_object() return numFailed; } +void (GL_FUNCPTR *sf_ptrc_glFramebufferTextureARB)(GLenum, GLenum, GLuint, GLint) = NULL; +void (GL_FUNCPTR *sf_ptrc_glFramebufferTextureFaceARB)(GLenum, GLenum, GLuint, GLint, GLenum) = NULL; +void (GL_FUNCPTR *sf_ptrc_glFramebufferTextureLayerARB)(GLenum, GLenum, GLuint, GLint, GLint) = NULL; +void (GL_FUNCPTR *sf_ptrc_glProgramParameteriARB)(GLuint, GLenum, GLint) = NULL; + +static int Load_ARB_geometry_shader4() +{ + int numFailed = 0; + + sf_ptrc_glFramebufferTextureARB = reinterpret_cast(glLoaderGetProcAddress("glFramebufferTextureARB")); + if (!sf_ptrc_glFramebufferTextureARB) + numFailed++; + + sf_ptrc_glFramebufferTextureFaceARB = reinterpret_cast(glLoaderGetProcAddress("glFramebufferTextureFaceARB")); + if (!sf_ptrc_glFramebufferTextureFaceARB) + numFailed++; + + sf_ptrc_glFramebufferTextureLayerARB = reinterpret_cast(glLoaderGetProcAddress("glFramebufferTextureLayerARB")); + if (!sf_ptrc_glFramebufferTextureLayerARB) + numFailed++; + + sf_ptrc_glProgramParameteriARB = reinterpret_cast(glLoaderGetProcAddress("glProgramParameteriARB")); + if (!sf_ptrc_glProgramParameteriARB) + numFailed++; + + return numFailed; +} + typedef int (*PFN_LOADFUNCPOINTERS)(); typedef struct sfogl_StrToExtMap_s { @@ -806,7 +835,7 @@ typedef struct sfogl_StrToExtMap_s PFN_LOADFUNCPOINTERS LoadExtension; } sfogl_StrToExtMap; -static sfogl_StrToExtMap ExtensionMap[13] = { +static sfogl_StrToExtMap ExtensionMap[14] = { {"GL_SGIS_texture_edge_clamp", &sfogl_ext_SGIS_texture_edge_clamp, NULL}, {"GL_EXT_texture_edge_clamp", &sfogl_ext_EXT_texture_edge_clamp, NULL}, {"GL_EXT_blend_minmax", &sfogl_ext_EXT_blend_minmax, Load_EXT_blend_minmax}, @@ -819,10 +848,11 @@ static sfogl_StrToExtMap ExtensionMap[13] = { {"GL_ARB_fragment_shader", &sfogl_ext_ARB_fragment_shader, NULL}, {"GL_ARB_texture_non_power_of_two", &sfogl_ext_ARB_texture_non_power_of_two, NULL}, {"GL_EXT_blend_equation_separate", &sfogl_ext_EXT_blend_equation_separate, Load_EXT_blend_equation_separate}, - {"GL_EXT_framebuffer_object", &sfogl_ext_EXT_framebuffer_object, Load_EXT_framebuffer_object} + {"GL_EXT_framebuffer_object", &sfogl_ext_EXT_framebuffer_object, Load_EXT_framebuffer_object}, + {"GL_ARB_geometry_shader4", &sfogl_ext_ARB_geometry_shader4, Load_ARB_geometry_shader4} }; -static int g_extensionMapSize = 13; +static int g_extensionMapSize = 14; static void ClearExtensionVars() @@ -840,6 +870,7 @@ static void ClearExtensionVars() sfogl_ext_ARB_texture_non_power_of_two = sfogl_LOAD_FAILED; sfogl_ext_EXT_blend_equation_separate = sfogl_LOAD_FAILED; sfogl_ext_EXT_framebuffer_object = sfogl_LOAD_FAILED; + sfogl_ext_ARB_geometry_shader4 = sfogl_LOAD_FAILED; } diff --git a/src/SFML/Graphics/GLLoader.hpp b/src/SFML/Graphics/GLLoader.hpp index b3c9fddc..588ba5a4 100644 --- a/src/SFML/Graphics/GLLoader.hpp +++ b/src/SFML/Graphics/GLLoader.hpp @@ -183,6 +183,7 @@ extern int sfogl_ext_ARB_fragment_shader; extern int sfogl_ext_ARB_texture_non_power_of_two; extern int sfogl_ext_EXT_blend_equation_separate; extern int sfogl_ext_EXT_framebuffer_object; +extern int sfogl_ext_ARB_geometry_shader4; #define GL_CLAMP_TO_EDGE_SGIS 0x812F @@ -360,6 +361,27 @@ extern int sfogl_ext_EXT_framebuffer_object; #define GL_STENCIL_INDEX4_EXT 0x8D47 #define GL_STENCIL_INDEX8_EXT 0x8D48 +#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB 0x8DA7 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB 0x8DA9 +#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS_ARB 0x8DA8 +#define GL_GEOMETRY_INPUT_TYPE_ARB 0x8DDB +#define GL_GEOMETRY_OUTPUT_TYPE_ARB 0x8DDC +#define GL_GEOMETRY_SHADER_ARB 0x8DD9 +#define GL_GEOMETRY_VERTICES_OUT_ARB 0x8DDA +#define GL_LINES_ADJACENCY_ARB 0x000A +#define GL_LINE_STRIP_ADJACENCY_ARB 0x000B +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES_ARB 0x8DE0 +#define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS_ARB 0x8C29 +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS_ARB 0x8DE1 +#define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS_ARB 0x8DDF +#define GL_MAX_GEOMETRY_VARYING_COMPONENTS_ARB 0x8DDD +#define GL_MAX_VARYING_COMPONENTS 0x8B4B +#define GL_MAX_VERTEX_VARYING_COMPONENTS_ARB 0x8DDE +#define GL_PROGRAM_POINT_SIZE_ARB 0x8642 +#define GL_TRIANGLES_ADJACENCY_ARB 0x000C +#define GL_TRIANGLE_STRIP_ADJACENCY_ARB 0x000D + #define GL_2D 0x0600 #define GL_2_BYTES 0x1407 #define GL_3D 0x0601 @@ -1201,6 +1223,18 @@ extern void (GL_FUNCPTR *sf_ptrc_glRenderbufferStorageEXT)(GLenum, GLenum, GLsiz #define glRenderbufferStorageEXT sf_ptrc_glRenderbufferStorageEXT #endif // GL_EXT_framebuffer_object +#ifndef GL_ARB_geometry_shader4 +#define GL_ARB_geometry_shader4 1 +extern void (GL_FUNCPTR *sf_ptrc_glFramebufferTextureARB)(GLenum, GLenum, GLuint, GLint); +#define glFramebufferTextureARB sf_ptrc_glFramebufferTextureARB +extern void (GL_FUNCPTR *sf_ptrc_glFramebufferTextureFaceARB)(GLenum, GLenum, GLuint, GLint, GLenum); +#define glFramebufferTextureFaceARB sf_ptrc_glFramebufferTextureFaceARB +extern void (GL_FUNCPTR *sf_ptrc_glFramebufferTextureLayerARB)(GLenum, GLenum, GLuint, GLint, GLint); +#define glFramebufferTextureLayerARB sf_ptrc_glFramebufferTextureLayerARB +extern void (GL_FUNCPTR *sf_ptrc_glProgramParameteriARB)(GLuint, GLenum, GLint); +#define glProgramParameteriARB sf_ptrc_glProgramParameteriARB +#endif // GL_ARB_geometry_shader4 + GLAPI void APIENTRY glAccum(GLenum, GLfloat); GLAPI void APIENTRY glAlphaFunc(GLenum, GLfloat); GLAPI void APIENTRY glBegin(GLenum); diff --git a/src/SFML/Graphics/Shader.cpp b/src/SFML/Graphics/Shader.cpp index 882b27fe..d8c9e68e 100644 --- a/src/SFML/Graphics/Shader.cpp +++ b/src/SFML/Graphics/Shader.cpp @@ -148,6 +148,20 @@ namespace return available; } + bool checkGeometryShadersAvailable() + { + // Create a temporary context in case the user checks + // before a GlResource is created, thus initializing + // the shared context + sf::Context context; + + // Make sure that extensions are initialized + sf::priv::ensureExtensionsInit(); + + bool available = checkShadersAvailable() && GLEXT_geometry_shader4; + + return available; + } // Transforms an array of 2D vectors into a contiguous array of scalars template @@ -285,9 +299,11 @@ bool Shader::loadFromFile(const std::string& filename, Type type) // Compile the shader program if (type == Vertex) - return compile(&shader[0], NULL); + return compile(&shader[0], NULL, NULL); + else if (type == Geometry) + return compile(NULL, &shader[0], NULL); else - return compile(NULL, &shader[0]); + return compile(NULL, NULL, &shader[0]); } @@ -311,7 +327,39 @@ bool Shader::loadFromFile(const std::string& vertexShaderFilename, const std::st } // Compile the shader program - return compile(&vertexShader[0], &fragmentShader[0]); + return compile(&vertexShader[0], NULL, &fragmentShader[0]); +} + + +//////////////////////////////////////////////////////////// +bool Shader::loadFromFile(const std::string& vertexShaderFilename, const std::string& geometryShaderFilename, const std::string& fragmentShaderFilename) +{ + // Read the vertex shader file + std::vector vertexShader; + if (!getFileContents(vertexShaderFilename, vertexShader)) + { + err() << "Failed to open vertex shader file \"" << vertexShaderFilename << "\"" << std::endl; + return false; + } + + // Read the geometry shader file + std::vector geometryShader; + if (!getFileContents(geometryShaderFilename, geometryShader)) + { + err() << "Failed to open geometry shader file \"" << geometryShaderFilename << "\"" << std::endl; + return false; + } + + // Read the fragment shader file + std::vector fragmentShader; + if (!getFileContents(fragmentShaderFilename, fragmentShader)) + { + err() << "Failed to open fragment shader file \"" << fragmentShaderFilename << "\"" << std::endl; + return false; + } + + // Compile the shader program + return compile(&vertexShader[0], &geometryShader[0], &fragmentShader[0]); } @@ -320,9 +368,11 @@ bool Shader::loadFromMemory(const std::string& shader, Type type) { // Compile the shader program if (type == Vertex) - return compile(shader.c_str(), NULL); + return compile(shader.c_str(), NULL, NULL); + else if (type == Geometry) + return compile(NULL, shader.c_str(), NULL); else - return compile(NULL, shader.c_str()); + return compile(NULL, NULL, shader.c_str()); } @@ -330,7 +380,15 @@ bool Shader::loadFromMemory(const std::string& shader, Type type) bool Shader::loadFromMemory(const std::string& vertexShader, const std::string& fragmentShader) { // Compile the shader program - return compile(vertexShader.c_str(), fragmentShader.c_str()); + return compile(vertexShader.c_str(), NULL, fragmentShader.c_str()); +} + + +//////////////////////////////////////////////////////////// +bool Shader::loadFromMemory(const std::string& vertexShader, const std::string& geometryShader, const std::string& fragmentShader) +{ + // Compile the shader program + return compile(vertexShader.c_str(), geometryShader.c_str(), fragmentShader.c_str()); } @@ -347,9 +405,11 @@ bool Shader::loadFromStream(InputStream& stream, Type type) // Compile the shader program if (type == Vertex) - return compile(&shader[0], NULL); + return compile(&shader[0], NULL, NULL); + else if (type == Geometry) + return compile(NULL, &shader[0], NULL); else - return compile(NULL, &shader[0]); + return compile(NULL, NULL, &shader[0]); } @@ -373,7 +433,39 @@ bool Shader::loadFromStream(InputStream& vertexShaderStream, InputStream& fragme } // Compile the shader program - return compile(&vertexShader[0], &fragmentShader[0]); + return compile(&vertexShader[0], NULL, &fragmentShader[0]); +} + + +//////////////////////////////////////////////////////////// +bool Shader::loadFromStream(InputStream& vertexShaderStream, InputStream& geometryShaderStream, InputStream& fragmentShaderStream) +{ + // Read the vertex shader code from the stream + std::vector vertexShader; + if (!getStreamContents(vertexShaderStream, vertexShader)) + { + err() << "Failed to read vertex shader from stream" << std::endl; + return false; + } + + // Read the geometry shader code from the stream + std::vector geometryShader; + if (!getStreamContents(geometryShaderStream, geometryShader)) + { + err() << "Failed to read geometry shader from stream" << std::endl; + return false; + } + + // Read the fragment shader code from the stream + std::vector fragmentShader; + if (!getStreamContents(fragmentShaderStream, fragmentShader)) + { + err() << "Failed to read fragment shader from stream" << std::endl; + return false; + } + + // Compile the shader program + return compile(&vertexShader[0], &geometryShader[0], &fragmentShader[0]); } @@ -738,7 +830,19 @@ bool Shader::isAvailable() //////////////////////////////////////////////////////////// -bool Shader::compile(const char* vertexShaderCode, const char* fragmentShaderCode) +bool Shader::isGeometryAvailable() +{ + // TODO: Remove this lock when it becomes unnecessary in C++11 + Lock lock(mutex); + + static bool available = checkGeometryShadersAvailable(); + + return available; +} + + +//////////////////////////////////////////////////////////// +bool Shader::compile(const char* vertexShaderCode, const char* geometryShaderCode, const char* fragmentShaderCode) { ensureGlContext(); @@ -750,6 +854,14 @@ bool Shader::compile(const char* vertexShaderCode, const char* fragmentShaderCod return false; } + // Make sure we can use geometry shaders + if (geometryShaderCode && !isGeometryAvailable()) + { + err() << "Failed to create a shader: your system doesn't support geometry shaders " + << "(you should test Shader::isGeometryAvailable() before trying to use geometry shaders)" << std::endl; + return false; + } + // Destroy the shader if it was already created if (m_shaderProgram) { @@ -794,6 +906,33 @@ bool Shader::compile(const char* vertexShaderCode, const char* fragmentShaderCod glCheck(GLEXT_glDeleteObject(vertexShader)); } + // Create the geometry shader if needed + if (geometryShaderCode) + { + // Create and compile the shader + GLEXT_GLhandle geometryShader = GLEXT_glCreateShaderObject(GLEXT_GL_GEOMETRY_SHADER); + glCheck(GLEXT_glShaderSource(geometryShader, 1, &geometryShaderCode, NULL)); + glCheck(GLEXT_glCompileShader(geometryShader)); + + // Check the compile log + GLint success; + glCheck(GLEXT_glGetObjectParameteriv(geometryShader, GLEXT_GL_OBJECT_COMPILE_STATUS, &success)); + if (success == GL_FALSE) + { + char log[1024]; + glCheck(GLEXT_glGetInfoLog(geometryShader, sizeof(log), 0, log)); + err() << "Failed to compile geometry shader:" << std::endl + << log << std::endl; + glCheck(GLEXT_glDeleteObject(geometryShader)); + glCheck(GLEXT_glDeleteObject(shaderProgram)); + return false; + } + + // Attach the shader to the program, and delete it (not needed anymore) + glCheck(GLEXT_glAttachObject(shaderProgram, geometryShader)); + glCheck(GLEXT_glDeleteObject(geometryShader)); + } + // Create the fragment shader if needed if (fragmentShaderCode) { @@ -929,6 +1068,13 @@ bool Shader::loadFromFile(const std::string& vertexShaderFilename, const std::st } +//////////////////////////////////////////////////////////// +bool Shader::loadFromFile(const std::string& vertexShaderFilename, const std::string& geometryShaderFilename, const std::string& fragmentShaderFilename) +{ + return false; +} + + //////////////////////////////////////////////////////////// bool Shader::loadFromMemory(const std::string& shader, Type type) { @@ -943,6 +1089,13 @@ bool Shader::loadFromMemory(const std::string& vertexShader, const std::string& } +//////////////////////////////////////////////////////////// +bool Shader::loadFromMemory(const std::string& vertexShader, const std::string& geometryShader, const std::string& fragmentShader) +{ + return false; +} + + //////////////////////////////////////////////////////////// bool Shader::loadFromStream(InputStream& stream, Type type) { @@ -957,6 +1110,13 @@ bool Shader::loadFromStream(InputStream& vertexShaderStream, InputStream& fragme } +//////////////////////////////////////////////////////////// +bool Shader::loadFromStream(InputStream& vertexShaderStream, InputStream& geometryShaderStream, InputStream& fragmentShaderStream) +{ + return false; +} + + //////////////////////////////////////////////////////////// void Shader::setUniform(const std::string& name, float x) { @@ -1170,7 +1330,14 @@ bool Shader::isAvailable() //////////////////////////////////////////////////////////// -bool Shader::compile(const char* vertexShaderCode, const char* fragmentShaderCode) +bool Shader::isGeometryAvailable() +{ + return false; +} + + +//////////////////////////////////////////////////////////// +bool Shader::compile(const char* vertexShaderCode, const char* geometryShaderCode, const char* fragmentShaderCode) { return false; }