diff --git a/examples/shader/Shader.cpp b/examples/shader/Shader.cpp index 0945497f4..bd5b134bf 100644 --- a/examples/shader/Shader.cpp +++ b/examples/shader/Shader.cpp @@ -130,16 +130,16 @@ int main() ShaderSelector globalShader(shaders, "nothing"); // Do specific initializations - shaders["nothing"].SetTexture("texture", sf::Shader::CurrentTexture); - shaders["blur"].SetTexture("texture", sf::Shader::CurrentTexture); + shaders["nothing"].SetCurrentTexture("texture"); + shaders["blur"].SetCurrentTexture("texture"); shaders["blur"].SetParameter("offset", 0.f); - shaders["colorize"].SetTexture("texture", sf::Shader::CurrentTexture); + shaders["colorize"].SetCurrentTexture("texture"); shaders["colorize"].SetParameter("color", 1.f, 1.f, 1.f); - shaders["edge"].SetTexture("texture", sf::Shader::CurrentTexture); - shaders["fisheye"].SetTexture("texture", sf::Shader::CurrentTexture); - shaders["wave"].SetTexture("texture", sf::Shader::CurrentTexture); + shaders["edge"].SetCurrentTexture("texture"); + shaders["fisheye"].SetCurrentTexture("texture"); + shaders["wave"].SetCurrentTexture("texture"); shaders["wave"].SetTexture("wave", waveImage); - shaders["pixelate"].SetTexture("texture", sf::Shader::CurrentTexture); + shaders["pixelate"].SetCurrentTexture("texture"); // Define a string for displaying the description of the current shader sf::Text shaderStr; diff --git a/include/SFML/Graphics/Image.hpp b/include/SFML/Graphics/Image.hpp index a447038df..1ef822d7e 100644 --- a/include/SFML/Graphics/Image.hpp +++ b/include/SFML/Graphics/Image.hpp @@ -29,6 +29,7 @@ // Headers //////////////////////////////////////////////////////////// #include +#include #include #include #include @@ -45,7 +46,7 @@ class RenderWindow; /// \brief Class for loading, manipulating and saving images /// //////////////////////////////////////////////////////////// -class SFML_API Image : public Resource +class SFML_API Image : public Resource, GlResource { public : diff --git a/include/SFML/Graphics/Renderer.hpp b/include/SFML/Graphics/Renderer.hpp index 40a13b4e0..b5fe0234a 100644 --- a/include/SFML/Graphics/Renderer.hpp +++ b/include/SFML/Graphics/Renderer.hpp @@ -30,6 +30,7 @@ //////////////////////////////////////////////////////////// #include #include +#include #include #include #include @@ -44,7 +45,7 @@ class Shader; /// \brief Handles the low-level rendering (states and geometry) /// //////////////////////////////////////////////////////////// -class SFML_API Renderer : NonCopyable +class SFML_API Renderer : GlResource, NonCopyable { public : diff --git a/include/SFML/Graphics/Shader.hpp b/include/SFML/Graphics/Shader.hpp index e49f34543..9f947e0e2 100644 --- a/include/SFML/Graphics/Shader.hpp +++ b/include/SFML/Graphics/Shader.hpp @@ -30,6 +30,7 @@ //////////////////////////////////////////////////////////// #include #include +#include #include #include #include @@ -44,7 +45,7 @@ class Renderer; /// \brief Pixel/fragment shader class /// //////////////////////////////////////////////////////////// -class SFML_API Shader +class SFML_API Shader : GlResource { public : @@ -120,7 +121,7 @@ public : /// \param name Name of the parameter in the shader /// \param x Value to assign /// - /// \see SetTexture + /// \see SetTexture, SetCurrentTexture /// //////////////////////////////////////////////////////////// void SetParameter(const std::string& name, float x); @@ -141,7 +142,7 @@ public : /// \param x First component of the value to assign /// \param y Second component of the value to assign /// - /// \see SetTexture + /// \see SetTexture, SetCurrentTexture /// //////////////////////////////////////////////////////////// void SetParameter(const std::string& name, float x, float y); @@ -163,7 +164,7 @@ public : /// \param y Second component of the value to assign /// \param z Third component of the value to assign /// - /// \see SetTexture + /// \see SetTexture, SetCurrentTexture /// //////////////////////////////////////////////////////////// void SetParameter(const std::string& name, float x, float y, float z); @@ -186,7 +187,7 @@ public : /// \param z Third component of the value to assign /// \param w Fourth component of the value to assign /// - /// \see SetTexture + /// \see SetTexture, SetCurrentTexture /// //////////////////////////////////////////////////////////// void SetParameter(const std::string& name, float x, float y, float z, float w); @@ -206,7 +207,7 @@ public : /// \param name Name of the parameter in the shader /// \param vector Vector to assign /// - /// \see SetTexture + /// \see SetTexture, SetCurrentTexture /// //////////////////////////////////////////////////////////// void SetParameter(const std::string& name, const Vector2f& vector); @@ -226,7 +227,7 @@ public : /// \param name Name of the parameter in the shader /// \param vector Vector to assign /// - /// \see SetTexture + /// \see SetTexture, SetCurrentTexture /// //////////////////////////////////////////////////////////// void SetParameter(const std::string& name, const Vector3f& vector); @@ -235,19 +236,18 @@ public : /// \brief Change a texture parameter of the shader /// /// \a name is the name of the texture to change in the shader. - /// To tell the shader to use the current texture of the object being - /// drawn, pass Shader::CurrentTexture. + /// This function maps an external image to the texture variable; + /// to use the current texture of the object being drawn, use + /// SetCurrentTexture instead. /// Example: /// \code /// // These are the variables in the pixel shader - /// uniform sampler2D current; - /// uniform sampler2D other; + /// uniform sampler2D texture; /// \endcode /// \code /// sf::Image image; /// ... - /// shader.SetParameter("current", sf::Shader::CurrentTexture); - /// shader.SetParameter("other", image); + /// shader.SetTexture("texture", image); /// \endcode /// It is important to note that \a texture must remain alive as long /// as the shader uses it, no copy is made internally. @@ -255,11 +255,32 @@ public : /// \param name Name of the texture in the shader /// \param texture Image to assign /// - /// \see SetParameter + /// \see SetParameter, SetCurrentTexture /// //////////////////////////////////////////////////////////// void SetTexture(const std::string& name, const Image& texture); + //////////////////////////////////////////////////////////// + /// \brief Set the current object texture in the shader + /// + /// This function maps a shader texture variable to the + /// image of the object being drawn. + /// Example: + /// \code + /// // This is the variable in the pixel shader + /// uniform sampler2D current; + /// \endcode + /// \code + /// shader.SetCurrentTexture("current"); + /// \endcode + /// + /// \param name Name of the texture in the shader + /// + /// \see SetParameter, SetTexture + /// + //////////////////////////////////////////////////////////// + void SetCurrentTexture(const std::string& name); + //////////////////////////////////////////////////////////// /// \brief Bind the shader for rendering (activate it) /// @@ -312,11 +333,6 @@ public : //////////////////////////////////////////////////////////// static bool IsAvailable(); - //////////////////////////////////////////////////////////// - // Static member data - //////////////////////////////////////////////////////////// - static const Image CurrentTexture; ///< Special image representing the texture used by the object being drawn - private : friend class Renderer; @@ -394,12 +410,12 @@ private : /// \code /// shader.SetParameter("offset", 2.f); /// shader.SetParameter("color", 0.5f, 0.8f, 0.3f); -/// shader.SetTexture("image", image); // image is a sf::Image -/// shader.SetTexture("current", sf::Shader::CurrentTexture); +/// shader.SetTexture("overlay", image); // image is a sf::Image +/// shader.SetCurrentTexture("texture"); /// \endcode /// -/// Shader::CurrentTexture is a special value that represents -/// the texture that the object being drawn is using. +/// Shader::SetCurrentTexture maps the given texture variable +/// to the current texture of the object being drawn. /// /// To apply a shader to a drawable, you must pass it as an /// additional parameter to the Draw function: diff --git a/include/SFML/Window/Context.hpp b/include/SFML/Window/Context.hpp index 9ec69c5ef..844d2c471 100644 --- a/include/SFML/Window/Context.hpp +++ b/include/SFML/Window/Context.hpp @@ -29,6 +29,7 @@ // Headers //////////////////////////////////////////////////////////// #include +#include #include @@ -43,7 +44,7 @@ namespace priv /// \brief Class holding a valid drawing context /// //////////////////////////////////////////////////////////// -class SFML_API Context : NonCopyable +class SFML_API Context : GlResource, NonCopyable { public : @@ -71,18 +72,6 @@ public : //////////////////////////////////////////////////////////// void SetActive(bool active); - //////////////////////////////////////////////////////////// - /// \brief Make the current thread's reference context active - /// - /// This function is meant to be called internally; it is used - /// to deactivate the current context by activating another one - /// (so that we still have an active context on the current thread). - /// - /// \return True if operation was successful, false otherwise - /// - //////////////////////////////////////////////////////////// - static bool SetReferenceActive(); - private : //////////////////////////////////////////////////////////// diff --git a/include/SFML/Window/GlResource.hpp b/include/SFML/Window/GlResource.hpp new file mode 100644 index 000000000..36e7ebd26 --- /dev/null +++ b/include/SFML/Window/GlResource.hpp @@ -0,0 +1,72 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +#ifndef SFML_GLRESOURCE_HPP +#define SFML_GLRESOURCE_HPP + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include + + +namespace sf +{ +//////////////////////////////////////////////////////////// +/// \brief Base class for classes that require an OpenGL context +/// +//////////////////////////////////////////////////////////// +class SFML_API GlResource +{ +protected : + + //////////////////////////////////////////////////////////// + /// \brief Default constructor + /// + //////////////////////////////////////////////////////////// + GlResource(); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + //////////////////////////////////////////////////////////// + ~GlResource(); + + static void EnsureGlContext(); +}; + +} // namespace sf + + +#endif // SFML_GLRESOURCE_HPP + +//////////////////////////////////////////////////////////// +/// \class sf::GlResource +/// \ingroup window +/// +/// This class is for internal use only, it must be the base +/// of every class that requires a valid OpenGL context in +/// order to work. +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Window/Window.hpp b/include/SFML/Window/Window.hpp index 90959147f..726707bce 100644 --- a/include/SFML/Window/Window.hpp +++ b/include/SFML/Window/Window.hpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -52,7 +53,7 @@ class Event; /// \brief Window that serves as a target for OpenGL rendering /// //////////////////////////////////////////////////////////// -class SFML_API Window : NonCopyable +class SFML_API Window : GlResource, NonCopyable { public : diff --git a/src/SFML/Graphics/Image.cpp b/src/SFML/Graphics/Image.cpp index 972de13bc..66134a652 100644 --- a/src/SFML/Graphics/Image.cpp +++ b/src/SFML/Graphics/Image.cpp @@ -84,6 +84,8 @@ Image::~Image() // Destroy the OpenGL texture if (myTexture) { + EnsureGlContext(); + GLuint Texture = static_cast(myTexture); GLCheck(glDeleteTextures(1, &Texture)); } @@ -410,6 +412,8 @@ void Image::UpdatePixels(const Uint8* pixels) { if (pixels && myTexture) { + EnsureGlContext(); + GLint previous; GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous)); @@ -468,6 +472,8 @@ void Image::SetSmooth(bool smooth) if (myTexture) { + EnsureGlContext(); + GLint previous; GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous)); @@ -535,6 +541,8 @@ FloatRect Image::GetTexCoords(const IntRect& rect) const //////////////////////////////////////////////////////////// unsigned int Image::GetMaximumSize() { + EnsureGlContext(); + GLint size; GLCheck(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size)); @@ -565,6 +573,8 @@ Image& Image::operator =(const Image& right) //////////////////////////////////////////////////////////// unsigned int Image::GetValidSize(unsigned int size) { + EnsureGlContext(); + // Make sure that GLEW is initialized priv::EnsureGlewInit(); @@ -613,6 +623,8 @@ bool Image::CreateTexture(unsigned int width, unsigned int height) myTextureWidth = textureWidth; myTextureHeight = textureHeight; + EnsureGlContext(); + // Create the OpenGL texture if it doesn't exist yet if (!myTexture) { @@ -645,6 +657,8 @@ void Image::EnsureTextureUpdate() const { if (myTexture && !myPixels.empty()) { + EnsureGlContext(); + GLint previous; GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous)); @@ -666,6 +680,8 @@ void Image::EnsureArrayUpdate() const { if (!myArrayUpdated) { + EnsureGlContext(); + // Save the previous texture GLint previous; GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous)); diff --git a/src/SFML/Graphics/Linux/RenderImageImplPBuffer.cpp b/src/SFML/Graphics/Linux/RenderImageImplPBuffer.cpp index 059411c8c..e68d14ae0 100644 --- a/src/SFML/Graphics/Linux/RenderImageImplPBuffer.cpp +++ b/src/SFML/Graphics/Linux/RenderImageImplPBuffer.cpp @@ -49,6 +49,8 @@ myHeight (0) //////////////////////////////////////////////////////////// RenderImageImplPBuffer::~RenderImageImplPBuffer() { + EnsureGlContext(); + if (myContext) glXDestroyContext(myDisplay, myContext); @@ -56,20 +58,18 @@ RenderImageImplPBuffer::~RenderImageImplPBuffer() glXDestroyGLXPbufferSGIX(myDisplay, myPBuffer); XCloseDisplay(myDisplay); - - // This is to make sure that another valid context is made - // active after we destroy the P-Buffer's one - Context::SetReferenceActive(); } //////////////////////////////////////////////////////////// bool RenderImageImplPBuffer::IsSupported() { + EnsureGlContext(); + // Make sure that GLEW is initialized EnsureGlewInit(); - return glxewIsSupported("GLX_SGIX_pbuffer"); + return GLXEW_SGIX_pbuffer && GLXEW_SGIX_fbconfig; } @@ -182,7 +182,9 @@ bool RenderImageImplPBuffer::Activate(bool active) // To deactivate the P-Buffer's context, we actually activate // another one so that we make sure that there is always an // active context for subsequent graphics operations - return Context::SetReferenceActive(); + // @odo fixme + //return Context::SetReferenceActive(); + return true; } } @@ -190,17 +192,14 @@ bool RenderImageImplPBuffer::Activate(bool active) //////////////////////////////////////////////////////////// void RenderImageImplPBuffer::UpdateTexture(unsigned int textureId) { - if (Activate(true)) - { - GLint previous; - GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous)); + GLint previous; + GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous)); - // Copy the rendered pixels to the image - GLCheck(glBindTexture(GL_TEXTURE_2D, textureId)); - GLCheck(glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, myWidth, myHeight)); + // Copy the rendered pixels to the image + GLCheck(glBindTexture(GL_TEXTURE_2D, textureId)); + GLCheck(glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, myWidth, myHeight)); - GLCheck(glBindTexture(GL_TEXTURE_2D, previous)); - } + GLCheck(glBindTexture(GL_TEXTURE_2D, previous)); } } // namespace priv diff --git a/src/SFML/Graphics/Linux/RenderImageImplPBuffer.hpp b/src/SFML/Graphics/Linux/RenderImageImplPBuffer.hpp index 78956fcc9..d092ff9e1 100644 --- a/src/SFML/Graphics/Linux/RenderImageImplPBuffer.hpp +++ b/src/SFML/Graphics/Linux/RenderImageImplPBuffer.hpp @@ -29,6 +29,7 @@ // Headers //////////////////////////////////////////////////////////// #include +#include #include #include #include @@ -42,7 +43,7 @@ namespace priv /// \brief Specialization of RenderImageImpl using GLX P-Buffers /// //////////////////////////////////////////////////////////// -class RenderImageImplPBuffer : public RenderImageImpl +class RenderImageImplPBuffer : public RenderImageImpl, GlResource { public : diff --git a/src/SFML/Graphics/OSX/RenderImageImplPBuffer.cpp b/src/SFML/Graphics/OSX/RenderImageImplPBuffer.cpp index 4b193e48f..3e8ab4176 100644 --- a/src/SFML/Graphics/OSX/RenderImageImplPBuffer.cpp +++ b/src/SFML/Graphics/OSX/RenderImageImplPBuffer.cpp @@ -66,16 +66,14 @@ RenderImageImplPBuffer::~RenderImageImplPBuffer() << aglGetError() << std::endl; } - - // This is to make sure that another valid context is made - // active after we destroy the P-Buffer's one - Context::SetReferenceActive(); } //////////////////////////////////////////////////////////// bool RenderImageImplPBuffer::IsSupported() { + EnsureGlContext(); + const GLubyte* strExt = glGetString(GL_EXTENSIONS); GLboolean isSupported = gluCheckExtension((const GLubyte*)"GL_APPLE_pixel_buffer", strExt); @@ -164,21 +162,24 @@ bool RenderImageImplPBuffer::Create(unsigned int width, unsigned int height, uns //////////////////////////////////////////////////////////// bool RenderImageImplPBuffer::Activate(bool active) { - if (active) { - if (!myContext || !myPBuffer) { // Not created yet. + if (active) + { + if (!myContext || !myPBuffer) // Not created yet. return false; - } - if (aglGetCurrentContext() == myContext) { + if (aglGetCurrentContext() == myContext) return true; - } else { + else return aglSetCurrentContext(myContext); - } - } else { + } + else + { // To deactivate the P-Buffer's context, we actually activate // another one so that we make sure that there is always an // active context for subsequent graphics operations - return Context::SetReferenceActive(); + // @todo fixme + // return Context::SetReferenceActive(); + return true; } } @@ -186,17 +187,14 @@ bool RenderImageImplPBuffer::Activate(bool active) //////////////////////////////////////////////////////////// void RenderImageImplPBuffer::UpdateTexture(unsigned int textureId) { - if (Activate(true)) - { - GLint previous; - GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous)); + GLint previous; + GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous)); - // Copy the rendered pixels to the image - GLCheck(glBindTexture(GL_TEXTURE_2D, textureId)); - GLCheck(glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, myWidth, myHeight)); + // Copy the rendered pixels to the image + GLCheck(glBindTexture(GL_TEXTURE_2D, textureId)); + GLCheck(glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, myWidth, myHeight)); - GLCheck(glBindTexture(GL_TEXTURE_2D, previous)); - } + GLCheck(glBindTexture(GL_TEXTURE_2D, previous)); } } // namespace priv diff --git a/src/SFML/Graphics/OSX/RenderImageImplPBuffer.hpp b/src/SFML/Graphics/OSX/RenderImageImplPBuffer.hpp index a4b3572c3..192eb9a10 100644 --- a/src/SFML/Graphics/OSX/RenderImageImplPBuffer.hpp +++ b/src/SFML/Graphics/OSX/RenderImageImplPBuffer.hpp @@ -30,6 +30,7 @@ // Headers //////////////////////////////////////////////////////////// #include +#include #include #include @@ -41,7 +42,7 @@ namespace priv /// \brief Specialization of RenderImageImpl using AGL P-Buffers /// //////////////////////////////////////////////////////////// -class RenderImageImplPBuffer : public RenderImageImpl +class RenderImageImplPBuffer : public RenderImageImpl, GlResource { public : diff --git a/src/SFML/Graphics/RenderImage.cpp b/src/SFML/Graphics/RenderImage.cpp index b2a5ed648..3c1770eb9 100644 --- a/src/SFML/Graphics/RenderImage.cpp +++ b/src/SFML/Graphics/RenderImage.cpp @@ -44,6 +44,7 @@ myRenderImage(NULL) //////////////////////////////////////////////////////////// RenderImage::~RenderImage() { + SetActive(false); delete myRenderImage; } @@ -117,7 +118,7 @@ bool RenderImage::SetActive(bool active) void RenderImage::Display() { // Update the target image - if (myRenderImage) + if (SetActive(true)) { myRenderImage->UpdateTexture(myImage.myTexture); diff --git a/src/SFML/Graphics/RenderImageImplFBO.cpp b/src/SFML/Graphics/RenderImageImplFBO.cpp index 4d5b7cdf1..f3fe9f36c 100644 --- a/src/SFML/Graphics/RenderImageImplFBO.cpp +++ b/src/SFML/Graphics/RenderImageImplFBO.cpp @@ -47,6 +47,8 @@ myDepthBuffer(0) //////////////////////////////////////////////////////////// RenderImageImplFBO::~RenderImageImplFBO() { + EnsureGlContext(); + // Destroy the depth buffer if (myDepthBuffer) { @@ -66,6 +68,8 @@ RenderImageImplFBO::~RenderImageImplFBO() //////////////////////////////////////////////////////////// bool RenderImageImplFBO::IsSupported() { + EnsureGlContext(); + // Make sure that GLEW is initialized priv::EnsureGlewInit(); @@ -76,6 +80,9 @@ bool RenderImageImplFBO::IsSupported() //////////////////////////////////////////////////////////// bool RenderImageImplFBO::Create(unsigned int width, unsigned int height, unsigned int textureId, bool depthBuffer) { + // Activate the render-image's context + myContext.SetActive(true); + // Create the framebuffer object GLuint frameBuffer = 0; GLCheck(glGenFramebuffersEXT(1, &frameBuffer)); diff --git a/src/SFML/Graphics/RenderImageImplFBO.hpp b/src/SFML/Graphics/RenderImageImplFBO.hpp index ae6512158..0a4d3e02f 100644 --- a/src/SFML/Graphics/RenderImageImplFBO.hpp +++ b/src/SFML/Graphics/RenderImageImplFBO.hpp @@ -30,6 +30,7 @@ //////////////////////////////////////////////////////////// #include #include +#include namespace sf @@ -41,7 +42,7 @@ namespace priv /// Frame Buffer Object OpenGL extension /// //////////////////////////////////////////////////////////// -class RenderImageImplFBO : public RenderImageImpl +class RenderImageImplFBO : public RenderImageImpl, GlResource { public : diff --git a/src/SFML/Graphics/Shader.cpp b/src/SFML/Graphics/Shader.cpp index df7035e98..8e7be3fe0 100644 --- a/src/SFML/Graphics/Shader.cpp +++ b/src/SFML/Graphics/Shader.cpp @@ -35,12 +35,6 @@ namespace sf { -//////////////////////////////////////////////////////////// -// Static member data -//////////////////////////////////////////////////////////// -const Image Shader::CurrentTexture; - - //////////////////////////////////////////////////////////// Shader::Shader() : myShaderProgram (0), @@ -66,6 +60,8 @@ myFragmentShader(copy.myFragmentShader) //////////////////////////////////////////////////////////// Shader::~Shader() { + EnsureGlContext(); + // Destroy effect program if (myShaderProgram) GLCheck(glDeleteObjectARB(myShaderProgram)); @@ -109,6 +105,8 @@ void Shader::SetParameter(const std::string& name, float x) { if (myShaderProgram) { + EnsureGlContext(); + // Enable program GLhandleARB program = glGetHandleARB(GL_PROGRAM_OBJECT_ARB); GLCheck(glUseProgramObjectARB(myShaderProgram)); @@ -131,6 +129,8 @@ void Shader::SetParameter(const std::string& name, float x, float y) { if (myShaderProgram) { + EnsureGlContext(); + // Enable program GLhandleARB program = glGetHandleARB(GL_PROGRAM_OBJECT_ARB); GLCheck(glUseProgramObjectARB(myShaderProgram)); @@ -153,6 +153,8 @@ void Shader::SetParameter(const std::string& name, float x, float y, float z) { if (myShaderProgram) { + EnsureGlContext(); + // Enable program GLhandleARB program = glGetHandleARB(GL_PROGRAM_OBJECT_ARB); GLCheck(glUseProgramObjectARB(myShaderProgram)); @@ -175,6 +177,8 @@ void Shader::SetParameter(const std::string& name, float x, float y, float z, fl { if (myShaderProgram) { + EnsureGlContext(); + // Enable program GLhandleARB program = glGetHandleARB(GL_PROGRAM_OBJECT_ARB); GLCheck(glUseProgramObjectARB(myShaderProgram)); @@ -211,16 +215,9 @@ void Shader::SetTexture(const std::string& name, const Image& texture) { if (myShaderProgram) { - // Check if there is a texture unit available - GLint maxUnits; - GLCheck(glGetIntegerv(GL_MAX_TEXTURE_COORDS_ARB, &maxUnits)); - if (myTextures.size() + 1 >= static_cast(maxUnits)) - { - Err() << "Impossible to use texture \"" << name << "\" for shader: all available texture units are used" << std::endl; - return; - } + EnsureGlContext(); - // Make sure the given name is a valid variable in the effect + // Find the location of the variable in the shader int location = glGetUniformLocationARB(myShaderProgram, name.c_str()); if (location == -1) { @@ -228,11 +225,41 @@ void Shader::SetTexture(const std::string& name, const Image& texture) return; } - // Store the texture for later use - if (&texture != &CurrentTexture) + // Store the location -> texture mapping + TextureTable::iterator it = myTextures.find(location); + if (it == myTextures.end()) + { + // New entry, make sure there are enough texture units + GLint maxUnits; + GLCheck(glGetIntegerv(GL_MAX_TEXTURE_COORDS_ARB, &maxUnits)); + if (myTextures.size() + 1 >= static_cast(maxUnits)) + { + Err() << "Impossible to use texture \"" << name << "\" for shader: all available texture units are used" << std::endl; + return; + } + myTextures[location] = &texture; + } else - myCurrentTexture = location; + { + // Location already used, just replace the texture + it->second = &texture; + } + } +} + + +//////////////////////////////////////////////////////////// +void Shader::SetCurrentTexture(const std::string& name) +{ + if (myShaderProgram) + { + EnsureGlContext(); + + // Find the location of the variable in the shader + int myCurrentTexture = glGetUniformLocationARB(myShaderProgram, name.c_str()); + if (myCurrentTexture == -1) + Err() << "Texture \"" << name << "\" not found in shader" << std::endl; } } @@ -242,6 +269,8 @@ void Shader::Bind() const { if (myShaderProgram) { + EnsureGlContext(); + // Enable the program GLCheck(glUseProgramObjectARB(myShaderProgram)); @@ -258,6 +287,8 @@ void Shader::Bind() const //////////////////////////////////////////////////////////// void Shader::Unbind() const { + EnsureGlContext(); + GLCheck(glUseProgramObjectARB(0)); } @@ -279,6 +310,8 @@ Shader& Shader::operator =(const Shader& right) //////////////////////////////////////////////////////////// bool Shader::IsAvailable() { + EnsureGlContext(); + // Make sure that GLEW is initialized priv::EnsureGlewInit(); @@ -292,6 +325,8 @@ bool Shader::IsAvailable() //////////////////////////////////////////////////////////// bool Shader::CompileProgram() { + EnsureGlContext(); + // First make sure that we can use shaders if (!IsAvailable()) { @@ -300,9 +335,6 @@ bool Shader::CompileProgram() return false; } - // Make sure that GLEW is initialized (extra safety -- it is already done in IsAvailable()) - priv::EnsureGlewInit(); - // Destroy the shader if it was already created if (myShaderProgram) GLCheck(glDeleteObjectARB(myShaderProgram)); @@ -398,7 +430,7 @@ void Shader::BindTextures() const GLCheck(glUniform1iARB(it->first, index)); GLCheck(glActiveTextureARB(GL_TEXTURE0_ARB + index)); it->second->Bind(); - it++; + ++it; } // Make sure that the texture unit which is left active is the number 0 diff --git a/src/SFML/Graphics/Win32/RenderImageImplPBuffer.cpp b/src/SFML/Graphics/Win32/RenderImageImplPBuffer.cpp index 32dbd78c0..8ab750309 100644 --- a/src/SFML/Graphics/Win32/RenderImageImplPBuffer.cpp +++ b/src/SFML/Graphics/Win32/RenderImageImplPBuffer.cpp @@ -50,6 +50,8 @@ myHeight (0) //////////////////////////////////////////////////////////// RenderImageImplPBuffer::~RenderImageImplPBuffer() { + EnsureGlContext(); + if (myContext) wglDeleteContext(myContext); @@ -58,16 +60,14 @@ RenderImageImplPBuffer::~RenderImageImplPBuffer() wglReleasePbufferDCARB(myPBuffer, myDeviceContext); wglDestroyPbufferARB(myPBuffer); } - - // This is to make sure that another valid context is made - // active after we destroy the P-Buffer's one - Context::SetReferenceActive(); } //////////////////////////////////////////////////////////// bool RenderImageImplPBuffer::IsSupported() { + EnsureGlContext(); + // Make sure that GLEW is initialized priv::EnsureGlewInit(); @@ -171,7 +171,9 @@ bool RenderImageImplPBuffer::Activate(bool active) // To deactivate the P-Buffer's context, we actually activate // another one so that we make sure that there is always an // active context for subsequent graphics operations - return Context::SetReferenceActive(); + // @todo fix + //return Context::SetReferenceActive(); + return true; } } @@ -179,17 +181,14 @@ bool RenderImageImplPBuffer::Activate(bool active) //////////////////////////////////////////////////////////// void RenderImageImplPBuffer::UpdateTexture(unsigned int textureId) { - if (Activate(true)) - { - GLint previous; - GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous)); + GLint previous; + GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous)); - // Copy the rendered pixels to the image - GLCheck(glBindTexture(GL_TEXTURE_2D, textureId)); - GLCheck(glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, myWidth, myHeight)); + // Copy the rendered pixels to the image + GLCheck(glBindTexture(GL_TEXTURE_2D, textureId)); + GLCheck(glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, myWidth, myHeight)); - GLCheck(glBindTexture(GL_TEXTURE_2D, previous)); - } + GLCheck(glBindTexture(GL_TEXTURE_2D, previous)); } } // namespace priv diff --git a/src/SFML/Graphics/Win32/RenderImageImplPBuffer.hpp b/src/SFML/Graphics/Win32/RenderImageImplPBuffer.hpp index 80ab3572b..b137dce92 100644 --- a/src/SFML/Graphics/Win32/RenderImageImplPBuffer.hpp +++ b/src/SFML/Graphics/Win32/RenderImageImplPBuffer.hpp @@ -29,6 +29,7 @@ // Headers //////////////////////////////////////////////////////////// #include +#include #include #include @@ -41,7 +42,7 @@ namespace priv /// \brief Specialization of RenderImageImpl using WGL P-Buffers /// //////////////////////////////////////////////////////////// -class RenderImageImplPBuffer : public RenderImageImpl +class RenderImageImplPBuffer : public RenderImageImpl, GlResource { public : diff --git a/src/SFML/Window/CMakeLists.txt b/src/SFML/Window/CMakeLists.txt index ba306d76a..9e942344b 100644 --- a/src/SFML/Window/CMakeLists.txt +++ b/src/SFML/Window/CMakeLists.txt @@ -8,6 +8,8 @@ set(SRC ${INCROOT}/Context.hpp ${SRCROOT}/GlContext.cpp ${SRCROOT}/GlContext.hpp + ${SRCROOT}/GlResource.cpp + ${INCROOT}/GlResource.hpp ${INCROOT}/ContextSettings.hpp ${INCROOT}/Event.hpp ${SRCROOT}/Input.cpp @@ -51,24 +53,24 @@ else() # MACOSX set(SRC ${SRC} ${SRCROOT}/OSX/cpp_objc_conversion.h - ${SRCROOT}/OSX/cpp_objc_conversion.mm - ${SRCROOT}/OSX/cg_sf_conversion.hpp + ${SRCROOT}/OSX/cpp_objc_conversion.mm + ${SRCROOT}/OSX/cg_sf_conversion.hpp ${SRCROOT}/OSX/cg_sf_conversion.cpp ${SRCROOT}/OSX/Joystick.cpp - ${SRCROOT}/OSX/Joystick.hpp - ${SRCROOT}/OSX/SFApplication.h - ${SRCROOT}/OSX/SFApplication.m - ${SRCROOT}/OSX/SFContext.hpp - ${SRCROOT}/OSX/SFContext.mm - ${SRCROOT}/OSX/SFOpenGLView.h - ${SRCROOT}/OSX/SFOpenGLView.mm - ${SRCROOT}/OSX/SFWindow.h - ${SRCROOT}/OSX/SFWindow.m - ${SRCROOT}/OSX/SFWindowController.h - ${SRCROOT}/OSX/SFWindowController.mm - ${SRCROOT}/OSX/VideoModeImpl.cpp - ${SRCROOT}/OSX/WindowImplCocoa.hpp - ${SRCROOT}/OSX/WindowImplCocoa.mm + ${SRCROOT}/OSX/Joystick.hpp + ${SRCROOT}/OSX/SFApplication.h + ${SRCROOT}/OSX/SFApplication.m + ${SRCROOT}/OSX/SFContext.hpp + ${SRCROOT}/OSX/SFContext.mm + ${SRCROOT}/OSX/SFOpenGLView.h + ${SRCROOT}/OSX/SFOpenGLView.mm + ${SRCROOT}/OSX/SFWindow.h + ${SRCROOT}/OSX/SFWindow.m + ${SRCROOT}/OSX/SFWindowController.h + ${SRCROOT}/OSX/SFWindowController.mm + ${SRCROOT}/OSX/VideoModeImpl.cpp + ${SRCROOT}/OSX/WindowImplCocoa.hpp + ${SRCROOT}/OSX/WindowImplCocoa.mm ${SRCROOT}/OSX/WindowImplDelegateProtocol.h ) endif() @@ -84,8 +86,8 @@ set(WINDOW_EXT_LIBS ${OPENGL_gl_LIBRARY}) if(WINDOWS) set(WINDOW_EXT_LIBS ${WINDOW_EXT_LIBS} winmm gdi32) elseif(LINUX) - set(WINDOW_EXT_LIBS ${WINDOW_EXT_LIBS} ${X11_X11_LIB} ${X11_Xrandr_LIB}) -elseif(MACOSX) + set(WINDOW_EXT_LIBS ${WINDOW_EXT_LIBS} ${X11_X11_LIB} ${X11_Xrandr_LIB}) +elseif(MACOSX) set(WINDOW_EXT_LIBS ${WINDOW_EXT_LIBS} "-framework Foundation -framework AppKit") endif() diff --git a/src/SFML/Window/Context.cpp b/src/SFML/Window/Context.cpp index feb46a09e..220a0cfe6 100644 --- a/src/SFML/Window/Context.cpp +++ b/src/SFML/Window/Context.cpp @@ -54,11 +54,4 @@ void Context::SetActive(bool active) } -//////////////////////////////////////////////////////////// -bool Context::SetReferenceActive() -{ - return priv::GlContext::SetReferenceActive(); -} - - } // namespace sf diff --git a/src/SFML/Window/GlContext.cpp b/src/SFML/Window/GlContext.cpp index 882a49a6a..8b7af3abb 100644 --- a/src/SFML/Window/GlContext.cpp +++ b/src/SFML/Window/GlContext.cpp @@ -27,9 +27,13 @@ //////////////////////////////////////////////////////////// #include #include +#include +#include #include #include +#include #include +#include #if defined(SFML_SYSTEM_WINDOWS) @@ -55,16 +59,29 @@ //////////////////////////////////////////////////////////// namespace { - // This thread-local variable will hold the "global" context for each thread - sf::ThreadLocalPtr threadContext(NULL); + // This per-thread variable holds the current context for each thread + sf::ThreadLocalPtr currentContext = NULL; - // Now we create two global contexts. - // The first one is the reference context: it will be shared with every other - // context, and it can't be activated if we want the sharing operation to always succeed. - // That's why we need the second context: this one will be activated and used - // in the main thread whenever there's no other context (window) active. - ContextType referenceContext(NULL); - ContextType defaultContext(&referenceContext); + // The hidden, inactive context that will be shared with all other contexts + ContextType* sharedContext = NULL; + + // Internal contexts + sf::ThreadLocalPtr internalContext = NULL; + std::vector internalContexts; + sf::Mutex internalContextsMutex; + + // Retrieve the internal context for the current thread + sf::priv::GlContext* GetInternalContext() + { + if (!internalContext) + { + internalContext = sf::priv::GlContext::New(); + sf::Lock lock(internalContextsMutex); + internalContexts.push_back(internalContext); + } + + return internalContext; + } } @@ -72,17 +89,58 @@ namespace sf { namespace priv { +//////////////////////////////////////////////////////////// +void GlContext::Initialize() +{ + // Create the shared context + sharedContext = new ContextType(NULL); + + // This call makes sure that: + // - the shared context is inactive (it must never be) + // - another valid context is activated in the current thread + sharedContext->SetActive(false); +} + + +//////////////////////////////////////////////////////////// +void GlContext::Cleanup() +{ + // Destroy the shared context + delete sharedContext; + sharedContext = NULL; + + // Destroy the internal contexts + sf::Lock lock(internalContextsMutex); + for (std::vector::iterator it = internalContexts.begin(); it != internalContexts.end(); ++it) + delete *it; + internalContexts.clear(); +} + + +//////////////////////////////////////////////////////////// +void GlContext::EnsureContext() +{ + // If there's no active context on the current thread, activate an internal one + if (!currentContext) + GetInternalContext()->SetActive(true); +} + + //////////////////////////////////////////////////////////// GlContext* GlContext::New() { - return new ContextType(&referenceContext); + return new ContextType(sharedContext); } //////////////////////////////////////////////////////////// GlContext* GlContext::New(const WindowImpl* owner, unsigned int bitsPerPixel, const ContextSettings& settings) { - ContextType* context = new ContextType(&referenceContext, owner, bitsPerPixel, settings); + // Make sure that there's an active context (context creation may need extensions, and thus a valid context) + EnsureContext(); + + // Create the context + GlContext* context = new ContextType(sharedContext, owner, bitsPerPixel, settings); // Enable antialiasing if needed if (context->GetSettings().AntialiasingLevel > 0) @@ -95,15 +153,8 @@ GlContext* GlContext::New(const WindowImpl* owner, unsigned int bitsPerPixel, co //////////////////////////////////////////////////////////// GlContext::~GlContext() { - if (threadContext == this) - { - threadContext = NULL; - } - else if (threadContext) - { - // Don't call this->SetActive(false), it would lead to a pure virtual function call - threadContext->SetActive(true); - } + // Deactivate the context before killing it + SetActive(false); } @@ -119,42 +170,40 @@ bool GlContext::SetActive(bool active) { if (active) { - // Activate the context - if (MakeCurrent()) + if (this != currentContext) { - // If this is the first context to be activated on this thread, make - // it the reference context for the whole thread. - // referenceContext must *not* be the threadContext of the main thread - if (!threadContext && (this != &referenceContext)) - threadContext = this; - + // Activate the context + if (MakeCurrent()) + { + // Set it as the new current context for this thread + currentContext = this; + return true; + } + else + { + return false; + } + } + else + { + // This context is already the active one on this thread, don't do anything return true; } } else { - // Deactivate the context - if (threadContext && (threadContext != this)) + if (this == currentContext) { - // To deactivate the context, we actually activate another one - // so that we make sure that there is always an active context - // for subsequent graphics operations - return threadContext->SetActive(true); + // To deactivate the context, we actually activate another one so that we make + // sure that there is always an active context for subsequent graphics operations + return GetInternalContext()->SetActive(true); + } + else + { + // This context is not the active one on this thread, don't do anything + return true; } } - - // If we got there then something failed - return false; -} - - -//////////////////////////////////////////////////////////// -bool GlContext::SetReferenceActive() -{ - if (threadContext) - return threadContext->SetActive(true); - else - return false; } diff --git a/src/SFML/Window/GlContext.hpp b/src/SFML/Window/GlContext.hpp index 9c4226740..db7b44fb1 100644 --- a/src/SFML/Window/GlContext.hpp +++ b/src/SFML/Window/GlContext.hpp @@ -47,6 +47,36 @@ class GlContext : NonCopyable { public : + //////////////////////////////////////////////////////////// + /// \brief Perform the global initialization + /// + /// This function is called once, before the very first OpenGL + /// resource is created. It makes sure that everything is ready + /// for contexts to work properly. + /// Note: this function doesn't need to be thread-safe, as it + /// can be called only once. + /// + //////////////////////////////////////////////////////////// + static void Initialize(); + + //////////////////////////////////////////////////////////// + /// \brief Perform the global cleanup + /// + /// This function is called after the very last OpenGL resource + /// is destroyed. It makes sure that everything that was + /// created by Initialize() is properly released. + /// Note: this function doesn't need to be thread-safe, as it + /// can be called only once. + /// + //////////////////////////////////////////////////////////// + static void Cleanup(); + + //////////////////////////////////////////////////////////// + /// \brief Ensures that an OpenGL context is active in the current thread + /// + //////////////////////////////////////////////////////////// + static void EnsureContext(); + //////////////////////////////////////////////////////////// /// \brief Create a new context, not associated to a window /// @@ -129,18 +159,6 @@ public : //////////////////////////////////////////////////////////// virtual void EnableVerticalSync(bool enabled) = 0; - //////////////////////////////////////////////////////////// - /// \brief Make the current thread's reference context active - /// - /// This function is meant to be called internally; it is used - /// to deactivate the current context by activating another one - /// (so that we still have an active context on the current thread). - /// - /// \return True if operation was successful, false otherwise - /// - //////////////////////////////////////////////////////////// - static bool SetReferenceActive(); - protected : //////////////////////////////////////////////////////////// diff --git a/src/SFML/Window/GlResource.cpp b/src/SFML/Window/GlResource.cpp new file mode 100644 index 000000000..d06a8fc98 --- /dev/null +++ b/src/SFML/Window/GlResource.cpp @@ -0,0 +1,89 @@ +//////////////////////////////////////////////////////////// +// +// SFML - Simple and Fast Multimedia Library +// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// Headers +//////////////////////////////////////////////////////////// +#include +#include +#include +#include + + +//////////////////////////////////////////////////////////// +// Private data +//////////////////////////////////////////////////////////// +namespace +{ + // OpenGL resources counter and its mutex + unsigned long count = 0; + bool initialized = false; + sf::Mutex mutex; +} + + +namespace sf +{ +//////////////////////////////////////////////////////////// +GlResource::GlResource() +{ + { + // Protect from concurrent access + Lock lock(mutex); + + // If this is the very first resource, trigger the global context initialization + if (count == 0) + priv::GlContext::Initialize(); + + // Increment the resources counter + count++; + } + + // Now make sure that there is an active OpenGL context in the current thread + priv::GlContext::EnsureContext(); +} + + +//////////////////////////////////////////////////////////// +GlResource::~GlResource() +{ + // Protect from concurrent access + Lock lock(mutex); + + // Decrement the resources counter + count--; + + // If there's no more resource alive, we can trigger the global context cleanup + if (count == 0) + priv::GlContext::Cleanup(); +} + + +//////////////////////////////////////////////////////////// +void GlResource::EnsureGlContext() +{ + priv::GlContext::EnsureContext(); +} + +} // namespace sf diff --git a/src/SFML/Window/Linux/GlxContext.cpp b/src/SFML/Window/Linux/GlxContext.cpp index 52c9e0a4b..f441cbcfc 100644 --- a/src/SFML/Window/Linux/GlxContext.cpp +++ b/src/SFML/Window/Linux/GlxContext.cpp @@ -116,17 +116,7 @@ GlxContext::~GlxContext() //////////////////////////////////////////////////////////// bool GlxContext::MakeCurrent() { - if (myContext) - { - if (glXGetCurrentContext() != myContext) - return glXMakeCurrent(myDisplay, myWindow, myContext) != 0; - else - return true; - } - else - { - return false; - } + return myContext && glXMakeCurrent(myDisplay, myWindow, myContext); } diff --git a/src/SFML/Window/Win32/WglContext.cpp b/src/SFML/Window/Win32/WglContext.cpp index da7a1dc60..3a65fb4fe 100644 --- a/src/SFML/Window/Win32/WglContext.cpp +++ b/src/SFML/Window/Win32/WglContext.cpp @@ -107,17 +107,7 @@ WglContext::~WglContext() //////////////////////////////////////////////////////////// bool WglContext::MakeCurrent() { - if (myDeviceContext && myContext) - { - if (wglGetCurrentContext() != myContext) - return wglMakeCurrent(myDeviceContext, myContext) != 0; - else - return true; - } - else - { - return false; - } + return myDeviceContext && myContext && wglMakeCurrent(myDeviceContext, myContext); }