Added support for geometry shaders

This commit is contained in:
Mrowqa 2013-07-18 18:47:41 +02:00 committed by Lukas Dürrenberger
parent 1217699fe0
commit 1763861b26
6 changed files with 359 additions and 33 deletions

View File

@ -46,7 +46,7 @@ class Texture;
class Transform; class Transform;
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Shader class (vertex and fragment) /// \brief Shader class (vertex, geometry and fragment)
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
class SFML_GRAPHICS_API Shader : GlResource, NonCopyable class SFML_GRAPHICS_API Shader : GlResource, NonCopyable
@ -60,6 +60,7 @@ public:
enum Type enum Type
{ {
Vertex, ///< %Vertex shader Vertex, ///< %Vertex shader
Geometry, ///< Geometry shader
Fragment ///< Fragment (pixel) shader Fragment ///< Fragment (pixel) shader
}; };
@ -97,9 +98,9 @@ public:
~Shader(); ~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. /// fragment, identified by the second argument.
/// The source must be a text file containing a valid /// The source must be a text file containing a valid
/// shader in GLSL language. GLSL is a C-like language /// shader in GLSL language. GLSL is a C-like language
@ -107,8 +108,8 @@ public:
/// read a good documentation for it before writing your /// read a good documentation for it before writing your
/// own shaders. /// own shaders.
/// ///
/// \param filename Path of the vertex or fragment shader file to load /// \param filename Path of the vertex, geometry or fragment shader file to load
/// \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 /// \return True if loading succeeded, false if it failed
/// ///
@ -139,17 +140,39 @@ public:
bool loadFromFile(const std::string& vertexShaderFilename, const std::string& fragmentShaderFilename); 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 /// This function loads the vertex, geometry and fragment
/// fragment, identified by the second argument. /// 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. /// The source code must be a valid shader in GLSL language.
/// GLSL is a C-like language dedicated to OpenGL shaders; /// GLSL is a C-like language dedicated to OpenGL shaders;
/// you'll probably need to read a good documentation for /// you'll probably need to read a good documentation for
/// it before writing your own shaders. /// it before writing your own shaders.
/// ///
/// \param shader String containing the source code of the shader /// \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 /// \return True if loading succeeded, false if it failed
/// ///
@ -180,17 +203,39 @@ public:
bool loadFromMemory(const std::string& vertexShader, const std::string& fragmentShader); 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 /// This function loads the vertex, geometry and fragment
/// fragment, identified by the second argument. /// 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. /// The source code must be a valid shader in GLSL language.
/// GLSL is a C-like language dedicated to OpenGL shaders; /// GLSL is a C-like language dedicated to OpenGL shaders;
/// you'll probably need to read a good documentation for it /// you'll probably need to read a good documentation for it
/// before writing your own shaders. /// before writing your own shaders.
/// ///
/// \param stream Source stream to read from /// \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 /// \return True if loading succeeded, false if it failed
/// ///
@ -220,6 +265,28 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool loadFromStream(InputStream& vertexShaderStream, InputStream& fragmentShaderStream); 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 /// \brief Specify value for \p float uniform
/// ///
@ -605,6 +672,25 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
static bool isAvailable(); 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: private:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -614,12 +700,13 @@ private:
/// is not created. /// is not created.
/// ///
/// \param vertexShaderCode Source code of the vertex shader /// \param vertexShaderCode Source code of the vertex shader
/// \param geometryShaderCode Source code of the geometry shader
/// \param fragmentShaderCode Source code of the fragment shader /// \param fragmentShaderCode Source code of the fragment shader
/// ///
/// \return True on success, false if any error happened /// \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 /// \brief Bind all the textures used by the shader
@ -678,13 +765,15 @@ private:
/// executed directly by the graphics card and allowing /// executed directly by the graphics card and allowing
/// to apply real-time operations to the rendered entities. /// 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 %Vertex shaders, that process vertices
/// \li Geometry shaders, that process primitives
/// \li Fragment (pixel) shaders, that process pixels /// \li Fragment (pixel) shaders, that process pixels
/// ///
/// A sf::Shader can be composed of either a vertex shader /// A sf::Shader can be composed of either a vertex shader
/// alone, a fragment shader alone, or both combined /// alone, a geometry shader alone, a fragment shader alone,
/// (see the variants of the load functions). /// or any combination of them. (see the variants of the
/// load functions).
/// ///
/// Shaders are written in GLSL, which is a C-like /// Shaders are written in GLSL, which is a C-like
/// language dedicated to OpenGL shaders. You'll probably /// language dedicated to OpenGL shaders. You'll probably

