Added automatic batching to improve performances

Moved the ConvertCoords function from RenderWindow to RenderTarget

git-svn-id: https://sfml.svn.sourceforge.net/svnroot/sfml/branches/sfml2@1221 4e206d99-4929-0410-ac5d-dfc041789085
This commit is contained in:
LaurentGom 2009-09-24 07:50:08 +00:00
parent 1852614e16
commit 565172fc75
51 changed files with 2835 additions and 865 deletions

123
src/SFML/Graphics/Batch.cpp Normal file
View file

@ -0,0 +1,123 @@
////////////////////////////////////////////////////////////
//
// 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/Batch.hpp>
#include <SFML/Graphics/Image.hpp>
#include <SFML/Graphics/GLCheck.hpp>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
Batch::Batch(const Image* texture, Blend::Mode blendMode, const IntRect& viewport) :
myTexture (texture),
myBlendMode(blendMode),
myViewport (viewport),
myStart (0),
myCount (0)
{
}
////////////////////////////////////////////////////////////
bool Batch::Matches(const Image* texture, Blend::Mode blendMode, const IntRect& viewport) const
{
return myTexture == texture &&
myBlendMode == blendMode &&
myViewport.Left == viewport.Left &&
myViewport.Top == viewport.Top &&
myViewport.Right == viewport.Right &&
myViewport.Bottom == viewport.Bottom;
}
////////////////////////////////////////////////////////////
void Batch::Begin(std::size_t index)
{
myStart = index;
}
////////////////////////////////////////////////////////////
void Batch::End(std::size_t index)
{
myCount = index - myStart;
}
////////////////////////////////////////////////////////////
std::size_t Batch::GetStartIndex() const
{
return myStart;
}
////////////////////////////////////////////////////////////
std::size_t Batch::GetIndexCount() const
{
return myCount;
}
////////////////////////////////////////////////////////////
void Batch::ApplyStates() const
{
// Set the viewport
GLCheck(glViewport(myViewport.Left, myViewport.Top, myViewport.GetSize().x, myViewport.GetSize().y));
// Set the blending mode
if (myBlendMode == Blend::None)
{
GLCheck(glDisable(GL_BLEND));
}
else
{
GLCheck(glEnable(GL_BLEND));
// @todo the resulting alpha may not be correct, which matters when target is a RenderImage.
// find a fix for this (glBlendFuncSeparate -- but not supported by every graphics card)
switch (myBlendMode)
{
default :
case Blend::Alpha : GLCheck(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); break;
case Blend::Add : GLCheck(glBlendFunc(GL_SRC_ALPHA, GL_ONE)); break;
case Blend::Multiply : GLCheck(glBlendFunc(GL_DST_COLOR, GL_ZERO)); break;
}
}
// Bind the texture
if (myTexture)
myTexture->Bind();
else
GLCheck(glDisable(GL_TEXTURE_2D));
}
} // namespace priv
} // namespace sf

125
src/SFML/Graphics/Batch.hpp Normal file
View file

@ -0,0 +1,125 @@
////////////////////////////////////////////////////////////
//
// 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_BATCH_HPP
#define SFML_BATCH_HPP
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Graphics/Drawable.hpp>
#include <SFML/Graphics/Rect.hpp>
#include <vector>
namespace sf
{
class Image;
namespace priv
{
////////////////////////////////////////////////////////////
/// \brief Batch of geometry / render states to render
///
////////////////////////////////////////////////////////////
class Batch
{
public :
////////////////////////////////////////////////////////////
/// \brief Construct the batch with its render states
///
/// \param texture Texture to use
/// \param blendMode Blending mode
/// \param viewport Target viewport
///
////////////////////////////////////////////////////////////
Batch(const Image* texture = NULL, Blend::Mode blendMode = Blend::Alpha, const IntRect& viewport = IntRect());
////////////////////////////////////////////////////////////
/// \brief Check if the batch matches a set of render states
///
/// \param texture Texture to use
/// \param blendMode Blending mode
/// \param viewport Target viewport
///
////////////////////////////////////////////////////////////
bool Matches(const Image* texture, Blend::Mode blendMode, const IntRect& viewport) const;
////////////////////////////////////////////////////////////
/// \brief Setup the start index of the batch
///
/// \param index Start index
///
////////////////////////////////////////////////////////////
void Begin(std::size_t index);
////////////////////////////////////////////////////////////
/// \brief Setup the end index of the batch
///
/// \param index End index
///
////////////////////////////////////////////////////////////
void End(std::size_t index);
////////////////////////////////////////////////////////////
/// \brief Return the start index of the batch
///
/// \return Start index
///
////////////////////////////////////////////////////////////
std::size_t GetStartIndex() const;
////////////////////////////////////////////////////////////
/// \brief Return the number of indices to render with this batch
///
/// \return Index count
///
////////////////////////////////////////////////////////////
std::size_t GetIndexCount() const;
////////////////////////////////////////////////////////////
/// \brief Apply the render states of the batch
///
////////////////////////////////////////////////////////////
void ApplyStates() const;
private :
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
const Image* myTexture; ///< Texture used by the batch
Blend::Mode myBlendMode; ///< Blending mode used by the batch
IntRect myViewport; ///< Target viewport for the batch
std::size_t myStart; ///< Index of the first index to render with this batch
std::size_t myCount; ///< Number of indices to render with this batch
};
} // namespace priv
} // namespace sf
#endif // SFML_BATCH_HPP

View file

@ -26,8 +26,8 @@
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Graphics/Drawable.hpp>
#include <SFML/Graphics/GLCheck.hpp>
#include <SFML/Window/Window.hpp>
#include <SFML/Graphics/RenderQueue.hpp>
#include <SFML/Graphics/RenderTarget.hpp>
#include <math.h>
@ -358,44 +358,21 @@ const Matrix3& Drawable::GetInverseMatrix() const
////////////////////////////////////////////////////////////
/// Draw the object into the specified window
/// Draw the object into the specified render target
////////////////////////////////////////////////////////////
void Drawable::Draw(RenderTarget& target) const
void Drawable::Draw(RenderTarget& target, RenderQueue& queue) const
{
// Save the current modelview matrix and set the new one
GLCheck(glMatrixMode(GL_MODELVIEW));
GLCheck(glPushMatrix());
GLCheck(glMultMatrixf(GetMatrix().Get4x4Elements()));
// Set the current model-view matrix
queue.ApplyModelView(GetMatrix());
// Setup alpha-blending
if (myBlendMode == Blend::None)
{
GLCheck(glDisable(GL_BLEND));
}
else
{
GLCheck(glEnable(GL_BLEND));
// Set the current global color
queue.ApplyColor(myColor);
// @todo the resulting alpha may not be correct, which matters when target is a RenderImage.
// find a fix for this (glBlendFuncSeparate -- but not supported by every graphics card)
switch (myBlendMode)
{
case Blend::Alpha : GLCheck(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); break;
case Blend::Add : GLCheck(glBlendFunc(GL_SRC_ALPHA, GL_ONE)); break;
case Blend::Multiply : GLCheck(glBlendFunc(GL_DST_COLOR, GL_ZERO)); break;
default : break;
}
}
// Set color
GLCheck(glColor4ub(myColor.r, myColor.g, myColor.b, myColor.a));
// Set the current alpha-blending mode
queue.SetBlendMode(myBlendMode);
// Let the derived class render the object geometry
Render(target);
// Restore the previous modelview matrix
GLCheck(glMatrixMode(GL_MODELVIEW));
GLCheck(glPopMatrix());
Render(target, queue);
}
} // namespace sf

View file

