Remove default empty state of sf::Texture

This commit is contained in:
Chris Thrasher 2024-05-23 23:05:13 -06:00
parent 24dc6b5ea9
commit bfd65989e9
22 changed files with 214 additions and 298 deletions

View File

@ -21,9 +21,7 @@
/// sf::RenderWindow window(sf::VideoMode({800, 600}), "SFML window");
///
/// // Load a sprite to display
/// sf::Texture texture;
/// if (!texture.loadFromFile("cute_image.jpg"))
/// return EXIT_FAILURE;
/// const auto texture = sf::Texture::loadFromFile("cute_image.jpg").value();
/// sf::Sprite sprite(texture);
///
/// // Create a graphical text to display

View File

@ -86,9 +86,7 @@ int main(int argc, char* argv[])
sf::RenderWindow window(screen, "");
window.setFramerateLimit(30);
sf::Texture texture;
if (!texture.loadFromFile("image.png"))
return EXIT_FAILURE;
const auto texture = sf::Texture::loadFromFile("image.png").value();
sf::Sprite image(texture);
image.setPosition(sf::Vector2f(screen.size) / 2.f);

View File

@ -41,9 +41,6 @@ struct SFMLmainWindow
{
SFMLmainWindow(sf::WindowHandle win) : renderWindow(win)
{
if (!logo.loadFromFile(resPath / "logo.png"))
NSLog(@"Couldn't load the logo image");
logo.setSmooth(true);
sprite.setOrigin(sprite.getLocalBounds().getCenter());
@ -57,7 +54,7 @@ struct SFMLmainWindow
sf::RenderWindow renderWindow;
sf::Font font{sf::Font::loadFromFile(resPath / "tuffy.ttf").value()};
sf::Text text{font};
sf::Texture logo;
sf::Texture logo{sf::Texture::loadFromFile(resPath / "logo.png").value()};
sf::Sprite sprite{logo};
sf::Color background{sf::Color::Blue};
};

View File

@ -58,10 +58,7 @@ int main()
window.setMaximumSize(sf::Vector2u(1200, 900));
// Create a sprite for the background
sf::Texture backgroundTexture;
backgroundTexture.setSrgb(sRgb);
if (!backgroundTexture.loadFromFile(resourcesDir() / "background.jpg"))
return EXIT_FAILURE;
const auto backgroundTexture = sf::Texture::loadFromFile(resourcesDir() / "background.jpg", sRgb).value();
const sf::Sprite background(backgroundTexture);
// Create some text to draw on top of our OpenGL object
@ -78,9 +75,7 @@ int main()
mipmapInstructions.setPosition({200.f, 550.f});
// Load a texture to apply to our 3D cube
sf::Texture texture;
if (!texture.loadFromFile(resourcesDir() / "logo.png"))
return EXIT_FAILURE;
auto texture = sf::Texture::loadFromFile(resourcesDir() / "logo.png").value();
// Attempt to generate a mipmap for our cube texture
// We don't check the return value here since
@ -230,8 +225,7 @@ int main()
if (mipmapEnabled)
{
// We simply reload the texture to disable mipmapping
if (!texture.loadFromFile(resourcesDir() / "logo.png"))
return EXIT_FAILURE;
texture = sf::Texture::loadFromFile(resourcesDir() / "logo.png").value();
mipmapEnabled = false;
}

View File

@ -34,9 +34,9 @@ public:
bool onLoad() override
{
// Load the texture and initialize the sprite
if (!m_texture.loadFromFile("resources/background.jpg"))
if (!(m_texture = sf::Texture::loadFromFile("resources/background.jpg")))
return false;
m_sprite.emplace(m_texture);
m_sprite.emplace(*m_texture);
// Load the shader
if (!(m_shader = sf::Shader::loadFromFile("resources/pixelate.frag", sf::Shader::Type::Fragment)))
@ -58,7 +58,7 @@ public:
}
private:
sf::Texture m_texture;
std::optional<sf::Texture> m_texture;
std::optional<sf::Sprite> m_sprite;
std::optional<sf::Shader> m_shader;
};
@ -193,21 +193,21 @@ public:
m_surface->setSmooth(true);
// Load the textures
if (!m_backgroundTexture.loadFromFile("resources/sfml.png"))
if (!(m_backgroundTexture = sf::Texture::loadFromFile("resources/sfml.png")))
return false;
m_backgroundTexture.setSmooth(true);
if (!m_entityTexture.loadFromFile("resources/devices.png"))
m_backgroundTexture->setSmooth(true);
if (!(m_entityTexture = sf::Texture::loadFromFile("resources/devices.png")))
return false;
m_entityTexture.setSmooth(true);
m_entityTexture->setSmooth(true);
// Initialize the background sprite
m_backgroundSprite.emplace(m_backgroundTexture);
m_backgroundSprite.emplace(*m_backgroundTexture);
m_backgroundSprite->setPosition({135.f, 100.f});
// Load the moving entities
for (int i = 0; i < 6; ++i)
{
const sf::Sprite entity(m_entityTexture, sf::IntRect({96 * i, 0}, {96, 96}));
const sf::Sprite entity(*m_entityTexture, sf::IntRect({96 * i, 0}, {96, 96}));
m_entities.push_back(entity);
}
@ -250,8 +250,8 @@ public:
private:
std::optional<sf::RenderTexture> m_surface;
sf::Texture m_backgroundTexture;
sf::Texture m_entityTexture;
std::optional<sf::Texture> m_backgroundTexture;
std::optional<sf::Texture> m_entityTexture;
std::optional<sf::Sprite> m_backgroundSprite;
std::vector<sf::Sprite> m_entities;
std::optional<sf::Shader> m_shader;
@ -284,7 +284,7 @@ public:
}
// Load the texture
if (!m_logoTexture.loadFromFile("resources/logo.png"))
if (!(m_logoTexture = sf::Texture::loadFromFile("resources/logo.png")))
return false;
// Load the shader
@ -320,7 +320,7 @@ public:
{
// Prepare the render state
states.shader = &*m_shader;
states.texture = &m_logoTexture;
states.texture = &*m_logoTexture;
states.transform = m_transform;
// Draw the point cloud
@ -328,7 +328,7 @@ public:
}
private:
sf::Texture m_logoTexture;
std::optional<sf::Texture> m_logoTexture;
sf::Transform m_transform;
std::optional<sf::Shader> m_shader;
sf::VertexArray m_pointCloud;
@ -367,9 +367,7 @@ int main()
effect->load();
// Create the messages background
sf::Texture textBackgroundTexture;
if (!textBackgroundTexture.loadFromFile("resources/text-background.png"))
return EXIT_FAILURE;
const auto textBackgroundTexture = sf::Texture::loadFromFile("resources/text-background.png").value();
sf::Sprite textBackground(textBackgroundTexture);
textBackground.setPosition({0.f, 520.f});
textBackground.setColor(sf::Color(255, 255, 255, 200));