View File

@ -228,6 +228,10 @@
#define GLEXT_GL_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING_EXT #define GLEXT_GL_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING_EXT
#define GLEXT_GL_INVALID_FRAMEBUFFER_OPERATION GL_INVALID_FRAMEBUFFER_OPERATION_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 #endif
namespace sf namespace sf

View File

@ -14,3 +14,4 @@ ARB_fragment_shader
ARB_texture_non_power_of_two ARB_texture_non_power_of_two
EXT_blend_equation_separate EXT_blend_equation_separate
EXT_framebuffer_object EXT_framebuffer_object
ARB_geometry_shader4

View File

@ -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_ARB_texture_non_power_of_two = sfogl_LOAD_FAILED;
int sfogl_ext_EXT_blend_equation_separate = 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_EXT_framebuffer_object = sfogl_LOAD_FAILED;
int sfogl_ext_ARB_geometry_shader4 = sfogl_LOAD_FAILED;
void (GL_FUNCPTR *sf_ptrc_glBlendEquationEXT)(GLenum) = NULL; void (GL_FUNCPTR *sf_ptrc_glBlendEquationEXT)(GLenum) = NULL;
@ -798,6 +799,34 @@ static int Load_EXT_framebuffer_object()
return numFailed; 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<void (GL_FUNCPTR *)(GLenum, GLenum, GLuint, GLint)>(glLoaderGetProcAddress("glFramebufferTextureARB"));
if (!sf_ptrc_glFramebufferTextureARB)
numFailed++;
sf_ptrc_glFramebufferTextureFaceARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLenum, GLuint, GLint, GLenum)>(glLoaderGetProcAddress("glFramebufferTextureFaceARB"));
if (!sf_ptrc_glFramebufferTextureFaceARB)
numFailed++;
sf_ptrc_glFramebufferTextureLayerARB = reinterpret_cast<void (GL_FUNCPTR *)(GLenum, GLenum, GLuint, GLint, GLint)>(glLoaderGetProcAddress("glFramebufferTextureLayerARB"));
if (!sf_ptrc_glFramebufferTextureLayerARB)
numFailed++;
sf_ptrc_glProgramParameteriARB = reinterpret_cast<void (GL_FUNCPTR *)(GLuint, GLenum, GLint)>(glLoaderGetProcAddress("glProgramParameteriARB"));
if (!sf_ptrc_glProgramParameteriARB)
numFailed++;
return numFailed;
}
typedef int (*PFN_LOADFUNCPOINTERS)(); typedef int (*PFN_LOADFUNCPOINTERS)();
typedef struct sfogl_StrToExtMap_s typedef struct sfogl_StrToExtMap_s
{ {
@ -806,7 +835,7 @@ typedef struct sfogl_StrToExtMap_s
PFN_LOADFUNCPOINTERS LoadExtension; PFN_LOADFUNCPOINTERS LoadExtension;
} sfogl_StrToExtMap; } 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_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_texture_edge_clamp", &sfogl_ext_EXT_texture_edge_clamp, NULL},
{"GL_EXT_blend_minmax", &sfogl_ext_EXT_blend_minmax, Load_EXT_blend_minmax}, {"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_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_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_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() static void ClearExtensionVars()
@ -840,6 +870,7 @@ static void ClearExtensionVars()
sfogl_ext_ARB_texture_non_power_of_two = sfogl_LOAD_FAILED; sfogl_ext_ARB_texture_non_power_of_two = sfogl_LOAD_FAILED;
sfogl_ext_EXT_blend_equation_separate = sfogl_LOAD_FAILED; sfogl_ext_EXT_blend_equation_separate = sfogl_LOAD_FAILED;
sfogl_ext_EXT_framebuffer_object = sfogl_LOAD_FAILED; sfogl_ext_EXT_framebuffer_object = sfogl_LOAD_FAILED;
sfogl_ext_ARB_geometry_shader4 = sfogl_LOAD_FAILED;
} }