@ -214,6 +214,11 @@ FT_Error FontLoader::CreateBitmapFont(FT_Face face, unsigned int charSize, const
glyphs.insert(std::make_pair(bitmapGlyph, charset[i]));
}
// Leave a small margin around characters, so that filtering doesn't
// pollute them with pixels from neighbours
unsigned int offset = 1;
unsigned int margin = offset + 1;
// Copy the rendered glyphs into the texture
unsigned int maxHeight = 0;
std::map<Uint32, IntRect> coords;
@ -225,31 +230,31 @@ FT_Error FontLoader::CreateBitmapFont(FT_Face face, unsigned int charSize, const
FT_Bitmap& bitmap = bitmapGlyph->bitmap;
// Make sure we don't go over the texture width
if (left + bitmap.width + 1 >= texWidth)
if (left + bitmap.width + margin >= texWidth)
left = 0;
// Compute the top coordinate
top = tops[left];
for (int x = 0; x < bitmap.width + 1; ++x)
for (unsigned int x = 0; x < bitmap.width + margin; ++x)
top = std::max(top, tops[left + x]);
top++;
top += margin;
// Make sure we don't go over the texture height -- resize it if we need more space
if (top + bitmap.rows + 1 >= texHeight)
if (top + bitmap.rows + margin >= texHeight)
{
texHeight *= 2;
glyphsBuffer.resize(texWidth * texHeight * 4);
}
// Store the character's position and size
curGlyph.Rectangle.Left = bitmapGlyph->left;
curGlyph.Rectangle.Top = -bitmapGlyph->top;
curGlyph.Rectangle.Right = curGlyph.Rectangle.Left + bitmap.width;
curGlyph.Rectangle.Bottom = bitmap.rows - bitmapGlyph->top;
curGlyph.Rectangle.Left = bitmapGlyph->left - offset;
curGlyph.Rectangle.Top = -bitmapGlyph->top - offset;
curGlyph.Rectangle.Right = (curGlyph.Rectangle.Left + bitmap.width + offset) / 1;
curGlyph.Rectangle.Bottom = bitmap.rows - bitmapGlyph->top + offset;
curGlyph.Advance = bitmapGlyph->root.advance.x >> 16;
// Texture size may change, so let the texture coordinates be calculated later
coords[i->second] = IntRect(left + 1, top + 1, left + bitmap.width + 1, top + bitmap.rows + 1);
coords[i->second] = IntRect(left + offset, top + offset, left + bitmap.width + offset + margin, top + bitmap.rows + offset + margin);
// Draw the glyph into our bitmap font
const Uint8* pixels = bitmap.buffer;
@ -257,19 +262,19 @@ FT_Error FontLoader::CreateBitmapFont(FT_Face face, unsigned int charSize, const
{
for (int x = 0; x < bitmap.width; ++x)
{
std::size_t index = x + left + 1 + (y + top + 1) * texWidth;
std::size_t index = x + left + margin + (y + top + margin) * texWidth;
glyphsBuffer[index * 4 + 0] = 255;
glyphsBuffer[index * 4 + 1] = 255;
glyphsBuffer[index * 4 + 2] = 255;
glyphsBuffer[index * 4 + 3] = pixels[x];
glyphsBuffer[index * 4 + 3] = pixels[x] * pixels[x] / 255;
}
pixels += bitmap.pitch;
}
// Update the rendering coordinates
for (int x = 0; x < bitmap.width + 1; ++x)
for (unsigned int x = 0; x < bitmap.width + margin; ++x)
tops[left + x] = top + bitmap.rows;
left += bitmap.width + 1;
left += bitmap.width + margin;
if (top + bitmap.rows > maxHeight)
maxHeight = top + bitmap.rows;
@ -278,7 +283,7 @@ FT_Error FontLoader::CreateBitmapFont(FT_Face face, unsigned int charSize, const
}
// Create the font's texture
texHeight = maxHeight + 1;
texHeight = maxHeight + margin;
glyphsBuffer.resize(texWidth * texHeight * 4);
font.myTexture.LoadFromPixels(texWidth, texHeight, &glyphsBuffer[0]);

View file

@ -0,0 +1,68 @@
////////////////////////////////////////////////////////////
//
// 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/GeometryRenderer.hpp>
#include <SFML/Graphics/GeometryRendererVBO.hpp>
#include <SFML/Graphics/GeometryRendererVA.hpp>
#include <SFML/Graphics/GeometryRendererIM.hpp>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
GeometryRenderer* GeometryRenderer::New()
{
// Choose the best implementation according to the graphics card's capabilities
if (priv::GeometryRendererVBO::IsSupported())
{
// Use Vertex Buffer Objects
return new priv::GeometryRendererVBO;
}
else if (priv::GeometryRendererVA::IsSupported())
{
// Use Vertex Arrays
return new priv::GeometryRendererVA;
}
else
{
// Use Immediate Mode
return new priv::GeometryRendererIM;
}
}
////////////////////////////////////////////////////////////
GeometryRenderer::~GeometryRenderer()
{
// Nothing to do
}
} // namespace priv
} // namespace sf

View file

@ -0,0 +1,106 @@
////////////////////////////////////////////////////////////
//
// 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_GEOMETRYRENDERER_HPP
#define SFML_GEOMETRYRENDERER_HPP
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/System/NonCopyable.hpp>
#include <cstdlib>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
/// \brief Abstract base class for optimized geometry renderers
///
////////////////////////////////////////////////////////////
class GeometryRenderer : NonCopyable
{
public :
////////////////////////////////////////////////////////////
/// \brief Construct a new GeometryRenderer
///
/// This function selects the best specialization available,
/// according to the capabilities of the system.
///
/// \return New instance of GeometryRenderer; cannot be NULL
///
////////////////////////////////////////////////////////////
static GeometryRenderer* New();
public :
////////////////////////////////////////////////////////////
/// \brief Virtual destructor
///
////////////////////////////////////////////////////////////
virtual ~GeometryRenderer();
////////////////////////////////////////////////////////////
/// \brief Prepare the geometry for rendering
///
/// This function is called once before all the triangles
/// are rendered.
///
/// \param vertices Pointer to the vertex array
/// \param verticesCount Number of vertices to render
/// \param indices Pointer to the index array
/// \param indicesCount Number of indices to render
///
////////////////////////////////////////////////////////////
virtual void Begin(const float* vertices, std::size_t verticesCount, const unsigned int* indices, std::size_t indicesCount) = 0;
////////////////////////////////////////////////////////////
/// \brief Stop rendering geometry
///
/// This function is called once after all the triangles
/// have been rendered.
///
////////////////////////////////////////////////////////////
virtual void End() = 0;
////////////////////////////////////////////////////////////
/// \brief Render a chunk of triangles
///
/// The primitives are rendered as a list of triangles (no strip or fan).
///
/// \param start Index in the indices array of the first index to be rendered
/// \param count Number of indices to be rendered
///
////////////////////////////////////////////////////////////
virtual void RenderTriangles(std::size_t start, std::size_t count) = 0;
};
} // namespace priv
} // namespace sf
#endif // SFML_GEOMETRYRENDERER_HPP

View file

@ -0,0 +1,95 @@
////////////////////////////////////////////////////////////
//
// 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/GeometryRendererIM.hpp>
#include <SFML/Graphics/GLCheck.hpp>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
bool GeometryRendererIM::IsSupported()
{
// Immediate mode is always supported
return true;
}
////////////////////////////////////////////////////////////
GeometryRendererIM::GeometryRendererIM() :
myVertices(NULL),
myIndices (NULL)
{
}
////////////////////////////////////////////////////////////
void GeometryRendererIM::Begin(const float* vertices, std::size_t, const unsigned int* indices, std::size_t)
{
// Store the geometry informations for later rendering
myVertices = vertices;
myIndices = indices;
}
////////////////////////////////////////////////////////////
void GeometryRendererIM::End()
{
// Nothing to do
}
////////////////////////////////////////////////////////////
void GeometryRendererIM::RenderTriangles(std::size_t start, std::size_t count)
{
// Caculate the bounds of the geometry range to render
const unsigned int* begin = myIndices + start;
const unsigned int* end = begin + count;
// Begin rendering
glBegin(GL_TRIANGLES);
// Send the vertices one by one
for (const unsigned int* index = begin; index != end; index++)
{
const float* vertex = myVertices + *index * 8;
glColor4f(vertex[2], vertex[3], vertex[4], vertex[5]);
glTexCoord2f(vertex[6], vertex[7]);
glVertex2f(vertex[0], vertex[1]);
}
// End rendering
glEnd();
}
} // namespace priv
} // namespace sf

View file

@ -0,0 +1,108 @@
////////////////////////////////////////////////////////////
//
// 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_GEOMETRYRENDERERIM_HPP
#define SFML_GEOMETRYRENDERERIM_HPP
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Graphics/GeometryRenderer.hpp>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
/// \brief Geometry renderer using immediate mode
///
////////////////////////////////////////////////////////////
class GeometryRendererIM : public GeometryRenderer
{
public :
////////////////////////////////////////////////////////////
/// \brief Check if this implementation is supported by the system
///
/// \return True if the immediate mode renderer is supported
///
////////////////////////////////////////////////////////////
static bool IsSupported();
public :
////////////////////////////////////////////////////////////
/// \brief Default constructor
///
////////////////////////////////////////////////////////////
GeometryRendererIM();
////////////////////////////////////////////////////////////
/// \brief Prepare the geometry for rendering
///
/// This function is called once before all the triangles
/// are rendered.
///
/// \param vertices Pointer to the vertex array
/// \param verticesCount Number of vertices to render
/// \param indices Pointer to the index array
/// \param indicesCount Number of indices to render
///
////////////////////////////////////////////////////////////
virtual void Begin(const float* vertices, std::size_t verticesCount, const unsigned int* indices, std::size_t indicesCount);
////////////////////////////////////////////////////////////
/// \brief Stop rendering geometry
///
/// This function is called once after all the triangles
/// have been rendered.
///
////////////////////////////////////////////////////////////
virtual void End();
////////////////////////////////////////////////////////////
/// \brief Render a chunk of triangles
///
/// The primitives are rendered as a list of triangles (no strip or fan).
///
/// \param start Index in the indices array of the first index to be rendered
/// \param count Number of indices to be rendered
///
////////////////////////////////////////////////////////////
virtual void RenderTriangles(std::size_t start, std::size_t count);
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
const float* myVertices; ///< Pointer to the vertices to render
const unsigned int* myIndices; ///< Pointer to the indices to render
};
} // namespace priv
} // namespace sf
#endif // SFML_GEOMETRYRENDERERIM_HPP

View file

@ -0,0 +1,99 @@
////////////////////////////////////////////////////////////
//
// 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/GeometryRendererVA.hpp>
#include <SFML/Graphics/GLCheck.hpp>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
bool GeometryRendererVA::IsSupported()
{
EnsureGlewInit();
return glewIsSupported("GL_EXT_vertex_array") != 0;
}
////////////////////////////////////////////////////////////
GeometryRendererVA::GeometryRendererVA() :
myIndices(NULL)
{
EnsureGlewInit();
myCanLock = glewIsSupported("GL_EXT_compiled_vertex_array") != 0;
}
////////////////////////////////////////////////////////////
void GeometryRendererVA::Begin(const float* vertices, std::size_t verticesCount, const unsigned int* indices, std::size_t)
{
static const GLsizei stride = 8 * sizeof(float);
// Setup positions
GLCheck(glEnableClientState(GL_VERTEX_ARRAY));
GLCheck(glVertexPointer(2, GL_FLOAT, stride, vertices));
// Setup colors
GLCheck(glEnableClientState(GL_COLOR_ARRAY));
GLCheck(glColorPointer(4, GL_FLOAT, stride, vertices + 2));
// Setup texture coordinates
GLCheck(glClientActiveTextureARB(GL_TEXTURE0_ARB));
GLCheck(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
GLCheck(glTexCoordPointer(2, GL_FLOAT, stride, vertices + 6));
// Lock (compile) the vertex array if supported
if (myCanLock)
GLCheck(glLockArraysEXT(0, verticesCount / 8));
// Store indices for later use
myIndices = indices;
}
////////////////////////////////////////////////////////////
void GeometryRendererVA::End()
{
// Unlock the vertex array if it was locked
if (myCanLock)
GLCheck(glUnlockArraysEXT());
}
////////////////////////////////////////////////////////////
void GeometryRendererVA::RenderTriangles(std::size_t start, std::size_t count)
{
GLCheck(glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, myIndices + start));
}
} // namespace priv
} // namespace sf

View file

@ -0,0 +1,108 @@
////////////////////////////////////////////////////////////
//
// 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_GEOMETRYRENDERERVA_HPP
#define SFML_GEOMETRYRENDERERVA_HPP
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Graphics/GeometryRenderer.hpp>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
/// \brief Geometry renderer using vertex arrays
///
////////////////////////////////////////////////////////////
class GeometryRendererVA : public GeometryRenderer
{
public :
////////////////////////////////////////////////////////////
/// \brief Check if this implementation is supported by the system
///
/// \return True if the vertex array renderer is supported
///
////////////////////////////////////////////////////////////
static bool IsSupported();
////////////////////////////////////////////////////////////
/// \brief Default constructor
///
////////////////////////////////////////////////////////////
GeometryRendererVA();
public :
////////////////////////////////////////////////////////////
/// \brief Prepare the geometry for rendering
///
/// This function is called once before all the triangles
/// are rendered.
///
/// \param vertices Pointer to the vertex array
/// \param verticesCount Number of vertices to render
/// \param indices Pointer to the index array
/// \param indicesCount Number of indices to render
///
////////////////////////////////////////////////////////////
virtual void Begin(const float* vertices, std::size_t verticesCount, const unsigned int* indices, std::size_t indicesCount);
////////////////////////////////////////////////////////////
/// \brief Stop rendering geometry
///
/// This function is called once after all the triangles
/// have been rendered.
///
////////////////////////////////////////////////////////////
virtual void End();
////////////////////////////////////////////////////////////
/// \brief Render a chunk of triangles
///
/// The primitives are rendered as a list of triangles (no strip or fan).
///
/// \param start Index in the indices array of the first index to be rendered
/// \param count Number of indices to be rendered
///
////////////////////////////////////////////////////////////
virtual void RenderTriangles(std::size_t start, std::size_t count);
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
bool myCanLock; ///< Is geometry locking supported?
const unsigned int* myIndices; ///< Pointer to the indices to render
};
} // namespace priv
} // namespace sf
#endif // SFML_GEOMETRYRENDERERVA_HPP

View file

@ -0,0 +1,127 @@
////////////////////////////////////////////////////////////
//
// 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/GeometryRendererVBO.hpp>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
bool GeometryRendererVBO::IsSupported()
{
EnsureGlewInit();
return glewIsSupported("GL_ARB_vertex_buffer_object") != 0;
}
////////////////////////////////////////////////////////////
GeometryRendererVBO::GeometryRendererVBO() :
myVertexBufferSize(0),
myIndexBufferSize (0)
{
EnsureGlewInit();
// Create the buffers
GLCheck(glGenBuffersARB(1, &myVertexBuffer));
GLCheck(glGenBuffersARB(1, &myIndexBuffer));
}
////////////////////////////////////////////////////////////
GeometryRendererVBO::~GeometryRendererVBO()
{
// Free the buffers
GLCheck(glDeleteBuffersARB(1, &myVertexBuffer));
GLCheck(glDeleteBuffersARB(1, &myIndexBuffer));
}
////////////////////////////////////////////////////////////
void GeometryRendererVBO::Begin(const float* vertices, std::size_t verticesCount, const unsigned int* indices, std::size_t indicesCount)
{
// Update the vertex buffer data (make it grow if it is not large enough)
GLCheck(glBindBufferARB(GL_ARRAY_BUFFER_ARB, myVertexBuffer));
if (verticesCount > myVertexBufferSize)
{
GLCheck(glBufferDataARB(GL_ARRAY_BUFFER_ARB, verticesCount * sizeof(float), vertices, GL_DYNAMIC_DRAW_ARB));
myVertexBufferSize = verticesCount;
}
else
{
GLCheck(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, verticesCount * sizeof(float), vertices));
}
// Update the index buffer data (make it grow if it is not large enough)
GLCheck(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, myIndexBuffer));
if (indicesCount > myIndexBufferSize)
{
GLCheck(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, indicesCount * sizeof(unsigned int), indices, GL_DYNAMIC_DRAW_ARB));
myIndexBufferSize = indicesCount;
}
else
{
GLCheck(glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, indicesCount * sizeof(unsigned int), indices));
}
static const GLsizei stride = 8 * sizeof(float);
static const float* pointer = NULL;
// Setup positions
GLCheck(glEnableClientState(GL_VERTEX_ARRAY));
GLCheck(glVertexPointer(2, GL_FLOAT, stride, pointer));
// Setup colors
GLCheck(glEnableClientState(GL_COLOR_ARRAY));
GLCheck(glColorPointer(4, GL_FLOAT, stride, pointer + 2));
// Setup texture coordinates
GLCheck(glClientActiveTextureARB(GL_TEXTURE0_ARB));
GLCheck(glEnableClientState(GL_TEXTURE_COORD_ARRAY));
GLCheck(glTexCoordPointer(2, GL_FLOAT, stride, pointer + 6));
}
////////////////////////////////////////////////////////////
void GeometryRendererVBO::End()
{
// Nothing to do
}
////////////////////////////////////////////////////////////
void GeometryRendererVBO::RenderTriangles(std::size_t start, std::size_t count)
{
static const unsigned int* pointer = NULL;
GLCheck(glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, pointer + start));
}
} // namespace priv
} // namespace sf

View file

@ -0,0 +1,117 @@
////////////////////////////////////////////////////////////
//
// 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_GEOMETRYRENDERERVBO_HPP
#define SFML_GEOMETRYRENDERERVBO_HPP
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Graphics/GeometryRenderer.hpp>
#include <SFML/Graphics/GLCheck.hpp>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
/// \brief Geometry renderer using vertex buffer objects
///
////////////////////////////////////////////////////////////
class GeometryRendererVBO : public GeometryRenderer
{
public :
////////////////////////////////////////////////////////////
/// \brief Check if this implementation is supported by the system
///
/// \return True if the vertex buffer objects renderer is supported
///
////////////////////////////////////////////////////////////
static bool IsSupported();
////////////////////////////////////////////////////////////
/// \brief Default constructor
///
////////////////////////////////////////////////////////////
GeometryRendererVBO();
////////////////////////////////////////////////////////////
/// \brief Destructor
///
////////////////////////////////////////////////////////////
~GeometryRendererVBO();
public :
////////////////////////////////////////////////////////////
/// \brief Prepare the geometry for rendering
///
/// This function is called once before all the triangles
/// are rendered.
///
/// \param vertices Pointer to the vertex array
/// \param verticesCount Number of vertices to render
/// \param indices Pointer to the index array
/// \param indicesCount Number of indices to render
///
////////////////////////////////////////////////////////////
virtual void Begin(const float* vertices, std::size_t verticesCount, const unsigned int* indices, std::size_t indicesCount);
////////////////////////////////////////////////////////////
/// \brief Stop rendering geometry
///
/// This function is called once after all the triangles
/// have been rendered.
///
////////////////////////////////////////////////////////////
virtual void End();
////////////////////////////////////////////////////////////
/// \brief Render a chunk of triangles
///
/// The primitives are rendered as a list of triangles (no strip or fan).
///
/// \param start Index in the indices array of the first index to be rendered
/// \param count Number of indices to be rendered
///
////////////////////////////////////////////////////////////
virtual void RenderTriangles(std::size_t start, std::size_t count);
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
GLuint myVertexBuffer;
GLuint myIndexBuffer;
std::size_t myVertexBufferSize;
std::size_t myIndexBufferSize;
};
} // namespace priv
} // namespace sf
#endif // SFML_GEOMETRYRENDERERVBO_HPP

View file

@ -50,7 +50,6 @@ myTexture (0),
myIsSmooth (true),
myNeedTextureUpdate(false),
myNeedArrayUpdate (false),
myUpdateSource (NULL),
myPixelsFlipped (false)
{
@ -71,7 +70,6 @@ myIsSmooth (copy.myIsSmooth),
myPixels (copy.myPixels),
myNeedTextureUpdate(false),
myNeedArrayUpdate (false),
myUpdateSource (copy.myUpdateSource),
myPixelsFlipped (copy.myPixelsFlipped)
{
CreateTexture();
@ -90,7 +88,6 @@ myTexture (0),
myIsSmooth (true),
myNeedTextureUpdate(false),
myNeedArrayUpdate (false),
myUpdateSource (NULL),
myPixelsFlipped (false)
{
Create(width, height, color);
@ -109,7 +106,6 @@ myTexture (0),
myIsSmooth (true),
myNeedTextureUpdate(false),
myNeedArrayUpdate (false),
myUpdateSource (NULL),
myPixelsFlipped (false)
{
LoadFromPixels(width, height, data);
@ -387,6 +383,9 @@ bool Image::CopyScreen(RenderWindow& window, const IntRect& sourceRect)
myWidth = srcRect.GetSize().x;
myHeight = srcRect.GetSize().y;
// Make sure that pending drawables are rendered on the target window
window.Flush();
// We can then create the texture
if (window.SetActive() && CreateTexture())
{
@ -402,6 +401,8 @@ bool Image::CopyScreen(RenderWindow& window, const IntRect& sourceRect)
myNeedArrayUpdate = true;
myPixelsFlipped = true;
window.SetActive(false);
return true;
}
else
@ -553,12 +554,13 @@ FloatRect Image::GetTexCoords(const IntRect& rect) const
{
float width = static_cast<float>(myTextureWidth);
float height = static_cast<float>(myTextureHeight);
float offset = myIsSmooth ? 0.5f : 0.0f;
FloatRect coords;
coords.Left = rect.Left / width;
coords.Top = rect.Top / height;
coords.Right = rect.Right / width;
coords.Bottom = rect.Bottom / height;
coords.Left = (rect.Left + offset) / width;
coords.Top = (rect.Top + offset) / height;
coords.Right = (rect.Right - offset) / width;
coords.Bottom = (rect.Bottom - offset) / height;
if (myPixelsFlipped)
std::swap(coords.Top, coords.Bottom);
@ -607,7 +609,6 @@ Image& Image::operator =(const Image& other)
std::swap(myIsSmooth, temp.myIsSmooth);
std::swap(myNeedArrayUpdate, temp.myNeedArrayUpdate);
std::swap(myNeedTextureUpdate, temp.myNeedTextureUpdate);
std::swap(myUpdateSource, temp.myUpdateSource);
std::swap(myPixelsFlipped, temp.myPixelsFlipped);
myPixels.swap(temp.myPixels);
@ -678,24 +679,15 @@ void Image::EnsureTextureUpdate()
{
if (myNeedTextureUpdate)
{
if (myTexture)
if (myTexture && !myPixels.empty())
{
GLint previous;
GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous));
if (myUpdateSource)
{
// External update
myPixelsFlipped = myUpdateSource->UpdateImage(*this);
myUpdateSource = NULL;
}
else if (!myPixels.empty())
{
// Update the texture with the pixels array in RAM
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
GLCheck(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, myWidth, myHeight, GL_RGBA, GL_UNSIGNED_BYTE, &myPixels[0]));
myPixelsFlipped = false;
}
// Update the texture with the pixels array in RAM
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
GLCheck(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, myWidth, myHeight, GL_RGBA, GL_UNSIGNED_BYTE, &myPixels[0]));
myPixelsFlipped = false;
GLCheck(glBindTexture(GL_TEXTURE_2D, previous));
}
@ -769,19 +761,6 @@ void Image::EnsureArrayUpdate()
}
////////////////////////////////////////////////////////////
/// Notify the image that an external source has modified
/// its content.
/// For internal use only (see RenderImage class).
////////////////////////////////////////////////////////////
void Image::ExternalUpdate(RenderImage& source)
{
myNeedTextureUpdate = true;
myNeedArrayUpdate = true;
myUpdateSource = &source;
}
////////////////////////////////////////////////////////////
/// Reset the image attributes
////////////////////////////////////////////////////////////
@ -797,7 +776,6 @@ void Image::Reset()
myIsSmooth = true;
myNeedTextureUpdate = false;
myNeedArrayUpdate = false;
myUpdateSource = NULL;
myPixelsFlipped = false;
myPixels.clear();
}

View file

@ -275,7 +275,7 @@ bool PostFX::CanUsePostFX()
////////////////////////////////////////////////////////////
/// /see Drawable::Render
////////////////////////////////////////////////////////////
void PostFX::Render(RenderTarget& target) const
void PostFX::Render(RenderTarget& target, RenderQueue&) const
{
// Check that we have a valid program
if (!myShaderProgram)
@ -283,7 +283,9 @@ void PostFX::Render(RenderTarget& target) const
// Copy the current framebuffer pixels to our frame buffer texture
// The ugly cast is temporary until PostFx are rewritten :)
myFrameBuffer.CopyScreen((RenderWindow&)target);
RenderWindow& window = static_cast<RenderWindow&>(target);
myFrameBuffer.CopyScreen(window);
window.SetActive();
// Enable program
GLCheck(glUseProgramObjectARB(myShaderProgram));

View file

@ -105,18 +105,24 @@ bool RenderImage::Create(unsigned int width, unsigned int height, bool depthBuff
////////////////////////////////////////////////////////////
bool RenderImage::SetActive(bool active)
{
if (myRenderImage && myRenderImage->Activate(active))
{
// After the RenderImage has been modified, we have to notify
// the underlying image that its pixels have changed
if (!active)
myImage.ExternalUpdate(*this);
return myRenderImage && myRenderImage->Activate(active);
}
return true;
}
else
////////////////////////////////////////////////////////////
/// Update the contents of the target
////////////////////////////////////////////////////////////
void RenderImage::Display()
{
// Render everything that has been drawn so far
Flush();
// Update the target image
if (myRenderImage)
{
return false;
bool pixelsFlipped = myRenderImage->UpdateTexture(myImage.myTexture);
myImage.myPixelsFlipped = pixelsFlipped;
myImage.myNeedArrayUpdate = true;
}
}
@ -158,17 +164,6 @@ bool RenderImage::CanUseRenderImage()
}
////////////////////////////////////////////////////////////
/// Update the pixels of the target image.
/// This function is called automatically by the image when it
/// needs to update its pixels, and is only meant for internal use.
////////////////////////////////////////////////////////////
bool RenderImage::UpdateImage(Image& target)
{
return myRenderImage && myRenderImage->UpdateTexture(target.myTexture);
}
////////////////////////////////////////////////////////////
/// Activate / deactivate the render image for rendering
////////////////////////////////////////////////////////////

View file

@ -0,0 +1,328 @@
////////////////////////////////////////////////////////////
//
// 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/RenderQueue.hpp>
#include <SFML/Graphics/Batch.hpp>
#include <SFML/Graphics/GeometryRenderer.hpp>
#include <SFML/Graphics/GLCheck.hpp>
////////////////////////////////////////////////////////////
// Private data
////////////////////////////////////////////////////////////
namespace
{
// Fast float to int conversion
inline sf::Int32 Round(double value)
{
value += 6755399441055744.0;
#if defined(SFML_ENDIAN_LITTLE)
return (reinterpret_cast<sf::Int32*>(&value))[0];
#else
return (reinterpret_cast<sf::Int32*>(&value))[1];
#endif
}
}
namespace sf
{
////////////////////////////////////////////////////////////
RenderQueue::RenderQueue() :
myCurrentTexture (NULL),
myCurrentBlendMode (Blend::Alpha),
myBaseIndex (0),
myRenderer (priv::GeometryRenderer::New()),
myCurrentBatch (NULL),
myVertices (512),
myIndices (512),
myCurrentVertexCount(0),
myCurrentIndexCount (0)
{
myCurrentStates = &myStatesStack[0];
}
////////////////////////////////////////////////////////////
RenderQueue::~RenderQueue()
{
// Destroy the geometry renderer
delete myRenderer;
}
////////////////////////////////////////////////////////////
void RenderQueue::PushStates()
{
myCurrentStates++;
*myCurrentStates = *(myCurrentStates - 1);
}
////////////////////////////////////////////////////////////
void RenderQueue::PopStates()
{
myCurrentStates--;
}
////////////////////////////////////////////////////////////
void RenderQueue::SetModelView(const Matrix3& matrix)
{
myCurrentStates->modelView = matrix;
}
////////////////////////////////////////////////////////////
void RenderQueue::ApplyModelView(const Matrix3& matrix)
{
myCurrentStates->modelView *= matrix;
}
////////////////////////////////////////////////////////////
void RenderQueue::SetProjection(const Matrix3& matrix)
{
myCurrentStates->projection = matrix;
}
////////////////////////////////////////////////////////////
void RenderQueue::ApplyProjection(const Matrix3& matrix)
{
myCurrentStates->projection *= matrix;
}
////////////////////////////////////////////////////////////
void RenderQueue::SetColor(const Color& color)
{
myCurrentStates->color = color;
}
////////////////////////////////////////////////////////////
void RenderQueue::ApplyColor(const Color& color)
{
myCurrentStates->color *= color;
}
////////////////////////////////////////////////////////////
void RenderQueue::SetViewport(const IntRect& viewport)
{
myCurrentViewport = viewport;
myCurrentViewportSize.x = viewport.GetSize().x / 2.f;
myCurrentViewportSize.y = viewport.GetSize().y / 2.f;
}
////////////////////////////////////////////////////////////
void RenderQueue::SetBlendMode(Blend::Mode mode)
{
myCurrentBlendMode = mode;
}
////////////////////////////////////////////////////////////
void RenderQueue::SetTexture(const Image* texture)
{
myCurrentTexture = texture;
}
////////////////////////////////////////////////////////////
void RenderQueue::BeginBatch()
{
// Check if the current batch differs from the new render states
if (!myCurrentBatch || !myCurrentBatch->Matches(myCurrentTexture, myCurrentBlendMode, myCurrentViewport))
{
// Close the current batch
if (myCurrentBatch)
myCurrentBatch->End(myCurrentIndexCount);
// Create a new one
priv::Batch batch(myCurrentTexture, myCurrentBlendMode, myCurrentViewport);
myBatches.push_back(batch);
myCurrentBatch = &myBatches.back();
myCurrentBatch->Begin(myCurrentIndexCount);
}
// Update the combined transform matrix
myCurrentTransform = myCurrentStates->projection * myCurrentStates->modelView;
// Update the current base index
myBaseIndex = myCurrentVertexCount / 8;
}
////////////////////////////////////////////////////////////
void RenderQueue::AddVertex(float x, float y)
{
AddVertex(x, y, 0.f, 0.f, Color::White);
}
////////////////////////////////////////////////////////////
void RenderQueue::AddVertex(float x, float y, float u, float v)
{
AddVertex(x, y, u, v, Color::White);
}
////////////////////////////////////////////////////////////
void RenderQueue::AddVertex(float x, float y, const Color& color)
{
AddVertex(x, y, 0.f, 0.f, color);
}
////////////////////////////////////////////////////////////
void RenderQueue::AddVertex(float x, float y, float u, float v, const Color& color)
{
// Apply the current transform matrix to the vertex position
sf::Vector2f transformedPoint = myCurrentTransform.Transform(sf::Vector2f(x, y));
// Apply the current global color
sf::Color combinedColor = myCurrentStates->color * color;
// Round the vertex position so that it matches the
// viewport's pixels, and thus avoid rendering artifacts
int i1 = Round((transformedPoint.x + 1.f) * myCurrentViewportSize.x);
int i2 = Round((transformedPoint.y + 1.f) * myCurrentViewportSize.y);
transformedPoint.x = i1 / myCurrentViewportSize.x - 1.f;
transformedPoint.y = i2 / myCurrentViewportSize.y - 1.f;
// Here we choose not to rely on vector::clear and vector::push_back,
// and to handle resizing and appending manually, for performances reasons
// Resize the vertex buffer if it is too small
std::size_t size = myVertices.size();
if (myCurrentVertexCount + 8 > size)
myVertices.resize(size + size / 2);
// Copy the vertex data
float* ptr = &myVertices[myCurrentVertexCount];
*ptr++ = transformedPoint.x;
*ptr++ = transformedPoint.y;
*ptr++ = combinedColor.r / 255.f;
*ptr++ = combinedColor.g / 255.f;
*ptr++ = combinedColor.b / 255.f;
*ptr++ = combinedColor.a / 255.f;
*ptr++ = u;
*ptr++ = v;
// Increase the vertex count
myCurrentVertexCount += 8;
}
////////////////////////////////////////////////////////////
void RenderQueue::AddTriangle(unsigned int index0, unsigned int index1, unsigned int index2)
{
// Here we choose not to rely on vector::clear and vector::push_back,
// and to handle resizing and appending manually, for performances reasons
// Resize the index buffer if it is too small
std::size_t size = myIndices.size();
if (myCurrentIndexCount + 3 > size)
myIndices.resize(size + size / 2);
// Copy the index data
myIndices[myCurrentIndexCount + 0] = index0 + myBaseIndex;
myIndices[myCurrentIndexCount + 1] = index1 + myBaseIndex;
myIndices[myCurrentIndexCount + 2] = index2 + myBaseIndex;
// Increase the index count
myCurrentIndexCount += 3;
}
////////////////////////////////////////////////////////////
void RenderQueue::Render()
{
if (myCurrentVertexCount && myCurrentIndexCount)
{
// Save the current OpenGL states
GLCheck(glPushAttrib(GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_VIEWPORT_BIT));
GLCheck(glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT));
GLCheck(glDisable(GL_LIGHTING));
GLCheck(glDisable(GL_DEPTH_TEST));
GLCheck(glEnable(GL_ALPHA_TEST));
GLCheck(glAlphaFunc(GL_GREATER, 0));
GLCheck(glMatrixMode(GL_MODELVIEW));
GLCheck(glPushMatrix());
GLCheck(glLoadIdentity());
GLCheck(glMatrixMode(GL_PROJECTION));
GLCheck(glPushMatrix());
GLCheck(glLoadIdentity());
// Close the last batch
if (myCurrentBatch)
myCurrentBatch->End(myCurrentIndexCount);
// Prepare the geometry renderer
myRenderer->Begin(&myVertices[0], myCurrentVertexCount, &myIndices[0], myCurrentIndexCount);
// Render the batches in order
for (BatchArray::const_iterator it = myBatches.begin(); it != myBatches.end(); ++it)
{
it->ApplyStates();
myRenderer->RenderTriangles(it->GetStartIndex(), it->GetIndexCount());
}
// Stop rendering
myRenderer->End();
// Restore the previous OpenGL states
GLCheck(glMatrixMode(GL_PROJECTION));
GLCheck(glPopMatrix());
GLCheck(glMatrixMode(GL_MODELVIEW));
GLCheck(glPopMatrix());
GLCheck(glPopAttrib());
GLCheck(glPopClientAttrib());
}
// Clear everything
Clear();
}
////////////////////////////////////////////////////////////
void RenderQueue::Clear()
{
// Reset the vertex and index counts
myCurrentVertexCount = 0;
myCurrentIndexCount = 0;
// Clear the batches
myBatches.clear();
myCurrentBatch = NULL;
}
} // namespace sf

View file

@ -37,9 +37,7 @@ namespace sf
/// Default constructor
////////////////////////////////////////////////////////////
RenderTarget::RenderTarget() :
myCurrentView (&myDefaultView),
myPreserveStates(false),
myIsDrawing (false)
myCurrentView(&myDefaultView)
{
}
@ -61,10 +59,13 @@ void RenderTarget::Clear(const Color& color)
{
if (Activate(true))
{
// Clear the frame buffer
// Clear the color buffer
GLCheck(glClearColor(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f));
GLCheck(glClear(GL_COLOR_BUFFER_BIT));
// Clear the render queue
myRenderQueue.Clear();
Activate(false);
}
}
@ -75,59 +76,34 @@ void RenderTarget::Clear(const Color& color)
////////////////////////////////////////////////////////////
void RenderTarget::Draw(const Drawable& object)
{
// Check whether we are called from the outside or from a previous call to Draw
if (!myIsDrawing)
// Save the current render states
myRenderQueue.PushStates();
// Setup the viewport
myRenderQueue.SetViewport(GetViewport(*myCurrentView));
// Setup the projection matrix
myRenderQueue.SetProjection(myCurrentView->GetMatrix());
// Let the object draw itself
object.Draw(*this, myRenderQueue);
// Restore the previous render states
myRenderQueue.PopStates();
}
////////////////////////////////////////////////////////////
/// Make sure that what has been drawn so far is rendered
////////////////////////////////////////////////////////////
void RenderTarget::Flush()
{
if (Activate(true))
{
myIsDrawing = true;
// Draw the whole render queue
myRenderQueue.Render();
// Set our target as the current target for rendering
if (Activate(true))
{
// Save the current render states and set the SFML ones
if (myPreserveStates)
{
GLCheck(glMatrixMode(GL_MODELVIEW)); GLCheck(glPushMatrix());
GLCheck(glMatrixMode(GL_PROJECTION)); GLCheck(glPushMatrix());
GLCheck(glPushAttrib(GL_COLOR_BUFFER_BIT | GL_CURRENT_BIT | GL_ENABLE_BIT |
GL_TEXTURE_BIT | GL_TRANSFORM_BIT | GL_VIEWPORT_BIT));
SetRenderStates();
}
// Setup the viewport
const FloatRect& viewport = myCurrentView->GetViewport();
int left = static_cast<int>(0.5f + GetWidth() * viewport.Left);
int top = static_cast<int>(0.5f + GetHeight() * (1.f - viewport.Bottom));
int width = static_cast<int>(0.5f + GetWidth() * viewport.GetSize().x);
int height = static_cast<int>(0.5f + GetHeight() * viewport.GetSize().y);
GLCheck(glViewport(left, top, width, height));
// Setup the transform matrices
GLCheck(glMatrixMode(GL_PROJECTION));
GLCheck(glLoadMatrixf(myCurrentView->GetMatrix().Get4x4Elements()));
GLCheck(glMatrixMode(GL_MODELVIEW));
GLCheck(glLoadIdentity());
// Let the object draw itself
object.Draw(*this);
// Restore render states
if (myPreserveStates)
{
GLCheck(glMatrixMode(GL_PROJECTION)); GLCheck(glPopMatrix());
GLCheck(glMatrixMode(GL_MODELVIEW)); GLCheck(glPopMatrix());
GLCheck(glPopAttrib());
}
// Deactivate rendering on this target
Activate(false);
}
myIsDrawing = false;
}
else
{
// We are already called from a previous Draw : we don't need to set the states again, just draw the object
object.Draw(*this);
Activate(false);
}
}
@ -160,16 +136,48 @@ View& RenderTarget::GetDefaultView()
////////////////////////////////////////////////////////////
/// Tell SFML to preserve external OpenGL states, at the expense of
/// more CPU charge. Use this function if you don't want SFML
/// to mess up your own OpenGL states (if any).
/// Don't enable state preservation if not needed, as it will allow
/// SFML to do internal optimizations and improve performances.
/// This parameter is false by default
/// Get the viewport of a view applied to this target
////////////////////////////////////////////////////////////
void RenderTarget::PreserveOpenGLStates(bool preserve)
IntRect RenderTarget::GetViewport(const View& view) const
{
myPreserveStates = preserve;
float width = static_cast<float>(GetWidth());
float height = static_cast<float>(GetHeight());
const FloatRect& viewport = view.GetViewport();
IntRect rect;
rect.Left = static_cast<int>(0.5f + width * viewport.Left);
rect.Top = static_cast<int>(0.5f + height * (1.f - viewport.Bottom));
rect.Right = static_cast<int>(0.5f + width * viewport.Right);
rect.Bottom = static_cast<int>(0.5f + height * (1.f - viewport.Top));
return rect;
}
////////////////////////////////////////////////////////////
/// Convert a point in window coordinates into view coordinates
/// This version uses the current view of the window
////////////////////////////////////////////////////////////
sf::Vector2f RenderTarget::ConvertCoords(unsigned int x, unsigned int y) const
{
return ConvertCoords(x, y, GetView());
}
////////////////////////////////////////////////////////////
/// Convert a point in window coordinates into view coordinates
/// This version uses the given view
////////////////////////////////////////////////////////////
sf::Vector2f RenderTarget::ConvertCoords(unsigned int x, unsigned int y, const View& view) const
{
// First, convert from viewport coordinates to homogeneous coordinates
Vector2f coords;
IntRect viewport = GetViewport(view);
coords.x = -1.f + 2.f * (static_cast<int>(x) - viewport.Left) / viewport.GetSize().x;
coords.y = 1.f - 2.f * (static_cast<int>(y) - viewport.Top) / viewport.GetSize().y;
// Then transform by the inverse of the view matrix
return view.GetInverseMatrix().Transform(coords);
}
@ -178,28 +186,12 @@ void RenderTarget::PreserveOpenGLStates(bool preserve)
////////////////////////////////////////////////////////////
void RenderTarget::Initialize()
{
if (Activate(true))
{
// Set the default rendering states
SetRenderStates();
// Setup the default view
myDefaultView.Reset(FloatRect(0, 0, static_cast<float>(GetWidth()), static_cast<float>(GetHeight())));
SetView(myDefaultView);
// Setup the default view
myDefaultView.Reset(FloatRect(0, 0, static_cast<float>(GetWidth()), static_cast<float>(GetHeight())));
SetView(myDefaultView);
Activate(false);
}
}
////////////////////////////////////////////////////////////
/// Set the OpenGL render states needed for the SFML rendering
////////////////////////////////////////////////////////////
void RenderTarget::SetRenderStates()
{
GLCheck(glDisable(GL_ALPHA_TEST));
GLCheck(glDisable(GL_DEPTH_TEST));
GLCheck(glDisable(GL_LIGHTING));
// Clear the render queue
myRenderQueue.Clear();
}
} // namespace sf