View File

@ -1080,9 +1080,7 @@ int main()
effects[current]->start();
// Create the messages background
sf::Texture textBackgroundTexture;
if (!textBackgroundTexture.loadFromFile(resourcesDir() / "text-background.png"))
return EXIT_FAILURE;
const auto textBackgroundTexture = sf::Texture::loadFromFile(resourcesDir() / "text-background.png").value();
sf::Sprite textBackground(textBackgroundTexture);
textBackground.setPosition({0.f, 520.f});
textBackground.setColor(sf::Color(255, 255, 255, 200));

View File

@ -53,9 +53,7 @@ int main()
sf::Sound ballSound(ballSoundBuffer);
// Create the SFML logo texture:
sf::Texture sfmlLogoTexture;
if (!sfmlLogoTexture.loadFromFile(resourcesDir() / "sfml_logo.png"))
return EXIT_FAILURE;
const auto sfmlLogoTexture = sf::Texture::loadFromFile(resourcesDir() / "sfml_logo.png").value();
sf::Sprite sfmlLogo(sfmlLogoTexture);
sfmlLogo.setPosition({170.f, 50.f});

View File

@ -111,10 +111,8 @@ int main()
sf::RenderWindow sfmlView2(view2);
// Load some textures to display
sf::Texture texture1;
sf::Texture texture2;
if (!texture1.loadFromFile("resources/image1.jpg") || !texture2.loadFromFile("resources/image2.jpg"))
return EXIT_FAILURE;
const auto texture1 = sf::Texture::loadFromFile("resources/image1.jpg").value();
const auto texture2 = sf::Texture::loadFromFile("resources/image2.jpg").value();
sf::Sprite sprite1(texture1);
sf::Sprite sprite2(texture2);
sprite1.setOrigin(sf::Vector2f(texture1.getSize()) / 2.f);

View File