View File

@ -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_ARB_texture_non_power_of_two;
extern int sfogl_ext_EXT_blend_equation_separate; extern int sfogl_ext_EXT_blend_equation_separate;
extern int sfogl_ext_EXT_framebuffer_object; extern int sfogl_ext_EXT_framebuffer_object;
extern int sfogl_ext_ARB_geometry_shader4;
#define GL_CLAMP_TO_EDGE_SGIS 0x812F #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_INDEX4_EXT 0x8D47
#define GL_STENCIL_INDEX8_EXT 0x8D48 #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_2D 0x0600
#define GL_2_BYTES 0x1407 #define GL_2_BYTES 0x1407
#define GL_3D 0x0601 #define GL_3D 0x0601
@ -1201,6 +1223,18 @@ extern void (GL_FUNCPTR *sf_ptrc_glRenderbufferStorageEXT)(GLenum, GLenum, GLsiz
#define glRenderbufferStorageEXT sf_ptrc_glRenderbufferStorageEXT #define glRenderbufferStorageEXT sf_ptrc_glRenderbufferStorageEXT
#endif // GL_EXT_framebuffer_object #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 glAccum(GLenum, GLfloat);
GLAPI void APIENTRY glAlphaFunc(GLenum, GLfloat); GLAPI void APIENTRY glAlphaFunc(GLenum, GLfloat);
GLAPI void APIENTRY glBegin(GLenum); GLAPI void APIENTRY glBegin(GLenum);

View File

@ -148,6 +148,20 @@ namespace
return available; 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 // Transforms an array of 2D vectors into a contiguous array of scalars
template <typename T> template <typename T>
@ -285,9 +299,11 @@ bool Shader::loadFromFile(const std::string& filename, Type type)
// Compile the shader program // Compile the shader program
if (type == Vertex) 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 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 // 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<char> vertexShader;
if (!getFileContents(vertexShaderFilename, vertexShader))
{
err() << "Failed to open vertex shader file \"" << vertexShaderFilename << "\"" << std::endl;
return false;
}
// Read the geometry shader file
std::vector<char> geometryShader;
if (!getFileContents(geometryShaderFilename, geometryShader))
{
err() << "Failed to open geometry shader file \"" << geometryShaderFilename << "\"" << std::endl;
return false;
}
// Read the fragment shader file
std::vector<char> 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 // Compile the shader program
if (type == Vertex) 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 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) bool Shader::loadFromMemory(const std::string& vertexShader, const std::string& fragmentShader)
{ {
// Compile the shader program // 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 // Compile the shader program
if (type == Vertex) 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 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 // 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<char> 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<char> 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<char> 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(); ensureGlContext();
@ -750,6 +854,14 @@ bool Shader::compile(const char* vertexShaderCode, const char* fragmentShaderCod
return false; 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 // Destroy the shader if it was already created
if (m_shaderProgram) if (m_shaderProgram)
{ {
@ -794,6 +906,33 @@ bool Shader::compile(const char* vertexShaderCode, const char* fragmentShaderCod
glCheck(GLEXT_glDeleteObject(vertexShader)); 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 // Create the fragment shader if needed
if (fragmentShaderCode) 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) 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) 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) 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; return false;
} }