View file

@ -75,11 +75,7 @@ RenderWindow::~RenderWindow()
////////////////////////////////////////////////////////////
bool RenderWindow::Activate(bool active)
{
// For performances and consistency reasons, we only handle activation
if (active)
return SetActive();
else
return true;
return SetActive(active);
}
@ -101,70 +97,6 @@ unsigned int RenderWindow::GetHeight() const
}
////////////////////////////////////////////////////////////
/// Save the content of the window to an image
////////////////////////////////////////////////////////////
Image RenderWindow::Capture() const
{
// Get the window dimensions
const unsigned int width = GetWidth();
const unsigned int height = GetHeight();
// Set our window as the current target for rendering
if (SetActive())
{
// Get pixels from the backbuffer
std::vector<Uint8> pixels(width * height * 4);
Uint8* ptr = &pixels[0];
GLCheck(glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, ptr));
// Flip the pixels
unsigned int pitch = width * 4;
for (unsigned int y = 0; y < height / 2; ++y)
std::swap_ranges(ptr + y * pitch, ptr + (y + 1) * pitch, ptr + (height - y - 1) * pitch);
// Create an image from the pixel buffer and return it
return Image(width, height, ptr);
}
else
{
return Image(width, height, Color::White);
}
}
////////////////////////////////////////////////////////////
/// Convert a point in window coordinates into view coordinates
/// This version uses the current view of the window
////////////////////////////////////////////////////////////
sf::Vector2f RenderWindow::ConvertCoords(unsigned int x, unsigned int y) const
{
return ConvertCoords(x, y, GetView());
}
////////////////////////////////////////////////////////////
/// Convert a point in window coordinates into view coordinates
/// This version uses the given view
////////////////////////////////////////////////////////////
sf::Vector2f RenderWindow::ConvertCoords(unsigned int x, unsigned int y, const View& view) const
{
// First, convert from viewport coordinates to homogeneous coordinates
const FloatRect& viewport = view.GetViewport();
int left = static_cast<int>(0.5f + GetWidth() * viewport.Left);
int top = static_cast<int>(0.5f + GetHeight() * viewport.Top);
int width = static_cast<int>(0.5f + GetWidth() * viewport.GetSize().x);
int height = static_cast<int>(0.5f + GetHeight() * viewport.GetSize().y);
Vector2f coords;
coords.x = -1.f + 2.f * (static_cast<int>(x) - left) / width;
coords.y = 1.f - 2.f * (static_cast<int>(y) - top) / height;
// Then transform by the inverse of the view matrix
return view.GetInverseMatrix().Transform(coords);
}
////////////////////////////////////////////////////////////
/// Called after the window has been created
////////////////////////////////////////////////////////////
@ -174,4 +106,14 @@ void RenderWindow::OnCreate()
RenderTarget::Initialize();
}
////////////////////////////////////////////////////////////
/// Called before the window has been displayed
////////////////////////////////////////////////////////////
void RenderWindow::OnDisplay()
{
// Render the drawables drawn so far
Flush();
}
} // namespace sf

View file

@ -26,7 +26,7 @@
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Graphics/Shape.hpp>
#include <SFML/Graphics/GLCheck.hpp>
#include <SFML/Graphics/RenderQueue.hpp>
#include <math.h>
@ -281,7 +281,7 @@ Shape Shape::Circle(const Vector2f& center, float radius, const Color& color, fl
////////////////////////////////////////////////////////////
/// /see Drawable::Render
////////////////////////////////////////////////////////////
void Shape::Render(RenderTarget&) const
void Shape::Render(RenderTarget&, RenderQueue& queue) const
{
// Make sure the shape has at least 3 points (4 if we count the center)
if (myPoints.size() < 4)
@ -292,50 +292,69 @@ void Shape::Render(RenderTarget&) const
const_cast<Shape*>(this)->Compile();
// Shapes only use color, no texture
GLCheck(glDisable(GL_TEXTURE_2D));
queue.SetTexture(NULL);
// Draw the shape
if (myIsFillEnabled)
{
glBegin(GL_TRIANGLE_FAN);
if (myPoints.size() == 4)
{
// Special case of a triangle
queue.BeginBatch();
queue.AddVertex(myPoints[1].Position.x, myPoints[1].Position.y, myPoints[1].Col);
queue.AddVertex(myPoints[2].Position.x, myPoints[2].Position.y, myPoints[2].Col);
queue.AddVertex(myPoints[3].Position.x, myPoints[3].Position.y, myPoints[3].Col);
queue.AddTriangle(0, 1, 2);
}
else if (myPoints.size() == 5)
{
// Special case of a quad
queue.BeginBatch();
queue.AddVertex(myPoints[1].Position.x, myPoints[1].Position.y, myPoints[1].Col);
queue.AddVertex(myPoints[2].Position.x, myPoints[2].Position.y, myPoints[2].Col);
queue.AddVertex(myPoints[3].Position.x, myPoints[3].Position.y, myPoints[3].Col);
queue.AddVertex(myPoints[4].Position.x, myPoints[4].Position.y, myPoints[4].Col);
queue.AddTriangle(0, 1, 3);
queue.AddTriangle(3, 1, 2);
}
else
{
// General case of a convex polygon
queue.BeginBatch();
for (std::vector<Point>::const_iterator i = myPoints.begin(); i != myPoints.end(); ++i)
{
Color color = i->Col * GetColor();
glColor4ub(color.r, color.g, color.b, color.a);
glVertex2f(i->Position.x, i->Position.y);
}
queue.AddVertex(i->Position.x, i->Position.y, i->Col);
for (std::size_t i = 1; i < myPoints.size() - 1; ++i)
queue.AddTriangle(0, i, i + 1);
// Close the shape by duplicating the first point at the end
Color color = myPoints[1].Col * GetColor();
glColor4ub(color.r, color.g, color.b, color.a);
glVertex2f(myPoints[1].Position.x, myPoints[1].Position.y);
queue.AddTriangle(0, myPoints.size() - 1, 1);
}
glEnd();
}
// Draw the outline
if (myIsOutlineEnabled)
if (myIsOutlineEnabled && (myOutline != 0))
{
glBegin(GL_TRIANGLE_STRIP);
queue.BeginBatch();
for (std::vector<Point>::const_iterator i = myPoints.begin() + 1; i != myPoints.end(); ++i)
{
for (std::size_t i = 1; i < myPoints.size(); ++i)
{
Color color = myPoints[i].OutlineCol * GetColor();
glColor4ub(color.r, color.g, color.b, color.a);
glVertex2f(myPoints[i].Position.x, myPoints[i].Position.y);
glColor4ub(color.r, color.g, color.b, color.a);
glVertex2f(myPoints[i].Position.x + myPoints[i].Normal.x * myOutline, myPoints[i].Position.y + myPoints[i].Normal.y * myOutline);
}
// Close the shape by duplicating the first point at the end
Color color = myPoints[1].OutlineCol * GetColor();
glColor4ub(color.r, color.g, color.b, color.a);
glVertex2f(myPoints[1].Position.x, myPoints[1].Position.y);
glColor4ub(color.r, color.g, color.b, color.a);
glVertex2f(myPoints[1].Position.x + myPoints[1].Normal.x * myOutline, myPoints[1].Position.y + myPoints[1].Normal.y * myOutline);
Vector2f point1 = i->Position;
Vector2f point2 = i->Position + i->Normal * myOutline;
queue.AddVertex(point1.x, point1.y, i->OutlineCol);
queue.AddVertex(point2.x, point2.y, i->OutlineCol);
}
glEnd();
for (std::size_t i = 0; i < myPoints.size() - 2; ++i)
{
queue.AddTriangle(i * 2 + 0, i * 2 + 1, i * 2 + 2);
queue.AddTriangle(i * 2 + 2, i * 2 + 1, i * 2 + 3);
}
// Close the shape by duplicating the first point at the end
unsigned int begin = 0;
unsigned int last = (myPoints.size() - 2) * 2;
queue.AddTriangle(last, last + 1, begin);
queue.AddTriangle(begin, last + 1, begin + 1);
}
}
@ -351,16 +370,17 @@ void Shape::Compile()
Point center(Vector2f(0, 0), Color(0, 0, 0, 0));
for (std::size_t i = 1; i < myPoints.size(); ++i)
{
center.Position += myPoints[i].Position / nbPoints;
r += myPoints[i].Col.r / nbPoints;
g += myPoints[i].Col.g / nbPoints;
b += myPoints[i].Col.b / nbPoints;
a += myPoints[i].Col.a / nbPoints;
center.Position += myPoints[i].Position;
r += myPoints[i].Col.r;
g += myPoints[i].Col.g;
b += myPoints[i].Col.b;
a += myPoints[i].Col.a;
}
center.Col.r = static_cast<Uint8>(r);
center.Col.g = static_cast<Uint8>(g);
center.Col.b = static_cast<Uint8>(b);
center.Col.a = static_cast<Uint8>(a);
center.Position /= nbPoints;
center.Col.r = static_cast<Uint8>(r / nbPoints);
center.Col.g = static_cast<Uint8>(g / nbPoints);
center.Col.b = static_cast<Uint8>(b / nbPoints);
center.Col.a = static_cast<Uint8>(a / nbPoints);
myPoints[0] = center;
// Compute the outline

View file

@ -27,7 +27,8 @@
////////////////////////////////////////////////////////////
#include <SFML/Graphics/Sprite.hpp>
#include <SFML/Graphics/Image.hpp>
#include <SFML/Graphics/GLCheck.hpp>
#include <SFML/Graphics/RenderQueue.hpp>
#include <utility>
namespace sf
@ -181,50 +182,32 @@ Color Sprite::GetPixel(unsigned int x, unsigned int y) const
////////////////////////////////////////////////////////////
/// /see Drawable::Render
////////////////////////////////////////////////////////////
void Sprite::Render(RenderTarget&) const
void Sprite::Render(RenderTarget&, RenderQueue& queue) const
{
// Get the sprite size
float width = static_cast<float>(mySubRect.GetSize().x);
float height = static_cast<float>(mySubRect.GetSize().y);
// Check if the image is valid
// Check if the image is valid, and calculate the texture coordinates
FloatRect coords;
if (myImage && (myImage->GetWidth() > 0) && (myImage->GetHeight() > 0))
{
// Use the "offset trick" to get pixel-perfect rendering
// see http://www.opengl.org/resources/faq/technical/transformations.htm#tran0030
GLCheck(glTranslatef(0.375f, 0.375f, 0.f));
// Bind the texture
myImage->Bind();
// Calculate the texture coordinates
FloatRect texCoords = myImage->GetTexCoords(mySubRect);
FloatRect rect(myIsFlippedX ? texCoords.Right : texCoords.Left,
myIsFlippedY ? texCoords.Bottom : texCoords.Top,
myIsFlippedX ? texCoords.Left : texCoords.Right,
myIsFlippedY ? texCoords.Top : texCoords.Bottom);
// Draw the sprite's triangles
glBegin(GL_QUADS);
glTexCoord2f(rect.Left, rect.Top); glVertex2f(0, 0);
glTexCoord2f(rect.Left, rect.Bottom); glVertex2f(0, height);
glTexCoord2f(rect.Right, rect.Bottom); glVertex2f(width, height);
glTexCoord2f(rect.Right, rect.Top); glVertex2f(width, 0) ;
glEnd();
coords = myImage->GetTexCoords(mySubRect);
if (myIsFlippedX) std::swap(coords.Left, coords.Right);
if (myIsFlippedY) std::swap(coords.Top, coords.Bottom);
}
else
{
// Disable texturing
GLCheck(glDisable(GL_TEXTURE_2D));
// Draw the sprite's triangles
glBegin(GL_QUADS);
glVertex2f(0, 0);
glVertex2f(0, height);
glVertex2f(width, height);
glVertex2f(width, 0);
glEnd();
}
// Bind the texture
queue.SetTexture(myImage);
// Draw the sprite's geometry
queue.BeginBatch();
queue.AddVertex(0, 0, coords.Left, coords.Top);
queue.AddVertex(0, height, coords.Left, coords.Bottom);
queue.AddVertex(width, height, coords.Right, coords.Bottom);
queue.AddVertex(width, 0, coords.Right, coords.Top);
queue.AddTriangle(0, 1, 3);
queue.AddTriangle(3, 1, 2);
}
} // namespace sf

