Added a render states cache to improve performances
This commit is contained in:
parent
b65b19343a
commit
191730ac0d
@ -36,12 +36,12 @@
|
|||||||
#include <SFML/Graphics/BlendMode.hpp>
|
#include <SFML/Graphics/BlendMode.hpp>
|
||||||
#include <SFML/Graphics/RenderStates.hpp>
|
#include <SFML/Graphics/RenderStates.hpp>
|
||||||
#include <SFML/Graphics/PrimitiveType.hpp>
|
#include <SFML/Graphics/PrimitiveType.hpp>
|
||||||
|
#include <SFML/Graphics/Vertex.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace sf
|
namespace sf
|
||||||
{
|
{
|
||||||
class Drawable;
|
class Drawable;
|
||||||
class Vertex;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Base class for all render targets (window, texture, ...)
|
/// \brief Base class for all render targets (window, texture, ...)
|
||||||
@ -303,6 +303,44 @@ protected :
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void Initialize();
|
void Initialize();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Apply the current view
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void ApplyCurrentView();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Apply a new blending mode
|
||||||
|
///
|
||||||
|
/// \param mode Blending mode to apply
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void ApplyBlendMode(BlendMode mode);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Apply a new transform
|
||||||
|
///
|
||||||
|
/// \param transform Transform to apply
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void ApplyTransform(const Transform& transform);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Apply a new texture
|
||||||
|
///
|
||||||
|
/// \param texture Texture to apply
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void ApplyTexture(const Texture* texture);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Apply a new shader
|
||||||
|
///
|
||||||
|
/// \param shader Shader to apply
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void ApplyShader(const Shader* shader);
|
||||||
|
|
||||||
private :
|
private :
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
@ -319,12 +357,27 @@ private :
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
virtual bool Activate(bool active) = 0;
|
virtual bool Activate(bool active) = 0;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Render states cache
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
struct StatesCache
|
||||||
|
{
|
||||||
|
enum {VertexCacheSize = 4};
|
||||||
|
|
||||||
|
bool ViewChanged; ///< Has the current view changed since last draw?
|
||||||
|
BlendMode LastBlendMode; ///< Cached blending mode
|
||||||
|
Uint64 LastTextureId; ///< Cached texture
|
||||||
|
bool UseVertexCache; ///< Did we previously use the vertex cache?
|
||||||
|
Vertex VertexCache[VertexCacheSize]; ///< Pre-transformed vertices cache
|
||||||
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
// Member data
|
// Member data
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
View myDefaultView; ///< Default view
|
View myDefaultView; ///< Default view
|
||||||
View myView; ///< Current view
|
View myView; ///< Current view
|
||||||
bool myViewChanged; ///< Has the current view changed since last Draw?
|
StatesCache myCache; ///< Render states cache
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
namespace sf
|
namespace sf
|
||||||
{
|
{
|
||||||
class Window;
|
class Window;
|
||||||
|
class RenderTarget;
|
||||||
class RenderTexture;
|
class RenderTexture;
|
||||||
class InputStream;
|
class InputStream;
|
||||||
|
|
||||||
@ -467,6 +468,7 @@ public :
|
|||||||
private :
|
private :
|
||||||
|
|
||||||
friend class RenderTexture;
|
friend class RenderTexture;
|
||||||
|
friend class RenderTarget;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Get a valid image size according to hardware support
|
/// \brief Get a valid image size according to hardware support
|
||||||
@ -494,6 +496,7 @@ private :
|
|||||||
bool myIsSmooth; ///< Status of the smooth filter
|
bool myIsSmooth; ///< Status of the smooth filter
|
||||||
bool myIsRepeated; ///< Is the texture in repeat mode?
|
bool myIsRepeated; ///< Is the texture in repeat mode?
|
||||||
mutable bool myPixelsFlipped; ///< To work around the inconsistency in Y orientation
|
mutable bool myPixelsFlipped; ///< To work around the inconsistency in Y orientation
|
||||||
|
Uint64 myCacheId; ///< Unique number that identifies the texture to the render target's cache
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
||||||
|
@ -51,6 +51,8 @@ set(SRC
|
|||||||
${INCROOT}/Text.hpp
|
${INCROOT}/Text.hpp
|
||||||
${SRCROOT}/Texture.cpp
|
${SRCROOT}/Texture.cpp
|
||||||
${INCROOT}/Texture.hpp
|
${INCROOT}/Texture.hpp
|
||||||
|
${SRCROOT}/TextureSaver.cpp
|
||||||
|
${SRCROOT}/TextureSaver.hpp
|
||||||
${SRCROOT}/Transform.cpp
|
${SRCROOT}/Transform.cpp
|
||||||
${INCROOT}/Transform.hpp
|
${INCROOT}/Transform.hpp
|
||||||
${SRCROOT}/Transformable.cpp
|
${SRCROOT}/Transformable.cpp
|
||||||
|
@ -40,7 +40,7 @@ namespace sf
|
|||||||
RenderTarget::RenderTarget() :
|
RenderTarget::RenderTarget() :
|
||||||
myDefaultView(),
|
myDefaultView(),
|
||||||
myView (),
|
myView (),
|
||||||
myViewChanged(false)
|
myCache ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +66,7 @@ void RenderTarget::Clear(const Color& color)
|
|||||||
void RenderTarget::SetView(const View& view)
|
void RenderTarget::SetView(const View& view)
|
||||||
{
|
{
|
||||||
myView = view;
|
myView = view;
|
||||||
myViewChanged = true;
|
myCache.ViewChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -136,81 +136,78 @@ void RenderTarget::Draw(const Vertex* vertices, unsigned int verticesCount,
|
|||||||
|
|
||||||
if (Activate(true))
|
if (Activate(true))
|
||||||
{
|
{
|
||||||
// Apply the new view if needed
|
// Check if the vertex count is low enough so that we can pre-transform them
|
||||||
if (myViewChanged)
|
bool useVertexCache = (verticesCount <= StatesCache::VertexCacheSize);
|
||||||
|
if (useVertexCache)
|
||||||
{
|
{
|
||||||
// Set the viewport
|
// Pre-transform the vertices and store them into the vertex cache
|
||||||
IntRect viewport = GetViewport(myView);
|
for (unsigned int i = 0; i < verticesCount; ++i)
|
||||||
int top = GetHeight() - (viewport.Top + viewport.Height);
|
{
|
||||||
GLCheck(glViewport(viewport.Left, top, viewport.Width, viewport.Height));
|
Vertex& vertex = myCache.VertexCache[i];
|
||||||
|
vertex.Position = states.Transform * vertices[i].Position;
|
||||||
|
vertex.Color = vertices[i].Color;
|
||||||
|
vertex.TexCoords = vertices[i].TexCoords;
|
||||||
|
}
|
||||||
|
|
||||||
// Set the projection matrix
|
// Since vertices are transformed, we must use an identity transform to render them
|
||||||
GLCheck(glMatrixMode(GL_PROJECTION));
|
if (!myCache.UseVertexCache)
|
||||||
GLCheck(glLoadMatrixf(myView.GetTransform().GetMatrix()));
|
ApplyTransform(Transform::Identity);
|
||||||
|
}
|
||||||
myViewChanged = false;
|
else
|
||||||
|
{
|
||||||
|
ApplyTransform(states.Transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply the transform
|
// Apply the view
|
||||||
GLCheck(glMatrixMode(GL_MODELVIEW));
|
if (myCache.ViewChanged)
|
||||||
GLCheck(glLoadMatrixf(states.Transform.GetMatrix()));
|
ApplyCurrentView();
|
||||||
|
|
||||||
// Apply the blend mode
|
// Apply the blend mode
|
||||||
switch (states.BlendMode)
|
if (states.BlendMode != myCache.LastBlendMode)
|
||||||
{
|
ApplyBlendMode(states.BlendMode);
|
||||||
// Alpha blending
|
|
||||||
// glBlendFuncSeparateEXT is used when available to avoid an incorrect alpha value when the target
|
|
||||||
// is a RenderTexture -- in this case the alpha value must be written directly to the target buffer
|
|
||||||
default :
|
|
||||||
case BlendAlpha :
|
|
||||||
if (GLEW_EXT_blend_func_separate)
|
|
||||||
GLCheck(glBlendFuncSeparateEXT(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
|
|
||||||
else
|
|
||||||
GLCheck(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Additive blending
|
|
||||||
case BlendAdd :
|
|
||||||
GLCheck(glBlendFunc(GL_SRC_ALPHA, GL_ONE));
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Multiplicative blending
|
|
||||||
case BlendMultiply :
|
|
||||||
GLCheck(glBlendFunc(GL_DST_COLOR, GL_ZERO));
|
|
||||||
break;
|
|
||||||
|
|
||||||
// No blending
|
|
||||||
case BlendNone :
|
|
||||||
GLCheck(glBlendFunc(GL_ONE, GL_ZERO));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply the texture
|
// Apply the texture
|
||||||
if (states.Texture)
|
Uint64 textureId = states.Texture ? states.Texture->myCacheId : 0;
|
||||||
states.Texture->Bind(Texture::Pixels);
|
if (textureId != myCache.LastTextureId)
|
||||||
else
|
ApplyTexture(states.Texture);
|
||||||
GLCheck(glBindTexture(GL_TEXTURE_2D, 0));
|
|
||||||
|
|
||||||
// Apply the shader
|
// Apply the shader
|
||||||
if (states.Shader)
|
if (states.Shader)
|
||||||
states.Shader->Bind();
|
ApplyShader(states.Shader);
|
||||||
else
|
|
||||||
GLCheck(glUseProgramObjectARB(0));
|
// If we pre-transform the vertices, we must use our internal vertex cache
|
||||||
|
if (useVertexCache)
|
||||||
|
{
|
||||||
|
// ... and if we already used it previously, we don't need to set the pointers again
|
||||||
|
if (!myCache.UseVertexCache)
|
||||||
|
vertices = myCache.VertexCache;
|
||||||
|
else
|
||||||
|
vertices = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// Setup the pointers to the vertices' components
|
// Setup the pointers to the vertices' components
|
||||||
const char* data = reinterpret_cast<const char*>(vertices);
|
if (vertices)
|
||||||
GLCheck(glVertexPointer(2, GL_FLOAT, sizeof(Vertex), data + 0));
|
{
|
||||||
GLCheck(glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), data + 8));
|
const char* data = reinterpret_cast<const char*>(vertices);
|
||||||
GLCheck(glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), data + 12));
|
GLCheck(glVertexPointer(2, GL_FLOAT, sizeof(Vertex), data + 0));
|
||||||
|
GLCheck(glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), data + 8));
|
||||||
|
GLCheck(glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), data + 12));
|
||||||
|
}
|
||||||
|
|
||||||
// Find the OpenGL primitive type
|
// Find the OpenGL primitive type
|
||||||
static const GLenum modes[] = {GL_POINTS, GL_LINES, GL_LINE_STRIP,
|
static const GLenum modes[] = {GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES,
|
||||||
GL_TRIANGLES, GL_TRIANGLE_STRIP,
|
GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS};
|
||||||
GL_TRIANGLE_FAN, GL_QUADS};
|
|
||||||
GLenum mode = modes[type];
|
GLenum mode = modes[type];
|
||||||
|
|
||||||
// Draw the primitives
|
// Draw the primitives
|
||||||
GLCheck(glDrawArrays(mode, 0, verticesCount));
|
GLCheck(glDrawArrays(mode, 0, verticesCount));
|
||||||
|
|
||||||
|
// Unbind the shader, if any
|
||||||
|
if (states.Shader)
|
||||||
|
ApplyShader(NULL);
|
||||||
|
|
||||||
|
// Update the cache
|
||||||
|
myCache.UseVertexCache = useVertexCache;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,16 +254,26 @@ void RenderTarget::ResetGLStates()
|
|||||||
// Make sure that GLEW is initialized
|
// Make sure that GLEW is initialized
|
||||||
priv::EnsureGlewInit();
|
priv::EnsureGlewInit();
|
||||||
|
|
||||||
|
// Define the default OpenGL states
|
||||||
GLCheck(glDisable(GL_LIGHTING));
|
GLCheck(glDisable(GL_LIGHTING));
|
||||||
GLCheck(glDisable(GL_DEPTH_TEST));
|
GLCheck(glDisable(GL_DEPTH_TEST));
|
||||||
GLCheck(glEnable(GL_TEXTURE_2D));
|
GLCheck(glEnable(GL_TEXTURE_2D));
|
||||||
GLCheck(glEnable(GL_ALPHA_TEST));
|
GLCheck(glEnable(GL_ALPHA_TEST));
|
||||||
GLCheck(glEnable(GL_BLEND));
|
GLCheck(glEnable(GL_BLEND));
|
||||||
GLCheck(glAlphaFunc(GL_GREATER, 0));
|
GLCheck(glAlphaFunc(GL_GREATER, 0));
|
||||||
|
GLCheck(glMatrixMode(GL_MODELVIEW));
|
||||||
GLCheck(glEnableClientState(GL_VERTEX_ARRAY));
|
GLCheck(glEnableClientState(GL_VERTEX_ARRAY));
|
||||||
GLCheck(glEnableClientState(GL_COLOR_ARRAY));
|
GLCheck(glEnableClientState(GL_COLOR_ARRAY));
|
||||||
GLCheck(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
|
GLCheck(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
|
||||||
|
|
||||||
|
// Apply the default SFML states
|
||||||
|
ApplyBlendMode(BlendAlpha);
|
||||||
|
ApplyTransform(Transform::Identity);
|
||||||
|
ApplyTexture(NULL);
|
||||||
|
ApplyShader(NULL);
|
||||||
|
myCache.UseVertexCache = false;
|
||||||
|
|
||||||
|
// Set the default view
|
||||||
SetView(GetView());
|
SetView(GetView());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -275,12 +282,135 @@ void RenderTarget::ResetGLStates()
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void RenderTarget::Initialize()
|
void RenderTarget::Initialize()
|
||||||
{
|
{
|
||||||
// Setup the default view
|
// Setup the default and current views
|
||||||
myDefaultView.Reset(FloatRect(0, 0, static_cast<float>(GetWidth()), static_cast<float>(GetHeight())));
|
myDefaultView.Reset(FloatRect(0, 0, static_cast<float>(GetWidth()), static_cast<float>(GetHeight())));
|
||||||
SetView(myDefaultView);
|
myView = myDefaultView;
|
||||||
|
|
||||||
// Initialize the default OpenGL render-states
|
// Initialize the default OpenGL render-states
|
||||||
ResetGLStates();
|
ResetGLStates();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void RenderTarget::ApplyCurrentView()
|
||||||
|
{
|
||||||
|
// Set the viewport
|
||||||
|
IntRect viewport = GetViewport(myView);
|
||||||
|
int top = GetHeight() - (viewport.Top + viewport.Height);
|
||||||
|
GLCheck(glViewport(viewport.Left, top, viewport.Width, viewport.Height));
|
||||||
|
|
||||||
|
// Set the projection matrix
|
||||||
|
GLCheck(glMatrixMode(GL_PROJECTION));
|
||||||
|
GLCheck(glLoadMatrixf(myView.GetTransform().GetMatrix()));
|
||||||
|
|
||||||
|
// Go back to model-view mode
|
||||||
|
GLCheck(glMatrixMode(GL_MODELVIEW));
|
||||||
|
|
||||||
|
myCache.ViewChanged = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void RenderTarget::ApplyBlendMode(BlendMode mode)
|
||||||
|
{
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
// Alpha blending
|
||||||
|
// glBlendFuncSeparateEXT is used when available to avoid an incorrect alpha value when the target
|
||||||
|
// is a RenderTexture -- in this case the alpha value must be written directly to the target buffer
|
||||||
|
default :
|
||||||
|
case BlendAlpha :
|
||||||
|
if (GLEW_EXT_blend_func_separate)
|
||||||
|
GLCheck(glBlendFuncSeparateEXT(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
|
||||||
|
else
|
||||||
|
GLCheck(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Additive blending
|
||||||
|
case BlendAdd :
|
||||||
|
GLCheck(glBlendFunc(GL_SRC_ALPHA, GL_ONE));
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Multiplicative blending
|
||||||
|
case BlendMultiply :
|
||||||
|
GLCheck(glBlendFunc(GL_DST_COLOR, GL_ZERO));
|
||||||
|
break;
|
||||||
|
|
||||||
|
// No blending
|
||||||
|
case BlendNone :
|
||||||
|
GLCheck(glBlendFunc(GL_ONE, GL_ZERO));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
myCache.LastBlendMode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void RenderTarget::ApplyTransform(const Transform& transform)
|
||||||
|
{
|
||||||
|
// No need to call glMatrixMode(GL_MODELVIEW), it is always the
|
||||||
|
// current mode (for optimization purpose, since it's the most used)
|
||||||
|
GLCheck(glLoadMatrixf(transform.GetMatrix()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void RenderTarget::ApplyTexture(const Texture* texture)
|
||||||
|
{
|
||||||
|
if (texture)
|
||||||
|
texture->Bind(Texture::Pixels);
|
||||||
|
else
|
||||||
|
GLCheck(glBindTexture(GL_TEXTURE_2D, 0));
|
||||||
|
|
||||||
|
myCache.LastTextureId = texture ? texture->myCacheId : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void RenderTarget::ApplyShader(const Shader* shader)
|
||||||
|
{
|
||||||
|
if (shader)
|
||||||
|
shader->Bind();
|
||||||
|
else
|
||||||
|
GLCheck(glUseProgramObjectARB(0));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace sf
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Render states caching strategies
|
||||||
|
//
|
||||||
|
// * View
|
||||||
|
// If SetView was called since last draw, the projection
|
||||||
|
// matrix is updated. We don't need more, the view doesn't
|
||||||
|
// change frequently.
|
||||||
|
//
|
||||||
|
// * Transform
|
||||||
|
// The transform matrix is usually expensive because each
|
||||||
|
// entity will most likely use a different transform. This can
|
||||||
|
// lead, in worst case, to changing it every 4 vertices.
|
||||||
|
// To avoid that, when the vertex count is low enough, we
|
||||||
|
// pre-transform them and therefore use an identity transform
|
||||||
|
// to render them.
|
||||||
|
//
|
||||||
|
// * Blending mode
|
||||||
|
// It's a simple integral value, so we can easily check
|
||||||
|
// whether the value to apply is the same as before or not.
|
||||||
|
//
|
||||||
|
// * Texture
|
||||||
|
// Storing the pointer or OpenGL ID of the last used texture
|
||||||
|
// is not enough; if the sf::Texture instance is destroyed,
|
||||||
|
// both the pointer and the OpenGL ID might be recycled in
|
||||||
|
// a new texture instance. We need to use our own unique
|
||||||
|
// identifier system to ensure consistent caching.
|
||||||
|
//
|
||||||
|
// * Shader
|
||||||
|
// Shaders are very hard to optimize, because they have
|
||||||
|
// parameters that can be hard (if not impossible) to track,
|
||||||
|
// like matrices or textures. The only optimization that we
|
||||||
|
// do is that we avoid setting a null shader if there was
|
||||||
|
// already none for the previous draw.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
#include <SFML/Graphics/RenderTextureImplDefault.hpp>
|
#include <SFML/Graphics/RenderTextureImplDefault.hpp>
|
||||||
#include <SFML/Graphics/GLCheck.hpp>
|
#include <SFML/Graphics/GLCheck.hpp>
|
||||||
|
#include <SFML/Graphics/TextureSaver.hpp>
|
||||||
#include <SFML/Window/Context.hpp>
|
#include <SFML/Window/Context.hpp>
|
||||||
#include <SFML/System/Err.hpp>
|
#include <SFML/System/Err.hpp>
|
||||||
|
|
||||||
@ -77,6 +78,9 @@ bool RenderTextureImplDefault::Activate(bool active)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void RenderTextureImplDefault::UpdateTexture(unsigned int textureId)
|
void RenderTextureImplDefault::UpdateTexture(unsigned int textureId)
|
||||||
{
|
{
|
||||||
|
// Make sure that the current texture binding will be preserved
|
||||||
|
priv::TextureSaver save;
|
||||||
|
|
||||||
// Copy the rendered pixels to the texture
|
// Copy the rendered pixels to the texture
|
||||||
GLCheck(glBindTexture(GL_TEXTURE_2D, textureId));
|
GLCheck(glBindTexture(GL_TEXTURE_2D, textureId));
|
||||||
GLCheck(glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, myWidth, myHeight));
|
GLCheck(glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, myWidth, myHeight));
|
||||||
|
@ -83,7 +83,7 @@ bool RenderTextureImplFBO::IsAvailable()
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
bool RenderTextureImplFBO::Create(unsigned int width, unsigned int height, unsigned int textureId, bool depthBuffer)
|
bool RenderTextureImplFBO::Create(unsigned int width, unsigned int height, unsigned int textureId, bool depthBuffer)
|
||||||
{
|
{
|
||||||
//Create the context
|
// Create the context
|
||||||
myContext = new Context;
|
myContext = new Context;
|
||||||
|
|
||||||
// Create the framebuffer object
|
// Create the framebuffer object
|
||||||
|
@ -28,12 +28,33 @@
|
|||||||
#include <SFML/Graphics/Texture.hpp>
|
#include <SFML/Graphics/Texture.hpp>
|
||||||
#include <SFML/Graphics/Image.hpp>
|
#include <SFML/Graphics/Image.hpp>
|
||||||
#include <SFML/Graphics/GLCheck.hpp>
|
#include <SFML/Graphics/GLCheck.hpp>
|
||||||
|
#include <SFML/Graphics/TextureSaver.hpp>
|
||||||
#include <SFML/Window/Window.hpp>
|
#include <SFML/Window/Window.hpp>
|
||||||
|
#include <SFML/System/Mutex.hpp>
|
||||||
|
#include <SFML/System/Lock.hpp>
|
||||||
#include <SFML/System/Err.hpp>
|
#include <SFML/System/Err.hpp>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Private data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// Thread-safe unique identifier generator,
|
||||||
|
// is used for states cache (see RenderTarget)
|
||||||
|
sf::Uint64 GetUniqueId()
|
||||||
|
{
|
||||||
|
static sf::Uint64 id = 1; // start at 1, zero is "no texture"
|
||||||
|
static sf::Mutex mutex;
|
||||||
|
|
||||||
|
sf::Lock lock(mutex);
|
||||||
|
return id++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
namespace sf
|
namespace sf
|
||||||
{
|
{
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
@ -45,7 +66,8 @@ myTextureHeight(0),
|
|||||||
myTexture (0),
|
myTexture (0),
|
||||||
myIsSmooth (false),
|
myIsSmooth (false),
|
||||||
myIsRepeated (false),
|
myIsRepeated (false),
|
||||||
myPixelsFlipped(false)
|
myPixelsFlipped(false),
|
||||||
|
myCacheId (GetUniqueId())
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -60,7 +82,8 @@ myTextureHeight(0),
|
|||||||
myTexture (0),
|
myTexture (0),
|
||||||
myIsSmooth (copy.myIsSmooth),
|
myIsSmooth (copy.myIsSmooth),
|
||||||
myIsRepeated (copy.myIsRepeated),
|
myIsRepeated (copy.myIsRepeated),
|
||||||
myPixelsFlipped(false)
|
myPixelsFlipped(false),
|
||||||
|
myCacheId (GetUniqueId())
|
||||||
{
|
{
|
||||||
if (copy.myTexture)
|
if (copy.myTexture)
|
||||||
LoadFromImage(copy.CopyToImage());
|
LoadFromImage(copy.CopyToImage());
|
||||||
@ -123,6 +146,9 @@ bool Texture::Create(unsigned int width, unsigned int height)
|
|||||||
myTexture = static_cast<unsigned int>(texture);
|
myTexture = static_cast<unsigned int>(texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure that the current texture binding will be preserved
|
||||||
|
priv::TextureSaver save;
|
||||||
|
|
||||||
// Initialize the texture
|
// Initialize the texture
|
||||||
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
||||||
GLCheck(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, myTextureWidth, myTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
|
GLCheck(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, myTextureWidth, myTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
|
||||||
@ -130,6 +156,7 @@ bool Texture::Create(unsigned int width, unsigned int height)
|
|||||||
GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, myIsRepeated ? GL_REPEAT : GL_CLAMP_TO_EDGE));
|
GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, myIsRepeated ? GL_REPEAT : GL_CLAMP_TO_EDGE));
|
||||||
GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, myIsSmooth ? GL_LINEAR : GL_NEAREST));
|
GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, myIsSmooth ? GL_LINEAR : GL_NEAREST));
|
||||||
GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, myIsSmooth ? GL_LINEAR : GL_NEAREST));
|
GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, myIsSmooth ? GL_LINEAR : GL_NEAREST));
|
||||||
|
myCacheId = GetUniqueId();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -195,6 +222,9 @@ bool Texture::LoadFromImage(const Image& image, const IntRect& area)
|
|||||||
// Create the texture and upload the pixels
|
// Create the texture and upload the pixels
|
||||||
if (Create(rectangle.Width, rectangle.Height))
|
if (Create(rectangle.Width, rectangle.Height))
|
||||||
{
|
{
|
||||||
|
// Make sure that the current texture binding will be preserved
|
||||||
|
priv::TextureSaver save;
|
||||||
|
|
||||||
// Copy the pixels to the texture, row by row
|
// Copy the pixels to the texture, row by row
|
||||||
const Uint8* pixels = image.GetPixelsPtr() + 4 * (rectangle.Left + (width * rectangle.Top));
|
const Uint8* pixels = image.GetPixelsPtr() + 4 * (rectangle.Left + (width * rectangle.Top));
|
||||||
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
||||||
@ -237,6 +267,9 @@ Image Texture::CopyToImage() const
|
|||||||
|
|
||||||
EnsureGlContext();
|
EnsureGlContext();
|
||||||
|
|
||||||
|
// Make sure that the current texture binding will be preserved
|
||||||
|
priv::TextureSaver save;
|
||||||
|
|
||||||
// Create an array of pixels
|
// Create an array of pixels
|
||||||
std::vector<Uint8> pixels(myWidth * myHeight * 4);
|
std::vector<Uint8> pixels(myWidth * myHeight * 4);
|
||||||
|
|
||||||
@ -302,10 +335,14 @@ void Texture::Update(const Uint8* pixels, unsigned int width, unsigned int heigh
|
|||||||
{
|
{
|
||||||
EnsureGlContext();
|
EnsureGlContext();
|
||||||
|
|
||||||
|
// Make sure that the current texture binding will be preserved
|
||||||
|
priv::TextureSaver save;
|
||||||
|
|
||||||
// Copy pixels from the given array to the texture
|
// Copy pixels from the given array to the texture
|
||||||
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
||||||
GLCheck(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
|
GLCheck(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
|
||||||
myPixelsFlipped = false;
|
myPixelsFlipped = false;
|
||||||
|
myCacheId = GetUniqueId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,10 +377,14 @@ void Texture::Update(const Window& window, unsigned int x, unsigned int y)
|
|||||||
|
|
||||||
if (myTexture && window.SetActive(true))
|
if (myTexture && window.SetActive(true))
|
||||||
{
|
{
|
||||||
|
// Make sure that the current texture binding will be preserved
|
||||||
|
priv::TextureSaver save;
|
||||||
|
|
||||||
// Copy pixels from the back-buffer to the texture
|
// Copy pixels from the back-buffer to the texture
|
||||||
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
||||||
GLCheck(glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x, y, 0, 0, window.GetWidth(), window.GetHeight()));
|
GLCheck(glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x, y, 0, 0, window.GetWidth(), window.GetHeight()));
|
||||||
myPixelsFlipped = true;
|
myPixelsFlipped = true;
|
||||||
|
myCacheId = GetUniqueId();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,6 +421,9 @@ void Texture::Bind(CoordinateType coordinateType) const
|
|||||||
// Load the matrix
|
// Load the matrix
|
||||||
GLCheck(glMatrixMode(GL_TEXTURE));
|
GLCheck(glMatrixMode(GL_TEXTURE));
|
||||||
GLCheck(glLoadMatrixf(matrix));
|
GLCheck(glLoadMatrixf(matrix));
|
||||||
|
|
||||||
|
// Go back to model-view mode (sf::RenderTarget relies on it)
|
||||||
|
GLCheck(glMatrixMode(GL_MODELVIEW));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,6 +439,9 @@ void Texture::SetSmooth(bool smooth)
|
|||||||
{
|
{
|
||||||
EnsureGlContext();
|
EnsureGlContext();
|
||||||
|
|
||||||
|
// Make sure that the current texture binding will be preserved
|
||||||
|
priv::TextureSaver save;
|
||||||
|
|
||||||
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
||||||
GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, myIsSmooth ? GL_LINEAR : GL_NEAREST));
|
GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, myIsSmooth ? GL_LINEAR : GL_NEAREST));
|
||||||
GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, myIsSmooth ? GL_LINEAR : GL_NEAREST));
|
GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, myIsSmooth ? GL_LINEAR : GL_NEAREST));
|
||||||
@ -421,6 +468,9 @@ void Texture::SetRepeated(bool repeated)
|
|||||||
{
|
{
|
||||||
EnsureGlContext();
|
EnsureGlContext();
|
||||||
|
|
||||||
|
// Make sure that the current texture binding will be preserved
|
||||||
|
priv::TextureSaver save;
|
||||||
|
|
||||||
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
||||||
GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, myIsRepeated ? GL_REPEAT : GL_CLAMP_TO_EDGE));
|
GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, myIsRepeated ? GL_REPEAT : GL_CLAMP_TO_EDGE));
|
||||||
GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, myIsRepeated ? GL_REPEAT : GL_CLAMP_TO_EDGE));
|
GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, myIsRepeated ? GL_REPEAT : GL_CLAMP_TO_EDGE));
|
||||||
@ -461,6 +511,7 @@ Texture& Texture::operator =(const Texture& right)
|
|||||||
std::swap(myIsSmooth, temp.myIsSmooth);
|
std::swap(myIsSmooth, temp.myIsSmooth);
|
||||||
std::swap(myIsRepeated, temp.myIsRepeated);
|
std::swap(myIsRepeated, temp.myIsRepeated);
|
||||||
std::swap(myPixelsFlipped, temp.myPixelsFlipped);
|
std::swap(myPixelsFlipped, temp.myPixelsFlipped);
|
||||||
|
myCacheId = GetUniqueId();
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
50
src/SFML/Graphics/TextureSaver.cpp
Normal file
50
src/SFML/Graphics/TextureSaver.cpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// 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/Graphics/TextureSaver.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
namespace priv
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
TextureSaver::TextureSaver()
|
||||||
|
{
|
||||||
|
GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &myTextureBinding));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
TextureSaver::~TextureSaver()
|
||||||
|
{
|
||||||
|
GLCheck(glBindTexture(GL_TEXTURE_2D, myTextureBinding));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace priv
|
||||||
|
|
||||||
|
} // namespace sf
|
75
src/SFML/Graphics/TextureSaver.hpp
Normal file
75
src/SFML/Graphics/TextureSaver.hpp
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// 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_TEXTURESAVER_HPP
|
||||||
|
#define SFML_TEXTURESAVER_HPP
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Headers
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
#include <SFML/Graphics/GLCheck.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace sf
|
||||||
|
{
|
||||||
|
namespace priv
|
||||||
|
{
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Automatic wrapper for saving and restoring the current texture binding
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
class TextureSaver
|
||||||
|
{
|
||||||
|
public :
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Default constructor
|
||||||
|
///
|
||||||
|
/// The current texture binding is saved.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
TextureSaver();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Destructor
|
||||||
|
///
|
||||||
|
/// The previous texture binding is restored.
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
~TextureSaver();
|
||||||
|
|
||||||
|
private :
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
// Member data
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
GLint myTextureBinding; ///< Texture binding to restore
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace priv
|
||||||
|
|
||||||
|
} // namespace sf
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SFML_TEXTURESAVER_HPP
|
Loading…
Reference in New Issue
Block a user