Split sf::Image into sf::Image and sf::Texture (implements issue #18)
This commit is contained in:
parent
d337a98321
commit
e509f01180
40 changed files with 1585 additions and 1294 deletions
|
@ -39,14 +39,10 @@ Sound::Sound()
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Sound::Sound(const SoundBuffer& buffer, bool loop, float pitch, float volume, const Vector3f& position) :
|
||||
Sound::Sound(const SoundBuffer& buffer) :
|
||||
myBuffer(NULL)
|
||||
{
|
||||
SetBuffer(buffer);
|
||||
SetLoop(loop);
|
||||
SetPitch(pitch);
|
||||
SetVolume(volume);
|
||||
SetPosition(position);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -25,14 +25,14 @@ set(SRC
|
|||
${INCROOT}/Rect.inl
|
||||
${SRCROOT}/Renderer.cpp
|
||||
${INCROOT}/Renderer.hpp
|
||||
${SRCROOT}/RenderImage.cpp
|
||||
${INCROOT}/RenderImage.hpp
|
||||
${SRCROOT}/RenderImageImpl.cpp
|
||||
${SRCROOT}/RenderImageImpl.hpp
|
||||
${SRCROOT}/RenderImageImplFBO.cpp
|
||||
${SRCROOT}/RenderImageImplFBO.hpp
|
||||
${SRCROOT}/RenderImageImplDefault.cpp
|
||||
${SRCROOT}/RenderImageImplDefault.hpp
|
||||
${SRCROOT}/RenderTexture.cpp
|
||||
${INCROOT}/RenderTexture.hpp
|
||||
${SRCROOT}/RenderTextureImpl.cpp
|
||||
${SRCROOT}/RenderTextureImpl.hpp
|
||||
${SRCROOT}/RenderTextureImplFBO.cpp
|
||||
${SRCROOT}/RenderTextureImplFBO.hpp
|
||||
${SRCROOT}/RenderTextureImplDefault.cpp
|
||||
${SRCROOT}/RenderTextureImplDefault.hpp
|
||||
${SRCROOT}/RenderTarget.cpp
|
||||
${INCROOT}/RenderTarget.hpp
|
||||
${SRCROOT}/RenderWindow.cpp
|
||||
|
@ -45,6 +45,8 @@ set(SRC
|
|||
${INCROOT}/Sprite.hpp
|
||||
${SRCROOT}/Text.cpp
|
||||
${INCROOT}/Text.hpp
|
||||
${SRCROOT}/Texture.cpp
|
||||
${INCROOT}/Texture.hpp
|
||||
${SRCROOT}/View.cpp
|
||||
${INCROOT}/View.hpp
|
||||
${SRCROOT}/stb_image/stb_image.h
|
||||
|
|
|
@ -33,20 +33,6 @@
|
|||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
Drawable::Drawable(const Vector2f& position, const Vector2f& scale, float rotation, const Color& color) :
|
||||
myPosition (position),
|
||||
myScale (scale),
|
||||
myOrigin (0, 0),
|
||||
myRotation (rotation),
|
||||
myColor (color),
|
||||
myBlendMode (Blend::Alpha),
|
||||
myMatrixUpdated (false),
|
||||
myInvMatrixUpdated(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Drawable::~Drawable()
|
||||
{
|
||||
|
@ -267,6 +253,20 @@ Vector2f Drawable::TransformToGlobal(const Vector2f& point) const
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
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
|
||||
{
|
||||
|
|
|
@ -309,7 +309,7 @@ int Font::GetLineSpacing(unsigned int characterSize) const
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const Image& Font::GetImage(unsigned int characterSize) const
|
||||
const Texture& Font::GetTexture(unsigned int characterSize) const
|
||||
{
|
||||
return myPages[characterSize].Texture;
|
||||
}
|
||||
|
@ -493,12 +493,11 @@ Glyph Font::LoadGlyph(Uint32 codePoint, unsigned int characterSize, bool bold) c
|
|||
}
|
||||
|
||||
// Write the pixels to the texture
|
||||
IntRect subrect = glyph.SubRect;
|
||||
subrect.Left += padding;
|
||||
subrect.Top += padding;
|
||||
subrect.Width -= 2 * padding;
|
||||
subrect.Height -= 2 * padding;
|
||||
page.Texture.UpdatePixels(&myPixelBuffer[0], subrect);
|
||||
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;
|
||||
page.Texture.Update(&myPixelBuffer[0], width, height, x, y);
|
||||
}
|
||||
|
||||
// Delete the FT glyph
|
||||
|
@ -545,19 +544,17 @@ IntRect Font::FindGlyphRect(Page& page, unsigned int width, unsigned int height)
|
|||
// Not enough space: resize the texture if possible
|
||||
unsigned int textureWidth = page.Texture.GetWidth();
|
||||
unsigned int textureHeight = page.Texture.GetHeight();
|
||||
if ((textureWidth * 2 <= Image::GetMaximumSize()) && (textureHeight * 2 <= Image::GetMaximumSize()))
|
||||
if ((textureWidth * 2 <= Texture::GetMaximumSize()) && (textureHeight * 2 <= Texture::GetMaximumSize()))
|
||||
{
|
||||
// Make the texture 2 times bigger
|
||||
std::size_t size = textureWidth * textureHeight * 4;
|
||||
std::vector<Uint8> pixels(size);
|
||||
memcpy(&pixels[0], page.Texture.GetPixelsPtr(), size);
|
||||
page.Texture.Create(textureWidth * 2, textureHeight * 2, Color(255, 255, 255, 0));
|
||||
page.Texture.UpdatePixels(&pixels[0], IntRect(0, 0, textureWidth, textureHeight));
|
||||
sf::Image pixels = page.Texture.CopyToImage();
|
||||
page.Texture.Create(textureWidth * 2, textureHeight * 2);
|
||||
page.Texture.Update(pixels);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Oops, we've reached the maximum texture size...
|
||||
Err() << "Failed to add a new character to the font: the maximum image size has been reached" << std::endl;
|
||||
Err() << "Failed to add a new character to the font: the maximum texture size has been reached" << std::endl;
|
||||
return IntRect(0, 0, 2, 2);
|
||||
}
|
||||
}
|
||||
|
@ -603,13 +600,17 @@ Font::Page::Page() :
|
|||
NextRow(2)
|
||||
{
|
||||
// Make sure that the texture is initialized by default
|
||||
Texture.Create(128, 128, Color(255, 255, 255, 0));
|
||||
Texture.SetSmooth(true);
|
||||
sf::Image image;
|
||||
image.Create(128, 128, Color(255, 255, 255, 0));
|
||||
|
||||
// Reserve a 2x2 white square for texturing underlines
|
||||
for (int x = 0; x < 2; ++x)
|
||||
for (int y = 0; y < 2; ++y)
|
||||
Texture.SetPixel(x, y, Color(255, 255, 255, 255));
|
||||
image.SetPixel(x, y, Color(255, 255, 255, 255));
|
||||
|
||||
// Create the texture
|
||||
Texture.LoadFromImage(image);
|
||||
Texture.SetSmooth(true);
|
||||
}
|
||||
|
||||
} // namespace sf
|
||||
|
|
|
@ -27,12 +27,8 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/Image.hpp>
|
||||
#include <SFML/Graphics/ImageLoader.hpp>
|
||||
#include <SFML/Graphics/RenderImage.hpp>
|
||||
#include <SFML/Graphics/RenderWindow.hpp>
|
||||
#include <SFML/Graphics/GLCheck.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
|
@ -40,54 +36,56 @@ namespace sf
|
|||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
Image::Image() :
|
||||
myWidth (0),
|
||||
myHeight (0),
|
||||
myTextureWidth (0),
|
||||
myTextureHeight (0),
|
||||
myTexture (0),
|
||||
myIsSmooth (false),
|
||||
myTextureUpdated(true),
|
||||
myArrayUpdated (true),
|
||||
myPixelsFlipped (false)
|
||||
myWidth (0),
|
||||
myHeight(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Image::Image(const Image& copy) :
|
||||
Resource<Image>()
|
||||
void Image::Create(unsigned int width, unsigned int height, const Color& color)
|
||||
{
|
||||
// First make sure that the source image is up-to-date
|
||||
copy.EnsureArrayUpdate();
|
||||
// Assign the new size
|
||||
myWidth = width;
|
||||
myHeight = height;
|
||||
|
||||
// Copy all its members
|
||||
myWidth = copy.myWidth;
|
||||
myHeight = copy.myHeight;
|
||||
myTextureWidth = copy.myTextureWidth;
|
||||
myTextureHeight = copy.myTextureHeight;
|
||||
myTexture = 0;
|
||||
myIsSmooth = copy.myIsSmooth;
|
||||
myPixels = copy.myPixels;
|
||||
myTextureUpdated = true;
|
||||
myArrayUpdated = true;
|
||||
myPixelsFlipped = false; // pixels can't be flipped, this is handled in copy.EnsureArrayUpdate()
|
||||
// Resize the pixel buffer
|
||||
myPixels.resize(width * height * 4);
|
||||
|
||||
// Create the texture
|
||||
CreateTexture(myWidth, myHeight);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Image::~Image()
|
||||
{
|
||||
// Destroy the OpenGL texture
|
||||
if (myTexture)
|
||||
// Fill it with the specified color
|
||||
Uint8* ptr = &myPixels[0];
|
||||
Uint8* end = ptr + myPixels.size();
|
||||
while (ptr < end)
|
||||
{
|
||||
EnsureGlContext();
|
||||
*ptr++ = color.r;
|
||||
*ptr++ = color.g;
|
||||
*ptr++ = color.b;
|
||||
*ptr++ = color.a;
|
||||
}
|
||||
}
|
||||
|
||||
GLuint Texture = static_cast<GLuint>(myTexture);
|
||||
GLCheck(glDeleteTextures(1, &Texture));
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Image::Create(unsigned int width, unsigned int height, const Uint8* pixels)
|
||||
{
|
||||
if (pixels)
|
||||
{
|
||||
// Assign the new size
|
||||
myWidth = width;
|
||||
myHeight = height;
|
||||
|
||||
// Copy the pixels
|
||||
std::size_t size = width * height * 4;
|
||||
myPixels.resize(size);
|
||||
std::memcpy(&myPixels[0], pixels, size); // faster than vector::assign
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create an empty image
|
||||
myWidth = 0;
|
||||
myHeight = 0;
|
||||
myPixels.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,142 +93,48 @@ Image::~Image()
|
|||
////////////////////////////////////////////////////////////
|
||||
bool Image::LoadFromFile(const std::string& filename)
|
||||
{
|
||||
// Forward the job to the image loader
|
||||
std::vector<Uint8> pixels;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
if (priv::ImageLoader::GetInstance().LoadImageFromFile(filename, pixels, width, height))
|
||||
{
|
||||
// Loading succeeded : we can create the texture
|
||||
if (CreateTexture(width, height))
|
||||
{
|
||||
// Copy the pixels
|
||||
myPixels.swap(pixels);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return priv::ImageLoader::GetInstance().LoadImageFromFile(filename, myPixels, myWidth, myHeight);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Image::LoadFromMemory(const void* data, std::size_t size)
|
||||
{
|
||||
// Forward the job to the image loader
|
||||
std::vector<Uint8> pixels;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
if (priv::ImageLoader::GetInstance().LoadImageFromMemory(data, size, pixels, width, height))
|
||||
{
|
||||
// Loading succeeded : we can create the texture
|
||||
if (CreateTexture(width, height))
|
||||
{
|
||||
// Copy the pixels
|
||||
myPixels.swap(pixels);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return priv::ImageLoader::GetInstance().LoadImageFromMemory(data, size, myPixels, myWidth, myHeight);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Image::LoadFromStream(InputStream& stream)
|
||||
{
|
||||
// Forward the job to the image loader
|
||||
std::vector<Uint8> pixels;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
if (priv::ImageLoader::GetInstance().LoadImageFromStream(stream, pixels, width, height))
|
||||
{
|
||||
// Loading succeeded : we can create the texture
|
||||
if (CreateTexture(width, height))
|
||||
{
|
||||
// Copy the pixels
|
||||
myPixels.swap(pixels);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Image::LoadFromPixels(unsigned int width, unsigned int height, const Uint8* data)
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
// Create the internal texture
|
||||
if (CreateTexture(width, height))
|
||||
{
|
||||
// Copy the pixels
|
||||
std::size_t size = width * height * 4;
|
||||
myPixels.resize(size);
|
||||
std::memcpy(&myPixels[0], data, size); // faster than vector::assign
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No data provided : create a white image
|
||||
return Create(width, height, Color(255, 255, 255));
|
||||
}
|
||||
return priv::ImageLoader::GetInstance().LoadImageFromStream(stream, myPixels, myWidth, myHeight);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Image::SaveToFile(const std::string& filename) const
|
||||
{
|
||||
// Check if the array of pixels needs to be updated
|
||||
EnsureArrayUpdate();
|
||||
|
||||
// Let the image loader save our pixel array into the image
|
||||
return priv::ImageLoader::GetInstance().SaveImageToFile(filename, myPixels, myWidth, myHeight);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Image::Create(unsigned int width, unsigned int height, const Color& color)
|
||||
unsigned int Image::GetWidth() const
|
||||
{
|
||||
// First create the texture
|
||||
if (CreateTexture(width, height))
|
||||
{
|
||||
// Resize the pixel buffer
|
||||
myPixels.resize(width * height * 4);
|
||||
return myWidth;
|
||||
}
|
||||
|
||||
// Fill it with the specified color
|
||||
Uint8* ptr = &myPixels[0];
|
||||
Uint8* end = ptr + myPixels.size();
|
||||
while (ptr < end)
|
||||
{
|
||||
*ptr++ = color.r;
|
||||
*ptr++ = color.g;
|
||||
*ptr++ = color.b;
|
||||
*ptr++ = color.a;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int Image::GetHeight() const
|
||||
{
|
||||
return myHeight;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Image::CreateMaskFromColor(const Color& color, Uint8 alpha)
|
||||
{
|
||||
// Check if the array of pixels needs to be updated
|
||||
EnsureArrayUpdate();
|
||||
|
||||
// Make sure that the image is not empty
|
||||
if (!myPixels.empty())
|
||||
{
|
||||
|
@ -243,9 +147,6 @@ void Image::CreateMaskFromColor(const Color& color, Uint8 alpha)
|
|||
ptr[3] = alpha;
|
||||
ptr += 4;
|
||||
}
|
||||
|
||||
// The texture will need to be updated
|
||||
myTextureUpdated = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -257,10 +158,6 @@ void Image::Copy(const Image& source, unsigned int destX, unsigned int destY, co
|
|||
if ((source.myWidth == 0) || (source.myHeight == 0) || (myWidth == 0) || (myHeight == 0))
|
||||
return;
|
||||
|
||||
// Make sure both images have up-to-date arrays
|
||||
EnsureArrayUpdate();
|
||||
source.EnsureArrayUpdate();
|
||||
|
||||
// Adjust the source rectangle
|
||||
IntRect srcRect = sourceRect;
|
||||
if (srcRect.Width == 0 || (srcRect.Height == 0))
|
||||
|
@ -330,84 +227,24 @@ void Image::Copy(const Image& source, unsigned int destX, unsigned int destY, co
|
|||
dstPixels += dstStride;
|
||||
}
|
||||
}
|
||||
|
||||
// The texture will need an update
|
||||
myTextureUpdated = false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Image::CopyScreen(RenderWindow& window, const IntRect& sourceRect)
|
||||
{
|
||||
// Adjust the source rectangle
|
||||
IntRect rect = sourceRect;
|
||||
if (rect.Width == 0 || (rect.Height == 0))
|
||||
{
|
||||
rect.Left = 0;
|
||||
rect.Top = 0;
|
||||
rect.Width = window.GetWidth();
|
||||
rect.Height = window.GetHeight();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rect.Left < 0) rect.Left = 0;
|
||||
if (rect.Top < 0) rect.Top = 0;
|
||||
if (rect.Width > static_cast<int>(window.GetWidth())) rect.Width = window.GetWidth();
|
||||
if (rect.Height > static_cast<int>(window.GetHeight())) rect.Height = window.GetHeight();
|
||||
}
|
||||
|
||||
// We can then create the texture
|
||||
if (window.SetActive() && CreateTexture(rect.Width, rect.Height))
|
||||
{
|
||||
GLint previous;
|
||||
GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous));
|
||||
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
||||
int y = window.GetHeight() - (rect.Top + rect.Height); // Y axis is inverted
|
||||
GLCheck(glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rect.Left, y, myWidth, myHeight));
|
||||
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, previous));
|
||||
|
||||
myTextureUpdated = true;
|
||||
myArrayUpdated = false;
|
||||
myPixelsFlipped = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Image::SetPixel(unsigned int x, unsigned int y, const Color& color)
|
||||
{
|
||||
// First check if the array of pixels needs to be updated
|
||||
EnsureArrayUpdate();
|
||||
|
||||
// Copy the color components
|
||||
Uint8* pixel = &myPixels[(x + y * myWidth) * 4];
|
||||
*pixel++ = color.r;
|
||||
*pixel++ = color.g;
|
||||
*pixel++ = color.b;
|
||||
*pixel++ = color.a;
|
||||
|
||||
// The texture will need to be updated
|
||||
myTextureUpdated = false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Color Image::GetPixel(unsigned int x, unsigned int y) const
|
||||
{
|
||||
// First check if the array of pixels needs to be updated
|
||||
EnsureArrayUpdate();
|
||||
|
||||
// Get the color at (x, y)
|
||||
const Uint8* pixel = &myPixels[(x + y * myWidth) * 4];
|
||||
|
||||
return Color(pixel[0], pixel[1], pixel[2], pixel[3]);
|
||||
}
|
||||
|
||||
|
@ -415,9 +252,6 @@ Color Image::GetPixel(unsigned int x, unsigned int y) const
|
|||
////////////////////////////////////////////////////////////
|
||||
const Uint8* Image::GetPixelsPtr() const
|
||||
{
|
||||
// First check if the array of pixels needs to be updated
|
||||
EnsureArrayUpdate();
|
||||
|
||||
if (!myPixels.empty())
|
||||
{
|
||||
return &myPixels[0];
|
||||
|
@ -429,339 +263,4 @@ const Uint8* Image::GetPixelsPtr() const
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Image::UpdatePixels(const Uint8* pixels)
|
||||
{
|
||||
if (pixels && myTexture)
|
||||
{
|
||||
EnsureGlContext();
|
||||
|
||||
GLint previous;
|
||||
GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous));
|
||||
|
||||
// Update the texture from the array of pixels
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
||||
GLCheck(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, myWidth, myHeight, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
|
||||
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, previous));
|
||||
|
||||
myArrayUpdated = false;
|
||||
myTextureUpdated = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Image::UpdatePixels(const Uint8* pixels, const IntRect& rectangle)
|
||||
{
|
||||
// Make sure that the texture is up-to-date
|
||||
EnsureTextureUpdate();
|
||||
|
||||
if (pixels && myTexture)
|
||||
{
|
||||
GLint previous;
|
||||
GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous));
|
||||
|
||||
// Update the texture from the array of pixels
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
||||
GLCheck(glTexSubImage2D(GL_TEXTURE_2D, 0, rectangle.Left, rectangle.Top, rectangle.Width, rectangle.Height, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
|
||||
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, previous));
|
||||
|
||||
// The pixel cache is no longer up-to-date
|
||||
myArrayUpdated = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Image::Bind() const
|
||||
{
|
||||
// First check if the texture needs to be updated
|
||||
EnsureTextureUpdate();
|
||||
|
||||
// Bind it
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Image::SetSmooth(bool smooth)
|
||||
{
|
||||
if (smooth != myIsSmooth)
|
||||
{
|
||||
myIsSmooth = smooth;
|
||||
|
||||
if (myTexture)
|
||||
{
|
||||
EnsureGlContext();
|
||||
|
||||
GLint previous;
|
||||
GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous));
|
||||
|
||||
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));
|
||||
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, previous));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int Image::GetWidth() const
|
||||
{
|
||||
return myWidth;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int Image::GetHeight() const
|
||||
{
|
||||
return myHeight;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Image::IsSmooth() const
|
||||
{
|
||||
return myIsSmooth;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
FloatRect Image::GetTexCoords(const IntRect& rect) const
|
||||
{
|
||||
if ((myTextureWidth != 0) && (myTextureHeight != 0))
|
||||
{
|
||||
float width = static_cast<float>(myTextureWidth);
|
||||
float height = static_cast<float>(myTextureHeight);
|
||||
|
||||
if (myPixelsFlipped)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return FloatRect(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int Image::GetMaximumSize()
|
||||
{
|
||||
EnsureGlContext();
|
||||
|
||||
GLint size;
|
||||
GLCheck(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size));
|
||||
|
||||
return static_cast<unsigned int>(size);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Image& Image::operator =(const Image& right)
|
||||
{
|
||||
Image temp(right);
|
||||
|
||||
std::swap(myWidth, temp.myWidth);
|
||||
std::swap(myHeight, temp.myHeight);
|
||||
std::swap(myTextureWidth, temp.myTextureWidth);
|
||||
std::swap(myTextureHeight, temp.myTextureHeight);
|
||||
std::swap(myTexture, temp.myTexture);
|
||||
std::swap(myIsSmooth, temp.myIsSmooth);
|
||||
std::swap(myArrayUpdated, temp.myArrayUpdated);
|
||||
std::swap(myTextureUpdated, temp.myTextureUpdated);
|
||||
std::swap(myPixelsFlipped, temp.myPixelsFlipped);
|
||||
std::swap(myPixels, temp.myPixels);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int Image::GetValidSize(unsigned int size)
|
||||
{
|
||||
EnsureGlContext();
|
||||
|
||||
// Make sure that GLEW is initialized
|
||||
priv::EnsureGlewInit();
|
||||
|
||||
if (GLEW_ARB_texture_non_power_of_two)
|
||||
{
|
||||
// If hardware supports NPOT textures, then just return the unmodified size
|
||||
return size;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If hardware doesn't support NPOT textures, we calculate the nearest power of two
|
||||
unsigned int powerOfTwo = 1;
|
||||
while (powerOfTwo < size)
|
||||
powerOfTwo *= 2;
|
||||
|
||||
return powerOfTwo;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Image::CreateTexture(unsigned int width, unsigned int height)
|
||||
{
|
||||
// Check if texture parameters are valid before creating it
|
||||
if (!width || !height)
|
||||
return false;
|
||||
|
||||
// Compute the internal texture dimensions depending on NPOT textures support
|
||||
unsigned int textureWidth = GetValidSize(width);
|
||||
unsigned int textureHeight = GetValidSize(height);
|
||||
|
||||
// Check the maximum texture size
|
||||
unsigned int maxSize = GetMaximumSize();
|
||||
if ((textureWidth > maxSize) || (textureHeight > maxSize))
|
||||
{
|
||||
Err() << "Failed to create image, its internal size is too high "
|
||||
<< "(" << textureWidth << "x" << textureHeight << ", "
|
||||
<< "maximum is " << maxSize << "x" << maxSize << ")"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// All the validity checks passed, we can store the new texture settings
|
||||
myWidth = width;
|
||||
myHeight = height;
|
||||
myTextureWidth = textureWidth;
|
||||
myTextureHeight = textureHeight;
|
||||
|
||||
EnsureGlContext();
|
||||
|
||||
// Create the OpenGL texture if it doesn't exist yet
|
||||
if (!myTexture)
|
||||
{
|
||||
GLuint texture;
|
||||
GLCheck(glGenTextures(1, &texture));
|
||||
myTexture = static_cast<unsigned int>(texture);
|
||||
}
|
||||
|
||||
// Initialize the texture
|
||||
GLint previous;
|
||||
GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous));
|
||||
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_MAG_FILTER, myIsSmooth ? GL_LINEAR : GL_NEAREST));
|
||||
GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, myIsSmooth ? GL_LINEAR : GL_NEAREST));
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, previous));
|
||||
|
||||
myTextureUpdated = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Image::EnsureTextureUpdate() const
|
||||
{
|
||||
if (!myTextureUpdated)
|
||||
{
|
||||
if (myTexture && !myPixels.empty())
|
||||
{
|
||||
EnsureGlContext();
|
||||
|
||||
GLint previous;
|
||||
GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous));
|
||||
|
||||
// Update the texture with the pixels array in RAM
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
||||
GLCheck(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, myWidth, myHeight, GL_RGBA, GL_UNSIGNED_BYTE, &myPixels[0]));
|
||||
myPixelsFlipped = false;
|
||||
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, previous));
|
||||
}
|
||||
|
||||
myTextureUpdated = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Image::EnsureArrayUpdate() const
|
||||
{
|
||||
if (!myArrayUpdated)
|
||||
{
|
||||
EnsureGlContext();
|
||||
|
||||
// Save the previous texture
|
||||
GLint previous;
|
||||
GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous));
|
||||
|
||||
// Resize the destination array of pixels
|
||||
myPixels.resize(myWidth * myHeight * 4);
|
||||
|
||||
if ((myWidth == myTextureWidth) && (myHeight == myTextureHeight) && !myPixelsFlipped)
|
||||
{
|
||||
// Texture and array have the same size, we can use a direct copy
|
||||
|
||||
// Copy pixels from texture to array
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
||||
GLCheck(glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &myPixels[0]));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Texture and array don't have the same size, we have to use a slower algorithm
|
||||
|
||||
// All the pixels will first be copied to a temporary array
|
||||
ColorArray allPixels(myTextureWidth * myTextureHeight * 4);
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
||||
GLCheck(glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &allPixels[0]));
|
||||
|
||||
// Then we copy the useful pixels from the temporary array to the final one
|
||||
const Uint8* src = &allPixels[0];
|
||||
Uint8* dst = &myPixels[0];
|
||||
int srcPitch = myTextureWidth * 4;
|
||||
int dstPitch = myWidth * 4;
|
||||
|
||||
// Handle the case where source pixels are flipped vertically
|
||||
if (myPixelsFlipped)
|
||||
{
|
||||
src += srcPitch * (myHeight - 1);
|
||||
srcPitch = -srcPitch;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < myHeight; ++i)
|
||||
{
|
||||
std::memcpy(dst, src, dstPitch);
|
||||
src += srcPitch;
|
||||
dst += dstPitch;
|
||||
}
|
||||
}
|
||||
|
||||
// Restore the previous texture
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, previous));
|
||||
|
||||
myArrayUpdated = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Image::Use() const
|
||||
{
|
||||
EnsureTextureUpdate();
|
||||
}
|
||||
|
||||
} // namespace sf
|
||||
|
|
|
@ -25,57 +25,57 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/RenderImage.hpp>
|
||||
#include <SFML/Graphics/RenderImageImplFBO.hpp>
|
||||
#include <SFML/Graphics/RenderImageImplDefault.hpp>
|
||||
#include <SFML/Graphics/RenderTexture.hpp>
|
||||
#include <SFML/Graphics/RenderTextureImplFBO.hpp>
|
||||
#include <SFML/Graphics/RenderTextureImplDefault.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderImage::RenderImage() :
|
||||
myRenderImage(NULL)
|
||||
RenderTexture::RenderTexture() :
|
||||
myRenderTexture(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderImage::~RenderImage()
|
||||
RenderTexture::~RenderTexture()
|
||||
{
|
||||
delete myRenderImage;
|
||||
delete myRenderTexture;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool RenderImage::Create(unsigned int width, unsigned int height, bool depthBuffer)
|
||||
bool RenderTexture::Create(unsigned int width, unsigned int height, bool depthBuffer)
|
||||
{
|
||||
// Create the image
|
||||
if (!myImage.Create(width, height))
|
||||
// Create the texture
|
||||
if (!myTexture.Create(width, height))
|
||||
{
|
||||
Err() << "Impossible to create render image (failed to create the target image)" << std::endl;
|
||||
Err() << "Impossible to create render texture (failed to create the target texture)" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// We disable smoothing by default for render images
|
||||
// We disable smoothing by default for render textures
|
||||
SetSmooth(false);
|
||||
|
||||
// Create the implementation
|
||||
delete myRenderImage;
|
||||
if (priv::RenderImageImplFBO::IsAvailable())
|
||||
delete myRenderTexture;
|
||||
if (priv::RenderTextureImplFBO::IsAvailable())
|
||||
{
|
||||
// Use frame-buffer object (FBO)
|
||||
myRenderImage = new priv::RenderImageImplFBO;
|
||||
myRenderTexture = new priv::RenderTextureImplFBO;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use default implementation
|
||||
myRenderImage = new priv::RenderImageImplDefault;
|
||||
myRenderTexture = new priv::RenderTextureImplDefault;
|
||||
}
|
||||
|
||||
// Initialize the render image
|
||||
if (!myRenderImage->Create(width, height, myImage.myTexture, depthBuffer))
|
||||
// Initialize the render texture
|
||||
if (!myRenderTexture->Create(width, height, myTexture.myTexture, depthBuffer))
|
||||
return false;
|
||||
|
||||
// We can now initialize the render target part
|
||||
|
@ -86,64 +86,61 @@ bool RenderImage::Create(unsigned int width, unsigned int height, bool depthBuff
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderImage::SetSmooth(bool smooth)
|
||||
void RenderTexture::SetSmooth(bool smooth)
|
||||
{
|
||||
myImage.SetSmooth(smooth);
|
||||
myTexture.SetSmooth(smooth);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool RenderImage::IsSmooth() const
|
||||
bool RenderTexture::IsSmooth() const
|
||||
{
|
||||
return myImage.IsSmooth();
|
||||
return myTexture.IsSmooth();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool RenderImage::SetActive(bool active)
|
||||
bool RenderTexture::SetActive(bool active)
|
||||
{
|
||||
return myRenderImage && myRenderImage->Activate(active);
|
||||
return myRenderTexture && myRenderTexture->Activate(active);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderImage::Display()
|
||||
void RenderTexture::Display()
|
||||
{
|
||||
// Update the target image
|
||||
// Update the target texture
|
||||
if (SetActive(true))
|
||||
{
|
||||
myRenderImage->UpdateTexture(myImage.myTexture);
|
||||
|
||||
myImage.myPixelsFlipped = true;
|
||||
myImage.myArrayUpdated = false;
|
||||
myImage.myTextureUpdated = true;
|
||||
myRenderTexture->UpdateTexture(myTexture.myTexture);
|
||||
myTexture.myPixelsFlipped = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int RenderImage::GetWidth() const
|
||||
unsigned int RenderTexture::GetWidth() const
|
||||
{
|
||||
return myImage.GetWidth();
|
||||
return myTexture.GetWidth();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int RenderImage::GetHeight() const
|
||||
unsigned int RenderTexture::GetHeight() const
|
||||
{
|
||||
return myImage.GetHeight();
|
||||
return myTexture.GetHeight();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const Image& RenderImage::GetImage() const
|
||||
const Texture& RenderTexture::GetTexture() const
|
||||
{
|
||||
return myImage;
|
||||
return myTexture;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool RenderImage::Activate(bool active)
|
||||
bool RenderTexture::Activate(bool active)
|
||||
{
|
||||
return SetActive(active);
|
||||
}
|
|
@ -25,7 +25,7 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/RenderImageImpl.hpp>
|
||||
#include <SFML/Graphics/RenderTextureImpl.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
|
@ -33,7 +33,7 @@ namespace sf
|
|||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderImageImpl::~RenderImageImpl()
|
||||
RenderTextureImpl::~RenderTextureImpl()
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
|
@ -22,8 +22,8 @@
|
|||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SFML_RENDERIMAGEIMPL_HPP
|
||||
#define SFML_RENDERIMAGEIMPL_HPP
|
||||
#ifndef SFML_RENDERTEXTUREIMPL_HPP
|
||||
#define SFML_RENDERTEXTUREIMPL_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
|
@ -36,10 +36,10 @@ namespace sf
|
|||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Abstract base class for render-image implementations
|
||||
/// \brief Abstract base class for render-texture implementations
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class RenderImageImpl : NonCopyable
|
||||
class RenderTextureImpl : NonCopyable
|
||||
{
|
||||
public :
|
||||
|
||||
|
@ -47,14 +47,14 @@ public :
|
|||
/// \brief Destructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
virtual ~RenderImageImpl();
|
||||
virtual ~RenderTextureImpl();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create the render image implementation
|
||||
/// \brief Create the render texture implementation
|
||||
///
|
||||
/// \param width Width of the image to render to
|
||||
/// \param height Height of the image to render to
|
||||
/// \param textureId OpenGL texture identifier of the target image
|
||||
/// \param width Width of the texture to render to
|
||||
/// \param height Height of the texture to render to
|
||||
/// \param textureId OpenGL identifier of the target texture
|
||||
/// \param depthBuffer Is a depth buffer requested?
|
||||
///
|
||||
/// \return True if creation has been successful
|
||||
|
@ -63,7 +63,7 @@ public :
|
|||
virtual bool Create(unsigned int width, unsigned int height, unsigned int textureId, bool depthBuffer) = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Activate or deactivate the render image for rendering
|
||||
/// \brief Activate or deactivate the render texture for rendering
|
||||
///
|
||||
/// \param active True to activate, false to deactivate
|
||||
///
|
||||
|
@ -86,4 +86,4 @@ public :
|
|||
} // namespace sf
|
||||
|
||||
|
||||
#endif // SFML_RENDERIMAGEIMPL_HPP
|
||||
#endif // SFML_RENDERTEXTUREIMPL_HPP
|
|
@ -25,7 +25,7 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/RenderImageImplDefault.hpp>
|
||||
#include <SFML/Graphics/RenderTextureImplDefault.hpp>
|
||||
#include <SFML/Graphics/GLCheck.hpp>
|
||||
#include <SFML/Window/Context.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
|
@ -36,7 +36,7 @@ namespace sf
|
|||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderImageImplDefault::RenderImageImplDefault() :
|
||||
RenderTextureImplDefault::RenderTextureImplDefault() :
|
||||
myContext(0),
|
||||
myWidth (0),
|
||||
myHeight (0)
|
||||
|
@ -46,7 +46,7 @@ myHeight (0)
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderImageImplDefault::~RenderImageImplDefault()
|
||||
RenderTextureImplDefault::~RenderTextureImplDefault()
|
||||
{
|
||||
// Destroy the context
|
||||
delete myContext;
|
||||
|
@ -54,33 +54,33 @@ RenderImageImplDefault::~RenderImageImplDefault()
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool RenderImageImplDefault::Create(unsigned int width, unsigned int height, unsigned int, bool depthBuffer)
|
||||
bool RenderTextureImplDefault::Create(unsigned int width, unsigned int height, unsigned int, bool depthBuffer)
|
||||
{
|
||||
// Store the dimensions
|
||||
myWidth = width;
|
||||
myHeight = height;
|
||||
|
||||
// Create the in-memory OpenGL context
|
||||
myContext = new Context(ContextSettings(depthBuffer ? 32 : 0, 0, 4), width, height);
|
||||
myContext = new Context(ContextSettings(depthBuffer ? 32 : 0), width, height);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool RenderImageImplDefault::Activate(bool active)
|
||||
bool RenderTextureImplDefault::Activate(bool active)
|
||||
{
|
||||
return myContext->SetActive(active);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderImageImplDefault::UpdateTexture(unsigned int textureId)
|
||||
void RenderTextureImplDefault::UpdateTexture(unsigned int textureId)
|
||||
{
|
||||
GLint previous;
|
||||
GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous));
|
||||
|
||||
// Copy the rendered pixels to the image
|
||||
// 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));
|
||||
|
|
@ -22,13 +22,13 @@
|
|||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SFML_RENDERIMAGEIMPLDEFAULT_HPP
|
||||
#define SFML_RENDERIMAGEIMPLDEFAULT_HPP
|
||||
#ifndef SFML_RENDERTEXTUREIMPLDEFAULT_HPP
|
||||
#define SFML_RENDERTEXTUREIMPLDEFAULT_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/RenderImageImpl.hpp>
|
||||
#include <SFML/Graphics/RenderTextureImpl.hpp>
|
||||
#include <SFML/Window/GlResource.hpp>
|
||||
#include <SFML/Window/Context.hpp>
|
||||
|
||||
|
@ -38,11 +38,11 @@ namespace sf
|
|||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Default specialization of RenderImageImpl,
|
||||
/// \brief Default specialization of RenderTextureImpl,
|
||||
/// using a in-memory context
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class RenderImageImplDefault : public RenderImageImpl, GlResource
|
||||
class RenderTextureImplDefault : public RenderTextureImpl, GlResource
|
||||
{
|
||||
public :
|
||||
|
||||
|
@ -50,22 +50,22 @@ public :
|
|||
/// \brief Default constructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderImageImplDefault();
|
||||
RenderTextureImplDefault();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Destructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
~RenderImageImplDefault();
|
||||
~RenderTextureImplDefault();
|
||||
|
||||
private :
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create the render image implementation
|
||||
/// \brief Create the render texture implementation
|
||||
///
|
||||
/// \param width Width of the image to render to
|
||||
/// \param height Height of the image to render to
|
||||
/// \param textureId OpenGL texture identifier of the target image
|
||||
/// \param width Width of the texture to render to
|
||||
/// \param height Height of the texture to render to
|
||||
/// \param textureId OpenGL identifier of the target texture
|
||||
/// \param depthBuffer Is a depth buffer requested?
|
||||
///
|
||||
/// \return True if creation has been successful
|
||||
|
@ -74,7 +74,7 @@ private :
|
|||
virtual bool Create(unsigned int width, unsigned int height, unsigned int textureId, bool depthBuffer);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Activate or deactivate the render image for rendering
|
||||
/// \brief Activate or deactivate the render texture for rendering
|
||||
///
|
||||
/// \param active True to activate, false to deactivate
|
||||
///
|
||||
|
@ -104,4 +104,4 @@ private :
|
|||
} // namespace sf
|
||||
|
||||
|
||||
#endif // SFML_RENDERIMAGEIMPLDEFAULT_HPP
|
||||
#endif // SFML_RENDERTEXTUREIMPLDEFAULT_HPP
|
|
@ -25,8 +25,8 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/RenderImageImplFBO.hpp>
|
||||
#include <SFML/Graphics/Image.hpp>
|
||||
#include <SFML/Graphics/RenderTextureImplFBO.hpp>
|
||||
#include <SFML/Graphics/Texture.hpp>
|
||||
#include <SFML/Graphics/GLCheck.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
|
||||
|
@ -36,7 +36,7 @@ namespace sf
|
|||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderImageImplFBO::RenderImageImplFBO() :
|
||||
RenderTextureImplFBO::RenderTextureImplFBO() :
|
||||
myFrameBuffer(0),
|
||||
myDepthBuffer(0)
|
||||
{
|
||||
|
@ -45,7 +45,7 @@ myDepthBuffer(0)
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderImageImplFBO::~RenderImageImplFBO()
|
||||
RenderTextureImplFBO::~RenderTextureImplFBO()
|
||||
{
|
||||
EnsureGlContext();
|
||||
|
||||
|
@ -69,7 +69,7 @@ RenderImageImplFBO::~RenderImageImplFBO()
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool RenderImageImplFBO::IsAvailable()
|
||||
bool RenderTextureImplFBO::IsAvailable()
|
||||
{
|
||||
EnsureGlContext();
|
||||
|
||||
|
@ -81,7 +81,7 @@ bool RenderImageImplFBO::IsAvailable()
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool RenderImageImplFBO::Create(unsigned int width, unsigned int height, unsigned int textureId, bool depthBuffer)
|
||||
bool RenderTextureImplFBO::Create(unsigned int width, unsigned int height, unsigned int textureId, bool depthBuffer)
|
||||
{
|
||||
//Create the context
|
||||
myContext = new Context;
|
||||
|
@ -92,7 +92,7 @@ bool RenderImageImplFBO::Create(unsigned int width, unsigned int height, unsigne
|
|||
myFrameBuffer = static_cast<unsigned int>(frameBuffer);
|
||||
if (!myFrameBuffer)
|
||||
{
|
||||
Err() << "Impossible to create render image (failed to create the frame buffer object)" << std::endl;
|
||||
Err() << "Impossible to create render texture (failed to create the frame buffer object)" << std::endl;
|
||||
return false;
|
||||
}
|
||||
GLCheck(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, myFrameBuffer));
|
||||
|
@ -105,7 +105,7 @@ bool RenderImageImplFBO::Create(unsigned int width, unsigned int height, unsigne
|
|||
myDepthBuffer = static_cast<unsigned int>(depth);
|
||||
if (!myDepthBuffer)
|
||||
{
|
||||
Err() << "Impossible to create render image (failed to create the attached depth buffer)" << std::endl;
|
||||
Err() << "Impossible to create render texture (failed to create the attached depth buffer)" << std::endl;
|
||||
return false;
|
||||
}
|
||||
GLCheck(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, myDepthBuffer));
|
||||
|
@ -113,14 +113,14 @@ bool RenderImageImplFBO::Create(unsigned int width, unsigned int height, unsigne
|
|||
GLCheck(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, myDepthBuffer));
|
||||
}
|
||||
|
||||
// Link the image to the frame buffer
|
||||
// Link the texture to the frame buffer
|
||||
GLCheck(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, textureId, 0));
|
||||
|
||||
// A final check, just to be sure...
|
||||
if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT)
|
||||
{
|
||||
GLCheck(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
|
||||
Err() << "Impossible to create render image (failed to link the target image to the frame buffer)" << std::endl;
|
||||
Err() << "Impossible to create render texture (failed to link the target texture to the frame buffer)" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -129,13 +129,13 @@ bool RenderImageImplFBO::Create(unsigned int width, unsigned int height, unsigne
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool RenderImageImplFBO::Activate(bool active)
|
||||
bool RenderTextureImplFBO::Activate(bool active)
|
||||
{
|
||||
return myContext->SetActive(active);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderImageImplFBO::UpdateTexture(unsigned int)
|
||||
void RenderTextureImplFBO::UpdateTexture(unsigned int)
|
||||
{
|
||||
glFlush();
|
||||
}
|
|
@ -22,13 +22,13 @@
|
|||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SFML_RENDERIMAGEIMPLFBO_HPP
|
||||
#define SFML_RENDERIMAGEIMPLFBO_HPP
|
||||
#ifndef SFML_RENDERTEXTUREIMPLFBO_HPP
|
||||
#define SFML_RENDERTEXTUREIMPLFBO_HPP
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/RenderImageImpl.hpp>
|
||||
#include <SFML/Graphics/RenderTextureImpl.hpp>
|
||||
#include <SFML/Window/Context.hpp>
|
||||
#include <SFML/Window/GlResource.hpp>
|
||||
|
||||
|
@ -38,11 +38,11 @@ namespace sf
|
|||
namespace priv
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Specialization of RenderImageImpl using the
|
||||
/// Frame Buffer Object OpenGL extension
|
||||
/// \brief Specialization of RenderTextureImpl using the
|
||||
/// FrameBuffer Object OpenGL extension
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
class RenderImageImplFBO : public RenderImageImpl, GlResource
|
||||
class RenderTextureImplFBO : public RenderTextureImpl, GlResource
|
||||
{
|
||||
public :
|
||||
|
||||
|
@ -50,18 +50,18 @@ public :
|
|||
/// \brief Default constructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
RenderImageImplFBO();
|
||||
RenderTextureImplFBO();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Destructor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
~RenderImageImplFBO();
|
||||
~RenderTextureImplFBO();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Check whether the system supports FBOs or not
|
||||
///
|
||||
/// \return True if FBO render images are supported
|
||||
/// \return True if FBO render textures are supported
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
static bool IsAvailable();
|
||||
|
@ -69,11 +69,11 @@ public :
|
|||
private :
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create the render image implementation
|
||||
/// \brief Create the render texture implementation
|
||||
///
|
||||
/// \param width Width of the image to render to
|
||||
/// \param height Height of the image to render to
|
||||
/// \param textureId OpenGL texture identifier of the target image
|
||||
/// \param width Width of the texture to render to
|
||||
/// \param height Height of the texture to render to
|
||||
/// \param textureId OpenGL identifier of the target texture
|
||||
/// \param depthBuffer Is a depth buffer requested?
|
||||
///
|
||||
/// \return True if creation has been successful
|
||||
|
@ -82,7 +82,7 @@ private :
|
|||
virtual bool Create(unsigned int width, unsigned int height, unsigned int textureId, bool depthBuffer);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Activate or deactivate the render image for rendering
|
||||
/// \brief Activate or deactivate the render texture for rendering
|
||||
///
|
||||
/// \param active True to activate, false to deactivate
|
||||
///
|
||||
|
@ -112,4 +112,4 @@ private :
|
|||
} // namespace sf
|
||||
|
||||
|
||||
#endif // SFML_RENDERIMAGEIMPLFBO_HPP
|
||||
#endif // SFML_RENDERTEXTUREIMPLFBO_HPP
|
|
@ -26,6 +26,7 @@
|
|||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/RenderWindow.hpp>
|
||||
#include <SFML/Graphics/GLCheck.hpp>
|
||||
|
||||
|
||||
namespace sf
|
||||
|
@ -81,6 +82,30 @@ unsigned int RenderWindow::GetHeight() const
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Image RenderWindow::Capture() const
|
||||
{
|
||||
Image image;
|
||||
if (SetActive())
|
||||
{
|
||||
int width = static_cast<int>(GetWidth());
|
||||
int height = static_cast<int>(GetHeight());
|
||||
|
||||
// copy rows one by one and flip them (OpenGL's origin is bottom while SFML's origin is top)
|
||||
std::vector<Uint8> pixels(width * height * 4);
|
||||
for (int i = 0; i < height; ++i)
|
||||
{
|
||||
Uint8* ptr = &pixels[i * width * 4];
|
||||
GLCheck(glReadPixels(0, height - i - 1, width, 1, GL_RGBA, GL_UNSIGNED_BYTE, ptr));
|
||||
}
|
||||
|
||||
image.Create(width, height, &pixels[0]);
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void RenderWindow::OnCreate()
|
||||
{
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/Renderer.hpp>
|
||||
#include <SFML/Graphics/RenderTarget.hpp>
|
||||
#include <SFML/Graphics/Image.hpp>
|
||||
#include <SFML/Graphics/Texture.hpp>
|
||||
#include <SFML/Graphics/Shader.hpp>
|
||||
#include <SFML/Graphics/GLCheck.hpp>
|
||||
|
||||
|
@ -202,7 +202,7 @@ void Renderer::SetBlendMode(Blend::Mode mode)
|
|||
{
|
||||
// Alpha blending
|
||||
// glBlendFuncSeparateEXT is used when available to avoid an incorrect alpha value when the target
|
||||
// is a RenderImage -- in this case the alpha value must be written directly to the target buffer
|
||||
// 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)
|
||||
|
@ -231,7 +231,7 @@ void Renderer::SetBlendMode(Blend::Mode mode)
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Renderer::SetTexture(const Image* texture)
|
||||
void Renderer::SetTexture(const Texture* texture)
|
||||
{
|
||||
if ((texture != myTexture) || (texture && (texture->myTexture != myTextureId)) || !myTextureIsValid)
|
||||
{
|
||||
|
@ -246,12 +246,6 @@ void Renderer::SetTexture(const Image* texture)
|
|||
myTextureId = texture ? texture->myTexture : 0;
|
||||
myTextureIsValid = true;
|
||||
}
|
||||
else if (texture && myTextureIsValid)
|
||||
{
|
||||
// If the texture was already the current one, make sure that
|
||||
// it is synchronized (in case it was modified since last use)
|
||||
texture->Use();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -225,7 +225,7 @@ void Shader::SetParameter(const std::string& name, const Vector3f& v)
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Shader::SetTexture(const std::string& name, const Image& texture)
|
||||
void Shader::SetTexture(const std::string& name, const Texture& texture)
|
||||
{
|
||||
if (myShaderProgram)
|
||||
{
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/Sprite.hpp>
|
||||
#include <SFML/Graphics/Image.hpp>
|
||||
#include <SFML/Graphics/Texture.hpp>
|
||||
#include <SFML/Graphics/Renderer.hpp>
|
||||
#include <utility>
|
||||
|
||||
|
@ -35,6 +35,7 @@ namespace sf
|
|||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
Sprite::Sprite() :
|
||||
Drawable (),
|
||||
mySubRect (0, 0, 1, 1),
|
||||
myIsFlippedX(false),
|
||||
myIsFlippedY(false)
|
||||
|
@ -44,31 +45,31 @@ myIsFlippedY(false)
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Sprite::Sprite(const Image& image, const Vector2f& position, const Vector2f& scale, float rotation, const Color& color) :
|
||||
Drawable (position, scale, rotation, color),
|
||||
Sprite::Sprite(const Texture& texture) :
|
||||
Drawable (),
|
||||
mySubRect (0, 0, 1, 1),
|
||||
myIsFlippedX(false),
|
||||
myIsFlippedY(false)
|
||||
{
|
||||
SetImage(image);
|
||||
SetTexture(texture);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Sprite::SetImage(const Image& image, bool adjustToNewSize)
|
||||
void Sprite::SetTexture(const Texture& texture, bool adjustToNewSize)
|
||||
{
|
||||
// If there was no valid image before, force adjusting to the new image size
|
||||
if (!myImage)
|
||||
// If there was no valid texture before, force adjusting to the new texture size
|
||||
if (!myTexture)
|
||||
adjustToNewSize = true;
|
||||
|
||||
// If we want to adjust the size and the new image is valid, we adjust the source rectangle
|
||||
if (adjustToNewSize && (image.GetWidth() > 0) && (image.GetHeight() > 0))
|
||||
// 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, image.GetWidth(), image.GetHeight()));
|
||||
SetSubRect(IntRect(0, 0, texture.GetWidth(), texture.GetHeight()));
|
||||
}
|
||||
|
||||
// Assign the new image
|
||||
myImage = ℑ
|
||||
// Assign the new texture
|
||||
myTexture = &texture;
|
||||
}
|
||||
|
||||
|
||||
|
@ -109,9 +110,9 @@ void Sprite::FlipY(bool flipped)
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const Image* Sprite::GetImage() const
|
||||
const Texture* Sprite::GetTexture() const
|
||||
{
|
||||
return myImage;
|
||||
return myTexture;
|
||||
}
|
||||
|
||||
|
||||
|
@ -129,26 +130,6 @@ Vector2f Sprite::GetSize() const
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Color Sprite::GetPixel(unsigned int x, unsigned int y) const
|
||||
{
|
||||
if (myImage)
|
||||
{
|
||||
unsigned int imageX = mySubRect.Left + x;
|
||||
unsigned int imageY = mySubRect.Top + y;
|
||||
|
||||
if (myIsFlippedX) imageX = mySubRect.Width - imageX - 1;
|
||||
if (myIsFlippedY) imageY = mySubRect.Height - imageY - 1;
|
||||
|
||||
return myImage->GetPixel(imageX, imageY) * GetColor();
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetColor();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Sprite::Render(RenderTarget&, Renderer& renderer) const
|
||||
{
|
||||
|
@ -156,10 +137,10 @@ void Sprite::Render(RenderTarget&, Renderer& renderer) const
|
|||
float width = static_cast<float>(mySubRect.Width);
|
||||
float height = static_cast<float>(mySubRect.Height);
|
||||
|
||||
// Check if the image is valid, and calculate the texture coordinates
|
||||
// Check if the texture is valid, and calculate the texture coordinates
|
||||
FloatRect coords;
|
||||
if (myImage)
|
||||
coords = myImage->GetTexCoords(mySubRect);
|
||||
if (myTexture)
|
||||
coords = myTexture->GetTexCoords(mySubRect);
|
||||
|
||||
// Compute the texture coordinates
|
||||
float left = coords.Left;
|
||||
|
@ -170,7 +151,7 @@ void Sprite::Render(RenderTarget&, Renderer& renderer) const
|
|||
if (myIsFlippedY) std::swap(top, bottom);
|
||||
|
||||
// Bind the texture
|
||||
renderer.SetTexture(myImage);
|
||||
renderer.SetTexture(myTexture);
|
||||
|
||||
// Draw the sprite's geometry
|
||||
renderer.Begin(Renderer::TriangleStrip);
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
// Headers
|
||||
////////////////////////////////////////////////////////////
|
||||
#include <SFML/Graphics/Text.hpp>
|
||||
#include <SFML/Graphics/Image.hpp>
|
||||
#include <SFML/Graphics/Texture.hpp>
|
||||
#include <SFML/Graphics/Renderer.hpp>
|
||||
|
||||
|
||||
|
@ -190,7 +190,7 @@ void Text::Render(RenderTarget&, Renderer& renderer) const
|
|||
return;
|
||||
|
||||
// Bind the font texture
|
||||
const Image& texture = myFont->GetImage(myCharacterSize);
|
||||
const Texture& texture = myFont->GetTexture(myCharacterSize);
|
||||
renderer.SetTexture(&texture);
|
||||
|
||||
// Computes values related to the text style
|
||||
|
|
506
src/SFML/Graphics/Texture.cpp
Normal file
506
src/SFML/Graphics/Texture.cpp
Normal file
|
@ -0,0 +1,506 @@
|
|||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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/Texture.hpp>
|
||||
#include <SFML/Graphics/Image.hpp>
|
||||
#include <SFML/Graphics/GLCheck.hpp>
|
||||
#include <SFML/Window/Window.hpp>
|
||||
#include <SFML/System/Err.hpp>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
Texture::Texture() :
|
||||
myWidth (0),
|
||||
myHeight (0),
|
||||
myTextureWidth (0),
|
||||
myTextureHeight(0),
|
||||
myTexture (0),
|
||||
myIsSmooth (false),
|
||||
myPixelsFlipped(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Texture::Texture(const Texture& copy) :
|
||||
Resource<Texture>(),
|
||||
myWidth (0),
|
||||
myHeight (0),
|
||||
myTextureWidth (0),
|
||||
myTextureHeight(0),
|
||||
myTexture (0),
|
||||
myIsSmooth (false),
|
||||
myPixelsFlipped(false)
|
||||
{
|
||||
LoadFromImage(copy.CopyToImage());
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Texture::~Texture()
|
||||
{
|
||||
// Destroy the OpenGL texture
|
||||
if (myTexture)
|
||||
{
|
||||
EnsureGlContext();
|
||||
|
||||
GLuint Texture = static_cast<GLuint>(myTexture);
|
||||
GLCheck(glDeleteTextures(1, &Texture));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Texture::Create(unsigned int width, unsigned int height)
|
||||
{
|
||||
// Check if texture parameters are valid before creating it
|
||||
if (!width || !height)
|
||||
{
|
||||
Err() << "Failed to create texture, invalid size (" << width << "x" << height << ")" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compute the internal texture dimensions depending on NPOT textures support
|
||||
unsigned int textureWidth = GetValidSize(width);
|
||||
unsigned int textureHeight = GetValidSize(height);
|
||||
|
||||
// Check the maximum texture size
|
||||
unsigned int maxSize = GetMaximumSize();
|
||||
if ((textureWidth > maxSize) || (textureHeight > maxSize))
|
||||
{
|
||||
Err() << "Failed to create texture, its internal size is too high "
|
||||
<< "(" << textureWidth << "x" << textureHeight << ", "
|
||||
<< "maximum is " << maxSize << "x" << maxSize << ")"
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// All the validity checks passed, we can store the new texture settings
|
||||
myWidth = width;
|
||||
myHeight = height;
|
||||
myTextureWidth = textureWidth;
|
||||
myTextureHeight = textureHeight;
|
||||
myPixelsFlipped = false;
|
||||
|
||||
EnsureGlContext();
|
||||
|
||||
// Create the OpenGL texture if it doesn't exist yet
|
||||
if (!myTexture)
|
||||
{
|
||||
GLuint texture;
|
||||
GLCheck(glGenTextures(1, &texture));
|
||||
myTexture = static_cast<unsigned int>(texture);
|
||||
}
|
||||
|
||||
// Save the current texture binding
|
||||
GLint previous;
|
||||
GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous));
|
||||
|
||||
// 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_MAG_FILTER, myIsSmooth ? GL_LINEAR : GL_NEAREST));
|
||||
GLCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, myIsSmooth ? GL_LINEAR : GL_NEAREST));
|
||||
|
||||
// Restore the previous texture
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, previous));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Texture::LoadFromFile(const std::string& filename, const IntRect& area)
|
||||
{
|
||||
Image image;
|
||||
return image.LoadFromFile(filename) && LoadFromImage(image, area);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Texture::LoadFromMemory(const void* data, std::size_t size, const IntRect& area)
|
||||
{
|
||||
Image image;
|
||||
return image.LoadFromMemory(data, size) && LoadFromImage(image, area);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Texture::LoadFromStream(InputStream& stream, const IntRect& area)
|
||||
{
|
||||
Image image;
|
||||
return image.LoadFromStream(stream) && LoadFromImage(image, area);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Texture::LoadFromImage(const Image& image, const IntRect& area)
|
||||
{
|
||||
// Retrieve the image size
|
||||
int width = static_cast<int>(image.GetWidth());
|
||||
int height = static_cast<int>(image.GetHeight());
|
||||
|
||||
// Load the entire image if the source area is either empty or contains the whole image
|
||||
if (area.Width == 0 || (area.Height == 0) ||
|
||||
((area.Left <= 0) && (area.Top <= 0) && (area.Width >= width) && (area.Height >= height)))
|
||||
{
|
||||
// Load the entire image
|
||||
if (Create(image.GetWidth(), image.GetHeight()))
|
||||
{
|
||||
Update(image);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Load a sub-area of the image
|
||||
|
||||
// Adjust the rectangle to the size of the image
|
||||
IntRect rectangle = area;
|
||||
if (rectangle.Left < 0) rectangle.Left = 0;
|
||||
if (rectangle.Top < 0) rectangle.Top = 0;
|
||||
if (rectangle.Width > width) rectangle.Width = width;
|
||||
if (rectangle.Height > height) rectangle.Height = height;
|
||||
|
||||
// Create the texture and upload the pixels
|
||||
if (Create(rectangle.Width, rectangle.Height))
|
||||
{
|
||||
// Save the current texture binding
|
||||
GLint previous;
|
||||
GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous));
|
||||
|
||||
// Copy the pixels to the texture, row by row
|
||||
const Uint8* pixels = image.GetPixelsPtr() + rectangle.Left + (width * rectangle.Top);
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
||||
for (int i = 0; i < rectangle.Height; ++i)
|
||||
{
|
||||
GLCheck(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, i, myWidth, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
|
||||
pixels += width;
|
||||
}
|
||||
myPixelsFlipped = false;
|
||||
|
||||
// Restore the previous texture
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, previous));
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int Texture::GetWidth() const
|
||||
{
|
||||
return myWidth;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int Texture::GetHeight() const
|
||||
{
|
||||
return myHeight;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Image Texture::CopyToImage() const
|
||||
{
|
||||
// Easy case: empty texture
|
||||
if (!myTexture)
|
||||
return Image();
|
||||
|
||||
EnsureGlContext();
|
||||
|
||||
// Save the previous texture
|
||||
GLint previous;
|
||||
GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous));
|
||||
|
||||
// Create an array of pixels
|
||||
std::vector<Uint8> pixels(myWidth * myHeight * 4);
|
||||
|
||||
if ((myWidth == myTextureWidth) && (myHeight == myTextureHeight) && !myPixelsFlipped)
|
||||
{
|
||||
// Texture is not padded nor flipped, we can use a direct copy
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
||||
GLCheck(glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Texture is either padded or flipped, we have to use a slower algorithm
|
||||
|
||||
// All the pixels will first be copied to a temporary array
|
||||
std::vector<Uint8> allPixels(myTextureWidth * myTextureHeight * 4);
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
||||
GLCheck(glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &allPixels[0]));
|
||||
|
||||
// Then we copy the useful pixels from the temporary array to the final one
|
||||
const Uint8* src = &allPixels[0];
|
||||
Uint8* dst = &pixels[0];
|
||||
int srcPitch = myTextureWidth * 4;
|
||||
int dstPitch = myWidth * 4;
|
||||
|
||||
// Handle the case where source pixels are flipped vertically
|
||||
if (myPixelsFlipped)
|
||||
{
|
||||
src += srcPitch * (myHeight - 1);
|
||||
srcPitch = -srcPitch;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < myHeight; ++i)
|
||||
{
|
||||
std::memcpy(dst, src, dstPitch);
|
||||
src += srcPitch;
|
||||
dst += dstPitch;
|
||||
}
|
||||
}
|
||||
|
||||
// Restore the previous texture
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, previous));
|
||||
|
||||
// Create the image
|
||||
Image image;
|
||||
image.Create(myWidth, myHeight, &pixels[0]);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Texture::Update(const Uint8* pixels)
|
||||
{
|
||||
// Update the whole texture
|
||||
Update(pixels, myWidth, myHeight, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Texture::Update(const Uint8* pixels, unsigned int width, unsigned int height, unsigned int x, unsigned int y)
|
||||
{
|
||||
assert(x + width <= myWidth);
|
||||
assert(y + height <= myHeight);
|
||||
|
||||
if (pixels && myTexture)
|
||||
{
|
||||
EnsureGlContext();
|
||||
|
||||
// Save the current texture binding
|
||||
GLint previous;
|
||||
GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous));
|
||||
|
||||
// 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;
|
||||
|
||||
// Restore the previous texture
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, previous));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Texture::Update(const Image& image)
|
||||
{
|
||||
// Update the whole texture
|
||||
Update(image.GetPixelsPtr(), image.GetWidth(), image.GetHeight(), 0, 0);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Texture::Update(const Image& image, unsigned int x, unsigned int y)
|
||||
{
|
||||
Update(image.GetPixelsPtr(), image.GetWidth(), image.GetHeight(), x, y);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Texture::Update(const Window& window)
|
||||
{
|
||||
Update(window, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Texture::Update(const Window& window, unsigned int x, unsigned int y)
|
||||
{
|
||||
assert(x + window.GetWidth() <= myWidth);
|
||||
assert(y + window.GetHeight() <= myHeight);
|
||||
|
||||
if (myTexture && window.SetActive(true))
|
||||
{
|
||||
// Save the current texture binding
|
||||
GLint previous;
|
||||
GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous));
|
||||
|
||||
// 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;
|
||||
|
||||
// Restore the previous texture
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, previous));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Texture::Bind() const
|
||||
{
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, myTexture));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Texture::SetSmooth(bool smooth)
|
||||
{
|
||||
if (smooth != myIsSmooth)
|
||||
{
|
||||
myIsSmooth = smooth;
|
||||
|
||||
if (myTexture)
|
||||
{
|
||||
EnsureGlContext();
|
||||
|
||||
GLint previous;
|
||||
GLCheck(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previous));
|
||||
|
||||
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));
|
||||
|
||||
GLCheck(glBindTexture(GL_TEXTURE_2D, previous));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
bool Texture::IsSmooth() const
|
||||
{
|
||||
return myIsSmooth;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
FloatRect Texture::GetTexCoords(const IntRect& rect) const
|
||||
{
|
||||
if ((myTextureWidth != 0) && (myTextureHeight != 0))
|
||||
{
|
||||
float width = static_cast<float>(myTextureWidth);
|
||||
float height = static_cast<float>(myTextureHeight);
|
||||
|
||||
if (myPixelsFlipped)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return FloatRect(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int Texture::GetMaximumSize()
|
||||
{
|
||||
EnsureGlContext();
|
||||
|
||||
GLint size;
|
||||
GLCheck(glGetIntegerv(GL_MAX_TEXTURE_SIZE, &size));
|
||||
|
||||
return static_cast<unsigned int>(size);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Texture& Texture::operator =(const Texture& right)
|
||||
{
|
||||
Texture temp(right);
|
||||
|
||||
std::swap(myWidth, temp.myWidth);
|
||||
std::swap(myHeight, temp.myHeight);
|
||||
std::swap(myTextureWidth, temp.myTextureWidth);
|
||||
std::swap(myTextureHeight, temp.myTextureHeight);
|
||||
std::swap(myTexture, temp.myTexture);
|
||||
std::swap(myIsSmooth, temp.myIsSmooth);
|
||||
std::swap(myPixelsFlipped, temp.myPixelsFlipped);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
unsigned int Texture::GetValidSize(unsigned int size)
|
||||
{
|
||||
EnsureGlContext();
|
||||
|
||||
// Make sure that GLEW is initialized
|
||||
priv::EnsureGlewInit();
|
||||
|
||||
if (GLEW_ARB_texture_non_power_of_two)
|
||||
{
|
||||
// If hardware supports NPOT textures, then just return the unmodified size
|
||||
return size;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If hardware doesn't support NPOT textures, we calculate the nearest power of two
|
||||
unsigned int powerOfTwo = 1;
|
||||
while (powerOfTwo < size)
|
||||
powerOfTwo *= 2;
|
||||
|
||||
return powerOfTwo;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sf
|
Loading…
Add table
Add a link
Reference in a new issue