View file

@ -27,8 +27,7 @@
////////////////////////////////////////////////////////////
#include <SFML/Graphics/String.hpp>
#include <SFML/Graphics/Image.hpp>
#include <SFML/Graphics/GLCheck.hpp>
#include <locale>
#include <SFML/Graphics/RenderQueue.hpp>
namespace sf
@ -210,7 +209,7 @@ FloatRect String::GetRect() const
////////////////////////////////////////////////////////////
/// /see sfDrawable::Render
////////////////////////////////////////////////////////////
void String::Render(RenderTarget&) const
void String::Render(RenderTarget&, RenderQueue& queue) const
{
// First get the internal UTF-32 string of the text
const Unicode::UTF32String& text = myText;
@ -222,10 +221,9 @@ void String::Render(RenderTarget&) const
// Set the scaling factor to get the actual size
float charSize = static_cast<float>(myFont->GetCharacterSize());
float factor = mySize / charSize;
GLCheck(glScalef(factor, factor, 1.f));
// Bind the font texture
myFont->GetImage().Bind();
queue.SetTexture(&myFont->GetImage());
// Initialize the rendering coordinates
float x = 0.f;
@ -239,7 +237,8 @@ void String::Render(RenderTarget&) const
float italicCoeff = (myStyle & Italic) ? 0.208f : 0.f; // 12 degrees
// Draw one quad for each character
glBegin(GL_QUADS);
unsigned int index = 0;
queue.BeginBatch();
for (std::size_t i = 0; i < text.size(); ++i)
{
// Get the current character and its corresponding glyph
@ -267,31 +266,67 @@ void String::Render(RenderTarget&) const
}
// Draw a textured quad for the current character
glTexCoord2f(coord.Left, coord.Top); glVertex2f(x + rect.Left - italicCoeff * rect.Top, y + rect.Top);
glTexCoord2f(coord.Left, coord.Bottom); glVertex2f(x + rect.Left - italicCoeff * rect.Bottom, y + rect.Bottom);
glTexCoord2f(coord.Right, coord.Bottom); glVertex2f(x + rect.Right - italicCoeff * rect.Bottom, y + rect.Bottom);
glTexCoord2f(coord.Right, coord.Top); glVertex2f(x + rect.Right - italicCoeff * rect.Top, y + rect.Top);
queue.AddVertex(factor * (x + rect.Left - italicCoeff * rect.Top), factor * (y + rect.Top), coord.Left, coord.Top);
queue.AddVertex(factor * (x + rect.Left - italicCoeff * rect.Bottom), factor * (y + rect.Bottom), coord.Left, coord.Bottom);
queue.AddVertex(factor * (x + rect.Right - italicCoeff * rect.Bottom), factor * (y + rect.Bottom), coord.Right, coord.Bottom);
queue.AddVertex(factor * (x + rect.Right - italicCoeff * rect.Top), factor * (y + rect.Top), coord.Right, coord.Top);
// If we're using the bold style, we must render the character 4 more times,
// slightly offseted, to simulate a higher weight
if (myStyle & Bold)
{
static const float offsetsX[] = {-0.5f, 0.5f, 0.f, 0.f};
static const float offsetsY[] = {0.f, 0.f, -0.5f, 0.5f};
for (int j = 0; j < 4; ++j)
{
glTexCoord2f(coord.Left, coord.Top); glVertex2f(x + offsetsX[j] + rect.Left - italicCoeff * rect.Top, y + offsetsY[j] + rect.Top);
glTexCoord2f(coord.Left, coord.Bottom); glVertex2f(x + offsetsX[j] + rect.Left - italicCoeff * rect.Bottom, y + offsetsY[j] + rect.Bottom);
glTexCoord2f(coord.Right, coord.Bottom); glVertex2f(x + offsetsX[j] + rect.Right - italicCoeff * rect.Bottom, y + offsetsY[j] + rect.Bottom);
glTexCoord2f(coord.Right, coord.Top); glVertex2f(x + offsetsX[j] + rect.Right - italicCoeff * rect.Top, y + offsetsY[j] + rect.Top);
}
}
queue.AddTriangle(index + 0, index + 1, index + 3);
queue.AddTriangle(index + 3, index + 1, index + 2);
index += 4;
// Advance to the next character
x += advance;
}
glEnd();
// If we're using the bold style, we must render the string 4 more times,
// slightly offseted, to simulate a higher weight
if (myStyle & Bold)
{
float offset = mySize * 0.02f;
static const float offsetsX[] = {-offset, offset, 0.f, 0.f};
static const float offsetsY[] = {0.f, 0.f, -offset, offset};
for (int j = 0; j < 4; ++j)
{
index = 0;
x = 0.f;
y = charSize;
queue.BeginBatch();
for (std::size_t i = 0; i < text.size(); ++i)
{
// Get the current character and its corresponding glyph
Uint32 curChar = text[i];
const Glyph& curGlyph = myFont->GetGlyph(curChar);
int advance = curGlyph.Advance;
const IntRect& rect = curGlyph.Rectangle;
const FloatRect& coord = curGlyph.TexCoords;
// Handle special characters
switch (curChar)
{
case L' ' : x += advance; continue;
case L'\n' : y += charSize; x = 0; continue;
case L'\t' : x += advance * 4; continue;
case L'\v' : y += charSize * 4; continue;
}
// Draw a textured quad for the current character
queue.AddVertex(factor * (x + offsetsX[j] + rect.Left - italicCoeff * rect.Top), factor * (y + offsetsY[j] + rect.Top), coord.Left, coord.Top);
queue.AddVertex(factor * (x + offsetsX[j] + rect.Left - italicCoeff * rect.Bottom), factor * (y + offsetsY[j] + rect.Bottom), coord.Left, coord.Bottom);
queue.AddVertex(factor * (x + offsetsX[j] + rect.Right - italicCoeff * rect.Bottom), factor * (y + offsetsY[j] + rect.Bottom), coord.Right, coord.Bottom);
queue.AddVertex(factor * (x + offsetsX[j] + rect.Right - italicCoeff * rect.Top), factor * (y + offsetsY[j] + rect.Top), coord.Right, coord.Top);
queue.AddTriangle(index + 0, index + 1, index + 3);
queue.AddTriangle(index + 3, index + 1, index + 2);
index += 4;
// Advance to the next character
x += advance;
}
}
}
// Draw the underlines if needed
if (myStyle & Underlined)
@ -304,16 +339,20 @@ void String::Render(RenderTarget&) const
underlineCoords.push_back(y + 2);
// Draw the underlines as quads
GLCheck(glDisable(GL_TEXTURE_2D));
glBegin(GL_QUADS);
index = 0;
queue.SetTexture(NULL);
queue.BeginBatch();
for (std::size_t i = 0; i < underlineCoords.size(); i += 2)
{
glVertex2f(0, underlineCoords[i + 1]);
glVertex2f(0, underlineCoords[i + 1] + thickness);
glVertex2f(underlineCoords[i], underlineCoords[i + 1] + thickness);
glVertex2f(underlineCoords[i], underlineCoords[i + 1]);
queue.AddVertex(factor * (0), factor * (underlineCoords[i + 1]));
queue.AddVertex(factor * (0), factor * (underlineCoords[i + 1] + thickness));
queue.AddVertex(factor * (underlineCoords[i]), factor * (underlineCoords[i + 1] + thickness));
queue.AddVertex(factor * (underlineCoords[i]), factor * (underlineCoords[i + 1]));
queue.AddTriangle(index + 0, index + 1, index + 3);
queue.AddTriangle(index + 3, index + 1, index + 2);
index += 4;
}
glEnd();
}
}

