Remove default empty state of sf::Image

This commit is contained in:
Chris Thrasher 2024-05-18 13:07:26 -06:00
parent add6422e6b
commit 0ac278b2d6
8 changed files with 122 additions and 250 deletions

View File

@ -1801,14 +1801,16 @@ public:
void setupTextureImage() void setupTextureImage()
{ {
// Load the image data // Load the image data
sf::Image imageData; const auto maybeImageData = sf::Image::loadFromFile("resources/logo.png");
if (!imageData.loadFromFile("resources/logo.png")) if (!maybeImageData)
{ {
vulkanAvailable = false; vulkanAvailable = false;
return; return;
} }
const auto& imageData = *maybeImageData;
// Create a staging buffer to transfer the data with // Create a staging buffer to transfer the data with
const VkDeviceSize imageSize = imageData.getSize().x * imageData.getSize().y * 4; const VkDeviceSize imageSize = imageData.getSize().x * imageData.getSize().y * 4;

View File

@ -55,16 +55,16 @@ class SFML_GRAPHICS_API Image
{ {
public: public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Create the image and fill it with a unique color /// \brief Construct the image and fill it with a unique color
/// ///
/// \param size Width and height of the image /// \param size Width and height of the image
/// \param color Fill color /// \param color Fill color
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void create(const Vector2u& size, const Color& color = Color::Black); explicit Image(const Vector2u& size, const Color& color = Color::Black);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Create the image from an array of pixels /// \brief Construct the image from an array of pixels
/// ///
/// The \a pixel array is assumed to contain 32-bits RGBA pixels, /// The \a pixel array is assumed to contain 32-bits RGBA pixels,
/// and have the given \a width and \a height. If not, this is /// and have the given \a width and \a height. If not, this is
@ -75,7 +75,7 @@ public:
/// \param pixels Array of pixels to copy to the image /// \param pixels Array of pixels to copy to the image
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void create(const Vector2u& size, const std::uint8_t* pixels); Image(const Vector2u& size, const std::uint8_t* pixels);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Load the image from a file on disk /// \brief Load the image from a file on disk
@ -87,12 +87,12 @@ public:
/// ///
/// \param filename Path of the image file to load /// \param filename Path of the image file to load
/// ///
/// \return True if loading was successful /// \return Image if loading was successful, `std::nullopt` otherwise
/// ///
/// \see loadFromMemory, loadFromStream, saveToFile /// \see loadFromMemory, loadFromStream, saveToFile
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
[[nodiscard]] bool loadFromFile(const std::filesystem::path& filename); [[nodiscard]] static std::optional<Image> loadFromFile(const std::filesystem::path& filename);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Load the image from a file in memory /// \brief Load the image from a file in memory
@ -105,12 +105,12 @@ public:
/// \param data Pointer to the file data in memory /// \param data Pointer to the file data in memory
/// \param size Size of the data to load, in bytes /// \param size Size of the data to load, in bytes
/// ///
/// \return True if loading was successful /// \return Image if loading was successful, `std::nullopt` otherwise
/// ///
/// \see loadFromFile, loadFromStream /// \see loadFromFile, loadFromStream
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
[[nodiscard]] bool loadFromMemory(const void* data, std::size_t size); [[nodiscard]] static std::optional<Image> loadFromMemory(const void* data, std::size_t size);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Load the image from a custom stream /// \brief Load the image from a custom stream
@ -122,12 +122,12 @@ public:
/// ///
/// \param stream Source stream to read from /// \param stream Source stream to read from
/// ///
/// \return True if loading was successful /// \return Image if loading was successful, `std::nullopt` otherwise
/// ///
/// \see loadFromFile, loadFromMemory /// \see loadFromFile, loadFromMemory
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
[[nodiscard]] bool loadFromStream(InputStream& stream); [[nodiscard]] static std::optional<Image> loadFromStream(InputStream& stream);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Save the image to a file on disk /// \brief Save the image to a file on disk
@ -281,6 +281,12 @@ public:
void flipVertically(); void flipVertically();
private: private:
////////////////////////////////////////////////////////////
/// \brief Directly initialize data members
///
////////////////////////////////////////////////////////////
Image(Vector2u size, std::vector<std::uint8_t>&& pixels);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -316,13 +322,10 @@ private:
/// Usage example: /// Usage example:
/// \code /// \code
/// // Load an image file from a file /// // Load an image file from a file
/// sf::Image background; /// const auto background = sf::Image::loadFromFile("background.jpg").value();
/// if (!background.loadFromFile("background.jpg"))
/// return -1;
/// ///
/// // Create a 20x20 image filled with black color /// // Create a 20x20 image filled with black color
/// sf::Image image; /// sf::Image image({20, 20}, sf::Color::Black);
/// image.create({20, 20}, sf::Color::Black);
/// ///
/// // Copy background on image at position (10, 10) /// // Copy background on image at position (10, 10)
/// if (!image.copy(background, {10, 10})) /// if (!image.copy(background, {10, 10}))

View File

@ -110,15 +110,6 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Load the texture from a file on disk /// \brief Load the texture from a file on disk
/// ///
/// This function is a shortcut for the following code:
/// \code
/// sf::Image image;
/// if (!image.loadFromFile(filename))
/// return false;
/// if (!texture.loadFromImage(image, area))
/// return false;
/// \endcode
///
/// The \a area argument can be used to load only a sub-rectangle /// The \a area argument can be used to load only a sub-rectangle
/// of the whole image. If you want the entire image then leave /// of the whole image. If you want the entire image then leave
/// the default value (which is an empty IntRect). /// the default value (which is an empty IntRect).
@ -143,15 +134,6 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Load the texture from a file in memory /// \brief Load the texture from a file in memory
/// ///
/// This function is a shortcut for the following code:
/// \code
/// sf::Image image;
/// if (!image.loadFromMemory(data, size))
/// return false;
/// if (!texture.loadFromImage(image, area))
/// return false;
/// \endcode
///
/// The \a area argument can be used to load only a sub-rectangle /// The \a area argument can be used to load only a sub-rectangle
/// of the whole image. If you want the entire image then leave /// of the whole image. If you want the entire image then leave
/// the default value (which is an empty IntRect). /// the default value (which is an empty IntRect).
@ -177,15 +159,6 @@ public:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Load the texture from a custom stream /// \brief Load the texture from a custom stream
/// ///
/// This function is a shortcut for the following code:
/// \code
/// sf::Image image;
/// if (!image.loadFromStream(stream))
/// return false;
/// if (!texture.loadFromImage(image, area))
/// return false;
/// \endcode
///
/// The \a area argument can be used to load only a sub-rectangle /// The \a area argument can be used to load only a sub-rectangle
/// of the whole image. If you want the entire image then leave /// of the whole image. If you want the entire image then leave
/// the default value (which is an empty IntRect). /// the default value (which is an empty IntRect).

View File

@ -784,8 +784,7 @@ bool Font::setCurrentSize(unsigned int characterSize) const
Font::Page::Page(bool smooth) Font::Page::Page(bool smooth)
{ {
// Make sure that the texture is initialized by default // Make sure that the texture is initialized by default
Image image; Image image({128, 128}, Color::Transparent);
image.create({128, 128}, Color::Transparent);
// Reserve a 2x2 white square for texturing underlines // Reserve a 2x2 white square for texturing underlines
for (unsigned int x = 0; x < 2; ++x) for (unsigned int x = 0; x < 2; ++x)

View File

@ -95,7 +95,7 @@ using StbPtr = std::unique_ptr<stbi_uc, StbDeleter>;
namespace sf namespace sf
{ {
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void Image::create(const Vector2u& size, const Color& color) Image::Image(const Vector2u& size, const Color& color)
{ {
if (size.x && size.y) if (size.x && size.y)
{ {
@ -131,7 +131,7 @@ void Image::create(const Vector2u& size, const Color& color)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void Image::create(const Vector2u& size, const std::uint8_t* pixels) Image::Image(const Vector2u& size, const std::uint8_t* pixels)
{ {
if (pixels && size.x && size.y) if (pixels && size.x && size.y)
{ {
@ -156,7 +156,13 @@ void Image::create(const Vector2u& size, const std::uint8_t* pixels)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool Image::loadFromFile(const std::filesystem::path& filename) Image::Image(Vector2u size, std::vector<std::uint8_t>&& pixels) : m_size(size), m_pixels(std::move(pixels))
{
}
////////////////////////////////////////////////////////////
std::optional<Image> Image::loadFromFile(const std::filesystem::path& filename)
{ {
#ifdef SFML_SYSTEM_ANDROID #ifdef SFML_SYSTEM_ANDROID
@ -168,9 +174,6 @@ bool Image::loadFromFile(const std::filesystem::path& filename)
#endif #endif
// Clear the array (just in case)
m_pixels.clear();
// Load the image and get a pointer to the pixels in memory // Load the image and get a pointer to the pixels in memory
int width = 0; int width = 0;
int height = 0; int height = 0;
@ -179,13 +182,7 @@ bool Image::loadFromFile(const std::filesystem::path& filename)
if (ptr) if (ptr)
{ {
// Assign the image properties return Image(Vector2u(Vector2i(width, height)), {ptr.get(), ptr.get() + width * height * 4});
m_size = Vector2u(Vector2i(width, height));
// Copy the loaded pixels to the pixel buffer
m_pixels.assign(ptr.get(), ptr.get() + width * height * 4);
return true;
} }
else else
{ {
@ -193,20 +190,17 @@ bool Image::loadFromFile(const std::filesystem::path& filename)
err() << "Failed to load image\n" err() << "Failed to load image\n"
<< formatDebugPathInfo(filename) << "\nReason: " << stbi_failure_reason() << std::endl; << formatDebugPathInfo(filename) << "\nReason: " << stbi_failure_reason() << std::endl;
return false; return std::nullopt;
} }
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool Image::loadFromMemory(const void* data, std::size_t size) std::optional<Image> Image::loadFromMemory(const void* data, std::size_t size)
{ {
// Check input parameters // Check input parameters
if (data && size) if (data && size)
{ {
// Clear the array (just in case)
m_pixels.clear();
// Load the image and get a pointer to the pixels in memory // Load the image and get a pointer to the pixels in memory
int width = 0; int width = 0;
int height = 0; int height = 0;
@ -217,41 +211,32 @@ bool Image::loadFromMemory(const void* data, std::size_t size)
if (ptr) if (ptr)
{ {
// Assign the image properties return Image(Vector2u(Vector2i(width, height)), {ptr.get(), ptr.get() + width * height * 4});
m_size = Vector2u(Vector2i(width, height));
// Copy the loaded pixels to the pixel buffer
m_pixels.assign(ptr.get(), ptr.get() + width * height * 4);
return true;
} }
else else
{ {
// Error, failed to load the image // Error, failed to load the image
err() << "Failed to load image from memory. Reason: " << stbi_failure_reason() << std::endl; err() << "Failed to load image from memory. Reason: " << stbi_failure_reason() << std::endl;
return false; return std::nullopt;
} }
} }
else else
{ {
err() << "Failed to load image from memory, no data provided" << std::endl; err() << "Failed to load image from memory, no data provided" << std::endl;
return false; return std::nullopt;
} }
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool Image::loadFromStream(InputStream& stream) std::optional<Image> Image::loadFromStream(InputStream& stream)
{ {
// Clear the array (just in case)
m_pixels.clear();
// Make sure that the stream's reading position is at the beginning // Make sure that the stream's reading position is at the beginning
if (stream.seek(0) == -1) if (stream.seek(0) == -1)
{ {
err() << "Failed to seek image stream" << std::endl; err() << "Failed to seek image stream" << std::endl;
return false; return std::nullopt;
} }
// Setup the stb_image callbacks // Setup the stb_image callbacks
@ -268,19 +253,13 @@ bool Image::loadFromStream(InputStream& stream)
if (ptr) if (ptr)
{ {
// Assign the image properties return Image(Vector2u(Vector2i(width, height)), {ptr.get(), ptr.get() + width * height * 4});
m_size = Vector2u(Vector2i(width, height));
// Copy the loaded pixels to the pixel buffer
m_pixels.assign(ptr.get(), ptr.get() + width * height * 4);
return true;
} }
else else
{ {
// Error, failed to load the image // Error, failed to load the image
err() << "Failed to load image from stream. Reason: " << stbi_failure_reason() << std::endl; err() << "Failed to load image from stream. Reason: " << stbi_failure_reason() << std::endl;
return false; return std::nullopt;
} }
} }

View File

@ -265,24 +265,30 @@ bool Texture::create(const Vector2u& size)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool Texture::loadFromFile(const std::filesystem::path& filename, const IntRect& area) bool Texture::loadFromFile(const std::filesystem::path& filename, const IntRect& area)
{ {
Image image; const auto image = sf::Image::loadFromFile(filename);
return image.loadFromFile(filename) && loadFromImage(image, area); if (!image)
return false;
return loadFromImage(*image, area);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool Texture::loadFromMemory(const void* data, std::size_t size, const IntRect& area) bool Texture::loadFromMemory(const void* data, std::size_t size, const IntRect& area)
{ {
Image image; const auto image = sf::Image::loadFromMemory(data, size);
return image.loadFromMemory(data, size) && loadFromImage(image, area); if (!image)
return false;
return loadFromImage(*image, area);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool Texture::loadFromStream(InputStream& stream, const IntRect& area) bool Texture::loadFromStream(InputStream& stream, const IntRect& area)
{ {
Image image; const auto image = sf::Image::loadFromStream(stream);
return image.loadFromStream(stream) && loadFromImage(image, area); if (!image)
return false;
return loadFromImage(*image, area);
} }
@ -364,8 +370,7 @@ Vector2u Texture::getSize() const
Image Texture::copyToImage() const Image Texture::copyToImage() const
{ {
// Easy case: empty texture // Easy case: empty texture
if (!m_texture) assert(m_texture && "Texture::copyToImage Cannot copy empty texture to image");
return {};
const TransientContextLock lock; const TransientContextLock lock;
@ -456,11 +461,7 @@ Image Texture::copyToImage() const
#endif // SFML_OPENGL_ES #endif // SFML_OPENGL_ES
// Create the image return {m_size, pixels.data()};
Image image;
image.create(m_size, pixels.data());
return image;
} }

View File

@ -13,25 +13,18 @@ TEST_CASE("[Graphics] sf::Image")
{ {
SECTION("Type traits") SECTION("Type traits")
{ {
STATIC_CHECK(!std::is_default_constructible_v<sf::Image>);
STATIC_CHECK(std::is_copy_constructible_v<sf::Image>); STATIC_CHECK(std::is_copy_constructible_v<sf::Image>);
STATIC_CHECK(std::is_copy_assignable_v<sf::Image>); STATIC_CHECK(std::is_copy_assignable_v<sf::Image>);
STATIC_CHECK(std::is_nothrow_move_constructible_v<sf::Image>); STATIC_CHECK(std::is_nothrow_move_constructible_v<sf::Image>);
STATIC_CHECK(std::is_nothrow_move_assignable_v<sf::Image>); STATIC_CHECK(std::is_nothrow_move_assignable_v<sf::Image>);
} }
SECTION("Default constructor") SECTION("Construction")
{ {
const sf::Image image; SECTION("Vector2 constructor")
CHECK(image.getSize() == sf::Vector2u());
CHECK(image.getPixelsPtr() == nullptr);
}
SECTION("Create")
{
SECTION("create(Vector2)")
{ {
sf::Image image; const sf::Image image(sf::Vector2u(10, 10));
image.create(sf::Vector2u(10, 10));
CHECK(image.getSize() == sf::Vector2u(10, 10)); CHECK(image.getSize() == sf::Vector2u(10, 10));
CHECK(image.getPixelsPtr() != nullptr); CHECK(image.getPixelsPtr() != nullptr);
@ -44,11 +37,9 @@ TEST_CASE("[Graphics] sf::Image")
} }
} }
SECTION("create(Vector2, Color)") SECTION("Vector2 and color constructor")
{ {
sf::Image image; const sf::Image image(sf::Vector2u(10, 10), sf::Color::Red);
image.create(sf::Vector2u(10, 10), sf::Color::Red);
CHECK(image.getSize() == sf::Vector2u(10, 10)); CHECK(image.getSize() == sf::Vector2u(10, 10));
CHECK(image.getPixelsPtr() != nullptr); CHECK(image.getPixelsPtr() != nullptr);
@ -61,7 +52,7 @@ TEST_CASE("[Graphics] sf::Image")
} }
} }
SECTION("create(Vector2, std::uint8_t*)") SECTION("Vector2 and std::uint8_t* constructor")
{ {
// 10 x 10, with 4 colour channels array // 10 x 10, with 4 colour channels array
std::array<std::uint8_t, 400> pixels{}; std::array<std::uint8_t, 400> pixels{};
@ -73,9 +64,7 @@ TEST_CASE("[Graphics] sf::Image")
pixels[i + 3] = 255; // a pixels[i + 3] = 255; // a
} }
sf::Image image; const sf::Image image(sf::Vector2u(10, 10), pixels.data());
image.create(sf::Vector2u(10, 10), pixels.data());
CHECK(image.getSize() == sf::Vector2u(10, 10)); CHECK(image.getSize() == sf::Vector2u(10, 10));
CHECK(image.getPixelsPtr() != nullptr); CHECK(image.getPixelsPtr() != nullptr);
@ -91,72 +80,72 @@ TEST_CASE("[Graphics] sf::Image")
SECTION("loadFromFile()") SECTION("loadFromFile()")
{ {
sf::Image image;
SECTION("Invalid file") SECTION("Invalid file")
{ {
CHECK(!image.loadFromFile(".")); CHECK(!sf::Image::loadFromFile("."));
CHECK(!image.loadFromFile("this/does/not/exist.jpg")); CHECK(!sf::Image::loadFromFile("this/does/not/exist.jpg"));
CHECK(image.getSize() == sf::Vector2u(0, 0));
CHECK(image.getPixelsPtr() == nullptr);
} }
SECTION("Successful load") SECTION("Successful load")
{ {
std::optional<sf::Image> image;
SECTION("bmp") SECTION("bmp")
{ {
REQUIRE(image.loadFromFile("Graphics/sfml-logo-big.bmp")); image = sf::Image::loadFromFile("Graphics/sfml-logo-big.bmp").value();
CHECK(image.getPixel({0, 0}) == sf::Color::White); REQUIRE(image.has_value());
CHECK(image.getPixel({200, 150}) == sf::Color(144, 208, 62)); CHECK(image->getPixel({0, 0}) == sf::Color::White);
CHECK(image->getPixel({200, 150}) == sf::Color(144, 208, 62));
} }
SECTION("png") SECTION("png")
{ {
REQUIRE(image.loadFromFile("Graphics/sfml-logo-big.png")); image = sf::Image::loadFromFile("Graphics/sfml-logo-big.png").value();
CHECK(image.getPixel({0, 0}) == sf::Color(255, 255, 255, 0)); REQUIRE(image.has_value());
CHECK(image.getPixel({200, 150}) == sf::Color(144, 208, 62)); CHECK(image->getPixel({0, 0}) == sf::Color(255, 255, 255, 0));
CHECK(image->getPixel({200, 150}) == sf::Color(144, 208, 62));
} }
SECTION("jpg") SECTION("jpg")
{ {
REQUIRE(image.loadFromFile("Graphics/sfml-logo-big.jpg")); image = sf::Image::loadFromFile("Graphics/sfml-logo-big.jpg").value();
CHECK(image.getPixel({0, 0}) == sf::Color::White); REQUIRE(image.has_value());
CHECK(image.getPixel({200, 150}) == sf::Color(144, 208, 62)); CHECK(image->getPixel({0, 0}) == sf::Color::White);
CHECK(image->getPixel({200, 150}) == sf::Color(144, 208, 62));
} }
SECTION("gif") SECTION("gif")
{ {
REQUIRE(image.loadFromFile("Graphics/sfml-logo-big.gif")); image = sf::Image::loadFromFile("Graphics/sfml-logo-big.gif").value();
CHECK(image.getPixel({0, 0}) == sf::Color::White); REQUIRE(image.has_value());
CHECK(image.getPixel({200, 150}) == sf::Color(146, 210, 62)); CHECK(image->getPixel({0, 0}) == sf::Color::White);
CHECK(image->getPixel({200, 150}) == sf::Color(146, 210, 62));
} }
SECTION("psd") SECTION("psd")
{ {
REQUIRE(image.loadFromFile("Graphics/sfml-logo-big.psd")); image = sf::Image::loadFromFile("Graphics/sfml-logo-big.psd").value();
CHECK(image.getPixel({0, 0}) == sf::Color::White); REQUIRE(image.has_value());
CHECK(image.getPixel({200, 150}) == sf::Color(144, 208, 62)); CHECK(image->getPixel({0, 0}) == sf::Color::White);
CHECK(image->getPixel({200, 150}) == sf::Color(144, 208, 62));
} }
CHECK(image.getSize() == sf::Vector2u(1001, 304)); CHECK(image->getSize() == sf::Vector2u(1001, 304));
CHECK(image.getPixelsPtr() != nullptr); CHECK(image->getPixelsPtr() != nullptr);
} }
} }
SECTION("loadFromMemory()") SECTION("loadFromMemory()")
{ {
sf::Image image;
SECTION("Invalid pointer") SECTION("Invalid pointer")
{ {
CHECK(!image.loadFromMemory(nullptr, 1)); CHECK(!sf::Image::loadFromMemory(nullptr, 1));
} }
SECTION("Invalid size") SECTION("Invalid size")
{ {
const std::byte testByte{0xAB}; const std::byte testByte{0xAB};
CHECK(!image.loadFromMemory(&testByte, 0)); CHECK(!sf::Image::loadFromMemory(&testByte, 0));
} }
SECTION("Failed load") SECTION("Failed load")
@ -173,19 +162,13 @@ TEST_CASE("[Graphics] sf::Image")
memory = {1, 2, 3, 4}; memory = {1, 2, 3, 4};
} }
CHECK(!image.loadFromMemory(memory.data(), memory.size())); CHECK(!sf::Image::loadFromMemory(memory.data(), memory.size()));
} }
SECTION("Successful load") SECTION("Successful load")
{ {
const auto memory = []() const auto memory = sf::Image({24, 24}, sf::Color::Green).saveToMemory("png").value();
{ const auto image = sf::Image::loadFromMemory(memory.data(), memory.size()).value();
sf::Image savedImage;
savedImage.create({24, 24}, sf::Color::Green);
return savedImage.saveToMemory("png").value();
}();
CHECK(image.loadFromMemory(memory.data(), memory.size()));
CHECK(image.getSize() == sf::Vector2u(24, 24)); CHECK(image.getSize() == sf::Vector2u(24, 24));
CHECK(image.getPixelsPtr() != nullptr); CHECK(image.getPixelsPtr() != nullptr);
CHECK(image.getPixel({0, 0}) == sf::Color::Green); CHECK(image.getPixel({0, 0}) == sf::Color::Green);
@ -195,18 +178,17 @@ TEST_CASE("[Graphics] sf::Image")
SECTION("loadFromStream()") SECTION("loadFromStream()")
{ {
sf::Image image;
sf::FileInputStream stream; sf::FileInputStream stream;
SECTION("Invalid stream") SECTION("Invalid stream")
{ {
CHECK(!image.loadFromStream(stream)); CHECK(!sf::Image::loadFromStream(stream));
} }
SECTION("Successful load") SECTION("Successful load")
{ {
CHECK(stream.open("Graphics/sfml-logo-big.png")); CHECK(stream.open("Graphics/sfml-logo-big.png"));
REQUIRE(image.loadFromStream(stream)); const auto image = sf::Image::loadFromStream(stream).value();
CHECK(image.getSize() == sf::Vector2u(1001, 304)); CHECK(image.getSize() == sf::Vector2u(1001, 304));
CHECK(image.getPixelsPtr() != nullptr); CHECK(image.getPixelsPtr() != nullptr);
CHECK(image.getPixel({0, 0}) == sf::Color(255, 255, 255, 0)); CHECK(image.getPixel({0, 0}) == sf::Color(255, 255, 255, 0));
@ -216,22 +198,13 @@ TEST_CASE("[Graphics] sf::Image")
SECTION("saveToFile()") SECTION("saveToFile()")
{ {
sf::Image image;
SECTION("Empty")
{
CHECK(!image.saveToFile("test.jpg"));
}
SECTION("Invalid size") SECTION("Invalid size")
{ {
image.create({10, 0}, sf::Color::Magenta); CHECK(!sf::Image({10, 0}, sf::Color::Magenta).saveToFile("test.jpg"));
CHECK(!image.saveToFile("test.jpg")); CHECK(!sf::Image({0, 10}, sf::Color::Magenta).saveToFile("test.jpg"));
image.create({0, 10}, sf::Color::Magenta);
CHECK(!image.saveToFile("test.jpg"));
} }
image.create({256, 256}, sf::Color::Magenta); const sf::Image image({256, 256}, sf::Color::Magenta);
SECTION("No extension") SECTION("No extension")
{ {
@ -269,8 +242,7 @@ TEST_CASE("[Graphics] sf::Image")
// Cannot test JPEG encoding due to it triggering UB in stbiw__jpg_writeBits // Cannot test JPEG encoding due to it triggering UB in stbiw__jpg_writeBits
sf::Image loadedImage; const auto loadedImage = sf::Image::loadFromFile(filename).value();
REQUIRE(loadedImage.loadFromFile(filename));
CHECK(loadedImage.getSize() == sf::Vector2u(256, 256)); CHECK(loadedImage.getSize() == sf::Vector2u(256, 256));
CHECK(loadedImage.getPixelsPtr() != nullptr); CHECK(loadedImage.getPixelsPtr() != nullptr);
@ -280,22 +252,13 @@ TEST_CASE("[Graphics] sf::Image")
SECTION("saveToMemory()") SECTION("saveToMemory()")
{ {
sf::Image image;
SECTION("Empty")
{
CHECK(!image.saveToMemory("test.jpg"));
}
SECTION("Invalid size") SECTION("Invalid size")
{ {
image.create({10, 0}, sf::Color::Magenta); CHECK(!sf::Image({10, 0}, sf::Color::Magenta).saveToMemory("test.jpg"));
CHECK(!image.saveToMemory("test.jpg")); CHECK(!sf::Image({0, 10}, sf::Color::Magenta).saveToMemory("test.jpg"));
image.create({0, 10}, sf::Color::Magenta);
CHECK(!image.saveToMemory("test.jpg"));
} }
image.create({16, 16}, sf::Color::Magenta); const sf::Image image({16, 16}, sf::Color::Magenta);
SECTION("No extension") SECTION("No extension")
{ {
@ -359,9 +322,7 @@ TEST_CASE("[Graphics] sf::Image")
SECTION("Set/get pixel") SECTION("Set/get pixel")
{ {
sf::Image image; sf::Image image(sf::Vector2u(10, 10), sf::Color::Green);
image.create(sf::Vector2u(10, 10), sf::Color::Green);
CHECK(image.getPixel(sf::Vector2u(2, 2)) == sf::Color::Green); CHECK(image.getPixel(sf::Vector2u(2, 2)) == sf::Color::Green);
image.setPixel(sf::Vector2u(2, 2), sf::Color::Blue); image.setPixel(sf::Vector2u(2, 2), sf::Color::Blue);
@ -372,11 +333,8 @@ TEST_CASE("[Graphics] sf::Image")
{ {
SECTION("Copy (Image, Vector2u)") SECTION("Copy (Image, Vector2u)")
{ {
sf::Image image1; const sf::Image image1(sf::Vector2u(10, 10), sf::Color::Blue);
image1.create(sf::Vector2u(10, 10), sf::Color::Blue); sf::Image image2(sf::Vector2u(10, 10));
sf::Image image2;
image2.create(sf::Vector2u(10, 10));
CHECK(image2.copy(image1, sf::Vector2u(0, 0))); CHECK(image2.copy(image1, sf::Vector2u(0, 0)));
for (std::uint32_t i = 0; i < 10; ++i) for (std::uint32_t i = 0; i < 10; ++i)
@ -390,11 +348,8 @@ TEST_CASE("[Graphics] sf::Image")
SECTION("Copy (Image, Vector2u, IntRect)") SECTION("Copy (Image, Vector2u, IntRect)")
{ {
sf::Image image1; const sf::Image image1(sf::Vector2u(5, 5), sf::Color::Blue);
image1.create(sf::Vector2u(5, 5), sf::Color::Blue); sf::Image image2(sf::Vector2u(10, 10));
sf::Image image2;
image2.create(sf::Vector2u(10, 10));
CHECK(image2.copy(image1, sf::Vector2u(0, 0), sf::IntRect(sf::Vector2i(0, 0), sf::Vector2i(5, 5)))); CHECK(image2.copy(image1, sf::Vector2u(0, 0), sf::IntRect(sf::Vector2i(0, 0), sf::Vector2i(5, 5))));
for (std::uint32_t i = 0; i < 10; ++i) for (std::uint32_t i = 0; i < 10; ++i)
@ -424,11 +379,8 @@ TEST_CASE("[Graphics] sf::Image")
((source.b * source.a) + ((dest.b * dest.a) * (255 - source.a)) / 255) / a); ((source.b * source.a) + ((dest.b * dest.a) * (255 - source.a)) / 255) / a);
const sf::Color composite(r, g, b, a); const sf::Color composite(r, g, b, a);
sf::Image image1; sf::Image image1(sf::Vector2u(10, 10), dest);
image1.create(sf::Vector2u(10, 10), dest); const sf::Image image2(sf::Vector2u(10, 10), source);
sf::Image image2;
image2.create(sf::Vector2u(10, 10), source);
CHECK(image1.copy(image2, sf::Vector2u(0, 0), sf::IntRect(sf::Vector2i(0, 0), sf::Vector2i(10, 10)), true)); CHECK(image1.copy(image2, sf::Vector2u(0, 0), sf::IntRect(sf::Vector2i(0, 0), sf::Vector2i(10, 10)), true));
for (std::uint32_t i = 0; i < 10; ++i) for (std::uint32_t i = 0; i < 10; ++i)
@ -440,31 +392,10 @@ TEST_CASE("[Graphics] sf::Image")
} }
} }
SECTION("Copy (Empty image)")
{
const sf::Image image1;
sf::Image image2;
image2.create(sf::Vector2u(10, 10), sf::Color::Red);
CHECK(!image2.copy(image1, sf::Vector2u(0, 0), sf::IntRect(sf::Vector2i(0, 0), sf::Vector2i(9, 9))));
for (std::uint32_t i = 0; i < 10; ++i)
{
for (std::uint32_t j = 0; j < 10; ++j)
{
CHECK(image2.getPixel(sf::Vector2u(i, j)) == sf::Color::Red);
}
}
}
SECTION("Copy (Out of bounds sourceRect)") SECTION("Copy (Out of bounds sourceRect)")
{ {
sf::Image image1; const sf::Image image1(sf::Vector2u(5, 5), sf::Color::Blue);
image1.create(sf::Vector2u(5, 5), sf::Color::Blue); sf::Image image2(sf::Vector2u(10, 10), sf::Color::Red);
sf::Image image2;
image2.create(sf::Vector2u(10, 10), sf::Color::Red);
CHECK(!image2.copy(image1, sf::Vector2u(0, 0), sf::IntRect(sf::Vector2i(5, 5), sf::Vector2i(9, 9)))); CHECK(!image2.copy(image1, sf::Vector2u(0, 0), sf::IntRect(sf::Vector2i(5, 5), sf::Vector2i(9, 9))));
for (std::uint32_t i = 0; i < 10; ++i) for (std::uint32_t i = 0; i < 10; ++i)
@ -481,8 +412,7 @@ TEST_CASE("[Graphics] sf::Image")
{ {
SECTION("createMaskFromColor(Color)") SECTION("createMaskFromColor(Color)")
{ {
sf::Image image; sf::Image image(sf::Vector2u(10, 10), sf::Color::Blue);
image.create(sf::Vector2u(10, 10), sf::Color::Blue);
image.createMaskFromColor(sf::Color::Blue); image.createMaskFromColor(sf::Color::Blue);
for (std::uint32_t i = 0; i < 10; ++i) for (std::uint32_t i = 0; i < 10; ++i)
@ -496,8 +426,7 @@ TEST_CASE("[Graphics] sf::Image")
SECTION("createMaskFromColor(Color, std::uint8_t)") SECTION("createMaskFromColor(Color, std::uint8_t)")
{ {
sf::Image image; sf::Image image(sf::Vector2u(10, 10), sf::Color::Blue);
image.create(sf::Vector2u(10, 10), sf::Color::Blue);
image.createMaskFromColor(sf::Color::Blue, 100); image.createMaskFromColor(sf::Color::Blue, 100);
for (std::uint32_t i = 0; i < 10; ++i) for (std::uint32_t i = 0; i < 10; ++i)
@ -512,8 +441,7 @@ TEST_CASE("[Graphics] sf::Image")
SECTION("Flip horizontally") SECTION("Flip horizontally")
{ {
sf::Image image; sf::Image image(sf::Vector2u(10, 10), sf::Color::Red);
image.create(sf::Vector2u(10, 10), sf::Color::Red);
image.setPixel(sf::Vector2u(0, 0), sf::Color::Green); image.setPixel(sf::Vector2u(0, 0), sf::Color::Green);
image.flipHorizontally(); image.flipHorizontally();
@ -522,8 +450,7 @@ TEST_CASE("[Graphics] sf::Image")
SECTION("Flip vertically") SECTION("Flip vertically")
{ {
sf::Image image; sf::Image image(sf::Vector2u(10, 10), sf::Color::Red);
image.create(sf::Vector2u(10, 10), sf::Color::Red);
image.setPixel(sf::Vector2u(0, 0), sf::Color::Green); image.setPixel(sf::Vector2u(0, 0), sf::Color::Green);
image.flipVertically(); image.flipVertically();

View File

@ -121,19 +121,10 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
SECTION("loadFromImage()") SECTION("loadFromImage()")
{ {
SECTION("Empty image")
{
const sf::Image image;
sf::Texture texture;
REQUIRE(!texture.loadFromImage(image));
REQUIRE(!texture.loadFromImage(image, {{0, 0}, {1, 1}}));
}
SECTION("Subarea of image") SECTION("Subarea of image")
{ {
sf::Image image; const sf::Image image(sf::Vector2u(10, 15));
image.create(sf::Vector2u(10, 15)); sf::Texture texture;
sf::Texture texture;
SECTION("Non-truncated area") SECTION("Non-truncated area")
{ {
@ -232,8 +223,7 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
SECTION("Image") SECTION("Image")
{ {
REQUIRE(texture.create(sf::Vector2u(16, 32))); REQUIRE(texture.create(sf::Vector2u(16, 32)));
sf::Image image; const sf::Image image(sf::Vector2u(16, 32), sf::Color::Red);
image.create(sf::Vector2u(16, 32), sf::Color::Red);
texture.update(image); texture.update(image);
CHECK(texture.copyToImage().getPixel(sf::Vector2u(7, 15)) == sf::Color::Red); CHECK(texture.copyToImage().getPixel(sf::Vector2u(7, 15)) == sf::Color::Red);
} }
@ -241,11 +231,9 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
SECTION("Image and destination") SECTION("Image and destination")
{ {
REQUIRE(texture.create(sf::Vector2u(16, 32))); REQUIRE(texture.create(sf::Vector2u(16, 32)));
sf::Image image1; const sf::Image image1(sf::Vector2u(16, 16), sf::Color::Red);
image1.create(sf::Vector2u(16, 16), sf::Color::Red);
texture.update(image1); texture.update(image1);
sf::Image image2; const sf::Image image2(sf::Vector2u(16, 16), sf::Color::Green);
image2.create(sf::Vector2u(16, 16), sf::Color::Green);
texture.update(image1, sf::Vector2u(0, 0)); texture.update(image1, sf::Vector2u(0, 0));
texture.update(image2, sf::Vector2u(0, 16)); texture.update(image2, sf::Vector2u(0, 16));
CHECK(texture.copyToImage().getPixel(sf::Vector2u(7, 7)) == sf::Color::Red); CHECK(texture.copyToImage().getPixel(sf::Vector2u(7, 7)) == sf::Color::Red);