@ -315,7 +315,8 @@ private:
////////////////////////////////////////////////////////////
struct Page
{
explicit Page(bool smooth);
[[nodiscard]] static std::optional<Page> make(bool smooth);
explicit Page(Texture&& texture);
GlyphTable glyphs; //!< Table mapping code points to their corresponding glyph
Texture texture; //!< Texture containing the pixels of the glyphs

View File

@ -266,11 +266,7 @@ private:
/// sf::RenderWindow window(sf::VideoMode({800, 600}), "SFML OpenGL");
///
/// // Create a sprite and a text to display
/// sf::Texture texture;
/// if (!texture.loadFromFile("circle.png"))
/// {
/// // error...
/// }
/// const auto texture = sf::Texture::loadFromFile("circle.png").value();
/// sf::Sprite sprite(texture);
/// const auto font = sf::Font::loadFromFile("arial.ttf").value();
/// sf::Text text(font);

View File

@ -266,12 +266,8 @@ private:
///
/// Usage example:
/// \code
/// // Declare and load a texture
/// sf::Texture texture;
/// if (!texture.loadFromFile("texture.png"))
/// {
/// // Handle error...
/// }
/// // Load a texture
/// const auto texture = sf::Texture::loadFromFile("texture.png").value();
///
/// // Create a sprite
/// sf::Sprite sprite(texture);

View File

@ -37,6 +37,7 @@
#include <SFML/System/Vector2.hpp>
#include <filesystem>
#include <optional>
#include <cstddef>
#include <cstdint>
@ -55,14 +56,6 @@ class Image;
class SFML_GRAPHICS_API Texture : GlResource
{
public:
////////////////////////////////////////////////////////////
/// \brief Default constructor
///
/// Creates an empty texture.
///
////////////////////////////////////////////////////////////
Texture();
////////////////////////////////////////////////////////////
/// \brief Destructor
///
@ -101,11 +94,12 @@ public:
/// If this function fails, the texture is left unchanged.
///
/// \param size Width and height of the texture
/// \param sRgb True to enable sRGB conversion, false to disable it
///
/// \return True if creation was successful
/// \return Texture if creation was successful, otherwise `std::nullopt`
///
////////////////////////////////////////////////////////////
[[nodiscard]] bool create(const Vector2u& size);
[[nodiscard]] static std::optional<Texture> create(const Vector2u& size, bool sRgb = false);
////////////////////////////////////////////////////////////
/// \brief Load the texture from a file on disk
@ -122,14 +116,17 @@ public:
/// If this function fails, the texture is left unchanged.
///
/// \param filename Path of the image file to load
/// \param sRgb True to enable sRGB conversion, false to disable it
/// \param area Area of the image to load
///
/// \return True if loading was successful
/// \return Texture if loading was successful, otherwise `std::nullopt`
///
/// \see loadFromMemory, loadFromStream, loadFromImage
///
////////////////////////////////////////////////////////////
[[nodiscard]] bool loadFromFile(const std::filesystem::path& filename, const IntRect& area = {});
[[nodiscard]] static std::optional<Texture> loadFromFile(const std::filesystem::path& filename,
bool sRgb = false,
const IntRect& area = {});
////////////////////////////////////////////////////////////
/// \brief Load the texture from a file in memory
@ -147,14 +144,19 @@ public:
///
/// \param data Pointer to the file data in memory
/// \param size Size of the data to load, in bytes
/// \param sRgb True to enable sRGB conversion, false to disable it
/// \param area Area of the image to load
///
/// \return True if loading was successful
/// \return Texture if loading was successful, otherwise `std::nullopt`
///
/// \see loadFromFile, loadFromStream, loadFromImage
///
////////////////////////////////////////////////////////////
[[nodiscard]] bool loadFromMemory(const void* data, std::size_t size, const IntRect& area = {});
[[nodiscard]] static std::optional<Texture> loadFromMemory(
const void* data,
std::size_t size,
bool sRgb = false,
const IntRect& area = {});
////////////////////////////////////////////////////////////
/// \brief Load the texture from a custom stream
@ -171,14 +173,15 @@ public:
/// If this function fails, the texture is left unchanged.
///
/// \param stream Source stream to read from
/// \param sRgb True to enable sRGB conversion, false to disable it
/// \param area Area of the image to load
///
/// \return True if loading was successful
/// \return Texture if loading was successful, otherwise `std::nullopt`
///
/// \see loadFromFile, loadFromMemory, loadFromImage
///
////////////////////////////////////////////////////////////
[[nodiscard]] bool loadFromStream(InputStream& stream, const IntRect& area = {});
[[nodiscard]] static std::optional<Texture> loadFromStream(InputStream& stream, bool sRgb = false, const IntRect& area = {});
////////////////////////////////////////////////////////////
/// \brief Load the texture from an image
@ -195,14 +198,15 @@ public:
/// If this function fails, the texture is left unchanged.
///
/// \param image Image to load into the texture
/// \param sRgb True to enable sRGB conversion, false to disable it
/// \param area Area of the image to load
///
/// \return True if loading was successful
/// \return Texture if loading was successful, otherwise `std::nullopt`
///
/// \see loadFromFile, loadFromMemory
///
////////////////////////////////////////////////////////////
[[nodiscard]] bool loadFromImage(const Image& image, const IntRect& area = {});
[[nodiscard]] static std::optional<Texture> loadFromImage(const Image& image, bool sRgb = false, const IntRect& area = {});
////////////////////////////////////////////////////////////
/// \brief Return the size of the texture
@ -402,31 +406,6 @@ public:
////////////////////////////////////////////////////////////
bool isSmooth() const;
////////////////////////////////////////////////////////////
/// \brief Enable or disable conversion from sRGB
///
/// When providing texture data from an image file or memory, it can
/// either be stored in a linear color space or an sRGB color space.
/// Most digital images account for gamma correction already, so they
/// would need to be "uncorrected" back to linear color space before
/// being processed by the hardware. The hardware can automatically
/// convert it from the sRGB color space to a linear color space when
/// it gets sampled. When the rendered image gets output to the final
/// framebuffer, it gets converted back to sRGB.
///
/// After enabling or disabling sRGB conversion, make sure to reload
/// the texture data in order for the setting to take effect.
///
/// This option is only useful in conjunction with an sRGB capable
/// framebuffer. This can be requested during window creation.
///
/// \param sRgb True to enable sRGB conversion, false to disable it
///
/// \see isSrgb
///
////////////////////////////////////////////////////////////
void setSrgb(bool sRgb);
////////////////////////////////////////////////////////////
/// \brief Tell whether the texture source is converted from sRGB or not
///
@ -566,6 +545,14 @@ private:
friend class RenderTexture;
friend class RenderTarget;
////////////////////////////////////////////////////////////
/// \brief Default constructor
///
/// Creates an empty texture.
///
////////////////////////////////////////////////////////////
Texture(const Vector2u& size, const Vector2u& actualSize, unsigned int texture, bool sRgb);
////////////////////////////////////////////////////////////
/// \brief Get a valid image size according to hardware support
///
@ -657,15 +644,25 @@ SFML_GRAPHICS_API void swap(Texture& left, Texture& right) noexcept;
/// that a pixel must be composed of 8 bits red, green, blue and
/// alpha channels -- just like a sf::Color.
///
/// When providing texture data from an image file or memory, it can
/// either be stored in a linear color space or an sRGB color space.
/// Most digital images account for gamma correction already, so they
/// would need to be "uncorrected" back to linear color space before
/// being processed by the hardware. The hardware can automatically
/// convert it from the sRGB color space to a linear color space when
/// it gets sampled. When the rendered image gets output to the final
/// framebuffer, it gets converted back to sRGB.
///
/// This option is only useful in conjunction with an sRGB capable
/// framebuffer. This can be requested during window creation.
///
/// Usage example:
/// \code
/// // This example shows the most common use of sf::Texture:
/// // drawing a sprite
///
/// // Load a texture from a file
/// sf::Texture texture;
/// if (!texture.loadFromFile("texture.png"))
/// return -1;
/// const auto texture = sf::Texture::loadFromFile("texture.png").value();
///
/// // Assign it to a sprite
/// sf::Sprite sprite(texture);
@ -679,9 +676,7 @@ SFML_GRAPHICS_API void swap(Texture& left, Texture& right) noexcept;
/// // streaming real-time data, like video frames
///
/// // Create an empty texture
/// sf::Texture texture;
/// if (!texture.create({640, 480}))
/// return -1;
/// auto texture = sf::Texture::create({640, 480}).value();
///
/// // Create a sprite that will display the texture
/// sf::Sprite sprite(texture);

View File

@ -133,7 +133,6 @@ public:
/// };
///
/// // now you can load textures...
/// sf::Texture texture;
/// ZipStream stream("resources.zip");
///
/// if (!stream.open("images/img.png"))
@ -141,10 +140,7 @@ public:
/// // Handle error...
/// }
///
/// if (!texture.loadFromStream(stream))
/// {
/// // Handle error...
/// }
/// const auto texture = sf::Texture::loadFromStream(stream).value();
///
/// // musics...
/// sf::Music music;

View File

@ -45,6 +45,7 @@
#include <ostream>
#include <utility>
#include <cassert>
#include <cmath>
#include <cstring>
@ -469,7 +470,9 @@ bool Font::isSmooth() const
////////////////////////////////////////////////////////////
Font::Page& Font::loadPage(unsigned int characterSize) const
{
return m_pages.try_emplace(characterSize, m_isSmooth).first->second;
auto page = Page::make(m_isSmooth);
assert(page && "Font::loadPage() Failed to load page");
return m_pages.try_emplace(characterSize, std::move(*page)).first->second;
}
@ -679,16 +682,16 @@ IntRect Font::findGlyphRect(Page& page, const Vector2u& size) const
if ((textureSize.x * 2 <= Texture::getMaximumSize()) && (textureSize.y * 2 <= Texture::getMaximumSize()))
{
// Make the texture 2 times bigger
Texture newTexture;
if (!newTexture.create(textureSize * 2u))
auto newTexture = sf::Texture::create(textureSize * 2u);
if (!newTexture)
{
err() << "Failed to create new page texture" << std::endl;
return {{0, 0}, {2, 2}};
}
newTexture.setSmooth(m_isSmooth);
newTexture.update(page.texture);
page.texture.swap(newTexture);
newTexture->setSmooth(m_isSmooth);
newTexture->update(page.texture);
page.texture.swap(*newTexture);
}
else
{
@ -757,7 +760,7 @@ bool Font::setCurrentSize(unsigned int characterSize) const
////////////////////////////////////////////////////////////
Font::Page::Page(bool smooth)
std::optional<Font::Page> Font::Page::make(bool smooth)
{
// Make sure that the texture is initialized by default
Image image({128, 128}, Color::Transparent);
@ -768,12 +771,21 @@ Font::Page::Page(bool smooth)
image.setPixel({x, y}, Color::White);
// Create the texture
if (!texture.loadFromImage(image))
auto texture = sf::Texture::loadFromImage(image);
if (!texture)
{
err() << "Failed to load font page texture" << std::endl;
return std::nullopt;
}
texture.setSmooth(smooth);
texture->setSmooth(smooth);
return Page(std::move(*texture));
}
////////////////////////////////////////////////////////////
Font::Page::Page(Texture&& theTexture) : texture(std::move(theTexture))
{
}
} // namespace sf

View File

@ -52,19 +52,15 @@ RenderTexture& RenderTexture::operator=(RenderTexture&&) noexcept = default;
////////////////////////////////////////////////////////////
std::optional<RenderTexture> RenderTexture::create(const Vector2u& size, const ContextSettings& settings)
{
sf::Texture texture;
// Set texture to be in sRGB scale if requested
texture.setSrgb(settings.sRgbCapable);
// Create the texture
if (!texture.create(size))
auto texture = sf::Texture::create(size, settings.sRgbCapable);
if (!texture)
{
err() << "Impossible to create render texture (failed to create the target texture)" << std::endl;
return std::nullopt;
}
RenderTexture renderTexture(std::move(texture));
RenderTexture renderTexture(std::move(*texture));
// We disable smoothing by default for render textures
renderTexture.setSmooth(false);

View File

@ -66,7 +66,12 @@ std::uint64_t getUniqueId() noexcept
namespace sf
{
////////////////////////////////////////////////////////////
Texture::Texture() : m_cacheId(TextureImpl::getUniqueId())
Texture::Texture(const Vector2u& size, const Vector2u& actualSize, unsigned int texture, bool sRgb) :
m_size(size),
m_actualSize(actualSize),
m_texture(texture),
m_sRgb(sRgb),
m_cacheId(TextureImpl::getUniqueId())
{
}
@ -79,10 +84,9 @@ m_sRgb(copy.m_sRgb),
m_isRepeated(copy.m_isRepeated),
m_cacheId(TextureImpl::getUniqueId())
{
if (copy.m_texture)
{
if (create(copy.getSize()))
if (auto texture = create(copy.getSize(), copy.isSrgb()))
{
*this = std::move(*texture);
update(copy);
}
else
@ -90,7 +94,6 @@ m_cacheId(TextureImpl::getUniqueId())
err() << "Failed to copy texture, failed to create new texture" << std::endl;
}
}
}
////////////////////////////////////////////////////////////
@ -151,13 +154,13 @@ Texture& Texture::operator=(Texture&& right) noexcept
////////////////////////////////////////////////////////////
bool Texture::create(const Vector2u& size)
std::optional<Texture> Texture::create(const Vector2u& size, bool sRgb)
{
// Check if texture parameters are valid before creating it
if ((size.x == 0) || (size.y == 0))
{
err() << "Failed to create texture, invalid size (" << size.x << "x" << size.y << ")" << std::endl;
return false;
return std::nullopt;
}
const TransientContextLock lock;
@ -175,22 +178,16 @@ bool Texture::create(const Vector2u& size)
err() << "Failed to create texture, its internal size is too high "
<< "(" << actualSize.x << "x" << actualSize.y << ", "
<< "maximum is " << maxSize << "x" << maxSize << ")" << std::endl;
return false;
return std::nullopt;
}
// Create the OpenGL texture
GLuint glTexture = 0;
glCheck(glGenTextures(1, &glTexture));
assert(glTexture);
// All the validity checks passed, we can store the new texture settings
m_size = size;
m_actualSize = actualSize;
m_pixelsFlipped = false;
m_fboAttachment = false;
// Create the OpenGL texture if it doesn't exist yet
if (!m_texture)
{
GLuint texture = 0;
glCheck(glGenTextures(1, &texture));
m_texture = texture;
}
Texture texture(size, actualSize, glTexture, sRgb);
// Make sure that the current texture binding will be preserved
const priv::TextureSaver save;
@ -198,7 +195,7 @@ bool Texture::create(const Vector2u& size)
static const bool textureEdgeClamp = GLEXT_texture_edge_clamp || GLEXT_GL_VERSION_1_2 ||
Context::isExtensionAvailable("GL_EXT_texture_edge_clamp");
if (!m_isRepeated && !textureEdgeClamp)
if (!textureEdgeClamp)
{
static bool warned = false;
@ -214,7 +211,7 @@ bool Texture::create(const Vector2u& size)
static const bool textureSrgb = GLEXT_texture_sRGB;
if (m_sRgb && !textureSrgb)
if (texture.m_sRgb && !textureSrgb)
{
static bool warned = false;
@ -230,70 +227,70 @@ bool Texture::create(const Vector2u& size)
warned = true;
}
m_sRgb = false;
texture.m_sRgb = false;
}
#ifndef SFML_OPENGL_ES
const GLint textureWrapParam = m_isRepeated ? GL_REPEAT : (textureEdgeClamp ? GLEXT_GL_CLAMP_TO_EDGE : GLEXT_GL_CLAMP);
const GLint textureWrapParam = textureEdgeClamp ? GLEXT_GL_CLAMP_TO_EDGE : GLEXT_GL_CLAMP;
#else
const GLint textureWrapParam = m_isRepeated ? GL_REPEAT : GLEXT_GL_CLAMP_TO_EDGE;
const GLint textureWrapParam = GLEXT_GL_CLAMP_TO_EDGE;
#endif
// Initialize the texture
glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
glCheck(glBindTexture(GL_TEXTURE_2D, texture.m_texture));
glCheck(glTexImage2D(GL_TEXTURE_2D,
0,
(m_sRgb ? GLEXT_GL_SRGB8_ALPHA8 : GL_RGBA),
static_cast<GLsizei>(m_actualSize.x),
static_cast<GLsizei>(m_actualSize.y),
(texture.m_sRgb ? GLEXT_GL_SRGB8_ALPHA8 : GL_RGBA),
static_cast<GLsizei>(texture.m_actualSize.x),
static_cast<GLsizei>(texture.m_actualSize.y),
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
nullptr));
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, textureWrapParam));
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, textureWrapParam));
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
m_cacheId = TextureImpl::getUniqueId();
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
texture.m_cacheId = TextureImpl::getUniqueId();
m_hasMipmap = false;
texture.m_hasMipmap = false;
return true;
return texture;
}
////////////////////////////////////////////////////////////
bool Texture::loadFromFile(const std::filesystem::path& filename, const IntRect& area)
std::optional<Texture> Texture::loadFromFile(const std::filesystem::path& filename, bool sRgb, const IntRect& area)
{
const auto image = sf::Image::loadFromFile(filename);
if (!image)
return false;
return loadFromImage(*image, area);
return std::nullopt;
return loadFromImage(*image, sRgb, area);
}
////////////////////////////////////////////////////////////
bool Texture::loadFromMemory(const void* data, std::size_t size, const IntRect& area)
std::optional<Texture> Texture::loadFromMemory(const void* data, std::size_t size, bool sRgb, const IntRect& area)
{
const auto image = sf::Image::loadFromMemory(data, size);
if (!image)
return false;
return loadFromImage(*image, area);
return std::nullopt;
return loadFromImage(*image, sRgb, area);
}
////////////////////////////////////////////////////////////
bool Texture::loadFromStream(InputStream& stream, const IntRect& area)
std::optional<Texture> Texture::loadFromStream(InputStream& stream, bool sRgb, const IntRect& area)
{
const auto image = sf::Image::loadFromStream(stream);
if (!image)
return false;
return loadFromImage(*image, area);
return std::nullopt;
return loadFromImage(*image, sRgb, area);
}
////////////////////////////////////////////////////////////
bool Texture::loadFromImage(const Image& image, const IntRect& area)
std::optional<Texture> Texture::loadFromImage(const Image& image, bool sRgb, const IntRect& area)
{
// Retrieve the image size
const auto [width, height] = Vector2i(image.getSize());
@ -303,15 +300,15 @@ bool Texture::loadFromImage(const Image& image, const IntRect& area)
((area.left <= 0) && (area.top <= 0) && (area.width >= width) && (area.height >= height)))
{
// Load the entire image
if (create(image.getSize()))
if (auto texture = sf::Texture::create(image.getSize(), sRgb))
{
update(image);
texture->update(image);
return true;
return texture;
}
else
{
return false;
return std::nullopt;
}
}
else
@ -326,7 +323,7 @@ bool Texture::loadFromImage(const Image& image, const IntRect& area)
rectangle.height = std::min(rectangle.height, height - rectangle.top);
// Create the texture and upload the pixels
if (create(Vector2u(rectangle.getSize())))
if (auto texture = sf::Texture::create(Vector2u(rectangle.getSize()), sRgb))
{
const TransientContextLock lock;
@ -335,25 +332,25 @@ bool Texture::loadFromImage(const Image& image, const IntRect& area)
// Copy the pixels to the texture, row by row
const std::uint8_t* pixels = image.getPixelsPtr() + 4 * (rectangle.left + (width * rectangle.top));
glCheck(glBindTexture(GL_TEXTURE_2D, m_texture));
glCheck(glBindTexture(GL_TEXTURE_2D, texture->m_texture));
for (int i = 0; i < rectangle.height; ++i)
{
glCheck(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, i, rectangle.width, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
pixels += 4 * width;
}
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_isSmooth ? GL_LINEAR : GL_NEAREST));
m_hasMipmap = false;
glCheck(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
texture->m_hasMipmap = false;
// Force an OpenGL flush, so that the texture will appear updated
// in all contexts immediately (solves problems in multi-threaded apps)
glCheck(glFlush());
return true;
return texture;
}
else
{
return false;
return std::nullopt;
}
}
}
@ -736,13 +733,6 @@ bool Texture::isSmooth() const
}
////////////////////////////////////////////////////////////
void Texture::setSrgb(bool sRgb)
{
m_sRgb = sRgb;
}
////////////////////////////////////////////////////////////
bool Texture::isSrgb() const
{

View File

@ -75,8 +75,7 @@ TEST_CASE("[Graphics] sf::RenderWindow", runDisplayTests())
sf::ContextSettings{});
REQUIRE(window.getSize() == sf::Vector2u(256, 256));
sf::Texture texture;
REQUIRE(texture.create(window.getSize()));
auto texture = sf::Texture::create(window.getSize()).value();
window.clear(sf::Color::Red);
texture.update(window);

View File

@ -66,7 +66,7 @@ TEST_CASE("[Graphics] sf::Shape", runDisplayTests())
SECTION("Set/get texture")
{
const sf::Texture texture;
const auto texture = sf::Texture::create({64, 64}).value();
TriangleShape triangleShape({});
triangleShape.setTexture(&texture, true);
CHECK(triangleShape.getTexture() == &texture);

View File

@ -19,7 +19,7 @@ TEST_CASE("[Graphics] sf::Sprite", runDisplayTests())
STATIC_CHECK(std::is_nothrow_move_assignable_v<sf::Sprite>);
}
const sf::Texture texture;
const auto texture = sf::Texture::create({64, 64}).value();
SECTION("Construction")
{
@ -27,10 +27,10 @@ TEST_CASE("[Graphics] sf::Sprite", runDisplayTests())
{
const sf::Sprite sprite(texture);
CHECK(&sprite.getTexture() == &texture);
CHECK(sprite.getTextureRect() == sf::IntRect());
CHECK(sprite.getTextureRect() == sf::IntRect({}, {64, 64}));
CHECK(sprite.getColor() == sf::Color::White);
CHECK(sprite.getLocalBounds() == sf::FloatRect());
CHECK(sprite.getGlobalBounds() == sf::FloatRect());
CHECK(sprite.getLocalBounds() == sf::FloatRect({}, {64, 64}));
CHECK(sprite.getGlobalBounds() == sf::FloatRect({}, {64, 64}));
}
SECTION("Texture and rectangle constructor")
@ -47,7 +47,7 @@ TEST_CASE("[Graphics] sf::Sprite", runDisplayTests())
SECTION("Set/get texture")
{
sf::Sprite sprite(texture);
const sf::Texture otherTexture;
const sf::Texture otherTexture = sf::Texture::create({64, 64}).value();
sprite.setTexture(otherTexture);
CHECK(&sprite.getTexture() == &otherTexture);
}

View File

@ -15,6 +15,7 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
{
SECTION("Type traits")
{
STATIC_CHECK(!std::is_default_constructible_v<sf::Texture>);
STATIC_CHECK(std::is_copy_constructible_v<sf::Texture>);
STATIC_CHECK(std::is_copy_assignable_v<sf::Texture>);
STATIC_CHECK(std::is_nothrow_move_constructible_v<sf::Texture>);
@ -22,71 +23,58 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
STATIC_CHECK(std::is_nothrow_swappable_v<sf::Texture>);
}
SECTION("Construction")
{
const sf::Texture texture;
CHECK(texture.getSize() == sf::Vector2u());
CHECK(!texture.isSmooth());
CHECK(!texture.isSrgb());
CHECK(!texture.isRepeated());
CHECK(texture.getNativeHandle() == 0);
}
SECTION("Move semantics")
{
SECTION("Construction")
{
sf::Texture movedTexture;
sf::Texture movedTexture = sf::Texture::create({64, 64}).value();
const sf::Texture texture = std::move(movedTexture);
CHECK(texture.getSize() == sf::Vector2u());
CHECK(texture.getSize() == sf::Vector2u(64, 64));
CHECK(!texture.isSmooth());
CHECK(!texture.isSrgb());
CHECK(!texture.isRepeated());
CHECK(texture.getNativeHandle() == 0);
CHECK(texture.getNativeHandle() != 0);
}
SECTION("Assignment")
{
sf::Texture movedTexture;
sf::Texture texture;
sf::Texture movedTexture = sf::Texture::create({64, 64}).value();
sf::Texture texture = sf::Texture::create({128, 128}).value();
texture = std::move(movedTexture);
CHECK(texture.getSize() == sf::Vector2u());
CHECK(texture.getSize() == sf::Vector2u(64, 64));
CHECK(!texture.isSmooth());
CHECK(!texture.isSrgb());
CHECK(!texture.isRepeated());
CHECK(texture.getNativeHandle() == 0);
CHECK(texture.getNativeHandle() != 0);
}
}
SECTION("create()")
{
sf::Texture texture;
SECTION("At least one zero dimension")
{
CHECK(!texture.create({}));
CHECK(!texture.create({0, 1}));
CHECK(!texture.create({1, 0}));
CHECK(!sf::Texture::create({}));
CHECK(!sf::Texture::create({0, 1}));
CHECK(!sf::Texture::create({1, 0}));
}
SECTION("Valid size")
{
CHECK(texture.create({100, 100}));
const auto texture = sf::Texture::create({100, 100}).value();
CHECK(texture.getSize() == sf::Vector2u(100, 100));
CHECK(texture.getNativeHandle() != 0);
}
SECTION("Too large")
{
CHECK(!texture.create({100'000, 100'000}));
CHECK(!texture.create({1'000'000, 1'000'000}));
CHECK(!sf::Texture::create({100'000, 100'000}));
CHECK(!sf::Texture::create({1'000'000, 1'000'000}));
}
}
SECTION("loadFromFile()")
{
sf::Texture texture;
REQUIRE(texture.loadFromFile("Graphics/sfml-logo-big.png"));
const auto texture = sf::Texture::loadFromFile("Graphics/sfml-logo-big.png").value();
CHECK(texture.getSize() == sf::Vector2u(1001, 304));
CHECK(!texture.isSmooth());
CHECK(!texture.isSrgb());
@ -97,8 +85,7 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
SECTION("loadFromMemory()")
{
const auto memory = loadIntoMemory("Graphics/sfml-logo-big.png");
sf::Texture texture;
REQUIRE(texture.loadFromMemory(memory.data(), memory.size()));
const auto texture = sf::Texture::loadFromMemory(memory.data(), memory.size()).value();
CHECK(texture.getSize() == sf::Vector2u(1001, 304));
CHECK(!texture.isSmooth());
CHECK(!texture.isSrgb());
@ -108,10 +95,9 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
SECTION("loadFromStream()")
{
sf::Texture texture;
sf::FileInputStream stream;
REQUIRE(stream.open("Graphics/sfml-logo-big.png"));
REQUIRE(texture.loadFromStream(stream));
const auto texture = sf::Texture::loadFromStream(stream).value();
CHECK(texture.getSize() == sf::Vector2u(1001, 304));
CHECK(!texture.isSmooth());
CHECK(!texture.isSrgb());
@ -124,36 +110,35 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
SECTION("Subarea of image")
{
const sf::Image image(sf::Vector2u(10, 15));
sf::Texture texture;
SECTION("Non-truncated area")
{
REQUIRE(texture.loadFromImage(image, {{0, 0}, {5, 10}}));
const auto texture = sf::Texture::loadFromImage(image, false, {{0, 0}, {5, 10}}).value();
CHECK(texture.getSize() == sf::Vector2u(5, 10));
CHECK(texture.getNativeHandle() != 0);
}
SECTION("Truncated area (negative position)")
{
REQUIRE(texture.loadFromImage(image, {{-5, -5}, {4, 8}}));
const auto texture = sf::Texture::loadFromImage(image, false, {{-5, -5}, {4, 8}}).value();
CHECK(texture.getSize() == sf::Vector2u(4, 8));
CHECK(texture.getNativeHandle() != 0);
}
SECTION("Truncated area (width/height too big)")
{
REQUIRE(texture.loadFromImage(image, {{5, 5}, {12, 18}}));
const auto texture = sf::Texture::loadFromImage(image, false, {{5, 5}, {12, 18}}).value();
CHECK(texture.getSize() == sf::Vector2u(5, 10));
}
CHECK(texture.getNativeHandle() != 0);
}
}
}
SECTION("Copy semantics")
{
constexpr std::uint8_t red[] = {0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF};
sf::Texture texture;
REQUIRE(texture.create(sf::Vector2u(1, 2)));
auto texture = sf::Texture::create({1, 2}).value();
texture.update(red);
SECTION("Construction")
@ -165,7 +150,7 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
SECTION("Assignment")
{
sf::Texture textureCopy;
sf::Texture textureCopy = sf::Texture::create({64, 64}).value();
textureCopy = texture;
REQUIRE(textureCopy.getSize() == sf::Vector2u(1, 2));
CHECK(textureCopy.copyToImage().getPixel(sf::Vector2u(0, 1)) == sf::Color::Red);
@ -177,18 +162,16 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
constexpr std::uint8_t yellow[] = {0xFF, 0xFF, 0x00, 0xFF};
constexpr std::uint8_t cyan[] = {0x00, 0xFF, 0xFF, 0xFF};
sf::Texture texture;
SECTION("Pixels")
{
REQUIRE(texture.create(sf::Vector2u(1, 1)));
auto texture = sf::Texture::create(sf::Vector2u(1, 1)).value();
texture.update(yellow);
CHECK(texture.copyToImage().getPixel(sf::Vector2u(0, 0)) == sf::Color::Yellow);
}
SECTION("Pixels, size and destination")
{
REQUIRE(texture.create(sf::Vector2u(2, 1)));
auto texture = sf::Texture::create(sf::Vector2u(2, 1)).value();
texture.update(yellow, sf::Vector2u(1, 1), sf::Vector2u(0, 0));
texture.update(cyan, sf::Vector2u(1, 1), sf::Vector2u(1, 0));
CHECK(texture.copyToImage().getPixel(sf::Vector2u(0, 0)) == sf::Color::Yellow);
@ -197,22 +180,19 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
SECTION("Another texture")
{
sf::Texture otherTexture;
REQUIRE(otherTexture.create(sf::Vector2u(1, 1)));
auto otherTexture = sf::Texture::create(sf::Vector2u(1, 1)).value();
otherTexture.update(cyan);
REQUIRE(texture.create(sf::Vector2u(1, 1)));
auto texture = sf::Texture::create(sf::Vector2u(1, 1)).value();
texture.update(otherTexture);
CHECK(texture.copyToImage().getPixel(sf::Vector2u(0, 0)) == sf::Color::Cyan);
}
SECTION("Another texture and destination")
{
REQUIRE(texture.create(sf::Vector2u(2, 1)));
sf::Texture otherTexture1;
REQUIRE(otherTexture1.create(sf::Vector2u(1, 1)));
auto texture = sf::Texture::create(sf::Vector2u(2, 1)).value();
auto otherTexture1 = sf::Texture::create(sf::Vector2u(1, 1)).value();
otherTexture1.update(cyan);
sf::Texture otherTexture2;
REQUIRE(otherTexture2.create(sf::Vector2u(1, 1)));
auto otherTexture2 = sf::Texture::create(sf::Vector2u(1, 1)).value();
otherTexture2.update(yellow);
texture.update(otherTexture1, sf::Vector2u(0, 0));
texture.update(otherTexture2, sf::Vector2u(1, 0));
@ -222,7 +202,7 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
SECTION("Image")
{
REQUIRE(texture.create(sf::Vector2u(16, 32)));
auto texture = sf::Texture::create(sf::Vector2u(16, 32)).value();
const sf::Image image(sf::Vector2u(16, 32), sf::Color::Red);
texture.update(image);
CHECK(texture.copyToImage().getPixel(sf::Vector2u(7, 15)) == sf::Color::Red);
@ -230,7 +210,7 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
SECTION("Image and destination")
{
REQUIRE(texture.create(sf::Vector2u(16, 32)));
auto texture = sf::Texture::create(sf::Vector2u(16, 32)).value();
const sf::Image image1(sf::Vector2u(16, 16), sf::Color::Red);
texture.update(image1);
const sf::Image image2(sf::Vector2u(16, 16), sf::Color::Green);
@ -243,7 +223,7 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
SECTION("Set/get smooth")
{
sf::Texture texture;
sf::Texture texture = sf::Texture::create({64, 64}).value();
CHECK(!texture.isSmooth());
texture.setSmooth(true);
CHECK(texture.isSmooth());
@ -251,19 +231,9 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
CHECK(!texture.isSmooth());
}
SECTION("Set/get srgb")
{
sf::Texture texture;
CHECK(!texture.isSrgb());
texture.setSrgb(true);
CHECK(texture.isSrgb());
texture.setSrgb(false);
CHECK(!texture.isSrgb());
}
SECTION("Set/get repeated")
{
sf::Texture texture;
sf::Texture texture = sf::Texture::create({64, 64}).value();
CHECK(!texture.isRepeated());
texture.setRepeated(true);
CHECK(texture.isRepeated());
@ -273,9 +243,7 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
SECTION("generateMipmap()")
{
sf::Texture texture;
CHECK(!texture.generateMipmap());
CHECK(texture.create({100, 100}));
sf::Texture texture = sf::Texture::create({100, 100}).value();
CHECK(texture.generateMipmap());
}
@ -284,17 +252,13 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
constexpr std::uint8_t blue[] = {0x00, 0x00, 0xFF, 0xFF};
constexpr std::uint8_t green[] = {0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF};
sf::Texture texture1;
REQUIRE(texture1.create(sf::Vector2u(1, 1)));
auto texture1 = sf::Texture::create(sf::Vector2u(1, 1), true).value();
texture1.update(blue);
texture1.setSrgb(true);
texture1.setSmooth(false);
texture1.setRepeated(true);
sf::Texture texture2;
REQUIRE(texture2.create(sf::Vector2u(2, 1)));
auto texture2 = sf::Texture::create(sf::Vector2u(2, 1), false).value();
texture2.update(green);
texture2.setSrgb(false);
texture2.setSmooth(true);
texture2.setRepeated(false);
@ -302,7 +266,7 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
CHECK_FALSE(texture1.isSrgb());
CHECK(texture1.isSmooth());
CHECK_FALSE(texture1.isRepeated());
CHECK(texture2.isSrgb());
// Cannot check texture2.isSrgb() because Srgb is sometimes disabled when using OpenGL ES
CHECK_FALSE(texture2.isSmooth());
CHECK(texture2.isRepeated());

View File

@ -30,11 +30,7 @@ int main()
window.setIcon(icon);
// Load a sprite to display
sf::Texture texture;
if (!texture.loadFromFile(resourcePath() / "background.jpg"))
{
return EXIT_FAILURE;
}
const auto texture = sf::Texture::loadFromFile(resourcePath() / "background.jpg").value();
sf::Sprite sprite(texture);
// Create a graphical text to display

View File

@ -28,11 +28,7 @@ int main()
window.setIcon(icon);
// Load a sprite to display
sf::Texture texture;
if (!texture.loadFromFile("background.jpg"))
{
return EXIT_FAILURE;
}
const auto texture = sf::Texture::loadFromFile("background.jpg").value();
sf::Sprite sprite(texture);
// Create a graphical text to display