View file

@ -179,7 +179,8 @@ bool RenderImageImplPBuffer::Activate(bool active)
}
else
{
// We don't actually unbind the P-Buffer, for performances reasons
// We don't actually unbind the P-Buffer,
// for performances and consistency reasons
}
return true;

View file

@ -140,21 +140,17 @@ void Window::Create(VideoMode mode, const std::string& title, unsigned long styl
delete myWindow;
myWindow = priv::WindowImpl::New(mode, title, style);
{
// Make sure another context is bound, so that:
// - the context creation can request OpenGL extensions if necessary
// - myContext can safely be destroyed (it's no longer bound)
Context context;
// Make sure another context is bound, so that:
// - the context creation can request OpenGL extensions if necessary
// - myContext can safely be destroyed (it's no longer bound)
Context context;
// Recreate the context
delete myContext;
myContext = priv::ContextGL::New(myWindow, mode.BitsPerPixel, settings);
// Recreate the context
delete myContext;
myContext = priv::ContextGL::New(myWindow, mode.BitsPerPixel, settings);
Initialize();
}
// Activate the window's context
SetActive();
// Perform common initializations
Initialize();
}
@ -167,21 +163,17 @@ void Window::Create(WindowHandle handle, const ContextSettings& settings)
Close();
myWindow = priv::WindowImpl::New(handle);
{
// Make sure another context is bound, so that:
// - the context creation can request OpenGL extensions if necessary
// - myContext can safely be destroyed (it's no longer bound)
Context context;
// Make sure another context is bound, so that:
// - the context creation can request OpenGL extensions if necessary
// - myContext can safely be destroyed (it's no longer bound)
Context context;
// Recreate the context
delete myContext;
myContext = priv::ContextGL::New(myWindow, VideoMode::GetDesktopMode().BitsPerPixel, settings);
// Recreate the context
delete myContext;
myContext = priv::ContextGL::New(myWindow, VideoMode::GetDesktopMode().BitsPerPixel, settings);
Initialize();
}
// Activate the window's context
SetActive();
// Perform common initializations
Initialize();
}
@ -391,6 +383,9 @@ bool Window::SetActive(bool active) const
////////////////////////////////////////////////////////////
void Window::Display()
{
// Notify the derived class
OnDisplay();
// Limit the framerate if needed
if (myFramerateLimit > 0)
{
@ -404,8 +399,11 @@ void Window::Display()
myClock.Reset();
// Display the backbuffer on screen
if (SetActive())
if (SetActive(true))
{
myContext->Display();
SetActive(false);
}
}
@ -456,6 +454,15 @@ void Window::OnCreate()
}
////////////////////////////////////////////////////////////
/// Called before the window has been displayed
////////////////////////////////////////////////////////////
void Window::OnDisplay()
{
// Nothing by default
}
////////////////////////////////////////////////////////////
/// Receive an event from window
////////////////////////////////////////////////////////////