Merge branch 'drawables'
This commit is contained in:
commit
f55da8d8bc
81 changed files with 5671 additions and 3805 deletions
|
@ -5,9 +5,9 @@ set(SRCROOT ${PROJECT_SOURCE_DIR}/src/SFML/Graphics)
|
|||
# all source files
|
||||
set(SRC
|
||||
${SRCROOT}/Arial.hpp
|
||||
${INCROOT}/BlendMode.hpp
|
||||
${SRCROOT}/Color.cpp
|
||||
${INCROOT}/Color.hpp
|
||||
${SRCROOT}/Drawable.cpp
|
||||
${INCROOT}/Drawable.hpp
|
||||
${SRCROOT}/Font.cpp
|
||||
${INCROOT}/Font.hpp
|
||||
|
@ -18,13 +18,11 @@ set(SRC
|
|||
${INCROOT}/Image.hpp
|
||||
${SRCROOT}/ImageLoader.cpp
|
||||
${SRCROOT}/ImageLoader.hpp
|
||||
${SRCROOT}/Matrix3.cpp
|
||||
${INCROOT}/Matrix3.hpp
|
||||
${INCROOT}/Matrix3.inl
|
||||
${INCROOT}/PrimitiveType.hpp
|
||||
${INCROOT}/Rect.hpp
|
||||
${INCROOT}/Rect.inl
|
||||
${SRCROOT}/Renderer.cpp
|
||||
${INCROOT}/Renderer.hpp
|
||||
${SRCROOT}/RenderStates.cpp
|
||||
${INCROOT}/RenderStates.hpp
|
||||
${SRCROOT}/RenderTexture.cpp
|
||||
${INCROOT}/RenderTexture.hpp
|
||||
${SRCROOT}/RenderTextureImpl.cpp
|
||||
|
@ -41,14 +39,30 @@ set(SRC
|
|||
${INCROOT}/Shader.hpp
|
||||
${SRCROOT}/Shape.cpp
|
||||
${INCROOT}/Shape.hpp
|
||||
${SRCROOT}/CircleShape.cpp
|
||||
${INCROOT}/CircleShape.hpp
|
||||
${SRCROOT}/RectangleShape.cpp
|
||||
${INCROOT}/RectangleShape.hpp
|
||||
${SRCROOT}/ConvexShape.cpp
|
||||
${INCROOT}/ConvexShape.hpp
|
||||
${SRCROOT}/Sprite.cpp
|
||||
${INCROOT}/Sprite.hpp
|
||||
${SRCROOT}/Text.cpp
|
||||
${INCROOT}/Text.hpp
|
||||
${SRCROOT}/Texture.cpp
|
||||
${INCROOT}/Texture.hpp
|
||||
${SRCROOT}/TextureSaver.cpp
|
||||
${SRCROOT}/TextureSaver.hpp
|
||||
${SRCROOT}/Transform.cpp
|
||||
${INCROOT}/Transform.hpp
|
||||
${SRCROOT}/Transformable.cpp
|
||||
${INCROOT}/Transformable.hpp
|
||||
${SRCROOT}/View.cpp
|
||||
${INCROOT}/View.hpp
|
||||
${SRCROOT}/Vertex.cpp
|
||||
${INCROOT}/Vertex.hpp
|
||||
${SRCROOT}/VertexArray.cpp
|
||||
${INCROOT}/VertexArray.hpp
|
||||
${SRCROOT}/stb_image/stb_image.h
|
||||
${SRCROOT}/stb_image/stb_image_write.h
|
||||
)
|
||||
|
|
84
src/SFML/Graphics/CircleShape.cpp
Normal file
84
src/SFML/Graphics/CircleShape.cpp
Normal file
|
@ -0,0 +1,84 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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/CircleShape.hpp>
|
||||
#include <cmath>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
CircleShape::CircleShape(float radius, unsigned int pointsCount) :
|
||||
myRadius (radius),
|
||||
myPointsCount(pointsCount)
|
||||
{
|
||||
Update();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void CircleShape::SetRadius(float radius)
|
||||
{
|
||||
myRadius = radius;
|
||||
Update();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
float CircleShape::GetRadius() const
|
||||
{
|
||||
return myRadius;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void CircleShape::SetPointsCount(unsigned int count)
|
||||
{
|
||||
myPointsCount = count;
|
||||
Update();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int CircleShape::GetPointsCount() const
|
||||
{
|
||||
return myPointsCount;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2f CircleShape::GetPoint(unsigned int index) const
|
||||
{
|
||||
static const float pi = 3.141592654f;
|
||||
|
||||
float angle = index * 2 * pi / myPointsCount - pi / 2;
|
||||
float x = std::cos(angle) * myRadius;
|
||||
float y = std::sin(angle) * myRadius;
|
||||
|
||||
return Vector2f(myRadius + x, myRadius + y);
|
||||
}
|
||||
|
||||
} // namespace sf
|
|
@ -42,6 +42,7 @@ const Color Color::Blue(0, 0, 255);
|
|||
const Color Color::Yellow(255, 255, 0);
|
||||
const Color Color::Magenta(255, 0, 255);
|
||||
const Color Color::Cyan(0, 255, 255);
|
||||
const Color Color::Transparent(0, 0, 0, 0);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
|
69
src/SFML/Graphics/ConvexShape.cpp
Normal file
69
src/SFML/Graphics/ConvexShape.cpp
Normal file
|
@ -0,0 +1,69 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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/ConvexShape.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
ConvexShape::ConvexShape(unsigned int pointsCount)
|
||||
{
|
||||
SetPointsCount(pointsCount);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ConvexShape::SetPointsCount(unsigned int count)
|
||||
{
|
||||
myPoints.resize(count);
|
||||
Update();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int ConvexShape::GetPointsCount() const
|
||||
{
|
||||
return myPoints.size();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void ConvexShape::SetPoint(unsigned int index, const Vector2f& point)
|
||||
{
|
||||
myPoints[index] = point;
|
||||
Update();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2f ConvexShape::GetPoint(unsigned int index) const
|
||||
{
|
||||
return myPoints[index];
|
||||
}
|
||||
|
||||
} // namespace sf
|
|
@ -1,314 +0,0 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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/Drawable.hpp>
|
||||
#include <SFML/Graphics/Renderer.hpp>
|
||||
#include <SFML/Graphics/RenderTarget.hpp>
|
||||
#include <cmath>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
Drawable::~Drawable()
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Drawable::SetPosition(float x, float y)
|
||||
{
|
||||
SetX(x);
|
||||
SetY(y);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Drawable::SetPosition(const Vector2f& position)
|
||||
{
|
||||
SetX(position.x);
|
||||
SetY(position.y);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Drawable::SetX(float x)
|
||||
{
|
||||
myPosition.x = x;
|
||||
|
||||
myMatrixUpdated = false;
|
||||
myInvMatrixUpdated = false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Drawable::SetY(float y)
|
||||
{
|
||||
myPosition.y = y;
|
||||
|
||||
myMatrixUpdated = false;
|
||||
myInvMatrixUpdated = false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Drawable::SetScale(float factorX, float factorY)
|
||||
{
|
||||
SetScaleX(factorX);
|
||||
SetScaleY(factorY);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Drawable::SetScale(const Vector2f& factors)
|
||||
{
|
||||
SetScaleX(factors.x);
|
||||
SetScaleY(factors.y);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Drawable::SetScaleX(float factor)
|
||||
{
|
||||
if (factor > 0)
|
||||
{
|
||||
myScale.x = factor;
|
||||
|
||||
myMatrixUpdated = false;
|
||||
myInvMatrixUpdated = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Drawable::SetScaleY(float factor)
|
||||
{
|
||||
if (factor > 0)
|
||||
{
|
||||
myScale.y = factor;
|
||||
|
||||
myMatrixUpdated = false;
|
||||
myInvMatrixUpdated = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Drawable::SetOrigin(float x, float y)
|
||||
{
|
||||
myOrigin.x = x;
|
||||
myOrigin.y = y;
|
||||
|
||||
myMatrixUpdated = false;
|
||||
myInvMatrixUpdated = false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Drawable::SetOrigin(const Vector2f& origin)
|
||||
{
|
||||
SetOrigin(origin.x, origin.y);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Drawable::SetRotation(float angle)
|
||||
{
|
||||
myRotation = static_cast<float>(std::fmod(angle, 360));
|
||||
if (myRotation < 0)
|
||||
myRotation += 360.f;
|
||||
|
||||
myMatrixUpdated = false;
|
||||
myInvMatrixUpdated = false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Drawable::SetColor(const Color& color)
|
||||
{
|
||||
myColor = color;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Drawable::SetBlendMode(Blend::Mode mode)
|
||||
{
|
||||
myBlendMode = mode;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const Vector2f& Drawable::GetPosition() const
|
||||
{
|
||||
return myPosition;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const Vector2f& Drawable::GetScale() const
|
||||
{
|
||||
return myScale;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const Vector2f& Drawable::GetOrigin() const
|
||||
{
|
||||
return myOrigin;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
float Drawable::GetRotation() const
|
||||
{
|
||||
return myRotation;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const Color& Drawable::GetColor() const
|
||||
{
|
||||
return myColor;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Blend::Mode Drawable::GetBlendMode() const
|
||||
{
|
||||
return myBlendMode;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Drawable::Move(float offsetX, float offsetY)
|
||||
{
|
||||
SetPosition(myPosition.x + offsetX, myPosition.y + offsetY);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Drawable::Move(const Vector2f& offset)
|
||||
{
|
||||
SetPosition(myPosition + offset);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Drawable::Scale(float factorX, float factorY)
|
||||
{
|
||||
SetScale(myScale.x * factorX, myScale.y * factorY);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Drawable::Scale(const Vector2f& factor)
|
||||
{
|
||||
SetScale(myScale.x * factor.x, myScale.y * factor.y);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Drawable::Rotate(float angle)
|
||||
{
|
||||
SetRotation(myRotation + angle);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2f Drawable::TransformToLocal(const Vector2f& point) const
|
||||
{
|
||||
return GetInverseMatrix().Transform(point);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2f Drawable::TransformToGlobal(const Vector2f& point) const
|
||||
{
|
||||
return GetMatrix().Transform(point);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Drawable::Drawable() :
|
||||
myPosition (0, 0),
|
||||
myScale (1, 1),
|
||||
myOrigin (0, 0),
|
||||
myRotation (0),
|
||||
myColor (255, 255, 255, 255),
|
||||
myBlendMode (Blend::Alpha),
|
||||
myMatrixUpdated (false),
|
||||
myInvMatrixUpdated(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const Matrix3& Drawable::GetMatrix() const
|
||||
{
|
||||
// First recompute it if needed
|
||||
if (!myMatrixUpdated)
|
||||
{
|
||||
myMatrix = Matrix3::Transformation(myOrigin, myPosition, myRotation, myScale);
|
||||
myMatrixUpdated = true;
|
||||
}
|
||||
|
||||
return myMatrix;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const Matrix3& Drawable::GetInverseMatrix() const
|
||||
{
|
||||
// First recompute it if needed
|
||||
if (!myInvMatrixUpdated)
|
||||
{
|
||||
myInvMatrix = GetMatrix().GetInverse();
|
||||
myInvMatrixUpdated = true;
|
||||
}
|
||||
|
||||
return myInvMatrix;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Drawable::Draw(RenderTarget& target, Renderer& renderer) const
|
||||
{
|
||||
// Set the current model-view matrix
|
||||
renderer.ApplyModelView(GetMatrix());
|
||||
|
||||
// Set the current global color
|
||||
renderer.ApplyColor(myColor);
|
||||
|
||||
// Set the current alpha-blending mode
|
||||
renderer.SetBlendMode(myBlendMode);
|
||||
|
||||
// Let the derived class render the object geometry
|
||||
Render(target, renderer);
|
||||
}
|
||||
|
||||
} // namespace sf
|
|
@ -451,7 +451,7 @@ Glyph Font::LoadGlyph(Uint32 codePoint, unsigned int characterSize, bool bold) c
|
|||
Page& page = myPages[characterSize];
|
||||
|
||||
// Find a good position for the new glyph into the texture
|
||||
glyph.SubRect = FindGlyphRect(page, width + 2 * padding, height + 2 * padding);
|
||||
glyph.TextureRect = FindGlyphRect(page, width + 2 * padding, height + 2 * padding);
|
||||
|
||||
// Compute the glyph's bounding box
|
||||
glyph.Bounds.Left = bitmapGlyph->left - padding;
|
||||
|
@ -492,10 +492,10 @@ Glyph Font::LoadGlyph(Uint32 codePoint, unsigned int characterSize, bool bold) c
|
|||
}
|
||||
|
||||
// Write the pixels to the texture
|
||||
unsigned int x = glyph.SubRect.Left + padding;
|
||||
unsigned int y = glyph.SubRect.Top + padding;
|
||||
unsigned int width = glyph.SubRect.Width - 2 * padding;
|
||||
unsigned int height = glyph.SubRect.Height - 2 * padding;
|
||||
unsigned int x = glyph.TextureRect.Left + padding;
|
||||
unsigned int y = glyph.TextureRect.Top + padding;
|
||||
unsigned int width = glyph.TextureRect.Width - 2 * padding;
|
||||
unsigned int height = glyph.TextureRect.Height - 2 * padding;
|
||||
page.Texture.Update(&myPixelBuffer[0], width, height, x, y);
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ namespace priv
|
|||
#ifdef SFML_DEBUG
|
||||
|
||||
// In debug mode, perform a test on every OpenGL call
|
||||
#define GLCheck(call) ((call), sf::priv::GLCheckError(__FILE__, __LINE__))
|
||||
#define GLCheck(call) ((call), sf::priv::GLCheckError(__FILE__, __LINE__))
|
||||
|
||||
#else
|
||||
|
||||
|
|
76
src/SFML/Graphics/RectangleShape.cpp
Normal file
76
src/SFML/Graphics/RectangleShape.cpp
Normal file
|
@ -0,0 +1,76 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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/RectangleShape.hpp>
|
||||
#include <cmath>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
RectangleShape::RectangleShape(const Vector2f& size)
|
||||
{
|
||||
SetSize(size);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RectangleShape::SetSize(const Vector2f& size)
|
||||
{
|
||||
mySize = size;
|
||||
Update();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const Vector2f& RectangleShape::GetSize() const
|
||||
{
|
||||
return mySize;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int RectangleShape::GetPointsCount() const
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2f RectangleShape::GetPoint(unsigned int index) const
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
default:
|
||||
case 0: return Vector2f(0, 0);
|
||||
case 1: return Vector2f(mySize.x, 0);
|
||||
case 2: return Vector2f(mySize.x, mySize.y);
|
||||
case 3: return Vector2f(0, mySize.y);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sf
|
98
src/SFML/Graphics/RenderStates.cpp
Normal file
98
src/SFML/Graphics/RenderStates.cpp
Normal file
|
@ -0,0 +1,98 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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/RenderStates.hpp>
|
||||
#include <cstddef>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
const RenderStates RenderStates::Default;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderStates::RenderStates() :
|
||||
BlendMode(BlendAlpha),
|
||||
Transform(),
|
||||
Texture (NULL),
|
||||
Shader (NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderStates::RenderStates(const sf::Transform& transform) :
|
||||
BlendMode(BlendAlpha),
|
||||
Transform(transform),
|
||||
Texture (NULL),
|
||||
Shader (NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderStates::RenderStates(sf::BlendMode blendMode) :
|
||||
BlendMode(blendMode),
|
||||
Transform(),
|
||||
Texture (NULL),
|
||||
Shader (NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderStates::RenderStates(const sf::Texture* texture) :
|
||||
BlendMode(BlendAlpha),
|
||||
Transform(),
|
||||
Texture (texture),
|
||||
Shader (NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderStates::RenderStates(const sf::Shader* shader) :
|
||||
BlendMode(BlendAlpha),
|
||||
Transform(),
|
||||
Texture (NULL),
|
||||
Shader (shader)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderStates::RenderStates(sf::BlendMode blendMode, const sf::Transform& transform,
|
||||
const sf::Texture* texture, const sf::Shader* shader) :
|
||||
BlendMode(blendMode),
|
||||
Transform(transform),
|
||||
Texture (texture),
|
||||
Shader (shader)
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace sf
|
|
@ -27,96 +27,37 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/RenderTarget.hpp>
|
||||
#include <SFML/Graphics/Drawable.hpp>
|
||||
#include <SFML/Graphics/Shader.hpp>
|
||||
#include <SFML/Graphics/Texture.hpp>
|
||||
#include <SFML/Graphics/VertexArray.hpp>
|
||||
#include <SFML/Graphics/GLCheck.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4355) // "'this' : used in base member initializer list"
|
||||
#endif
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderTarget::RenderTarget() :
|
||||
myRenderer (*this),
|
||||
myStatesSaved (false),
|
||||
myViewHasChanged(false)
|
||||
myDefaultView(),
|
||||
myView (),
|
||||
myCache ()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderTarget::~RenderTarget()
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::Clear(const Color& color)
|
||||
{
|
||||
if (Activate(true))
|
||||
myRenderer.Clear(color);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::Draw(const Drawable& object)
|
||||
{
|
||||
if (Activate(true))
|
||||
{
|
||||
// Update the projection matrix and viewport if the current view has changed
|
||||
// Note: we do the changes here and not directly in SetView in order to gather
|
||||
// rendering commands, which is safer in multithreaded environments
|
||||
if (myViewHasChanged)
|
||||
{
|
||||
myRenderer.SetProjection(myCurrentView.GetMatrix());
|
||||
myRenderer.SetViewport(GetViewport(myCurrentView));
|
||||
myViewHasChanged = false;
|
||||
}
|
||||
|
||||
// Save the current render states
|
||||
myRenderer.PushStates();
|
||||
|
||||
// Setup the shader
|
||||
myRenderer.SetShader(NULL);
|
||||
|
||||
// Let the object draw itself
|
||||
object.Draw(*this, myRenderer);
|
||||
|
||||
// Restore the previous render states
|
||||
myRenderer.PopStates();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::Draw(const Drawable& object, const Shader& shader)
|
||||
{
|
||||
if (Activate(true))
|
||||
{
|
||||
// Update the projection matrix and viewport if the current view has changed
|
||||
// Note: we do the changes here and not directly in SetView in order to gather
|
||||
// rendering commands, which is safer in multithreaded environments
|
||||
if (myViewHasChanged)
|
||||
{
|
||||
myRenderer.SetProjection(myCurrentView.GetMatrix());
|
||||
myRenderer.SetViewport(GetViewport(myCurrentView));
|
||||
myViewHasChanged = false;
|
||||
}
|
||||
|
||||
// Save the current render states
|
||||
myRenderer.PushStates();
|
||||
|
||||
// Setup the shader
|
||||
myRenderer.SetShader(&shader);
|
||||
|
||||
// Let the object draw itself
|
||||
object.Draw(*this, myRenderer);
|
||||
|
||||
// Restore the previous render states
|
||||
myRenderer.PopStates();
|
||||
GLCheck(glClearColor(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f));
|
||||
GLCheck(glClear(GL_COLOR_BUFFER_BIT));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,16 +65,15 @@ void RenderTarget::Draw(const Drawable& object, const Shader& shader)
|
|||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::SetView(const View& view)
|
||||
{
|
||||
// Save it for later use
|
||||
myCurrentView = view;
|
||||
myViewHasChanged = true;
|
||||
myView = view;
|
||||
myCache.ViewChanged = true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const View& RenderTarget::GetView() const
|
||||
{
|
||||
return myCurrentView;
|
||||
return myView;
|
||||
}
|
||||
|
||||
|
||||
|
@ -175,35 +115,166 @@ Vector2f RenderTarget::ConvertCoords(unsigned int x, unsigned int y, const View&
|
|||
coords.y = 1.f - 2.f * (static_cast<int>(y) - viewport.Top) / viewport.Height;
|
||||
|
||||
// Then transform by the inverse of the view matrix
|
||||
return view.GetInverseMatrix().Transform(coords);
|
||||
return view.GetInverseTransform().TransformPoint(coords);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::SaveGLStates()
|
||||
void RenderTarget::Draw(const Drawable& drawable, const RenderStates& states)
|
||||
{
|
||||
drawable.Draw(*this, states);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::Draw(const Vertex* vertices, unsigned int verticesCount,
|
||||
PrimitiveType type, const RenderStates& states)
|
||||
{
|
||||
// Nothing to draw?
|
||||
if (!vertices || (verticesCount == 0))
|
||||
return;
|
||||
|
||||
if (Activate(true))
|
||||
{
|
||||
myRenderer.SaveGLStates();
|
||||
myStatesSaved = true;
|
||||
// Check if the vertex count is low enough so that we can pre-transform them
|
||||
bool useVertexCache = (verticesCount <= StatesCache::VertexCacheSize);
|
||||
if (useVertexCache)
|
||||
{
|
||||
// Pre-transform the vertices and store them into the vertex cache
|
||||
for (unsigned int i = 0; i < verticesCount; ++i)
|
||||
{
|
||||
Vertex& vertex = myCache.VertexCache[i];
|
||||
vertex.Position = states.Transform * vertices[i].Position;
|
||||
vertex.Color = vertices[i].Color;
|
||||
vertex.TexCoords = vertices[i].TexCoords;
|
||||
}
|
||||
|
||||
// Restore the render states and the current view, for SFML rendering
|
||||
myRenderer.Initialize();
|
||||
SetView(GetView());
|
||||
// Since vertices are transformed, we must use an identity transform to render them
|
||||
if (!myCache.UseVertexCache)
|
||||
ApplyTransform(Transform::Identity);
|
||||
}
|
||||
else
|
||||
{
|
||||
ApplyTransform(states.Transform);
|
||||
}
|
||||
|
||||
// Apply the view
|
||||
if (myCache.ViewChanged)
|
||||
ApplyCurrentView();
|
||||
|
||||
// Apply the blend mode
|
||||
if (states.BlendMode != myCache.LastBlendMode)
|
||||
ApplyBlendMode(states.BlendMode);
|
||||
|
||||
// Apply the texture
|
||||
Uint64 textureId = states.Texture ? states.Texture->myCacheId : 0;
|
||||
if (textureId != myCache.LastTextureId)
|
||||
ApplyTexture(states.Texture);
|
||||
|
||||
// Apply the shader
|
||||
if (states.Shader)
|
||||
ApplyShader(states.Shader);
|
||||
|
||||
// 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
|
||||
if (vertices)
|
||||
{
|
||||
const char* data = reinterpret_cast<const char*>(vertices);
|
||||
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
|
||||
static const GLenum modes[] = {GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES,
|
||||
GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS};
|
||||
GLenum mode = modes[type];
|
||||
|
||||
// Draw the primitives
|
||||
GLCheck(glDrawArrays(mode, 0, verticesCount));
|
||||
|
||||
// Unbind the shader, if any
|
||||
if (states.Shader)
|
||||
ApplyShader(NULL);
|
||||
|
||||
// Update the cache
|
||||
myCache.UseVertexCache = useVertexCache;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::RestoreGLStates()
|
||||
void RenderTarget::PushGLStates()
|
||||
{
|
||||
if (myStatesSaved)
|
||||
if (Activate(true))
|
||||
{
|
||||
if (Activate(true))
|
||||
{
|
||||
myRenderer.RestoreGLStates();
|
||||
myStatesSaved = false;
|
||||
}
|
||||
GLCheck(glPushAttrib(GL_ALL_ATTRIB_BITS));
|
||||
GLCheck(glMatrixMode(GL_MODELVIEW));
|
||||
GLCheck(glPushMatrix());
|
||||
GLCheck(glMatrixMode(GL_PROJECTION));
|
||||
GLCheck(glPushMatrix());
|
||||
GLCheck(glMatrixMode(GL_TEXTURE));
|
||||
GLCheck(glPushMatrix());
|
||||
}
|
||||
|
||||
ResetGLStates();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::PopGLStates()
|
||||
{
|
||||
if (Activate(true))
|
||||
{
|
||||
GLCheck(glPopAttrib());
|
||||
GLCheck(glMatrixMode(GL_PROJECTION));
|
||||
GLCheck(glPopMatrix());
|
||||
GLCheck(glMatrixMode(GL_MODELVIEW));
|
||||
GLCheck(glPopMatrix());
|
||||
GLCheck(glMatrixMode(GL_TEXTURE));
|
||||
GLCheck(glPopMatrix());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderTarget::ResetGLStates()
|
||||
{
|
||||
if (Activate(true))
|
||||
{
|
||||
// Make sure that GLEW is initialized
|
||||
priv::EnsureGlewInit();
|
||||
|
||||
// Define the default OpenGL states
|
||||
GLCheck(glDisable(GL_LIGHTING));
|
||||
GLCheck(glDisable(GL_DEPTH_TEST));
|
||||
GLCheck(glEnable(GL_TEXTURE_2D));
|
||||
GLCheck(glEnable(GL_ALPHA_TEST));
|
||||
GLCheck(glEnable(GL_BLEND));
|
||||
GLCheck(glAlphaFunc(GL_GREATER, 0));
|
||||
GLCheck(glMatrixMode(GL_MODELVIEW));
|
||||
GLCheck(glEnableClientState(GL_VERTEX_ARRAY));
|
||||
GLCheck(glEnableClientState(GL_COLOR_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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,13 +282,135 @@ void RenderTarget::RestoreGLStates()
|
|||
////////////////////////////////////////////////////////////
|
||||
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())));
|
||||
SetView(myDefaultView);
|
||||
myView = myDefaultView;
|
||||
|
||||
// Initialize the renderer
|
||||
if (Activate(true))
|
||||
myRenderer.Initialize();
|
||||
// Initialize the default OpenGL render-states
|
||||
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
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// 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/GLCheck.hpp>
|
||||
#include <SFML/Graphics/TextureSaver.hpp>
|
||||
#include <SFML/Window/Context.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
|
||||
|
@ -77,6 +78,9 @@ bool RenderTextureImplDefault::Activate(bool active)
|
|||
////////////////////////////////////////////////////////////
|
||||
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
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, textureId));
|
||||
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)
|
||||
{
|
||||
//Create the context
|
||||
// Create the context
|
||||
myContext = new Context;
|
||||
|
||||
// Create the framebuffer object
|
||||
|
|
|
@ -1,348 +0,0 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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/Renderer.hpp>
|
||||
#include <SFML/Graphics/RenderTarget.hpp>
|
||||
#include <SFML/Graphics/Texture.hpp>
|
||||
#include <SFML/Graphics/Shader.hpp>
|
||||
#include <SFML/Graphics/GLCheck.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
Renderer::Renderer(RenderTarget& target) :
|
||||
myTarget (target),
|
||||
myTextureIsValid (false),
|
||||
myShaderIsValid (false),
|
||||
myBlendModeIsValid(false),
|
||||
myViewportIsValid (false)
|
||||
{
|
||||
myStates = &myStatesStack[0];
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Renderer::Initialize()
|
||||
{
|
||||
// Default render states
|
||||
GLCheck(glDisable(GL_LIGHTING));
|
||||
GLCheck(glDisable(GL_DEPTH_TEST));
|
||||
GLCheck(glEnable(GL_TEXTURE_2D));
|
||||
GLCheck(glEnable(GL_ALPHA_TEST));
|
||||
GLCheck(glAlphaFunc(GL_GREATER, 0));
|
||||
|
||||
// Default transform matrices
|
||||
GLCheck(glMatrixMode(GL_MODELVIEW));
|
||||
GLCheck(glLoadIdentity());
|
||||
GLCheck(glMatrixMode(GL_PROJECTION));
|
||||
GLCheck(glLoadIdentity());
|
||||
|
||||
// Invalidate the cached SFML states
|
||||
myTextureIsValid = false;
|
||||
myShaderIsValid = false;
|
||||
myBlendModeIsValid = false;
|
||||
myViewportIsValid = false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Renderer::SaveGLStates()
|
||||
{
|
||||
// Save render states
|
||||
GLCheck(glPushAttrib(GL_ALL_ATTRIB_BITS));
|
||||
|
||||
// Save matrices
|
||||
GLCheck(glMatrixMode(GL_MODELVIEW));
|
||||
GLCheck(glPushMatrix());
|
||||
GLCheck(glMatrixMode(GL_PROJECTION));
|
||||
GLCheck(glPushMatrix());
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Renderer::RestoreGLStates()
|
||||
{
|
||||
// Restore render states
|
||||
GLCheck(glPopAttrib());
|
||||
|
||||
// Restore matrices
|
||||
GLCheck(glMatrixMode(GL_PROJECTION));
|
||||
GLCheck(glPopMatrix());
|
||||
GLCheck(glMatrixMode(GL_MODELVIEW));
|
||||
GLCheck(glPopMatrix());
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Renderer::Clear(const Color& color)
|
||||
{
|
||||
GLCheck(glClearColor(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f));
|
||||
GLCheck(glClear(GL_COLOR_BUFFER_BIT));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Renderer::PushStates()
|
||||
{
|
||||
myStates++;
|
||||
*myStates = *(myStates - 1);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Renderer::PopStates()
|
||||
{
|
||||
myStates--;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Renderer::SetModelView(const Matrix3& matrix)
|
||||
{
|
||||
myStates->modelView = matrix;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Renderer::ApplyModelView(const Matrix3& matrix)
|
||||
{
|
||||
myStates->modelView = myStates->modelView * matrix;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Renderer::SetProjection(const Matrix3& matrix)
|
||||
{
|
||||
// Apply it immediately (this one is not critical for performances)
|
||||
GLCheck(glMatrixMode(GL_PROJECTION));
|
||||
GLCheck(glLoadMatrixf(matrix.Get4x4Elements()));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Renderer::SetColor(const Color& color)
|
||||
{
|
||||
myStates->r = color.r / 255.f;
|
||||
myStates->g = color.g / 255.f;
|
||||
myStates->b = color.b / 255.f;
|
||||
myStates->a = color.a / 255.f;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Renderer::ApplyColor(const Color& color)
|
||||
{
|
||||
myStates->r *= color.r / 255.f;
|
||||
myStates->g *= color.g / 255.f;
|
||||
myStates->b *= color.b / 255.f;
|
||||
myStates->a *= color.a / 255.f;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Renderer::SetViewport(const IntRect& viewport)
|
||||
{
|
||||
if ((viewport.Left != myViewport.Left) || (viewport.Width != myViewport.Width) ||
|
||||
(viewport.Top != myViewport.Top) || (viewport.Height != myViewport.Height) ||
|
||||
!myViewportIsValid)
|
||||
{
|
||||
// Revert the Y axis to match the OpenGL convention
|
||||
int top = myTarget.GetHeight() - (viewport.Top + viewport.Height);
|
||||
|
||||
// Apply the new viewport
|
||||
GLCheck(glViewport(viewport.Left, top, viewport.Width, viewport.Height));
|
||||
|
||||
// Store it
|
||||
myViewport = viewport;
|
||||
myViewportIsValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Renderer::SetBlendMode(Blend::Mode mode)
|
||||
{
|
||||
if ((mode != myBlendMode) || !myBlendModeIsValid)
|
||||
{
|
||||
// Apply the new blending mode
|
||||
if (mode == Blend::None)
|
||||
{
|
||||
GLCheck(glDisable(GL_BLEND));
|
||||
}
|
||||
else
|
||||
{
|
||||
GLCheck(glEnable(GL_BLEND));
|
||||
|
||||
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 Blend::Alpha :
|
||||
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 Blend::Add :
|
||||
GLCheck(glBlendFunc(GL_SRC_ALPHA, GL_ONE));
|
||||
break;
|
||||
|
||||
// Multiplicative blending
|
||||
case Blend::Multiply :
|
||||
GLCheck(glBlendFunc(GL_DST_COLOR, GL_ZERO));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Store it
|
||||
myBlendMode = mode;
|
||||
myBlendModeIsValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Renderer::SetTexture(const Texture* texture)
|
||||
{
|
||||
if ((texture != myTexture) || (texture && (texture->myTexture != myTextureId)) || !myTextureIsValid)
|
||||
{
|
||||
// Apply the new texture
|
||||
if (texture)
|
||||
texture->Bind();
|
||||
else
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, 0));
|
||||
|
||||
// Store it
|
||||
myTexture = texture;
|
||||
myTextureId = texture ? texture->myTexture : 0;
|
||||
myTextureIsValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Renderer::SetShader(const Shader* shader)
|
||||
{
|
||||
if ((shader != myShader) || !myShaderIsValid)
|
||||
{
|
||||
if (Shader::IsAvailable()) // to avoid calling possibly unsupported functions
|
||||
{
|
||||
// Apply the new shader
|
||||
if (shader)
|
||||
shader->Bind();
|
||||
else
|
||||
GLCheck(glUseProgramObjectARB(0));
|
||||
|
||||
// Store it
|
||||
myShader = shader;
|
||||
myShaderIsValid = true;
|
||||
}
|
||||
}
|
||||
else if (shader && myShaderIsValid)
|
||||
{
|
||||
// If the shader was already the current one, make sure that
|
||||
// it is synchronized (in case it was modified since last use)
|
||||
shader->Use();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Renderer::Begin(PrimitiveType type)
|
||||
{
|
||||
// Begin rendering
|
||||
switch (type)
|
||||
{
|
||||
case TriangleList : glBegin(GL_TRIANGLES); break;
|
||||
case TriangleStrip : glBegin(GL_TRIANGLE_STRIP); break;
|
||||
case TriangleFan : glBegin(GL_TRIANGLE_FAN); break;
|
||||
case QuadList : glBegin(GL_QUADS); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Renderer::End()
|
||||
{
|
||||
// End rendering
|
||||
glEnd();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Renderer::AddVertex(float x, float y)
|
||||
{
|
||||
ProcessVertex(x, y, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Renderer::AddVertex(float x, float y, float u, float v)
|
||||
{
|
||||
ProcessVertex(x, y, u, v, 1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Renderer::AddVertex(float x, float y, const Color& color)
|
||||
{
|
||||
ProcessVertex(x, y, 0.f, 0.f, color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Renderer::AddVertex(float x, float y, float u, float v, const Color& color)
|
||||
{
|
||||
ProcessVertex(x, y, u, v, color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Renderer::ProcessVertex(float x, float y, float u, float v, float r, float g, float b, float a)
|
||||
{
|
||||
// Transform the vertex position by the current model-view matrix
|
||||
Vector2f position = myStates->modelView.Transform(Vector2f(x, y));
|
||||
|
||||
// Modulate the vertex color with the current global color
|
||||
r *= myStates->r;
|
||||
g *= myStates->g;
|
||||
b *= myStates->b;
|
||||
a *= myStates->a;
|
||||
|
||||
// Render the vertex
|
||||
glColor4f(r, g, b, a);
|
||||
glTexCoord2f(u, v);
|
||||
glVertex2f(position.x, position.y);
|
||||
}
|
||||
|
||||
} // namespace sf
|
|
@ -27,6 +27,7 @@
|
|||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/Shader.hpp>
|
||||
#include <SFML/Graphics/Texture.hpp>
|
||||
#include <SFML/Graphics/GLCheck.hpp>
|
||||
#include <SFML/System/InputStream.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
|
@ -46,30 +47,50 @@ namespace
|
|||
GLCheck(glGetIntegerv(GL_MAX_TEXTURE_COORDS_ARB, &maxUnits));
|
||||
return maxUnits;
|
||||
}
|
||||
|
||||
// Read the contents of a file into an array of char
|
||||
bool GetFileContents(const std::string& filename, std::vector<char>& buffer)
|
||||
{
|
||||
std::ifstream file(filename.c_str(), std::ios_base::binary);
|
||||
if (file)
|
||||
{
|
||||
file.seekg(0, std::ios_base::end);
|
||||
std::streamsize size = file.tellg();
|
||||
file.seekg(0, std::ios_base::beg);
|
||||
buffer.resize(size);
|
||||
file.read(&buffer[0], size);
|
||||
buffer.push_back('\0');
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Read the contents of a stream into an array of char
|
||||
bool GetStreamContents(sf::InputStream& stream, std::vector<char>& buffer)
|
||||
{
|
||||
sf::Int64 size = stream.GetSize();
|
||||
buffer.resize(static_cast<std::size_t>(size));
|
||||
sf::Int64 read = stream.Read(&buffer[0], size);
|
||||
buffer.push_back('\0');
|
||||
return read == size;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
Shader::CurrentTextureType Shader::CurrentTexture;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Shader::Shader() :
|
||||
myShaderProgram (0),
|
||||
myCurrentTexture(-1)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Shader::Shader(const Shader& copy) :
|
||||
myShaderProgram (0),
|
||||
myCurrentTexture(copy.myCurrentTexture),
|
||||
myTextures (copy.myTextures),
|
||||
myFragmentShader(copy.myFragmentShader)
|
||||
{
|
||||
// Create the shaders and the program
|
||||
if (copy.myShaderProgram)
|
||||
CompileProgram();
|
||||
}
|
||||
|
||||
|
||||
|
@ -85,48 +106,107 @@ Shader::~Shader()
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Shader::LoadFromFile(const std::string& filename)
|
||||
bool Shader::LoadFromFile(const std::string& filename, Type type)
|
||||
{
|
||||
// Open the file
|
||||
std::ifstream file(filename.c_str());
|
||||
if (!file)
|
||||
// Read the file
|
||||
std::vector<char> shader;
|
||||
if (!GetFileContents(filename, shader))
|
||||
{
|
||||
Err() << "Failed to open shader file \"" << filename << "\"" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the shader code from the file
|
||||
myFragmentShader.clear();
|
||||
std::string line;
|
||||
while (std::getline(file, line))
|
||||
myFragmentShader += line + "\n";
|
||||
|
||||
// Create the shaders and the program
|
||||
return CompileProgram();
|
||||
// Compile the shader program
|
||||
if (type == Vertex)
|
||||
return CompileProgram(&shader[0], NULL);
|
||||
else
|
||||
return CompileProgram(NULL, &shader[0]);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Shader::LoadFromMemory(const std::string& shader)
|
||||
bool Shader::LoadFromFile(const std::string& vertexShaderFilename, const std::string& fragmentShaderFilename)
|
||||
{
|
||||
// Save the shader code
|
||||
myFragmentShader = shader;
|
||||
// Read the vertex shader file
|
||||
std::vector<char> vertexShader;
|
||||
if (!GetFileContents(vertexShaderFilename, vertexShader))
|
||||
{
|
||||
Err() << "Failed to open vertex shader file \"" << vertexShaderFilename << "\"" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create the shaders and the program
|
||||
return CompileProgram();
|
||||
// Read the fragment shader file
|
||||
std::vector<char> fragmentShader;
|
||||
if (!GetFileContents(fragmentShaderFilename, fragmentShader))
|
||||
{
|
||||
Err() << "Failed to open fragment shader file \"" << fragmentShaderFilename << "\"" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compile the shader program
|
||||
return CompileProgram(&vertexShader[0], &fragmentShader[0]);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Shader::LoadFromStream(InputStream& stream)
|
||||
bool Shader::LoadFromMemory(const std::string& shader, Type type)
|
||||
{
|
||||
// Compile the shader program
|
||||
if (type == Vertex)
|
||||
return CompileProgram(shader.c_str(), NULL);
|
||||
else
|
||||
return CompileProgram(NULL, shader.c_str());
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Shader::LoadFromMemory(const std::string& vertexShader, const std::string& fragmentShader)
|
||||
{
|
||||
// Compile the shader program
|
||||
return CompileProgram(vertexShader.c_str(), fragmentShader.c_str());
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Shader::LoadFromStream(InputStream& stream, Type type)
|
||||
{
|
||||
// Read the shader code from the stream
|
||||
std::vector<char> buffer(static_cast<std::size_t>(stream.GetSize()));
|
||||
Int64 read = stream.Read(&buffer[0], buffer.size());
|
||||
myFragmentShader.assign(&buffer[0], &buffer[0] + read);
|
||||
std::vector<char> shader;
|
||||
if (!GetStreamContents(stream, shader))
|
||||
{
|
||||
Err() << "Failed to read shader from stream" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create the shaders and the program
|
||||
return CompileProgram();
|
||||
// Compile the shader program
|
||||
if (type == Vertex)
|
||||
return CompileProgram(&shader[0], NULL);
|
||||
else
|
||||
return CompileProgram(NULL, &shader[0]);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Shader::LoadFromStream(InputStream& vertexShaderStream, InputStream& fragmentShaderStream)
|
||||
{
|
||||
// Read the vertex shader code from the stream
|
||||
std::vector<char> vertexShader;
|
||||
if (!GetStreamContents(vertexShaderStream, vertexShader))
|
||||
{
|
||||
Err() << "Failed to read vertex shader from stream" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the fragment shader code from the stream
|
||||
std::vector<char> fragmentShader;
|
||||
if (!GetStreamContents(fragmentShaderStream, fragmentShader))
|
||||
{
|
||||
Err() << "Failed to read fragment shader from stream" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compile the shader program
|
||||
return CompileProgram(&vertexShader[0], &fragmentShader[0]);
|
||||
}
|
||||
|
||||
|
||||
|
@ -241,7 +321,38 @@ void Shader::SetParameter(const std::string& name, const Vector3f& v)
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Shader::SetTexture(const std::string& name, const Texture& texture)
|
||||
void Shader::SetParameter(const std::string& name, const Color& color)
|
||||
{
|
||||
SetParameter(name, color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Shader::SetParameter(const std::string& name, const sf::Transform& transform)
|
||||
{
|
||||
if (myShaderProgram)
|
||||
{
|
||||
EnsureGlContext();
|
||||
|
||||
// Enable program
|
||||
GLhandleARB program = glGetHandleARB(GL_PROGRAM_OBJECT_ARB);
|
||||
GLCheck(glUseProgramObjectARB(myShaderProgram));
|
||||
|
||||
// Get parameter location and assign it new values
|
||||
GLint location = glGetUniformLocationARB(myShaderProgram, name.c_str());
|
||||
if (location != -1)
|
||||
GLCheck(glUniformMatrix4fvARB(location, 1, GL_FALSE, transform.GetMatrix()));
|
||||
else
|
||||
Err() << "Parameter \"" << name << "\" not found in shader" << std::endl;
|
||||
|
||||
// Disable program
|
||||
GLCheck(glUseProgramObjectARB(program));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Shader::SetParameter(const std::string& name, const Texture& texture)
|
||||
{
|
||||
if (myShaderProgram)
|
||||
{
|
||||
|
@ -279,7 +390,7 @@ void Shader::SetTexture(const std::string& name, const Texture& texture)
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Shader::SetCurrentTexture(const std::string& name)
|
||||
void Shader::SetParameter(const std::string& name, CurrentTextureType)
|
||||
{
|
||||
if (myShaderProgram)
|
||||
{
|
||||
|
@ -322,20 +433,6 @@ void Shader::Unbind() const
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Shader& Shader::operator =(const Shader& right)
|
||||
{
|
||||
Shader temp(right);
|
||||
|
||||
std::swap(myShaderProgram, temp.myShaderProgram);
|
||||
std::swap(myCurrentTexture, temp.myCurrentTexture);
|
||||
std::swap(myTextures, temp.myTextures);
|
||||
std::swap(myFragmentShader, temp.myFragmentShader);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Shader::IsAvailable()
|
||||
{
|
||||
|
@ -352,7 +449,7 @@ bool Shader::IsAvailable()
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Shader::CompileProgram()
|
||||
bool Shader::CompileProgram(const char* vertexShaderCode, const char* fragmentShaderCode)
|
||||
{
|
||||
EnsureGlContext();
|
||||
|
||||
|
@ -368,74 +465,73 @@ bool Shader::CompileProgram()
|
|||
if (myShaderProgram)
|
||||
GLCheck(glDeleteObjectARB(myShaderProgram));
|
||||
|
||||
// Define the vertex shader source (we provide it directly as it doesn't have to change)
|
||||
static const char* vertexSrc =
|
||||
"void main()"
|
||||
"{"
|
||||
" gl_TexCoord[0] = gl_MultiTexCoord0;"
|
||||
" gl_FrontColor = gl_Color;"
|
||||
" gl_Position = ftransform();"
|
||||
"}";
|
||||
|
||||
// Create the program
|
||||
myShaderProgram = glCreateProgramObjectARB();
|
||||
|
||||
// Create the shaders
|
||||
GLhandleARB vertexShader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
|
||||
GLhandleARB fragmentShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
|
||||
|
||||
// Compile them
|
||||
const char* fragmentSrc = myFragmentShader.c_str();
|
||||
GLCheck(glShaderSourceARB(vertexShader, 1, &vertexSrc, NULL));
|
||||
GLCheck(glShaderSourceARB(fragmentShader, 1, &fragmentSrc, NULL));
|
||||
GLCheck(glCompileShaderARB(vertexShader));
|
||||
GLCheck(glCompileShaderARB(fragmentShader));
|
||||
|
||||
// Check the compile logs
|
||||
GLint success;
|
||||
GLCheck(glGetObjectParameterivARB(vertexShader, GL_OBJECT_COMPILE_STATUS_ARB, &success));
|
||||
if (success == GL_FALSE)
|
||||
// Create the vertex shader if needed
|
||||
if (vertexShaderCode)
|
||||
{
|
||||
char log[1024];
|
||||
GLCheck(glGetInfoLogARB(vertexShader, sizeof(log), 0, log));
|
||||
Err() << "Failed to compile shader:" << std::endl
|
||||
<< log << std::endl;
|
||||
// Create and compile the shader
|
||||
GLhandleARB vertexShader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
|
||||
GLCheck(glShaderSourceARB(vertexShader, 1, &vertexShaderCode, NULL));
|
||||
GLCheck(glCompileShaderARB(vertexShader));
|
||||
|
||||
// Check the compile log
|
||||
GLint success;
|
||||
GLCheck(glGetObjectParameterivARB(vertexShader, GL_OBJECT_COMPILE_STATUS_ARB, &success));
|
||||
if (success == GL_FALSE)
|
||||
{
|
||||
char log[1024];
|
||||
GLCheck(glGetInfoLogARB(vertexShader, sizeof(log), 0, log));
|
||||
Err() << "Failed to compile vertex shader:" << std::endl
|
||||
<< log << std::endl;
|
||||
GLCheck(glDeleteObjectARB(vertexShader));
|
||||
GLCheck(glDeleteObjectARB(myShaderProgram));
|
||||
myShaderProgram = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Attach the shader to the program, and delete it (not needed anymore)
|
||||
GLCheck(glAttachObjectARB(myShaderProgram, vertexShader));
|
||||
GLCheck(glDeleteObjectARB(vertexShader));
|
||||
GLCheck(glDeleteObjectARB(fragmentShader));
|
||||
GLCheck(glDeleteObjectARB(myShaderProgram));
|
||||
myShaderProgram = 0;
|
||||
return false;
|
||||
}
|
||||
GLCheck(glGetObjectParameterivARB(fragmentShader, GL_OBJECT_COMPILE_STATUS_ARB, &success));
|
||||
if (success == GL_FALSE)
|
||||
{
|
||||
char log[1024];
|
||||
GLCheck(glGetInfoLogARB(fragmentShader, sizeof(log), 0, log));
|
||||
Err() << "Failed to compile shader:" << std::endl
|
||||
<< log << std::endl;
|
||||
GLCheck(glDeleteObjectARB(vertexShader));
|
||||
GLCheck(glDeleteObjectARB(fragmentShader));
|
||||
GLCheck(glDeleteObjectARB(myShaderProgram));
|
||||
myShaderProgram = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Attach the shaders to the program
|
||||
GLCheck(glAttachObjectARB(myShaderProgram, vertexShader));
|
||||
GLCheck(glAttachObjectARB(myShaderProgram, fragmentShader));
|
||||
// Create the fragment shader if needed
|
||||
if (fragmentShaderCode)
|
||||
{
|
||||
// Create and compile the shader
|
||||
GLhandleARB fragmentShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
|
||||
GLCheck(glShaderSourceARB(fragmentShader, 1, &fragmentShaderCode, NULL));
|
||||
GLCheck(glCompileShaderARB(fragmentShader));
|
||||
|
||||
// We can now delete the shaders
|
||||
GLCheck(glDeleteObjectARB(vertexShader));
|
||||
GLCheck(glDeleteObjectARB(fragmentShader));
|
||||
// Check the compile log
|
||||
GLint success;
|
||||
GLCheck(glGetObjectParameterivARB(fragmentShader, GL_OBJECT_COMPILE_STATUS_ARB, &success));
|
||||
if (success == GL_FALSE)
|
||||
{
|
||||
char log[1024];
|
||||
GLCheck(glGetInfoLogARB(fragmentShader, sizeof(log), 0, log));
|
||||
Err() << "Failed to compile fragment shader:" << std::endl
|
||||
<< log << std::endl;
|
||||
GLCheck(glDeleteObjectARB(fragmentShader));
|
||||
GLCheck(glDeleteObjectARB(myShaderProgram));
|
||||
myShaderProgram = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Attach the shader to the program, and delete it (not needed anymore)
|
||||
GLCheck(glAttachObjectARB(myShaderProgram, fragmentShader));
|
||||
GLCheck(glDeleteObjectARB(fragmentShader));
|
||||
}
|
||||
|
||||
// Link the program
|
||||
GLCheck(glLinkProgramARB(myShaderProgram));
|
||||
|
||||
// Get link log
|
||||
// Check the link log
|
||||
GLint success;
|
||||
GLCheck(glGetObjectParameterivARB(myShaderProgram, GL_OBJECT_LINK_STATUS_ARB, &success));
|
||||
if (success == GL_FALSE)
|
||||
{
|
||||
// Oops... link errors
|
||||
char log[1024];
|
||||
GLCheck(glGetInfoLogARB(myShaderProgram, sizeof(log), 0, log));
|
||||
Err() << "Failed to link shader:" << std::endl
|
||||
|
@ -466,11 +562,4 @@ void Shader::BindTextures() const
|
|||
GLCheck(glActiveTextureARB(GL_TEXTURE0_ARB));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Shader::Use() const
|
||||
{
|
||||
BindTextures();
|
||||
}
|
||||
|
||||
} // namespace sf
|
||||
|
|
|
@ -26,365 +26,270 @@
|
|||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/Shape.hpp>
|
||||
#include <SFML/Graphics/Renderer.hpp>
|
||||
#include <SFML/Graphics/RenderTarget.hpp>
|
||||
#include <SFML/Graphics/Texture.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <cmath>
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Private data
|
||||
////////////////////////////////////////////////////////////
|
||||
namespace
|
||||
{
|
||||
// Compute the normal of a segment
|
||||
sf::Vector2f ComputeNormal(const sf::Vector2f& p1, const sf::Vector2f& p2)
|
||||
{
|
||||
sf::Vector2f normal(p1.y - p2.y, p2.x - p1.x);
|
||||
float length = std::sqrt(normal.x * normal.x + normal.y * normal.y);
|
||||
if (length != 0.f)
|
||||
normal /= length;
|
||||
return normal;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
Shape::Shape() :
|
||||
myOutline (0.f),
|
||||
myIsFillEnabled (true),
|
||||
myIsOutlineEnabled(true),
|
||||
myIsCompiled (false)
|
||||
Shape::~Shape()
|
||||
{
|
||||
// Put a placeholder for the center of the shape
|
||||
myPoints.push_back(Point());
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Shape::AddPoint(float x, float y, const Color& color, const Color& outlineColor)
|
||||
void Shape::SetTexture(const Texture* texture, bool resetRect)
|
||||
{
|
||||
AddPoint(Vector2f(x, y), color, outlineColor);
|
||||
// Recompute the texture area if requested, or if there was no texture before
|
||||
if (texture && (resetRect || !myTexture))
|
||||
SetTextureRect(IntRect(0, 0, texture->GetWidth(), texture->GetHeight()));
|
||||
|
||||
// Assign the new texture
|
||||
myTexture = texture;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Shape::AddPoint(const Vector2f& position, const Color& color, const Color& outlineColor)
|
||||
const Texture* Shape::GetTexture() const
|
||||
{
|
||||
myPoints.push_back(Point(position, color, outlineColor));
|
||||
myIsCompiled = false;
|
||||
return myTexture;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int Shape::GetPointsCount() const
|
||||
void Shape::SetTextureRect(const IntRect& rect)
|
||||
{
|
||||
return static_cast<unsigned int>(myPoints.size() - 1);
|
||||
myTextureRect = rect;
|
||||
UpdateTexCoords();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Shape::EnableFill(bool enable)
|
||||
const IntRect& Shape::GetTextureRect() const
|
||||
{
|
||||
myIsFillEnabled = enable;
|
||||
return myTextureRect;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Shape::EnableOutline(bool enable)
|
||||
void Shape::SetFillColor(const Color& color)
|
||||
{
|
||||
myIsOutlineEnabled = enable;
|
||||
myFillColor = color;
|
||||
UpdateFillColors();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Shape::SetPointPosition(unsigned int index, const Vector2f& position)
|
||||
const Color& Shape::GetFillColor() const
|
||||
{
|
||||
myPoints[index + 1].Position = position;
|
||||
myIsCompiled = false;
|
||||
return myFillColor;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Shape::SetPointPosition(unsigned int index, float x, float y)
|
||||
void Shape::SetOutlineColor(const Color& color)
|
||||
{
|
||||
SetPointPosition(index, Vector2f(x, y));
|
||||
myOutlineColor = color;
|
||||
UpdateOutlineColors();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Shape::SetPointColor(unsigned int index, const Color& color)
|
||||
const Color& Shape::GetOutlineColor() const
|
||||
{
|
||||
myPoints[index + 1].Col = color;
|
||||
myIsCompiled = false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Shape::SetPointOutlineColor(unsigned int index, const Color& color)
|
||||
{
|
||||
myPoints[index + 1].OutlineCol = color;
|
||||
myIsCompiled = false;
|
||||
return myOutlineColor;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Shape::SetOutlineThickness(float thickness)
|
||||
{
|
||||
myOutline = thickness;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const Vector2f& Shape::GetPointPosition(unsigned int index) const
|
||||
{
|
||||
return myPoints[index + 1].Position;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const Color& Shape::GetPointColor(unsigned int index) const
|
||||
{
|
||||
return myPoints[index + 1].Col;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const Color& Shape::GetPointOutlineColor(unsigned int index) const
|
||||
{
|
||||
return myPoints[index + 1].OutlineCol;
|
||||
myOutlineThickness = thickness;
|
||||
Update(); // recompute everything because the whole shape must be offset
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
float Shape::GetOutlineThickness() const
|
||||
{
|
||||
return myOutline;
|
||||
return myOutlineThickness;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Shape Shape::Line(float p1x, float p1y, float p2x, float p2y, float thickness, const Color& color, float outline, const Color& outlineColor)
|
||||
FloatRect Shape::GetLocalBounds() const
|
||||
{
|
||||
Vector2f p1(p1x, p1y);
|
||||
Vector2f p2(p2x, p2y);
|
||||
|
||||
return Shape::Line(p1, p2, thickness, color, outline, outlineColor);
|
||||
return myBounds;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Shape Shape::Line(const Vector2f& p1, const Vector2f& p2, float thickness, const Color& color, float outline, const Color& outlineColor)
|
||||
FloatRect Shape::GetGlobalBounds() const
|
||||
{
|
||||
// Compute the extrusion direction
|
||||
Vector2f normal;
|
||||
ComputeNormal(p1, p2, normal);
|
||||
normal *= thickness / 2;
|
||||
|
||||
// Create the shape's points
|
||||
Shape shape;
|
||||
shape.AddPoint(p1 - normal, color, outlineColor);
|
||||
shape.AddPoint(p2 - normal, color, outlineColor);
|
||||
shape.AddPoint(p2 + normal, color, outlineColor);
|
||||
shape.AddPoint(p1 + normal, color, outlineColor);
|
||||
shape.SetOutlineThickness(outline);
|
||||
|
||||
// Compile it
|
||||
shape.Compile();
|
||||
|
||||
return shape;
|
||||
return GetTransform().TransformRect(GetLocalBounds());
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Shape Shape::Rectangle(float left, float top, float width, float height, const Color& color, float outline, const Color& outlineColor)
|
||||
Shape::Shape() :
|
||||
myTexture (NULL),
|
||||
myTextureRect (),
|
||||
myFillColor (255, 255, 255),
|
||||
myOutlineColor (255, 255, 255),
|
||||
myOutlineThickness(0),
|
||||
myVertices (TrianglesFan),
|
||||
myOutlineVertices (TrianglesStrip),
|
||||
myInsideBounds (),
|
||||
myBounds ()
|
||||
{
|
||||
// Create the shape's points
|
||||
Shape shape;
|
||||
shape.AddPoint(Vector2f(left, top), color, outlineColor);
|
||||
shape.AddPoint(Vector2f(left + width, top), color, outlineColor);
|
||||
shape.AddPoint(Vector2f(left + width, top + height), color, outlineColor);
|
||||
shape.AddPoint(Vector2f(left, top + height), color, outlineColor);
|
||||
shape.SetOutlineThickness(outline);
|
||||
|
||||
// Compile it
|
||||
shape.Compile();
|
||||
|
||||
return shape;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Shape Shape::Rectangle(const FloatRect& rectangle, const Color& color, float outline, const Color& outlineColor)
|
||||
void Shape::Update()
|
||||
{
|
||||
return Shape::Rectangle(rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height, color, outline, outlineColor);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Shape Shape::Circle(float x, float y, float radius, const Color& color, float outline, const Color& outlineColor)
|
||||
{
|
||||
return Shape::Circle(Vector2f(x, y), radius, color, outline, outlineColor);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Shape Shape::Circle(const Vector2f& center, float radius, const Color& color, float outline, const Color& outlineColor)
|
||||
{
|
||||
static const int nbSegments = 40;
|
||||
|
||||
// Create the points set
|
||||
Shape shape;
|
||||
for (int i = 0; i < nbSegments; ++i)
|
||||
// Get the total number of points of the shape
|
||||
unsigned int count = GetPointsCount();
|
||||
if (count < 3)
|
||||
{
|
||||
float angle = i * 2 * 3.141592654f / nbSegments;
|
||||
Vector2f offset(std::cos(angle), std::sin(angle));
|
||||
|
||||
shape.AddPoint(center + offset * radius, color, outlineColor);
|
||||
}
|
||||
|
||||
// Compile it
|
||||
shape.SetOutlineThickness(outline);
|
||||
shape.Compile();
|
||||
|
||||
return shape;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Shape::Render(RenderTarget&, Renderer& renderer) const
|
||||
{
|
||||
// Make sure the shape has at least 3 points (4 if we count the center)
|
||||
if (myPoints.size() < 4)
|
||||
myVertices.Resize(0);
|
||||
myOutlineVertices.Resize(0);
|
||||
return;
|
||||
|
||||
// Make sure the shape is compiled
|
||||
if (!myIsCompiled)
|
||||
const_cast<Shape*>(this)->Compile();
|
||||
|
||||
// Shapes only use color, no texture
|
||||
renderer.SetTexture(NULL);
|
||||
|
||||
// Draw the shape
|
||||
if (myIsFillEnabled)
|
||||
{
|
||||
if (myPoints.size() == 4)
|
||||
{
|
||||
// Special case of a triangle
|
||||
renderer.Begin(Renderer::TriangleList);
|
||||
renderer.AddVertex(myPoints[1].Position.x, myPoints[1].Position.y, myPoints[1].Col);
|
||||
renderer.AddVertex(myPoints[2].Position.x, myPoints[2].Position.y, myPoints[2].Col);
|
||||
renderer.AddVertex(myPoints[3].Position.x, myPoints[3].Position.y, myPoints[3].Col);
|
||||
renderer.End();
|
||||
}
|
||||
else if (myPoints.size() == 5)
|
||||
{
|
||||
// Special case of a quad
|
||||
renderer.Begin(Renderer::TriangleStrip);
|
||||
renderer.AddVertex(myPoints[1].Position.x, myPoints[1].Position.y, myPoints[1].Col);
|
||||
renderer.AddVertex(myPoints[2].Position.x, myPoints[2].Position.y, myPoints[2].Col);
|
||||
renderer.AddVertex(myPoints[4].Position.x, myPoints[4].Position.y, myPoints[4].Col);
|
||||
renderer.AddVertex(myPoints[3].Position.x, myPoints[3].Position.y, myPoints[3].Col);
|
||||
renderer.End();
|
||||
}
|
||||
else
|
||||
{
|
||||
renderer.Begin(Renderer::TriangleFan);
|
||||
|
||||
// General case of a convex polygon
|
||||
for (std::vector<Point>::const_iterator i = myPoints.begin(); i != myPoints.end(); ++i)
|
||||
renderer.AddVertex(i->Position.x, i->Position.y, i->Col);
|
||||
|
||||
// Close the shape by duplicating the first point at the end
|
||||
const Point& first = myPoints[1];
|
||||
renderer.AddVertex(first.Position.x, first.Position.y, first.Col);
|
||||
|
||||
renderer.End();
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the outline
|
||||
if (myIsOutlineEnabled && (myOutline != 0))
|
||||
myVertices.Resize(count + 2); // + 2 for center and repeated first point
|
||||
|
||||
// Position
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
myVertices[i + 1].Position = GetPoint(i);
|
||||
myVertices[count + 1].Position = myVertices[1].Position;
|
||||
|
||||
// Update the bounding rectangle
|
||||
myVertices[0] = myVertices[1]; // so that the result of GetBounds() is correct
|
||||
myInsideBounds = myVertices.GetBounds();
|
||||
|
||||
// Compute the center and make it the first vertex
|
||||
myVertices[0].Position.x = myInsideBounds.Left + myInsideBounds.Width / 2;
|
||||
myVertices[0].Position.y = myInsideBounds.Top + myInsideBounds.Height / 2;
|
||||
|
||||
// Color
|
||||
UpdateFillColors();
|
||||
|
||||
// Texture coordinates
|
||||
UpdateTexCoords();
|
||||
|
||||
// Outline
|
||||
UpdateOutline();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Shape::Draw(RenderTarget& target, RenderStates states) const
|
||||
{
|
||||
states.Transform *= GetTransform();
|
||||
|
||||
// Render the inside
|
||||
if (myFillColor.a > 0)
|
||||
{
|
||||
renderer.Begin(Renderer::TriangleStrip);
|
||||
states.Texture = myTexture;
|
||||
target.Draw(myVertices, states);
|
||||
}
|
||||
|
||||
for (std::vector<Point>::const_iterator i = myPoints.begin() + 1; i != myPoints.end(); ++i)
|
||||
{
|
||||
Vector2f point1 = i->Position;
|
||||
Vector2f point2 = i->Position + i->Normal * myOutline;
|
||||
renderer.AddVertex(point1.x, point1.y, i->OutlineCol);
|
||||
renderer.AddVertex(point2.x, point2.y, i->OutlineCol);
|
||||
}
|
||||
|
||||
// Close the shape by duplicating the first point at the end
|
||||
const Point& first = myPoints[1];
|
||||
Vector2f point1 = first.Position;
|
||||
Vector2f point2 = first.Position + first.Normal * myOutline;
|
||||
renderer.AddVertex(point1.x, point1.y, first.OutlineCol);
|
||||
renderer.AddVertex(point2.x, point2.y, first.OutlineCol);
|
||||
|
||||
renderer.End();
|
||||
// Render the outline
|
||||
if ((myOutlineColor.a > 0) && (myOutlineThickness > 0))
|
||||
{
|
||||
states.Texture = NULL;
|
||||
target.Draw(myOutlineVertices, states);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Shape::Compile()
|
||||
void Shape::UpdateFillColors()
|
||||
{
|
||||
// Compute the center
|
||||
float nbPoints = static_cast<float>(myPoints.size() - 1);
|
||||
float r = 0, g = 0, b = 0, a = 0;
|
||||
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;
|
||||
r += myPoints[i].Col.r;
|
||||
g += myPoints[i].Col.g;
|
||||
b += myPoints[i].Col.b;
|
||||
a += myPoints[i].Col.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;
|
||||
for (unsigned int i = 0; i < myVertices.GetVerticesCount(); ++i)
|
||||
myVertices[i].Color = myFillColor;
|
||||
}
|
||||
|
||||
// Compute the outline
|
||||
for (std::size_t i = 1; i < myPoints.size(); ++i)
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Shape::UpdateTexCoords()
|
||||
{
|
||||
for (unsigned int i = 0; i < myVertices.GetVerticesCount(); ++i)
|
||||
{
|
||||
float xratio = (myVertices[i].Position.x - myInsideBounds.Left) / myInsideBounds.Width;
|
||||
float yratio = (myVertices[i].Position.y - myInsideBounds.Top) / myInsideBounds.Height;
|
||||
myVertices[i].TexCoords.x = myTextureRect.Left + myTextureRect.Width * xratio;
|
||||
myVertices[i].TexCoords.y = myTextureRect.Top + myTextureRect.Height * yratio;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Shape::UpdateOutline()
|
||||
{
|
||||
unsigned int count = myVertices.GetVerticesCount() - 2;
|
||||
myOutlineVertices.Resize((count + 1) * 2);
|
||||
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
{
|
||||
unsigned int index = i + 1;
|
||||
|
||||
// Get the two segments shared by the current point
|
||||
Point& p0 = (i == 1) ? myPoints[myPoints.size() - 1] : myPoints[i - 1];
|
||||
Point& p1 = myPoints[i];
|
||||
Point& p2 = (i == myPoints.size() - 1) ? myPoints[1] : myPoints[i + 1];
|
||||
Vector2f p0 = (i == 0) ? myVertices[count].Position : myVertices[index - 1].Position;
|
||||
Vector2f p1 = myVertices[index].Position;
|
||||
Vector2f p2 = myVertices[index + 1].Position;
|
||||
|
||||
// Compute their normal
|
||||
Vector2f normal1, normal2;
|
||||
if (!ComputeNormal(p0.Position, p1.Position, normal1) || !ComputeNormal(p1.Position, p2.Position, normal2))
|
||||
continue;
|
||||
Vector2f n1 = ComputeNormal(p0, p1);
|
||||
Vector2f n2 = ComputeNormal(p1, p2);
|
||||
|
||||
// Add them to get the extrusion direction
|
||||
float factor = 1.f + (normal1.x * normal2.x + normal1.y * normal2.y);
|
||||
p1.Normal = (normal1 + normal2) / factor;
|
||||
// Combine them to get the extrusion direction
|
||||
float factor = 1.f + (n1.x * n2.x + n1.y * n2.y);
|
||||
Vector2f normal = -(n1 + n2) / factor;
|
||||
|
||||
// Make sure it points towards the outside of the shape
|
||||
float dot = (p1.Position.x - center.Position.x) * p1.Normal.x + (p1.Position.y - center.Position.y) * p1.Normal.y;
|
||||
if (dot < 0)
|
||||
p1.Normal = -p1.Normal;
|
||||
// Update the outline points
|
||||
myOutlineVertices[i * 2 + 0].Position = p1;
|
||||
myOutlineVertices[i * 2 + 1].Position = p1 + normal * myOutlineThickness;
|
||||
}
|
||||
|
||||
myIsCompiled = true;
|
||||
// Duplicate the first point at the end, to close the outline
|
||||
myOutlineVertices[count * 2 + 0].Position = myOutlineVertices[0].Position;
|
||||
myOutlineVertices[count * 2 + 1].Position = myOutlineVertices[1].Position;
|
||||
|
||||
// Update outline colors
|
||||
UpdateOutlineColors();
|
||||
|
||||
// Update the shape's bounds
|
||||
myBounds = myOutlineVertices.GetBounds();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Shape::ComputeNormal(const Vector2f& p1, const Vector2f& p2, Vector2f& normal)
|
||||
void Shape::UpdateOutlineColors()
|
||||
{
|
||||
normal.x = p1.y - p2.y;
|
||||
normal.y = p2.x - p1.x;
|
||||
|
||||
float len = std::sqrt(normal.x * normal.x + normal.y * normal.y);
|
||||
if (len == 0.f)
|
||||
return false;
|
||||
|
||||
normal.x /= len;
|
||||
normal.y /= len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Shape::Point::Point(const Vector2f& position, const Color& color, const Color& outlineColor) :
|
||||
Position (position),
|
||||
Normal (0.f, 0.f),
|
||||
Col (color),
|
||||
OutlineCol(outlineColor)
|
||||
{
|
||||
|
||||
for (unsigned int i = 0; i < myOutlineVertices.GetVerticesCount(); ++i)
|
||||
myOutlineVertices[i].Color = myOutlineColor;
|
||||
}
|
||||
|
||||
} // namespace sf
|
||||
|
|
|
@ -27,48 +27,44 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/Sprite.hpp>
|
||||
#include <SFML/Graphics/Texture.hpp>
|
||||
#include <SFML/Graphics/Renderer.hpp>
|
||||
#include <utility>
|
||||
#include <SFML/Graphics/RenderTarget.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
Sprite::Sprite() :
|
||||
Drawable (),
|
||||
myTexture (NULL),
|
||||
mySubRect (0, 0, 1, 1),
|
||||
myIsFlippedX(false),
|
||||
myIsFlippedY(false)
|
||||
myTexture (NULL),
|
||||
myTextureRect(0, 0, 0, 0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Sprite::Sprite(const Texture& texture) :
|
||||
Drawable (),
|
||||
myTexture (NULL),
|
||||
mySubRect (0, 0, 1, 1),
|
||||
myIsFlippedX(false),
|
||||
myIsFlippedY(false)
|
||||
myTexture (NULL),
|
||||
myTextureRect(0, 0, 0, 0)
|
||||
{
|
||||
SetTexture(texture);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Sprite::SetTexture(const Texture& texture, bool adjustToNewSize)
|
||||
Sprite::Sprite(const Texture& texture, const IntRect& rectangle) :
|
||||
myTexture (NULL),
|
||||
myTextureRect(0, 0, 0, 0)
|
||||
{
|
||||
// If there was no valid texture before, force adjusting to the new texture size
|
||||
if (!myTexture)
|
||||
adjustToNewSize = true;
|
||||
SetTexture(texture);
|
||||
SetTextureRect(rectangle);
|
||||
}
|
||||
|
||||
// If we want to adjust the size and the new texture is valid, we adjust the source rectangle
|
||||
if (adjustToNewSize && (texture.GetWidth() > 0) && (texture.GetHeight() > 0))
|
||||
{
|
||||
SetSubRect(IntRect(0, 0, texture.GetWidth(), texture.GetHeight()));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Sprite::SetTexture(const Texture& texture, bool resetRect)
|
||||
{
|
||||
// Recompute the texture area if requested, or if there was no valid texture before
|
||||
if (resetRect || !myTexture)
|
||||
SetTextureRect(IntRect(0, 0, texture.GetWidth(), texture.GetHeight()));
|
||||
|
||||
// Assign the new texture
|
||||
myTexture = &texture;
|
||||
|
@ -76,38 +72,25 @@ void Sprite::SetTexture(const Texture& texture, bool adjustToNewSize)
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Sprite::SetSubRect(const IntRect& rectangle)
|
||||
void Sprite::SetTextureRect(const IntRect& rectangle)
|
||||
{
|
||||
mySubRect = rectangle;
|
||||
if (rectangle != myTextureRect)
|
||||
{
|
||||
myTextureRect = rectangle;
|
||||
UpdatePositions();
|
||||
UpdateTexCoords();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Sprite::Resize(float width, float height)
|
||||
void Sprite::SetColor(const Color& color)
|
||||
{
|
||||
if ((mySubRect.Width > 0) && (mySubRect.Height > 0))
|
||||
SetScale(width / mySubRect.Width, height / mySubRect.Height);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Sprite::Resize(const Vector2f& size)
|
||||
{
|
||||
Resize(size.x, size.y);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Sprite::FlipX(bool flipped)
|
||||
{
|
||||
myIsFlippedX = flipped;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Sprite::FlipY(bool flipped)
|
||||
{
|
||||
myIsFlippedY = flipped;
|
||||
// Update the vertices' color
|
||||
myVertices[0].Color = color;
|
||||
myVertices[1].Color = color;
|
||||
myVertices[2].Color = color;
|
||||
myVertices[3].Color = color;
|
||||
}
|
||||
|
||||
|
||||
|
@ -119,49 +102,73 @@ const Texture* Sprite::GetTexture() const
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const IntRect& Sprite::GetSubRect() const
|
||||
const IntRect& Sprite::GetTextureRect() const
|
||||
{
|
||||
return mySubRect;
|
||||
return myTextureRect;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2f Sprite::GetSize() const
|
||||
const Color& Sprite::GetColor() const
|
||||
{
|
||||
return Vector2f(mySubRect.Width * GetScale().x, mySubRect.Height * GetScale().y);
|
||||
return myVertices[0].Color;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Sprite::Render(RenderTarget&, Renderer& renderer) const
|
||||
FloatRect Sprite::GetLocalBounds() const
|
||||
{
|
||||
// Get the sprite size
|
||||
float width = static_cast<float>(mySubRect.Width);
|
||||
float height = static_cast<float>(mySubRect.Height);
|
||||
float width = static_cast<float>(myTextureRect.Width);
|
||||
float height = static_cast<float>(myTextureRect.Height);
|
||||
|
||||
// Check if the texture is valid, and calculate the texture coordinates
|
||||
FloatRect coords;
|
||||
return FloatRect(0.f, 0.f, width, height);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
FloatRect Sprite::GetGlobalBounds() const
|
||||
{
|
||||
return GetTransform().TransformRect(GetLocalBounds());
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Sprite::Draw(RenderTarget& target, RenderStates states) const
|
||||
{
|
||||
if (myTexture)
|
||||
coords = myTexture->GetTexCoords(mySubRect);
|
||||
{
|
||||
states.Transform *= GetTransform();
|
||||
states.Texture = myTexture;
|
||||
target.Draw(myVertices, 4, Quads, states);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the texture coordinates
|
||||
float left = coords.Left;
|
||||
float top = coords.Top;
|
||||
float right = coords.Left + coords.Width;
|
||||
float bottom = coords.Top + coords.Height;
|
||||
if (myIsFlippedX) std::swap(left, right);
|
||||
if (myIsFlippedY) std::swap(top, bottom);
|
||||
|
||||
// Bind the texture
|
||||
renderer.SetTexture(myTexture);
|
||||
////////////////////////////////////////////////////////////
|
||||
void Sprite::UpdatePositions()
|
||||
{
|
||||
float width = static_cast<float>(myTextureRect.Width);
|
||||
float height = static_cast<float>(myTextureRect.Height);
|
||||
|
||||
// Draw the sprite's geometry
|
||||
renderer.Begin(Renderer::TriangleStrip);
|
||||
renderer.AddVertex(0, 0, left, top);
|
||||
renderer.AddVertex(width, 0, right, top);
|
||||
renderer.AddVertex(0, height, left, bottom);
|
||||
renderer.AddVertex(width, height, right, bottom);
|
||||
renderer.End();
|
||||
myVertices[0].Position = Vector2f(0, 0);
|
||||
myVertices[1].Position = Vector2f(0, height);
|
||||
myVertices[2].Position = Vector2f(width, height);
|
||||
myVertices[3].Position = Vector2f(width, 0);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Sprite::UpdateTexCoords()
|
||||
{
|
||||
float left = static_cast<float>(myTextureRect.Left);
|
||||
float right = left + myTextureRect.Width;
|
||||
float top = static_cast<float>(myTextureRect.Top);
|
||||
float bottom = top + myTextureRect.Height;
|
||||
|
||||
myVertices[0].TexCoords = Vector2f(left, top);
|
||||
myVertices[1].TexCoords = Vector2f(left, bottom);
|
||||
myVertices[2].TexCoords = Vector2f(right, bottom);
|
||||
myVertices[3].TexCoords = Vector2f(right, top);
|
||||
}
|
||||
|
||||
} // namespace sf
|
||||
|
|
|
@ -27,17 +27,20 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/Text.hpp>
|
||||
#include <SFML/Graphics/Texture.hpp>
|
||||
#include <SFML/Graphics/Renderer.hpp>
|
||||
#include <SFML/Graphics/RenderTarget.hpp>
|
||||
#include <cassert>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
Text::Text() :
|
||||
myString (),
|
||||
myFont (&Font::GetDefaultFont()),
|
||||
myCharacterSize(30),
|
||||
myStyle (Regular),
|
||||
myRectUpdated (true)
|
||||
myVertices (Quads),
|
||||
myBounds ()
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -45,12 +48,14 @@ myRectUpdated (true)
|
|||
|
||||
////////////////////////////////////////////////////////////
|
||||
Text::Text(const String& string, const Font& font, unsigned int characterSize) :
|
||||
myString (string),
|
||||
myFont (&font),
|
||||
myCharacterSize(characterSize),
|
||||
myStyle (Regular),
|
||||
myRectUpdated (true)
|
||||
myVertices (Quads),
|
||||
myBounds ()
|
||||
{
|
||||
SetString(string);
|
||||
UpdateGeometry();
|
||||
}
|
||||
|
||||
|
||||
|
@ -58,7 +63,7 @@ myRectUpdated (true)
|
|||
void Text::SetString(const String& string)
|
||||
{
|
||||
myString = string;
|
||||
myRectUpdated = false;
|
||||
UpdateGeometry();
|
||||
}
|
||||
|
||||
|
||||
|
@ -68,7 +73,7 @@ void Text::SetFont(const Font& font)
|
|||
if (myFont != &font)
|
||||
{
|
||||
myFont = &font;
|
||||
myRectUpdated = false;
|
||||
UpdateGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,7 +84,7 @@ void Text::SetCharacterSize(unsigned int size)
|
|||
if (myCharacterSize != size)
|
||||
{
|
||||
myCharacterSize = size;
|
||||
myRectUpdated = false;
|
||||
UpdateGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,7 +95,19 @@ void Text::SetStyle(Uint32 style)
|
|||
if (myStyle != style)
|
||||
{
|
||||
myStyle = style;
|
||||
myRectUpdated = false;
|
||||
UpdateGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Text::SetColor(const Color& color)
|
||||
{
|
||||
if (color != myColor)
|
||||
{
|
||||
myColor = color;
|
||||
for (unsigned int i = 0; i < myVertices.GetVerticesCount(); ++i)
|
||||
myVertices[i].Color = myColor;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,6 +122,7 @@ const String& Text::GetString() const
|
|||
////////////////////////////////////////////////////////////
|
||||
const Font& Text::GetFont() const
|
||||
{
|
||||
assert(myFont != NULL); // can never be NULL, always &Font::GetDefaultFont() by default
|
||||
return *myFont;
|
||||
}
|
||||
|
||||
|
@ -124,24 +142,29 @@ Uint32 Text::GetStyle() const
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2f Text::GetCharacterPos(std::size_t index) const
|
||||
const Color& Text::GetColor() const
|
||||
{
|
||||
// Make sure that we have a valid font
|
||||
if (!myFont)
|
||||
return Vector2f(0, 0);
|
||||
return myColor;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2f Text::FindCharacterPos(std::size_t index) const
|
||||
{
|
||||
assert(myFont != NULL);
|
||||
|
||||
// Adjust the index if it's out of range
|
||||
if (index > myString.GetSize())
|
||||
index = myString.GetSize();
|
||||
|
||||
// We'll need this a lot
|
||||
bool bold = (myStyle & Bold) != 0;
|
||||
float space = static_cast<float>(myFont->GetGlyph(L' ', myCharacterSize, bold).Advance);
|
||||
// Precompute the variables needed by the algorithm
|
||||
bool bold = (myStyle & Bold) != 0;
|
||||
float hspace = static_cast<float>(myFont->GetGlyph(L' ', myCharacterSize, bold).Advance);
|
||||
float vspace = static_cast<float>(myFont->GetLineSpacing(myCharacterSize));
|
||||
|
||||
// Compute the position
|
||||
Vector2f position;
|
||||
Uint32 prevChar = 0;
|
||||
float lineSpacing = static_cast<float>(myFont->GetLineSpacing(myCharacterSize));
|
||||
for (std::size_t i = 0; i < index; ++i)
|
||||
{
|
||||
Uint32 curChar = myString[i];
|
||||
|
@ -153,69 +176,75 @@ Vector2f Text::GetCharacterPos(std::size_t index) const
|
|||
// Handle special characters
|
||||
switch (curChar)
|
||||
{
|
||||
case L' ' : position.x += space; continue;
|
||||
case L'\t' : position.x += space * 4; continue;
|
||||
case L'\v' : position.y += lineSpacing * 4; continue;
|
||||
case L'\n' : position.y += lineSpacing; position.x = 0; continue;
|
||||
case L' ' : position.x += hspace; continue;
|
||||
case L'\t' : position.x += hspace * 4; continue;
|
||||
case L'\n' : position.y += vspace; position.x = 0; continue;
|
||||
case L'\v' : position.y += vspace * 4; continue;
|
||||
}
|
||||
|
||||
// For regular characters, add the advance offset of the glyph
|
||||
position.x += static_cast<float>(myFont->GetGlyph(curChar, myCharacterSize, bold).Advance);
|
||||
}
|
||||
|
||||
// Transform the position to global coordinates
|
||||
position = GetTransform().TransformPoint(position);
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
FloatRect Text::GetRect() const
|
||||
FloatRect Text::GetLocalBounds() const
|
||||
{
|
||||
UpdateRect();
|
||||
|
||||
FloatRect rect;
|
||||
rect.Left = (myBaseRect.Left - GetOrigin().x) * GetScale().x + GetPosition().x;
|
||||
rect.Top = (myBaseRect.Top - GetOrigin().y) * GetScale().y + GetPosition().y;
|
||||
rect.Width = myBaseRect.Width * GetScale().x;
|
||||
rect.Height = myBaseRect.Height * GetScale().y;
|
||||
|
||||
return rect;
|
||||
return myBounds;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Text::Render(RenderTarget&, Renderer& renderer) const
|
||||
FloatRect Text::GetGlobalBounds() const
|
||||
{
|
||||
// No text or not font: nothing to render
|
||||
if (!myFont || myString.IsEmpty())
|
||||
return GetTransform().TransformRect(GetLocalBounds());
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Text::Draw(RenderTarget& target, RenderStates states) const
|
||||
{
|
||||
assert(myFont != NULL);
|
||||
|
||||
states.Transform *= GetTransform();
|
||||
states.BlendMode = BlendAlpha; // alpha blending is mandatory for proper text rendering
|
||||
states.Texture = &myFont->GetTexture(myCharacterSize);
|
||||
target.Draw(myVertices, states);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Text::UpdateGeometry()
|
||||
{
|
||||
assert(myFont != NULL);
|
||||
|
||||
// Clear the previous geometry
|
||||
myVertices.Clear();
|
||||
|
||||
// No text: nothing to draw
|
||||
if (myString.IsEmpty())
|
||||
return;
|
||||
|
||||
// Bind the font texture
|
||||
const Texture& texture = myFont->GetTexture(myCharacterSize);
|
||||
renderer.SetTexture(&texture);
|
||||
// Compute values related to the text style
|
||||
bool bold = (myStyle & Bold) != 0;
|
||||
bool underlined = (myStyle & Underlined) != 0;
|
||||
float italic = (myStyle & Italic) ? 0.208f : 0.f; // 12 degrees
|
||||
float underlineOffset = myCharacterSize * 0.1f;
|
||||
float underlineThickness = myCharacterSize * (bold ? 0.1f : 0.07f);
|
||||
|
||||
// Computes values related to the text style
|
||||
bool bold = (myStyle & Bold) != 0;
|
||||
bool underlined = (myStyle & Underlined) != 0;
|
||||
float italicCoeff = (myStyle & Italic) ? 0.208f : 0.f; // 12 degrees
|
||||
float underlineOffset = myCharacterSize * 0.1f;
|
||||
float underlineThickness = myCharacterSize * (bold ? 0.1f : 0.07f);
|
||||
FloatRect underlineCoords = texture.GetTexCoords(IntRect(1, 1, 1, 1));
|
||||
float underlineLeft = underlineCoords.Left;
|
||||
float underlineTop = underlineCoords.Top;
|
||||
float underlineRight = underlineCoords.Left + underlineCoords.Width;
|
||||
float underlineBottom = underlineCoords.Top + underlineCoords.Height;
|
||||
// Precompute the variables needed by the algorithm
|
||||
float hspace = static_cast<float>(myFont->GetGlyph(L' ', myCharacterSize, bold).Advance);
|
||||
float vspace = static_cast<float>(myFont->GetLineSpacing(myCharacterSize));
|
||||
float x = 0.f;
|
||||
float y = static_cast<float>(myCharacterSize);
|
||||
|
||||
// Initialize the rendering coordinates
|
||||
float space = static_cast<float>(myFont->GetGlyph(L' ', myCharacterSize, bold).Advance);
|
||||
float lineSpacing = static_cast<float>(myFont->GetLineSpacing(myCharacterSize));
|
||||
float x = 0.f;
|
||||
float y = static_cast<float>(myCharacterSize);
|
||||
|
||||
// Note:
|
||||
// Here we use a Begin/End pair for each quad because
|
||||
// the font's texture may change in a call to GetGlyph
|
||||
|
||||
// Draw one quad for each character
|
||||
// Create one quad for each character
|
||||
Uint32 prevChar = 0;
|
||||
for (std::size_t i = 0; i < myString.GetSize(); ++i)
|
||||
{
|
||||
|
@ -231,44 +260,42 @@ void Text::Render(RenderTarget&, Renderer& renderer) const
|
|||
float top = y + underlineOffset;
|
||||
float bottom = top + underlineThickness;
|
||||
|
||||
renderer.Begin(Renderer::QuadList);
|
||||
renderer.AddVertex(0, top, underlineLeft, underlineTop);
|
||||
renderer.AddVertex(x, top, underlineRight, underlineTop);
|
||||
renderer.AddVertex(x, bottom, underlineRight, underlineBottom);
|
||||
renderer.AddVertex(0, bottom, underlineLeft, underlineBottom);
|
||||
renderer.End();
|
||||
myVertices.Append(Vertex(Vector2f(0, top), myColor, Vector2f(1, 1)));
|
||||
myVertices.Append(Vertex(Vector2f(x, top), myColor, Vector2f(2, 1)));
|
||||
myVertices.Append(Vertex(Vector2f(x, bottom), myColor, Vector2f(2, 2)));
|
||||
myVertices.Append(Vertex(Vector2f(0, bottom), myColor, Vector2f(1, 2)));
|
||||
}
|
||||
|
||||
// Handle special characters
|
||||
switch (curChar)
|
||||
{
|
||||
case L' ' : x += space; continue;
|
||||
case L'\t' : x += space * 4; continue;
|
||||
case L'\n' : y += lineSpacing; x = 0; continue;
|
||||
case L'\v' : y += lineSpacing * 4; continue;
|
||||
case L' ' : x += hspace; continue;
|
||||
case L'\t' : x += hspace * 4; continue;
|
||||
case L'\n' : y += vspace; x = 0; continue;
|
||||
case L'\v' : y += vspace * 4; continue;
|
||||
}
|
||||
|
||||
// Extract the current glyph's description
|
||||
const Glyph& glyph = myFont->GetGlyph(curChar, myCharacterSize, bold);
|
||||
int advance = glyph.Advance;
|
||||
const IntRect& bounds = glyph.Bounds;
|
||||
FloatRect coords = texture.GetTexCoords(glyph.SubRect);
|
||||
const Glyph& glyph = myFont->GetGlyph(curChar, myCharacterSize, bold);
|
||||
|
||||
int boundsRight = bounds.Left + bounds.Width;
|
||||
int boundsBottom = bounds.Top + bounds.Height;
|
||||
float coordsRight = coords.Left + coords.Width;
|
||||
float coordsBottom = coords.Top + coords.Height;
|
||||
int left = glyph.Bounds.Left;
|
||||
int top = glyph.Bounds.Top;
|
||||
int right = glyph.Bounds.Left + glyph.Bounds.Width;
|
||||
int bottom = glyph.Bounds.Top + glyph.Bounds.Height;
|
||||
|
||||
// Draw a textured quad for the current character
|
||||
renderer.Begin(Renderer::QuadList);
|
||||
renderer.AddVertex(x + bounds.Left - italicCoeff * bounds.Top, y + bounds.Top, coords.Left, coords.Top);
|
||||
renderer.AddVertex(x + boundsRight - italicCoeff * bounds.Top, y + bounds.Top, coordsRight, coords.Top);
|
||||
renderer.AddVertex(x + boundsRight - italicCoeff * boundsBottom, y + boundsBottom, coordsRight, coordsBottom);
|
||||
renderer.AddVertex(x + bounds.Left - italicCoeff * boundsBottom, y + boundsBottom, coords.Left, coordsBottom);
|
||||
renderer.End();
|
||||
float u1 = static_cast<float>(glyph.TextureRect.Left);
|
||||
float v1 = static_cast<float>(glyph.TextureRect.Top);
|
||||
float u2 = static_cast<float>(glyph.TextureRect.Left + glyph.TextureRect.Width);
|
||||
float v2 = static_cast<float>(glyph.TextureRect.Top + glyph.TextureRect.Height);
|
||||
|
||||
// Add a quad for the current character
|
||||
myVertices.Append(Vertex(Vector2f(x + left - italic * top, y + top), myColor, Vector2f(u1, v1)));
|
||||
myVertices.Append(Vertex(Vector2f(x + right - italic * top, y + top), myColor, Vector2f(u2, v1)));
|
||||
myVertices.Append(Vertex(Vector2f(x + right - italic * bottom, y + bottom), myColor, Vector2f(u2, v2)));
|
||||
myVertices.Append(Vertex(Vector2f(x + left - italic * bottom, y + bottom), myColor, Vector2f(u1, v2)));
|
||||
|
||||
// Advance to the next character
|
||||
x += advance;
|
||||
x += glyph.Advance;
|
||||
}
|
||||
|
||||
// If we're using the underlined style, add the last line
|
||||
|
@ -277,113 +304,14 @@ void Text::Render(RenderTarget&, Renderer& renderer) const
|
|||
float top = y + underlineOffset;
|
||||
float bottom = top + underlineThickness;
|
||||
|
||||
renderer.Begin(Renderer::QuadList);
|
||||
renderer.AddVertex(0, top, underlineLeft, underlineTop);
|
||||
renderer.AddVertex(x, top, underlineRight, underlineTop);
|
||||
renderer.AddVertex(x, bottom, underlineRight, underlineBottom);
|
||||
renderer.AddVertex(0, bottom, underlineLeft, underlineBottom);
|
||||
renderer.End();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Text::UpdateRect() const
|
||||
{
|
||||
if (myRectUpdated)
|
||||
return;
|
||||
|
||||
// Reset the previous states
|
||||
myRectUpdated = true;
|
||||
myBaseRect = FloatRect(0, 0, 0, 0);
|
||||
|
||||
// No text or not font: empty box
|
||||
if (!myFont || myString.IsEmpty())
|
||||
return;
|
||||
|
||||
// Initial values
|
||||
bool bold = (myStyle & Bold) != 0;
|
||||
float charSize = static_cast<float>(myCharacterSize);
|
||||
float space = static_cast<float>(myFont->GetGlyph(L' ', myCharacterSize, bold).Advance);
|
||||
float lineSpacing = static_cast<float>(myFont->GetLineSpacing(myCharacterSize));
|
||||
float curWidth = 0;
|
||||
float curHeight = 0;
|
||||
float width = 0;
|
||||
float height = 0;
|
||||
Uint32 prevChar = 0;
|
||||
|
||||
// Go through each character
|
||||
for (std::size_t i = 0; i < myString.GetSize(); ++i)
|
||||
{
|
||||
Uint32 curChar = myString[i];
|
||||
|
||||
// Apply the kerning offset
|
||||
curWidth += static_cast<float>(myFont->GetKerning(prevChar, curChar, myCharacterSize));
|
||||
prevChar = curChar;
|
||||
|
||||
// Handle special characters
|
||||
switch (curChar)
|
||||
{
|
||||
case L' ' :
|
||||
curWidth += space;
|
||||
continue;
|
||||
|
||||
case L'\t' :
|
||||
curWidth += space * 4;
|
||||
continue;
|
||||
|
||||
case L'\v' :
|
||||
height += lineSpacing * 4;
|
||||
curHeight = 0;
|
||||
continue;
|
||||
|
||||
case L'\n' :
|
||||
height += lineSpacing;
|
||||
curHeight = 0;
|
||||
if (curWidth > width)
|
||||
width = curWidth;
|
||||
curWidth = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Extract the current glyph's description
|
||||
const Glyph& curGlyph = myFont->GetGlyph(curChar, myCharacterSize, bold);
|
||||
|
||||
// Advance to the next character
|
||||
curWidth += static_cast<float>(curGlyph.Advance);
|
||||
|
||||
// Update the maximum height
|
||||
float charHeight = charSize + curGlyph.Bounds.Top + curGlyph.Bounds.Height;
|
||||
if (charHeight > curHeight)
|
||||
curHeight = charHeight;
|
||||
myVertices.Append(Vertex(Vector2f(0, top), myColor, Vector2f(1, 1)));
|
||||
myVertices.Append(Vertex(Vector2f(x, top), myColor, Vector2f(2, 1)));
|
||||
myVertices.Append(Vertex(Vector2f(x, bottom), myColor, Vector2f(2, 2)));
|
||||
myVertices.Append(Vertex(Vector2f(0, bottom), myColor, Vector2f(1, 2)));
|
||||
}
|
||||
|
||||
// Update the last line
|
||||
if (curWidth > width)
|
||||
width = curWidth;
|
||||
height += curHeight;
|
||||
|
||||
// Add a slight width if we're using the italic style
|
||||
if (myStyle & Italic)
|
||||
{
|
||||
width += 0.208f * charSize;
|
||||
}
|
||||
|
||||
// Add a slight height if we're using the underlined style
|
||||
if (myStyle & Underlined)
|
||||
{
|
||||
float underlineOffset = myCharacterSize * 0.1f;
|
||||
float underlineThickness = myCharacterSize * (bold ? 0.1f : 0.07f);
|
||||
|
||||
if (curHeight < charSize + underlineOffset + underlineThickness)
|
||||
height += underlineOffset + underlineThickness;
|
||||
}
|
||||
|
||||
// Finally update the rectangle
|
||||
myBaseRect.Left = 0;
|
||||
myBaseRect.Top = 0;
|
||||
myBaseRect.Width = width;
|
||||
myBaseRect.Height = height;
|
||||
// Recompute the bounding rectangle
|
||||
myBounds = myVertices.GetBounds();
|
||||
}
|
||||
|
||||
} // namespace sf
|
||||
|
|
|
@ -28,12 +28,33 @@
|
|||
#include <SFML/Graphics/Texture.hpp>
|
||||
#include <SFML/Graphics/Image.hpp>
|
||||
#include <SFML/Graphics/GLCheck.hpp>
|
||||
#include <SFML/Graphics/TextureSaver.hpp>
|
||||
#include <SFML/Window/Window.hpp>
|
||||
#include <SFML/System/Mutex.hpp>
|
||||
#include <SFML/System/Lock.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <cassert>
|
||||
#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
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
|
@ -44,7 +65,9 @@ myTextureWidth (0),
|
|||
myTextureHeight(0),
|
||||
myTexture (0),
|
||||
myIsSmooth (false),
|
||||
myPixelsFlipped(false)
|
||||
myIsRepeated (false),
|
||||
myPixelsFlipped(false),
|
||||
myCacheId (GetUniqueId())
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -58,7 +81,9 @@ myTextureWidth (0),
|
|||
myTextureHeight(0),
|
||||
myTexture (0),
|
||||
myIsSmooth (copy.myIsSmooth),
|
||||
myPixelsFlipped(false)
|
||||
myIsRepeated (copy.myIsRepeated),
|
||||
myPixelsFlipped(false),
|
||||
myCacheId (GetUniqueId())
|
||||
{
|
||||
if (copy.myTexture)
|
||||
LoadFromImage(copy.CopyToImage());
|
||||
|
@ -121,13 +146,17 @@ bool Texture::Create(unsigned int width, unsigned int height)
|
|||
myTexture = static_cast<unsigned int>(texture);
|
||||
}
|
||||
|
||||
// Make sure that the current texture binding will be preserved
|
||||
priv::TextureSaver save;
|
||||
|
||||
// Initialize the texture
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
||||
GLCheck(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, myTextureWidth, myTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
|
||||
GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
|
||||
GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 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_MAG_FILTER, myIsSmooth ? GL_LINEAR : GL_NEAREST));
|
||||
GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, myIsSmooth ? GL_LINEAR : GL_NEAREST));
|
||||
myCacheId = GetUniqueId();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -193,6 +222,9 @@ bool Texture::LoadFromImage(const Image& image, const IntRect& area)
|
|||
// Create the texture and upload the pixels
|
||||
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
|
||||
const Uint8* pixels = image.GetPixelsPtr() + 4 * (rectangle.Left + (width * rectangle.Top));
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
||||
|
@ -235,6 +267,9 @@ Image Texture::CopyToImage() const
|
|||
|
||||
EnsureGlContext();
|
||||
|
||||
// Make sure that the current texture binding will be preserved
|
||||
priv::TextureSaver save;
|
||||
|
||||
// Create an array of pixels
|
||||
std::vector<Uint8> pixels(myWidth * myHeight * 4);
|
||||
|
||||
|
@ -300,10 +335,14 @@ void Texture::Update(const Uint8* pixels, unsigned int width, unsigned int heigh
|
|||
{
|
||||
EnsureGlContext();
|
||||
|
||||
// Make sure that the current texture binding will be preserved
|
||||
priv::TextureSaver save;
|
||||
|
||||
// Copy pixels from the given array to the texture
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
||||
GLCheck(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
|
||||
myPixelsFlipped = false;
|
||||
myCacheId = GetUniqueId();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,18 +377,54 @@ void Texture::Update(const Window& window, unsigned int x, unsigned int y)
|
|||
|
||||
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
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
||||
GLCheck(glCopyTexSubImage2D(GL_TEXTURE_2D, 0, x, y, 0, 0, window.GetWidth(), window.GetHeight()));
|
||||
myPixelsFlipped = true;
|
||||
myCacheId = GetUniqueId();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Texture::Bind() const
|
||||
void Texture::Bind(CoordinateType coordinateType) const
|
||||
{
|
||||
// Bind the texture
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
||||
|
||||
// Check if we need to define a special texture matrix
|
||||
if ((coordinateType == Pixels) || myPixelsFlipped)
|
||||
{
|
||||
GLfloat matrix[16] = {1.f, 0.f, 0.f, 0.f,
|
||||
0.f, 1.f, 0.f, 0.f,
|
||||
0.f, 0.f, 1.f, 0.f,
|
||||
0.f, 0.f, 0.f, 1.f};
|
||||
|
||||
// If non-normalized coordinates (= pixels) are requested, we need to
|
||||
// setup scale factors that convert the range [0 .. size] to [0 .. 1]
|
||||
if (coordinateType == Pixels)
|
||||
{
|
||||
matrix[0] = 1.f / myTextureWidth;
|
||||
matrix[5] = 1.f / myTextureHeight;
|
||||
}
|
||||
|
||||
// If pixels are flipped we must invert the Y axis
|
||||
if (myPixelsFlipped)
|
||||
{
|
||||
matrix[5] = -matrix[5];
|
||||
matrix[13] = static_cast<float>(myHeight / myTextureHeight);
|
||||
}
|
||||
|
||||
// Load the matrix
|
||||
GLCheck(glMatrixMode(GL_TEXTURE));
|
||||
GLCheck(glLoadMatrixf(matrix));
|
||||
|
||||
// Go back to model-view mode (sf::RenderTarget relies on it)
|
||||
GLCheck(glMatrixMode(GL_MODELVIEW));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -364,6 +439,9 @@ void Texture::SetSmooth(bool smooth)
|
|||
{
|
||||
EnsureGlContext();
|
||||
|
||||
// Make sure that the current texture binding will be preserved
|
||||
priv::TextureSaver save;
|
||||
|
||||
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_MIN_FILTER, myIsSmooth ? GL_LINEAR : GL_NEAREST));
|
||||
|
@ -380,32 +458,31 @@ bool Texture::IsSmooth() const
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
FloatRect Texture::GetTexCoords(const IntRect& rect) const
|
||||
void Texture::SetRepeated(bool repeated)
|
||||
{
|
||||
if ((myTextureWidth != 0) && (myTextureHeight != 0))
|
||||
if (repeated != myIsRepeated)
|
||||
{
|
||||
float width = static_cast<float>(myTextureWidth);
|
||||
float height = static_cast<float>(myTextureHeight);
|
||||
myIsRepeated = repeated;
|
||||
|
||||
if (myPixelsFlipped)
|
||||
if (myTexture)
|
||||
{
|
||||
return FloatRect( rect.Left / width,
|
||||
(myHeight - rect.Top) / height,
|
||||
rect.Width / width,
|
||||
-rect.Height / height);
|
||||
}
|
||||
else
|
||||
{
|
||||
return FloatRect(rect.Left / width,
|
||||
rect.Top / height,
|
||||
rect.Width / width,
|
||||
rect.Height / height);
|
||||
EnsureGlContext();
|
||||
|
||||
// Make sure that the current texture binding will be preserved
|
||||
priv::TextureSaver save;
|
||||
|
||||
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_T, myIsRepeated ? GL_REPEAT : GL_CLAMP_TO_EDGE));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return FloatRect(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Texture::IsRepeated() const
|
||||
{
|
||||
return myIsRepeated;
|
||||
}
|
||||
|
||||
|
||||
|
@ -432,7 +509,9 @@ Texture& Texture::operator =(const Texture& right)
|
|||
std::swap(myTextureHeight, temp.myTextureHeight);
|
||||
std::swap(myTexture, temp.myTexture);
|
||||
std::swap(myIsSmooth, temp.myIsSmooth);
|
||||
std::swap(myIsRepeated, temp.myIsRepeated);
|
||||
std::swap(myPixelsFlipped, temp.myPixelsFlipped);
|
||||
myCacheId = GetUniqueId();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
|
|
@ -1,40 +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/Matrix3.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
// Static member data
|
||||
////////////////////////////////////////////////////////////
|
||||
const Matrix3 Matrix3::Identity(1, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 1);
|
||||
|
||||
} // namespace sf
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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
|
270
src/SFML/Graphics/Transform.cpp
Normal file
270
src/SFML/Graphics/Transform.cpp
Normal file
|
@ -0,0 +1,270 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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/Transform.hpp>
|
||||
#include <cmath>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
const Transform Transform::Identity;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Transform::Transform()
|
||||
{
|
||||
// Identity matrix
|
||||
myMatrix[0] = 1.f; myMatrix[4] = 0.f; myMatrix[8] = 0.f; myMatrix[12] = 0.f;
|
||||
myMatrix[1] = 0.f; myMatrix[5] = 1.f; myMatrix[9] = 0.f; myMatrix[13] = 0.f;
|
||||
myMatrix[2] = 0.f; myMatrix[6] = 0.f; myMatrix[10] = 1.f; myMatrix[14] = 0.f;
|
||||
myMatrix[3] = 0.f; myMatrix[7] = 0.f; myMatrix[11] = 0.f; myMatrix[15] = 1.f;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Transform::Transform(float a00, float a01, float a02,
|
||||
float a10, float a11, float a12,
|
||||
float a20, float a21, float a22)
|
||||
{
|
||||
myMatrix[0] = a00; myMatrix[4] = a01; myMatrix[8] = 0.f; myMatrix[12] = a02;
|
||||
myMatrix[1] = a10; myMatrix[5] = a11; myMatrix[9] = 0.f; myMatrix[13] = a12;
|
||||
myMatrix[2] = 0.f; myMatrix[6] = 0.f; myMatrix[10] = 1.f; myMatrix[14] = 0.f;
|
||||
myMatrix[3] = a20; myMatrix[7] = a21; myMatrix[11] = 0.f; myMatrix[15] = a22;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const float* Transform::GetMatrix() const
|
||||
{
|
||||
return myMatrix;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Transform Transform::GetInverse() const
|
||||
{
|
||||
// Compute the determinant
|
||||
float det = myMatrix[0] * (myMatrix[15] * myMatrix[5] - myMatrix[7] * myMatrix[13]) -
|
||||
myMatrix[1] * (myMatrix[15] * myMatrix[4] - myMatrix[7] * myMatrix[12]) +
|
||||
myMatrix[3] * (myMatrix[13] * myMatrix[4] - myMatrix[5] * myMatrix[12]);
|
||||
|
||||
// Compute the inverse if the determinant is not zero
|
||||
// (don't use an epsilon because the determinant may *really* be tiny)
|
||||
if (det != 0.f)
|
||||
{
|
||||
return Transform( (myMatrix[15] * myMatrix[5] - myMatrix[7] * myMatrix[13]) / det,
|
||||
-(myMatrix[15] * myMatrix[4] - myMatrix[7] * myMatrix[12]) / det,
|
||||
(myMatrix[13] * myMatrix[4] - myMatrix[5] * myMatrix[12]) / det,
|
||||
-(myMatrix[15] * myMatrix[1] - myMatrix[3] * myMatrix[13]) / det,
|
||||
(myMatrix[15] * myMatrix[0] - myMatrix[3] * myMatrix[12]) / det,
|
||||
-(myMatrix[13] * myMatrix[0] - myMatrix[1] * myMatrix[12]) / det,
|
||||
(myMatrix[7] * myMatrix[1] - myMatrix[3] * myMatrix[5]) / det,
|
||||
-(myMatrix[7] * myMatrix[0] - myMatrix[3] * myMatrix[4]) / det,
|
||||
(myMatrix[5] * myMatrix[0] - myMatrix[1] * myMatrix[4]) / det);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Identity;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2f Transform::TransformPoint(float x, float y) const
|
||||
{
|
||||
return Vector2f(myMatrix[0] * x + myMatrix[4] * y + myMatrix[12],
|
||||
myMatrix[1] * x + myMatrix[5] * y + myMatrix[13]);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2f Transform::TransformPoint(const Vector2f& point) const
|
||||
{
|
||||
return TransformPoint(point.x, point.y);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
FloatRect Transform::TransformRect(const FloatRect& rectangle) const
|
||||
{
|
||||
// Transform the 4 corners of the rectangle
|
||||
const Vector2f points[] =
|
||||
{
|
||||
TransformPoint(rectangle.Left, rectangle.Top),
|
||||
TransformPoint(rectangle.Left, rectangle.Top + rectangle.Height),
|
||||
TransformPoint(rectangle.Left + rectangle.Width, rectangle.Top),
|
||||
TransformPoint(rectangle.Left + rectangle.Width, rectangle.Top + rectangle.Height)
|
||||
};
|
||||
|
||||
// Compute the bounding rectangle of the transformed points
|
||||
float left = points[0].x;
|
||||
float top = points[0].y;
|
||||
float right = points[0].x;
|
||||
float bottom = points[0].y;
|
||||
for (int i = 1; i < 4; ++i)
|
||||
{
|
||||
if (points[i].x < left) left = points[i].x;
|
||||
else if (points[i].x > right) right = points[i].x;
|
||||
if (points[i].y < top) top = points[i].y;
|
||||
else if (points[i].y > bottom) bottom = points[i].y;
|
||||
}
|
||||
|
||||
return FloatRect(left, top, right - left, bottom - top);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Transform Transform::Combine(const Transform& transform) const
|
||||
{
|
||||
const float* a = myMatrix;
|
||||
const float* b = transform.myMatrix;
|
||||
|
||||
return Transform(a[0] * b[0] + a[4] * b[1] + a[12] * b[3],
|
||||
a[0] * b[4] + a[4] * b[5] + a[12] * b[7],
|
||||
a[0] * b[12] + a[4] * b[13] + a[12] * b[15],
|
||||
a[1] * b[0] + a[5] * b[1] + a[13] * b[3],
|
||||
a[1] * b[4] + a[5] * b[5] + a[13] * b[7],
|
||||
a[1] * b[12] + a[5] * b[13] + a[13] * b[15],
|
||||
a[3] * b[0] + a[7] * b[1] + a[15] * b[3],
|
||||
a[3] * b[4] + a[7] * b[5] + a[15] * b[7],
|
||||
a[3] * b[12] + a[7] * b[13] + a[15] * b[15]);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Transform& Transform::Translate(float x, float y)
|
||||
{
|
||||
Transform translation(1, 0, x,
|
||||
0, 1, y,
|
||||
0, 0, 1);
|
||||
|
||||
return *this = Combine(translation);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Transform& Transform::Translate(const Vector2f& offset)
|
||||
{
|
||||
return Translate(offset.x, offset.y);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Transform& Transform::Rotate(float angle)
|
||||
{
|
||||
float rad = angle * 3.141592654f / 180.f;
|
||||
float cos = std::cos(rad);
|
||||
float sin = std::sin(rad);
|
||||
|
||||
Transform rotation(cos, -sin, 0,
|
||||
sin, cos, 0,
|
||||
0, 0, 1);
|
||||
|
||||
return *this = Combine(rotation);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Transform& Transform::Rotate(float angle, float centerX, float centerY)
|
||||
{
|
||||
float rad = angle * 3.141592654f / 180.f;
|
||||
float cos = std::cos(rad);
|
||||
float sin = std::sin(rad);
|
||||
|
||||
Transform rotation(cos, -sin, centerX * (1 - cos) + centerY * sin,
|
||||
sin, cos, centerY * (1 - cos) - centerX * sin,
|
||||
0, 0, 1);
|
||||
|
||||
return *this = Combine(rotation);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Transform& Transform::Rotate(float angle, const Vector2f& center)
|
||||
{
|
||||
return Rotate(angle, center.x, center.y);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Transform& Transform::Scale(float scaleX, float scaleY)
|
||||
{
|
||||
Transform scaling(scaleX, 0, 0,
|
||||
0, scaleY, 0,
|
||||
0, 0, 1);
|
||||
|
||||
return *this = Combine(scaling);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Transform& Transform::Scale(float scaleX, float scaleY, float centerX, float centerY)
|
||||
{
|
||||
Transform scaling(scaleX, 0, centerX * (1 - scaleX),
|
||||
0, scaleY, centerY * (1 - scaleY),
|
||||
0, 0, 1);
|
||||
|
||||
return *this = Combine(scaling);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Transform& Transform::Scale(const Vector2f& factors)
|
||||
{
|
||||
return Scale(factors.x, factors.y);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Transform& Transform::Scale(const Vector2f& factors, const Vector2f& center)
|
||||
{
|
||||
return Scale(factors.x, factors.y, center.x, center.y);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Transform operator *(const Transform& left, const Transform& right)
|
||||
{
|
||||
return left.Combine(right);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Transform& operator *=(Transform& left, const Transform& right)
|
||||
{
|
||||
return left = left.Combine(right);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vector2f operator *(const Transform& left, const Vector2f& right)
|
||||
{
|
||||
return left.TransformPoint(right);
|
||||
}
|
||||
|
||||
} // namespace sf
|
216
src/SFML/Graphics/Transformable.cpp
Normal file
216
src/SFML/Graphics/Transformable.cpp
Normal file
|
@ -0,0 +1,216 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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/Transformable.hpp>
|
||||
#include <cmath>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
Transformable::Transformable() :
|
||||
myOrigin (0, 0),
|
||||
myPosition (0, 0),
|
||||
myRotation (0),
|
||||
myScale (1, 1),
|
||||
myTransform (),
|
||||
myTransformNeedUpdate (true),
|
||||
myInverseTransform (),
|
||||
myInverseTransformNeedUpdate(true)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Transformable::~Transformable()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Transformable::SetPosition(float x, float y)
|
||||
{
|
||||
myPosition.x = x;
|
||||
myPosition.y = y;
|
||||
myTransformNeedUpdate = true;
|
||||
myInverseTransformNeedUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Transformable::SetPosition(const Vector2f& position)
|
||||
{
|
||||
SetPosition(position.x, position.y);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Transformable::SetRotation(float angle)
|
||||
{
|
||||
myRotation = angle;
|
||||
myTransformNeedUpdate = true;
|
||||
myInverseTransformNeedUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Transformable::SetScale(float factorX, float factorY)
|
||||
{
|
||||
myScale.x = factorX;
|
||||
myScale.y = factorY;
|
||||
myTransformNeedUpdate = true;
|
||||
myInverseTransformNeedUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Transformable::SetScale(const Vector2f& factors)
|
||||
{
|
||||
SetScale(factors.x, factors.y);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Transformable::SetOrigin(float x, float y)
|
||||
{
|
||||
myOrigin.x = x;
|
||||
myOrigin.y = y;
|
||||
myTransformNeedUpdate = true;
|
||||
myInverseTransformNeedUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Transformable::SetOrigin(const Vector2f& origin)
|
||||
{
|
||||
SetOrigin(origin.x, origin.y);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const Vector2f& Transformable::GetPosition() const
|
||||
{
|
||||
return myPosition;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
float Transformable::GetRotation() const
|
||||
{
|
||||
return myRotation;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const Vector2f& Transformable::GetScale() const
|
||||
{
|
||||
return myScale;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const Vector2f& Transformable::GetOrigin() const
|
||||
{
|
||||
return myOrigin;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Transformable::Move(float offsetX, float offsetY)
|
||||
{
|
||||
SetPosition(myPosition.x + offsetX, myPosition.y + offsetY);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Transformable::Move(const Vector2f& offset)
|
||||
{
|
||||
SetPosition(myPosition.x + offset.x, myPosition.y + offset.y);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Transformable::Rotate(float angle)
|
||||
{
|
||||
SetRotation(myRotation + angle);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Transformable::Scale(float factorX, float factorY)
|
||||
{
|
||||
SetScale(myScale.x * factorX, myScale.y * factorY);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Transformable::Scale(const Vector2f& factor)
|
||||
{
|
||||
SetScale(myScale.x * factor.x, myScale.y * factor.y);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const Transform& Transformable::GetTransform() const
|
||||
{
|
||||
// Recompute the combined transform if needed
|
||||
if (myTransformNeedUpdate)
|
||||
{
|
||||
float angle = -myRotation * 3.141592654f / 180.f;
|
||||
float cosine = static_cast<float>(std::cos(angle));
|
||||
float sine = static_cast<float>(std::sin(angle));
|
||||
float sxc = myScale.x * cosine;
|
||||
float syc = myScale.y * cosine;
|
||||
float sxs = myScale.x * sine;
|
||||
float sys = myScale.y * sine;
|
||||
float tx = -myOrigin.x * sxc - myOrigin.y * sys + myPosition.x;
|
||||
float ty = myOrigin.x * sxs - myOrigin.y * syc + myPosition.y;
|
||||
|
||||
myTransform = Transform( sxc, sys, tx,
|
||||
-sxs, syc, ty,
|
||||
0.f, 0.f, 1.f);
|
||||
myTransformNeedUpdate = false;
|
||||
}
|
||||
|
||||
return myTransform;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const Transform& Transformable::GetInverseTransform() const
|
||||
{
|
||||
// Recompute the inverse transform if needed
|
||||
if (myInverseTransformNeedUpdate)
|
||||
{
|
||||
myInverseTransform = GetTransform().GetInverse();
|
||||
myInverseTransformNeedUpdate = false;
|
||||
}
|
||||
|
||||
return myInverseTransform;
|
||||
}
|
||||
|
||||
} // namespace sf
|
77
src/SFML/Graphics/Vertex.cpp
Normal file
77
src/SFML/Graphics/Vertex.cpp
Normal file
|
@ -0,0 +1,77 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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/Vertex.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
Vertex::Vertex() :
|
||||
Position (0, 0),
|
||||
Color (255, 255, 255),
|
||||
TexCoords(0, 0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vertex::Vertex(const Vector2f& position) :
|
||||
Position (position),
|
||||
Color (255, 255, 255),
|
||||
TexCoords(0, 0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vertex::Vertex(const Vector2f& position, const sf::Color& color) :
|
||||
Position (position),
|
||||
Color (color),
|
||||
TexCoords(0, 0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vertex::Vertex(const Vector2f& position, const Vector2f& texCoords) :
|
||||
Position (position),
|
||||
Color (255, 255, 255),
|
||||
TexCoords(texCoords)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vertex::Vertex(const Vector2f& position, const sf::Color& color, const Vector2f& texCoords) :
|
||||
Position (position),
|
||||
Color (color),
|
||||
TexCoords(texCoords)
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace sf
|
150
src/SFML/Graphics/VertexArray.cpp
Normal file
150
src/SFML/Graphics/VertexArray.cpp
Normal file
|
@ -0,0 +1,150 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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/VertexArray.hpp>
|
||||
#include <SFML/Graphics/RenderTarget.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
VertexArray::VertexArray() :
|
||||
myVertices (),
|
||||
myPrimitiveType(Points)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
VertexArray::VertexArray(PrimitiveType type, unsigned int verticesCount) :
|
||||
myVertices (verticesCount),
|
||||
myPrimitiveType(type)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int VertexArray::GetVerticesCount() const
|
||||
{
|
||||
return myVertices.size();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Vertex& VertexArray::operator [](unsigned int index)
|
||||
{
|
||||
return myVertices[index];
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const Vertex& VertexArray::operator [](unsigned int index) const
|
||||
{
|
||||
return myVertices[index];
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void VertexArray::Clear()
|
||||
{
|
||||
myVertices.clear();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void VertexArray::Resize(unsigned int verticesCount)
|
||||
{
|
||||
myVertices.resize(verticesCount);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void VertexArray::Append(const Vertex& vertex)
|
||||
{
|
||||
myVertices.push_back(vertex);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void VertexArray::SetPrimitiveType(PrimitiveType type)
|
||||
{
|
||||
myPrimitiveType = type;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
PrimitiveType VertexArray::GetPrimitiveType() const
|
||||
{
|
||||
return myPrimitiveType;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
FloatRect VertexArray::GetBounds() const
|
||||
{
|
||||
if (!myVertices.empty())
|
||||
{
|
||||
float left = myVertices[0].Position.x;
|
||||
float top = myVertices[0].Position.y;
|
||||
float right = myVertices[0].Position.x;
|
||||
float bottom = myVertices[0].Position.y;
|
||||
|
||||
for (std::size_t i = 0; i < myVertices.size(); ++i)
|
||||
{
|
||||
Vector2f position = myVertices[i].Position;
|
||||
|
||||
// Update left and right
|
||||
if (position.x < left)
|
||||
left = position.x;
|
||||
else if (position.x > right)
|
||||
right = position.x;
|
||||
|
||||
// Update top and bottom
|
||||
if (position.y < top)
|
||||
top = position.y;
|
||||
else if (position.y > bottom)
|
||||
bottom = position.y;
|
||||
}
|
||||
|
||||
return FloatRect(left, top, right - left, bottom - top);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Array is empty
|
||||
return FloatRect();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void VertexArray::Draw(RenderTarget& target, RenderStates states) const
|
||||
{
|
||||
if (!myVertices.empty())
|
||||
target.Draw(&myVertices[0], myVertices.size(), myPrimitiveType, states);
|
||||
}
|
||||
|
||||
} // namespace sf
|
|
@ -26,18 +26,19 @@
|
|||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/View.hpp>
|
||||
#include <cmath>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
View::View() :
|
||||
myCenter (),
|
||||
mySize (),
|
||||
myRotation (0),
|
||||
myViewport (0, 0, 1, 1),
|
||||
myMatrixUpdated (false),
|
||||
myInvMatrixUpdated(false)
|
||||
myCenter (),
|
||||
mySize (),
|
||||
myRotation (0),
|
||||
myViewport (0, 0, 1, 1),
|
||||
myTransformUpdated (false),
|
||||
myInvTransformUpdated(false)
|
||||
{
|
||||
Reset(FloatRect(0, 0, 1000, 1000));
|
||||
}
|
||||
|
@ -45,12 +46,12 @@ myInvMatrixUpdated(false)
|
|||
|
||||
////////////////////////////////////////////////////////////
|
||||
View::View(const FloatRect& rectangle) :
|
||||
myCenter (),
|
||||
mySize (),
|
||||
myRotation (0),
|
||||
myViewport (0, 0, 1, 1),
|
||||
myMatrixUpdated (false),
|
||||
myInvMatrixUpdated(false)
|
||||
myCenter (),
|
||||
mySize (),
|
||||
myRotation (0),
|
||||
myViewport (0, 0, 1, 1),
|
||||
myTransformUpdated (false),
|
||||
myInvTransformUpdated(false)
|
||||
{
|
||||
Reset(rectangle);
|
||||
}
|
||||
|
@ -58,12 +59,12 @@ myInvMatrixUpdated(false)
|
|||
|
||||
////////////////////////////////////////////////////////////
|
||||
View::View(const Vector2f& center, const Vector2f& size) :
|
||||
myCenter (center),
|
||||
mySize (size),
|
||||
myRotation (0),
|
||||
myViewport (0, 0, 1, 1),
|
||||
myMatrixUpdated (false),
|
||||
myInvMatrixUpdated(false)
|
||||
myCenter (center),
|
||||
mySize (size),
|
||||
myRotation (0),
|
||||
myViewport (0, 0, 1, 1),
|
||||
myTransformUpdated (false),
|
||||
myInvTransformUpdated(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -74,8 +75,8 @@ void View::SetCenter(float x, float y)
|
|||
myCenter.x = x;
|
||||
myCenter.y = y;
|
||||
|
||||
myMatrixUpdated = false;
|
||||
myInvMatrixUpdated = false;
|
||||
myTransformUpdated = false;
|
||||
myInvTransformUpdated = false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -92,8 +93,8 @@ void View::SetSize(float width, float height)
|
|||
mySize.x = width;
|
||||
mySize.y = height;
|
||||
|
||||
myMatrixUpdated = false;
|
||||
myInvMatrixUpdated = false;
|
||||
myTransformUpdated = false;
|
||||
myInvTransformUpdated = false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -111,8 +112,8 @@ void View::SetRotation(float angle)
|
|||
if (myRotation < 0)
|
||||
myRotation += 360.f;
|
||||
|
||||
myMatrixUpdated = false;
|
||||
myInvMatrixUpdated = false;
|
||||
myTransformUpdated = false;
|
||||
myInvTransformUpdated = false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -132,8 +133,8 @@ void View::Reset(const FloatRect& rectangle)
|
|||
mySize.y = rectangle.Height;
|
||||
myRotation = 0;
|
||||
|
||||
myMatrixUpdated = false;
|
||||
myInvMatrixUpdated = false;
|
||||
myTransformUpdated = false;
|
||||
myInvTransformUpdated = false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -194,30 +195,46 @@ void View::Zoom(float factor)
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const Matrix3& View::GetMatrix() const
|
||||
const Transform& View::GetTransform() const
|
||||
{
|
||||
// Recompute the matrix if needed
|
||||
if (!myMatrixUpdated)
|
||||
if (!myTransformUpdated)
|
||||
{
|
||||
myMatrix = Matrix3::Projection(myCenter, mySize, myRotation);
|
||||
myMatrixUpdated = true;
|
||||
// Rotation components
|
||||
float angle = myRotation * 3.141592654f / 180.f;
|
||||
float cosine = static_cast<float>(std::cos(angle));
|
||||
float sine = static_cast<float>(std::sin(angle));
|
||||
float tx = -myCenter.x * cosine - myCenter.y * sine + myCenter.x;
|
||||
float ty = myCenter.x * sine - myCenter.y * cosine + myCenter.y;
|
||||
|
||||
// Projection components
|
||||
float a = 2.f / mySize.x;
|
||||
float b = -2.f / mySize.y;
|
||||
float c = -a * myCenter.x;
|
||||
float d = -b * myCenter.y;
|
||||
|
||||
// Rebuild the projection matrix
|
||||
myTransform = Transform( a * cosine, a * sine, a * tx + c,
|
||||
-b * sine, b * cosine, b * ty + d,
|
||||
0.f, 0.f, 1.f);
|
||||
myTransformUpdated = true;
|
||||
}
|
||||
|
||||
return myMatrix;
|
||||
return myTransform;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const Matrix3& View::GetInverseMatrix() const
|
||||
const Transform& View::GetInverseTransform() const
|
||||
{
|
||||
// Recompute the matrix if needed
|
||||
if (!myInvMatrixUpdated)
|
||||
if (!myInvTransformUpdated)
|
||||
{
|
||||
myInverseMatrix = GetMatrix().GetInverse();
|
||||
myInvMatrixUpdated = true;
|
||||
myInverseTransform = GetTransform().GetInverse();
|
||||
myInvTransformUpdated = true;
|
||||
}
|
||||
|
||||
return myInverseMatrix;
|
||||
return myInverseTransform;
|
||||
}
|
||||
|
||||
} // namespace sf
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue