git-svn-id: https://sfml.svn.sourceforge.net/svnroot/sfml/branches/sfml2@1809 4e206d99-4929-0410-ac5d-dfc041789085
This commit is contained in:
laurentgom 2011-03-21 07:08:26 +00:00
parent 6cf2303484
commit a94ed51702
25 changed files with 496 additions and 229 deletions

View File

@ -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;

View File

@ -29,6 +29,7 @@
// Headers
////////////////////////////////////////////////////////////
#include <SFML/System/Resource.hpp>
#include <SFML/Window/GlResource.hpp>
#include <SFML/Graphics/Color.hpp>
#include <SFML/Graphics/Rect.hpp>
#include <string>
@ -45,7 +46,7 @@ class RenderWindow;
/// \brief Class for loading, manipulating and saving images
///
////////////////////////////////////////////////////////////
class SFML_API Image : public Resource<Image>
class SFML_API Image : public Resource<Image>, GlResource
{
public :

View File

@ -30,6 +30,7 @@
////////////////////////////////////////////////////////////
#include <SFML/Config.hpp>
#include <SFML/System/NonCopyable.hpp>
#include <SFML/Window/GlResource.hpp>
#include <SFML/Graphics/Color.hpp>
#include <SFML/Graphics/Drawable.hpp>
#include <SFML/Graphics/Matrix3.hpp>
@ -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 :

View File

@ -30,6 +30,7 @@
////////////////////////////////////////////////////////////
#include <SFML/Config.hpp>
#include <SFML/Graphics/Image.hpp>
#include <SFML/Window/GlResource.hpp>
#include <SFML/System/Vector2.hpp>
#include <SFML/System/Vector3.hpp>
#include <map>
@ -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:

View File

@ -29,6 +29,7 @@
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Config.hpp>
#include <SFML/Window/GlResource.hpp>
#include <SFML/System/NonCopyable.hpp>
@ -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 :
////////////////////////////////////////////////////////////

View File

@ -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 <SFML/Config.hpp>
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.
///
////////////////////////////////////////////////////////////

View File

@ -33,6 +33,7 @@
#include <SFML/Window/VideoMode.hpp>
#include <SFML/Window/WindowHandle.hpp>
#include <SFML/Window/WindowStyle.hpp>
#include <SFML/Window/GlResource.hpp>
#include <SFML/System/Clock.hpp>
#include <SFML/System/NonCopyable.hpp>
#include <string>
@ -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 :

View File

@ -84,6 +84,8 @@ Image::~Image()
// Destroy the OpenGL texture
if (myTexture)
{
EnsureGlContext();
GLuint Texture = static_cast<GLuint>(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));

View File

@ -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

View File

@ -29,6 +29,7 @@
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Graphics/RenderImageImpl.hpp>
#include <SFML/Window/GlResource.hpp>
#include <GL/glew.h>
#include <GL/glxew.h>
#include <X11/Xlib.h>
@ -42,7 +43,7 @@ namespace priv
/// \brief Specialization of RenderImageImpl using GLX P-Buffers
///
////////////////////////////////////////////////////////////
class RenderImageImplPBuffer : public RenderImageImpl
class RenderImageImplPBuffer : public RenderImageImpl, GlResource
{
public :

View File

@ -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

View File

@ -30,6 +30,7 @@
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Graphics/RenderImageImpl.hpp>
#include <SFML/Window/GlResource.hpp>
#include <GL/glew.h>
#include <AGL/agl.h>
@ -41,7 +42,7 @@ namespace priv
/// \brief Specialization of RenderImageImpl using AGL P-Buffers
///
////////////////////////////////////////////////////////////
class RenderImageImplPBuffer : public RenderImageImpl
class RenderImageImplPBuffer : public RenderImageImpl, GlResource
{
public :

View File

@ -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);

View File

@ -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));

View File

@ -30,6 +30,7 @@
////////////////////////////////////////////////////////////
#include <SFML/Graphics/RenderImageImpl.hpp>
#include <SFML/Window/Context.hpp>
#include <SFML/Window/GlResource.hpp>
namespace sf
@ -41,7 +42,7 @@ namespace priv
/// Frame Buffer Object OpenGL extension
///
////////////////////////////////////////////////////////////
class RenderImageImplFBO : public RenderImageImpl
class RenderImageImplFBO : public RenderImageImpl, GlResource
{
public :

View File

@ -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<std::size_t>(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<std::size_t>(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

View File

@ -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

View File

@ -29,6 +29,7 @@
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Graphics/RenderImageImpl.hpp>
#include <SFML/Window/GlResource.hpp>
#include <GL/glew.h>
#include <GL/wglew.h>
@ -41,7 +42,7 @@ namespace priv
/// \brief Specialization of RenderImageImpl using WGL P-Buffers
///
////////////////////////////////////////////////////////////
class RenderImageImplPBuffer : public RenderImageImpl
class RenderImageImplPBuffer : public RenderImageImpl, GlResource
{
public :

View File

@ -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

View File

@ -54,11 +54,4 @@ void Context::SetActive(bool active)
}
////////////////////////////////////////////////////////////
bool Context::SetReferenceActive()
{
return priv::GlContext::SetReferenceActive();
}
} // namespace sf

View File

@ -27,9 +27,13 @@
////////////////////////////////////////////////////////////
#include <SFML/Window/GlContext.hpp>
#include <SFML/System/ThreadLocalPtr.hpp>
#include <SFML/System/Mutex.hpp>
#include <SFML/System/Lock.hpp>
#include <SFML/OpenGL.hpp>
#include <SFML/Window/glext/glext.h>
#include <vector>
#include <cstdlib>
#include <cassert>
#if defined(SFML_SYSTEM_WINDOWS)
@ -55,16 +59,29 @@
////////////////////////////////////////////////////////////
namespace
{
// This thread-local variable will hold the "global" context for each thread
sf::ThreadLocalPtr<sf::priv::GlContext> threadContext(NULL);
// This per-thread variable holds the current context for each thread
sf::ThreadLocalPtr<sf::priv::GlContext> 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<sf::priv::GlContext> internalContext = NULL;
std::vector<sf::priv::GlContext*> 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<GlContext*>::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;
}

View File

@ -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 :
////////////////////////////////////////////////////////////

View File

@ -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 <SFML/Window/GlResource.hpp>
#include <SFML/Window/GlContext.hpp>
#include <SFML/System/Mutex.hpp>
#include <SFML/System/Lock.hpp>
////////////////////////////////////////////////////////////
// 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

View File

@ -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);
}

View File

@ -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);
}