Replace factory functions with throwing constructors

This commit is contained in:
binary1248 2024-07-06 04:24:00 +02:00 committed by Chris Thrasher
parent 698f265277
commit e185f6d53e
67 changed files with 2360 additions and 2263 deletions

View File

@ -21,15 +21,15 @@
/// sf::RenderWindow window(sf::VideoMode({800, 600}), "SFML window");
///
/// // Load a sprite to display
/// const auto texture = sf::Texture::loadFromFile("cute_image.jpg").value();
/// const sf::Texture texture("cute_image.jpg");
/// sf::Sprite sprite(texture);
///
/// // Create a graphical text to display
/// const auto font = sf::Font::openFromFile("arial.ttf").value();
/// const sf::Font font("arial.ttf");
/// sf::Text text(font, "Hello SFML", 50);
///
/// // Load a music to play
/// auto music = sf::Music::openFromFile("nice_music.ogg").value();
/// sf::Music music("nice_music.ogg");
///
/// // Play the music
/// music.play();

View File

@ -86,13 +86,13 @@ int main(int argc, char* argv[])
sf::RenderWindow window(screen, "");
window.setFramerateLimit(30);
const auto texture = sf::Texture::createFromFile("image.png").value();
const sf::Texture texture("image.png");
sf::Sprite image(texture);
image.setPosition(sf::Vector2f(screen.size) / 2.f);
image.setOrigin(sf::Vector2f(texture.getSize()) / 2.f);
const auto font = sf::Font::createFromFile("tuffy.ttf").value();
const sf::Font font("tuffy.ttf");
sf::Text text(font, "Tap anywhere to move the logo.", 64);
text.setFillColor(sf::Color::Black);

View File

@ -52,9 +52,9 @@ struct SFMLmainWindow
std::filesystem::path resPath{[[[NSBundle mainBundle] resourcePath] tostdstring]};
sf::RenderWindow renderWindow;
sf::Font font{sf::Font::createFromFile(resPath / "tuffy.ttf").value()};
sf::Font font{resPath / "tuffy.ttf"};
sf::Text text{font};
sf::Texture logo{sf::Texture::createFromFile(resPath / "logo.png").value()};
sf::Texture logo{resPath / "logo.png"};
sf::Sprite sprite{logo};
sf::Color background{sf::Color::Blue};
};

View File

@ -316,7 +316,7 @@ private:
// Member data
////////////////////////////////////////////////////////////
sf::RenderWindow m_window{sf::VideoMode({800u, 600u}), "SFML Event Handling", sf::Style::Titlebar | sf::Style::Close};
const sf::Font m_font{sf::Font::createFromFile("resources/tuffy.ttf").value()};
const sf::Font m_font{"resources/tuffy.ttf"};
sf::Text m_logText{m_font, "", 20};
sf::Text m_handlerText{m_font, "Current Handler: Classic", 24};
sf::Text m_instructions{m_font, "Press Enter to change handler type", 24};

View File

@ -91,14 +91,14 @@ int main()
sf::RenderWindow window(sf::VideoMode({windowWidth, windowHeight}), "SFML Island", sf::Style::Titlebar | sf::Style::Close);
window.setVerticalSyncEnabled(true);
const auto font = sf::Font::createFromFile("resources/tuffy.ttf").value();
const sf::Font font("resources/tuffy.ttf");
// Create all of our graphics resources
sf::Text hudText(font);
sf::Text statusText(font);
std::optional<sf::Shader> terrainShader;
sf::RenderStates terrainStates;
sf::VertexBuffer terrain(sf::PrimitiveType::Triangles, sf::VertexBuffer::Usage::Static);
sf::Text hudText(font);
sf::Text statusText(font);
sf::Shader terrainShader;
sf::RenderStates terrainStates;
sf::VertexBuffer terrain(sf::PrimitiveType::Triangles, sf::VertexBuffer::Usage::Static);
// Set up our text drawables
statusText.setCharacterSize(28);
@ -120,7 +120,7 @@ int main()
{
statusText.setString("Shaders and/or Vertex Buffers Unsupported");
}
else if (!(terrainShader = sf::Shader::createFromFile("resources/terrain.vert", "resources/terrain.frag")))
else if (!terrainShader.loadFromFile("resources/terrain.vert", "resources/terrain.frag"))
{
statusText.setString("Failed to load shader program");
}
@ -148,7 +148,7 @@ int main()
statusText.setString("Generating Terrain...");
// Set up the render states
terrainStates = sf::RenderStates(&*terrainShader);
terrainStates = sf::RenderStates(&terrainShader);
}
// Center the status text
@ -186,7 +186,8 @@ int main()
}
// Arrow key pressed:
if (terrainShader.has_value() && event->is<sf::Event::KeyPressed>())
// TODO Replace use of getNativeHandle() when validity function is added
if (terrainShader.getNativeHandle() != 0 && event->is<sf::Event::KeyPressed>())
{
switch (event->getIf<sf::Event::KeyPressed>()->code)
{
@ -216,7 +217,7 @@ int main()
window.draw(statusText);
if (terrainShader.has_value())
if (terrainShader.getNativeHandle() != 0)
{
{
const std::lock_guard lock(workQueueMutex);
@ -236,7 +237,7 @@ int main()
bufferUploadPending = false;
}
terrainShader->setUniform("lightFactor", lightFactor);
terrainShader.setUniform("lightFactor", lightFactor);
window.draw(terrain, terrainStates);
}
}

View File

@ -94,7 +94,7 @@ int main()
window.setVerticalSyncEnabled(true);
// Open the text font
const auto font = sf::Font::createFromFile("resources/tuffy.ttf").value();
const sf::Font font("resources/tuffy.ttf");
// Set up our string conversion parameters
sstr.precision(2);

View File

@ -58,11 +58,11 @@ int main()
window.setMaximumSize(sf::Vector2u(1200, 900));
// Create a sprite for the background
const auto backgroundTexture = sf::Texture::createFromFile(resourcesDir() / "background.jpg", sRgb).value();
const sf::Sprite background(backgroundTexture);
const sf::Texture backgroundTexture(resourcesDir() / "background.jpg", sRgb);
const sf::Sprite background(backgroundTexture);
// Create some text to draw on top of our OpenGL object
const auto font = sf::Font::createFromFile(resourcesDir() / "tuffy.ttf").value();
const sf::Font font(resourcesDir() / "tuffy.ttf");
sf::Text text(font, "SFML / OpenGL demo");
sf::Text sRgbInstructions(font, "Press space to toggle sRGB conversion");
@ -75,7 +75,7 @@ int main()
mipmapInstructions.setPosition({200.f, 550.f});
// Load a texture to apply to our 3D cube
auto texture = sf::Texture::createFromFile(resourcesDir() / "logo.png").value();
sf::Texture texture(resourcesDir() / "logo.png");
// Attempt to generate a mipmap for our cube texture
// We don't check the return value here since
@ -219,7 +219,7 @@ int main()
if (mipmapEnabled)
{
// We simply reload the texture to disable mipmapping
texture = sf::Texture::createFromFile(resourcesDir() / "logo.png").value();
texture = sf::Texture(resourcesDir() / "logo.png");
// Rebind the texture
sf::Texture::bind(&texture);

View File

@ -19,7 +19,7 @@ int main()
window.setVerticalSyncEnabled(true);
// Open the application font
const auto font = sf::Font::createFromFile("resources/tuffy.ttf").value();
const sf::Font font("resources/tuffy.ttf");
// Create the mouse position text
sf::Text mousePosition(font, "", 20);

View File

@ -278,69 +278,66 @@ private:
////////////////////////////////////////////////////////////
std::optional<Pixelate> tryLoadPixelate()
{
auto texture = sf::Texture::createFromFile("resources/background.jpg");
if (!texture.has_value())
sf::Texture texture;
if (!texture.loadFromFile("resources/background.jpg"))
return std::nullopt;
auto shader = sf::Shader::createFromFile("resources/pixelate.frag", sf::Shader::Type::Fragment);
if (!shader.has_value())
sf::Shader shader;
if (!shader.loadFromFile("resources/pixelate.frag", sf::Shader::Type::Fragment))
return std::nullopt;
return std::make_optional<Pixelate>(std::move(*texture), std::move(*shader));
return std::make_optional<Pixelate>(std::move(texture), std::move(shader));
}
std::optional<WaveBlur> tryLoadWaveBlur(const sf::Font& font)
{
auto shader = sf::Shader::createFromFile("resources/wave.vert", "resources/blur.frag");
if (!shader.has_value())
sf::Shader shader;
if (!shader.loadFromFile("resources/wave.vert", "resources/blur.frag"))
return std::nullopt;
return std::make_optional<WaveBlur>(font, std::move(*shader));
return std::make_optional<WaveBlur>(font, std::move(shader));
}
std::optional<StormBlink> tryLoadStormBlink()
{
auto shader = sf::Shader::createFromFile("resources/storm.vert", "resources/blink.frag");
if (!shader.has_value())
sf::Shader shader;
if (!shader.loadFromFile("resources/storm.vert", "resources/blink.frag"))
return std::nullopt;
return std::make_optional<StormBlink>(std::move(*shader));
return std::make_optional<StormBlink>(std::move(shader));
}
std::optional<Edge> tryLoadEdge()
{
// Create the off-screen surface
auto surface = sf::RenderTexture::create({800, 600});
if (!surface.has_value())
sf::RenderTexture surface;
if (!surface.resize({800, 600}))
return std::nullopt;
surface->setSmooth(true);
surface.setSmooth(true);
// Load the background texture
auto backgroundTexture = sf::Texture::createFromFile("resources/sfml.png");
if (!backgroundTexture.has_value())
sf::Texture backgroundTexture;
if (!backgroundTexture.loadFromFile("resources/sfml.png"))
return std::nullopt;
backgroundTexture->setSmooth(true);
backgroundTexture.setSmooth(true);
// Load the entity texture
auto entityTexture = sf::Texture::createFromFile("resources/devices.png");
if (!entityTexture.has_value())
sf::Texture entityTexture;
if (!entityTexture.loadFromFile("resources/devices.png"))
return std::nullopt;
entityTexture->setSmooth(true);
entityTexture.setSmooth(true);
// Load the shader
auto shader = sf::Shader::createFromFile("resources/edge.frag", sf::Shader::Type::Fragment);
if (!shader.has_value())
sf::Shader shader;
if (!shader.loadFromFile("resources/edge.frag", sf::Shader::Type::Fragment))
return std::nullopt;
shader->setUniform("texture", sf::Shader::CurrentTexture);
shader.setUniform("texture", sf::Shader::CurrentTexture);
return std::make_optional<Edge>(std::move(*surface),
std::move(*backgroundTexture),
std::move(*entityTexture),
std::move(*shader));
return std::make_optional<Edge>(std::move(surface), std::move(backgroundTexture), std::move(entityTexture), std::move(shader));
}
std::optional<Geometry> tryLoadGeometry()
@ -350,25 +347,23 @@ std::optional<Geometry> tryLoadGeometry()
return std::nullopt;
// Load the logo texture
auto logoTexture = sf::Texture::createFromFile("resources/logo.png");
if (!logoTexture.has_value())
sf::Texture logoTexture;
if (!logoTexture.loadFromFile("resources/logo.png"))
return std::nullopt;
logoTexture->setSmooth(true);
logoTexture.setSmooth(true);
// Load the shader
auto shader = sf::Shader::createFromFile("resources/billboard.vert",
"resources/billboard.geom",
"resources/billboard.frag");
if (!shader.has_value())
sf::Shader shader;
if (!shader.loadFromFile("resources/billboard.vert", "resources/billboard.geom", "resources/billboard.frag"))
return std::nullopt;
shader->setUniform("texture", sf::Shader::CurrentTexture);
shader.setUniform("texture", sf::Shader::CurrentTexture);
// Set the render resolution (used for proper scaling)
shader->setUniform("resolution", sf::Vector2f(800, 600));
shader.setUniform("resolution", sf::Vector2f(800, 600));
return std::make_optional<Geometry>(std::move(*logoTexture), std::move(*shader));
return std::make_optional<Geometry>(std::move(logoTexture), std::move(shader));
}
} // namespace
@ -394,7 +389,7 @@ int main()
window.setVerticalSyncEnabled(true);
// Open the application font
const auto font = sf::Font::createFromFile("resources/tuffy.ttf").value();
const sf::Font font("resources/tuffy.ttf");
// Create the effects
std::optional pixelateEffect = tryLoadPixelate();
@ -418,8 +413,8 @@ int main()
std::size_t current = 0;
// Create the messages background
const auto textBackgroundTexture = sf::Texture::createFromFile("resources/text-background.png").value();
sf::Sprite textBackground(textBackgroundTexture);
const sf::Texture textBackgroundTexture("resources/text-background.png");
sf::Sprite textBackground(textBackgroundTexture);
textBackground.setPosition({0.f, 520.f});
textBackground.setColor(sf::Color(255, 255, 255, 200));

View File

@ -13,7 +13,7 @@
void playSound()
{
// Load a sound buffer from a wav file
const auto buffer = sf::SoundBuffer::createFromFile("resources/killdeer.wav").value();
const sf::SoundBuffer buffer("resources/killdeer.wav");
// Display sound information
std::cout << "killdeer.wav:" << '\n'
@ -46,7 +46,7 @@ void playSound()
void playMusic(const std::filesystem::path& filename)
{
// Load an ogg music file
auto music = sf::Music::createFromFile("resources" / filename).value();
sf::Music music("resources" / filename);
// Display music information
std::cout << filename << ":" << '\n'

View File

@ -115,23 +115,23 @@ public:
m_listener.setFillColor(sf::Color::Red);
// Load the music file
if (!(m_music = sf::Music::createFromFile(resourcesDir() / "doodle_pop.ogg")))
if (!m_music.openFromFile(resourcesDir() / "doodle_pop.ogg"))
{
std::cerr << "Failed to load " << (resourcesDir() / "doodle_pop.ogg").string() << std::endl;
std::abort();
}
// Set the music to loop
m_music->setLoop(true);
m_music.setLoop(true);
// Set attenuation to a nice value
m_music->setAttenuation(0.04f);
m_music.setAttenuation(0.04f);
}
void onUpdate(float /*time*/, float x, float y) override
{
m_position = {windowWidth * x - 10.f, windowHeight * y - 10.f};
m_music->setPosition({m_position.x, m_position.y, 0.f});
m_music.setPosition({m_position.x, m_position.y, 0.f});
}
void onDraw(sf::RenderTarget& target, sf::RenderStates states) const override
@ -149,19 +149,19 @@ public:
// Synchronize listener audio position with graphical position
sf::Listener::setPosition({m_listener.getPosition().x, m_listener.getPosition().y, 0.f});
m_music->play();
m_music.play();
}
void onStop() override
{
m_music->stop();
m_music.stop();
}
private:
sf::CircleShape m_listener{20.f};
sf::CircleShape m_soundShape{20.f};
sf::Vector2f m_position;
std::optional<sf::Music> m_music;
sf::CircleShape m_listener{20.f};
sf::CircleShape m_soundShape{20.f};
sf::Vector2f m_position;
sf::Music m_music;
};
@ -177,23 +177,23 @@ public:
m_volumeText(getFont(), "Volume: " + std::to_string(m_volume))
{
// Load the music file
if (!(m_music = sf::Music::createFromFile(resourcesDir() / "doodle_pop.ogg")))
if (!m_music.openFromFile(resourcesDir() / "doodle_pop.ogg"))
{
std::cerr << "Failed to load " << (resourcesDir() / "doodle_pop.ogg").string() << std::endl;
std::abort();
}
// Set the music to loop
m_music->setLoop(true);
m_music.setLoop(true);
// We don't care about attenuation in this effect
m_music->setAttenuation(0.f);
m_music.setAttenuation(0.f);
// Set initial pitch
m_music->setPitch(m_pitch);
m_music.setPitch(m_pitch);
// Set initial volume
m_music->setVolume(m_volume);
m_music.setVolume(m_volume);
m_pitchText.setPosition({windowWidth / 2.f - 120.f, windowHeight / 2.f - 80.f});
m_volumeText.setPosition({windowWidth / 2.f - 120.f, windowHeight / 2.f - 30.f});
@ -204,8 +204,8 @@ public:
m_pitch = std::clamp(2.f * x, 0.f, 2.f);
m_volume = std::clamp(100.f * (1.f - y), 0.f, 100.f);
m_music->setPitch(m_pitch);
m_music->setVolume(m_volume);
m_music.setPitch(m_pitch);
m_music.setVolume(m_volume);
m_pitchText.setString("Pitch: " + std::to_string(m_pitch));
m_volumeText.setString("Volume: " + std::to_string(m_volume));
@ -223,20 +223,20 @@ public:
// so that the music is right on top of the listener
sf::Listener::setPosition({0.f, 0.f, 0.f});
m_music->play();
m_music.play();
}
void onStop() override
{
m_music->stop();
m_music.stop();
}
private:
float m_pitch{1.f};
float m_volume{100.f};
sf::Text m_pitchText;
sf::Text m_volumeText;
std::optional<sf::Music> m_music;
float m_pitch{1.f};
float m_volume{100.f};
sf::Text m_pitchText;
sf::Text m_volumeText;
sf::Music m_music;
};
@ -283,23 +283,23 @@ public:
makeCone(m_soundConeInner, innerConeAngle);
// Load the music file
if (!(m_music = sf::Music::createFromFile(resourcesDir() / "doodle_pop.ogg")))
if (!m_music.openFromFile(resourcesDir() / "doodle_pop.ogg"))
{
std::cerr << "Failed to load " << (resourcesDir() / "doodle_pop.ogg").string() << std::endl;
std::abort();
}
// Set the music to loop
m_music->setLoop(true);
m_music.setLoop(true);
// Set attenuation factor
m_music->setAttenuation(m_attenuation);
m_music.setAttenuation(m_attenuation);
// Set direction to face "downwards"
m_music->setDirection({0.f, 1.f, 0.f});
m_music.setDirection({0.f, 1.f, 0.f});
// Set cone
m_music->setCone({innerConeAngle, outerConeAngle, 0.f});
m_music.setCone({innerConeAngle, outerConeAngle, 0.f});
m_text.setString(
"Attenuation factor dampens full volume of sound while within inner cone based on distance to "
@ -314,7 +314,7 @@ public:
void onUpdate(float /*time*/, float x, float y) override
{
m_position = {windowWidth * x - 10.f, windowHeight * y - 10.f};
m_music->setPosition({m_position.x, m_position.y, 0.f});
m_music.setPosition({m_position.x, m_position.y, 0.f});
}
void onDraw(sf::RenderTarget& target, sf::RenderStates states) const override
@ -336,22 +336,22 @@ public:
// Synchronize listener audio position with graphical position
sf::Listener::setPosition({m_listener.getPosition().x, m_listener.getPosition().y, 0.f});
m_music->play();
m_music.play();
}
void onStop() override
{
m_music->stop();
m_music.stop();
}
private:
sf::CircleShape m_listener{20.f};
sf::CircleShape m_soundShape{20.f};
sf::ConvexShape m_soundConeOuter;
sf::ConvexShape m_soundConeInner;
sf::Text m_text;
sf::Vector2f m_position;
std::optional<sf::Music> m_music;
sf::CircleShape m_listener{20.f};
sf::CircleShape m_soundShape{20.f};
sf::ConvexShape m_soundConeOuter;
sf::ConvexShape m_soundConeInner;
sf::Text m_text;
sf::Vector2f m_position;
sf::Music m_music;
float m_attenuation{0.01f};
};
@ -636,7 +636,7 @@ public:
void onUpdate([[maybe_unused]] float time, float x, float y) override
{
m_position = {windowWidth * x - 10.f, windowHeight * y - 10.f};
m_music->setPosition({m_position.x, m_position.y, 0.f});
m_music.setPosition({m_position.x, m_position.y, 0.f});
}
void onDraw(sf::RenderTarget& target, sf::RenderStates states) const override
@ -656,12 +656,12 @@ public:
// Synchronize listener audio position with graphical position
sf::Listener::setPosition({m_listener.getPosition().x, m_listener.getPosition().y, 0.f});
m_music->play();
m_music.play();
}
void onStop() override
{
m_music->stop();
m_music.stop();
}
protected:
@ -677,22 +677,22 @@ protected:
m_instructions.setPosition({windowWidth / 2.f - 250.f, windowHeight * 3.f / 4.f});
// Load the music file
if (!(m_music = sf::Music::createFromFile(resourcesDir() / "doodle_pop.ogg")))
if (!m_music.openFromFile(resourcesDir() / "doodle_pop.ogg"))
{
std::cerr << "Failed to load " << (resourcesDir() / "doodle_pop.ogg").string() << std::endl;
std::abort();
}
// Set the music to loop
m_music->setLoop(true);
m_music.setLoop(true);
// Set attenuation to a nice value
m_music->setAttenuation(0.0f);
m_music.setAttenuation(0.0f);
}
sf::Music& getMusic()
{
return *m_music;
return m_music;
}
const std::shared_ptr<bool>& getEnabled() const
@ -709,13 +709,13 @@ private:
m_enabledText.setString(*m_enabled ? "Processing: Enabled" : "Processing: Disabled");
}
sf::CircleShape m_listener{20.f};
sf::CircleShape m_soundShape{20.f};
sf::Vector2f m_position;
std::optional<sf::Music> m_music;
std::shared_ptr<bool> m_enabled{std::make_shared<bool>(true)};
sf::Text m_enabledText;
sf::Text m_instructions;
sf::CircleShape m_listener{20.f};
sf::CircleShape m_soundShape{20.f};
sf::Vector2f m_position;
sf::Music m_music;
std::shared_ptr<bool> m_enabled{std::make_shared<bool>(true)};
sf::Text m_enabledText;
sf::Text m_instructions;
};
@ -1077,7 +1077,7 @@ int main()
window.setVerticalSyncEnabled(true);
// Open the application font and pass it to the Effect class
const auto font = sf::Font::createFromFile(resourcesDir() / "tuffy.ttf").value();
const sf::Font font(resourcesDir() / "tuffy.ttf");
Effect::setFont(font);
// Create the effects
@ -1106,8 +1106,8 @@ int main()
effects[current]->start();
// Create the messages background
const auto textBackgroundTexture = sf::Texture::createFromFile(resourcesDir() / "text-background.png").value();
sf::Sprite textBackground(textBackgroundTexture);
const sf::Texture textBackgroundTexture(resourcesDir() / "text-background.png");
sf::Sprite textBackground(textBackgroundTexture);
textBackground.setPosition({0.f, 520.f});
textBackground.setColor(sf::Color(255, 255, 255, 200));

View File

@ -49,12 +49,12 @@ int main()
window.setVerticalSyncEnabled(true);
// Load the sounds used in the game
const auto ballSoundBuffer = sf::SoundBuffer::createFromFile(resourcesDir() / "ball.wav").value();
sf::Sound ballSound(ballSoundBuffer);
const sf::SoundBuffer ballSoundBuffer(resourcesDir() / "ball.wav");
sf::Sound ballSound(ballSoundBuffer);
// Create the SFML logo texture:
const auto sfmlLogoTexture = sf::Texture::createFromFile(resourcesDir() / "sfml_logo.png").value();
sf::Sprite sfmlLogo(sfmlLogoTexture);
const sf::Texture sfmlLogoTexture(resourcesDir() / "sfml_logo.png");
sf::Sprite sfmlLogo(sfmlLogoTexture);
sfmlLogo.setPosition({170.f, 50.f});
// Create the left paddle
@ -82,7 +82,7 @@ int main()
ball.setOrigin({ballRadius / 2.f, ballRadius / 2.f});
// Open the text font
const auto font = sf::Font::createFromFile(resourcesDir() / "tuffy.ttf").value();
const sf::Font font(resourcesDir() / "tuffy.ttf");
// Initialize the pause message
sf::Text pauseMessage(font);

View File

@ -923,17 +923,17 @@ public:
// Use the vertex shader SPIR-V code to create a vertex shader module
{
auto file = sf::FileInputStream::create("resources/shader.vert.spv");
if (!file)
sf::FileInputStream file;
if (!file.open("resources/shader.vert.spv"))
{
vulkanAvailable = false;
return;
}
const auto fileSize = file->getSize().value();
const auto fileSize = file.getSize().value();
std::vector<std::uint32_t> buffer(fileSize / sizeof(std::uint32_t));
if (file->read(buffer.data(), fileSize) != file->getSize())
if (file.read(buffer.data(), fileSize) != file.getSize())
{
vulkanAvailable = false;
return;
@ -951,17 +951,17 @@ public:
// Use the fragment shader SPIR-V code to create a fragment shader module
{
auto file = sf::FileInputStream::create("resources/shader.frag.spv");
if (!file)
sf::FileInputStream file;
if (!file.open("resources/shader.frag.spv"))
{
vulkanAvailable = false;
return;
}
const auto fileSize = file->getSize().value();
const auto fileSize = file.getSize().value();
std::vector<std::uint32_t> buffer(fileSize / sizeof(std::uint32_t));
if (file->read(buffer.data(), fileSize) != file->getSize())
if (file.read(buffer.data(), fileSize) != file.getSize())
{
vulkanAvailable = false;
return;
@ -1801,16 +1801,13 @@ public:
void setupTextureImage()
{
// Load the image data
const auto maybeImageData = sf::Image::createFromFile("resources/logo.png");
if (!maybeImageData)
sf::Image imageData;
if (!imageData.loadFromFile("resources/logo.png"))
{
vulkanAvailable = false;
return;
}
const auto& imageData = *maybeImageData;
// Create a staging buffer to transfer the data with
const VkDeviceSize imageSize = imageData.getSize().x * imageData.getSize().y * 4;

View File

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

View File

@ -33,7 +33,6 @@
#include <filesystem>
#include <memory>
#include <optional>
#include <vector>
#include <cstddef>
@ -61,6 +60,51 @@ public:
////////////////////////////////////////////////////////////
InputSoundFile() = default;
////////////////////////////////////////////////////////////
/// \brief Construct a sound file from the disk for reading
///
/// The supported audio formats are: WAV (PCM only), OGG/Vorbis, FLAC, MP3.
/// The supported sample sizes for FLAC and WAV are 8, 16, 24 and 32 bit.
///
/// Because of minimp3_ex limitation, for MP3 files with big (>16kb) APEv2 tag,
/// it may not be properly removed, tag data will be treated as MP3 data
/// and there is a low chance of garbage decoded at the end of file.
/// See also: https://github.com/lieff/minimp3
///
/// \param filename Path of the sound file to load
///
/// \throws std::runtime_error if opening the file was unsuccessful
///
////////////////////////////////////////////////////////////
InputSoundFile(const std::filesystem::path& filename);
////////////////////////////////////////////////////////////
/// \brief Construct a sound file in memory for reading
///
/// The supported audio formats are: WAV (PCM only), OGG/Vorbis, FLAC.
/// The supported sample sizes for FLAC and WAV are 8, 16, 24 and 32 bit.
///
/// \param data Pointer to the file data in memory
/// \param sizeInBytes Size of the data to load, in bytes
///
/// \throws std::runtime_error if opening the file was unsuccessful
///
////////////////////////////////////////////////////////////
InputSoundFile(const void* data, std::size_t sizeInBytes);
////////////////////////////////////////////////////////////
/// \brief Construct a sound file from a custom stream for reading
///
/// The supported audio formats are: WAV (PCM only), OGG/Vorbis, FLAC.
/// The supported sample sizes for FLAC and WAV are 8, 16, 24 and 32 bit.
///
/// \param stream Source stream to read from
///
/// \throws std::runtime_error if opening the file was unsuccessful
///
////////////////////////////////////////////////////////////
InputSoundFile(InputStream& stream);
////////////////////////////////////////////////////////////
/// \brief Open a sound file from the disk for reading
///
@ -106,51 +150,6 @@ public:
////////////////////////////////////////////////////////////
[[nodiscard]] bool openFromStream(InputStream& stream);
////////////////////////////////////////////////////////////
/// \brief Create a sound file from the disk for reading
///
/// The supported audio formats are: WAV (PCM only), OGG/Vorbis, FLAC, MP3.
/// The supported sample sizes for FLAC and WAV are 8, 16, 24 and 32 bit.
///
/// Because of minimp3_ex limitation, for MP3 files with big (>16kb) APEv2 tag,
/// it may not be properly removed, tag data will be treated as MP3 data
/// and there is a low chance of garbage decoded at the end of file.
/// See also: https://github.com/lieff/minimp3
///
/// \param filename Path of the sound file to load
///
/// \return Input sound file if the file was successfully opened, otherwise `std::nullopt`
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<InputSoundFile> createFromFile(const std::filesystem::path& filename);
////////////////////////////////////////////////////////////
/// \brief Create a sound file in memory for reading
///
/// The supported audio formats are: WAV (PCM only), OGG/Vorbis, FLAC.
/// The supported sample sizes for FLAC and WAV are 8, 16, 24 and 32 bit.
///
/// \param data Pointer to the file data in memory
/// \param sizeInBytes Size of the data to load, in bytes
///
/// \return Input sound file if the file was successfully opened, otherwise `std::nullopt`
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<InputSoundFile> createFromMemory(const void* data, std::size_t sizeInBytes);
////////////////////////////////////////////////////////////
/// \brief Create a sound file from a custom stream for reading
///
/// The supported audio formats are: WAV (PCM only), OGG/Vorbis, FLAC.
/// The supported sample sizes for FLAC and WAV are 8, 16, 24 and 32 bit.
///
/// \param stream Source stream to read from
///
/// \return Input sound file if the file was successfully opened, otherwise `std::nullopt`
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<InputSoundFile> createFromStream(InputStream& stream);
////////////////////////////////////////////////////////////
/// \brief Get the total number of audio samples in the file
///
@ -311,7 +310,7 @@ private:
/// Usage example:
/// \code
/// // Open a sound file
/// auto file = sf::InputSoundFile::createFromFile("music.ogg").value();
/// sf::InputSoundFile file("music.ogg");
///
/// // Print the sound attributes
/// std::cout << "duration: " << file.getDuration().asSeconds() << '\n'

View File

@ -74,6 +74,71 @@ public:
////////////////////////////////////////////////////////////
Music();
////////////////////////////////////////////////////////////
/// \brief Construct a music from an audio file
///
/// This function doesn't start playing the music (call play()
/// to do so).
/// See the documentation of sf::InputSoundFile for the list
/// of supported formats.
///
/// \warning Since the music is not loaded at once but rather
/// streamed continuously, the file must remain accessible until
/// the sf::Music object loads a new music or is destroyed.
///
/// \param filename Path of the music file to open
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see openFromMemory, openFromStream
///
////////////////////////////////////////////////////////////
Music(const std::filesystem::path& filename);
////////////////////////////////////////////////////////////
/// \brief Construct a music from an audio file in memory
///
/// This function doesn't start playing the music (call play()
/// to do so).
/// See the documentation of sf::InputSoundFile for the list
/// of supported formats.
///
/// \warning Since the music is not loaded at once but rather streamed
/// continuously, the \a data buffer must remain accessible until
/// the sf::Music object loads a new music or is destroyed. That is,
/// you can't deallocate the buffer right after calling this function.
///
/// \param data Pointer to the file data in memory
/// \param sizeInBytes Size of the data to load, in bytes
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see openFromFile, openFromStream
///
////////////////////////////////////////////////////////////
Music(const void* data, std::size_t sizeInBytes);
////////////////////////////////////////////////////////////
/// \brief Construct a music from an audio file in a custom stream
///
/// This function doesn't start playing the music (call play()
/// to do so).
/// See the documentation of sf::InputSoundFile for the list
/// of supported formats.
///
/// \warning Since the music is not loaded at once but rather
/// streamed continuously, the \a stream must remain accessible
/// until the sf::Music object loads a new music or is destroyed.
///
/// \param stream Source stream to read from
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see openFromFile, openFromMemory
///
////////////////////////////////////////////////////////////
Music(InputStream& stream);
////////////////////////////////////////////////////////////
/// \brief Destructor
///
@ -157,71 +222,6 @@ public:
////////////////////////////////////////////////////////////
[[nodiscard]] bool openFromStream(InputStream& stream);
////////////////////////////////////////////////////////////
/// \brief Create a music from an audio file
///
/// This function doesn't start playing the music (call play()
/// to do so).
/// See the documentation of sf::InputSoundFile for the list
/// of supported formats.
///
/// \warning Since the music is not loaded at once but rather
/// streamed continuously, the file must remain accessible until
/// the sf::Music object loads a new music or is destroyed.
///
/// \param filename Path of the music file to open
///
/// \return Music if loading succeeded, `std::nullopt` if it failed
///
/// \see createFromMemory, createFromStream
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Music> createFromFile(const std::filesystem::path& filename);
////////////////////////////////////////////////////////////
/// \brief Create a music from an audio file in memory
///
/// This function doesn't start playing the music (call play()
/// to do so).
/// See the documentation of sf::InputSoundFile for the list
/// of supported formats.
///
/// \warning Since the music is not loaded at once but rather streamed
/// continuously, the \a data buffer must remain accessible until
/// the sf::Music object loads a new music or is destroyed. That is,
/// you can't deallocate the buffer right after calling this function.
///
/// \param data Pointer to the file data in memory
/// \param sizeInBytes Size of the data to load, in bytes
///
/// \return Music if loading succeeded, `std::nullopt` if it failed
///
/// \see createFromFile, createFromStream
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Music> createFromMemory(const void* data, std::size_t sizeInBytes);
////////////////////////////////////////////////////////////
/// \brief Create a music from an audio file in a custom stream
///
/// This function doesn't start playing the music (call play()
/// to do so).
/// See the documentation of sf::InputSoundFile for the list
/// of supported formats.
///
/// \warning Since the music is not loaded at once but rather
/// streamed continuously, the \a stream must remain accessible
/// until the sf::Music object loads a new music or is destroyed.
///
/// \param stream Source stream to read from
///
/// \return Music if loading succeeded, `std::nullopt` if it failed
///
/// \see createFromFile, createFromMemory
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Music> createFromStream(InputStream& stream);
////////////////////////////////////////////////////////////
/// \brief Get the total duration of the music
///
@ -360,7 +360,7 @@ private:
/// Usage example:
/// \code
/// // Open a music from an audio file
/// auto music = sf::Music::createFromFile("music.ogg").value();
/// sf::Music music("music.ogg");
///
/// // Change some parameters
/// music.setPosition({0, 1, 10}); // change its 3D position

View File

@ -34,7 +34,6 @@
#include <filesystem>
#include <memory>
#include <optional>
#include <vector>
#include <cstdint>
@ -58,6 +57,24 @@ public:
////////////////////////////////////////////////////////////
OutputSoundFile() = default;
////////////////////////////////////////////////////////////
/// \brief Construct the sound file from the disk for writing
///
/// The supported audio formats are: WAV, OGG/Vorbis, FLAC.
///
/// \param filename Path of the sound file to write
/// \param sampleRate Sample rate of the sound
/// \param channelCount Number of channels in the sound
/// \param channelMap Map of position in sample frame to sound channel
///
/// \throws std::runtime_error if the file could not be opened successfully
///
////////////////////////////////////////////////////////////
OutputSoundFile(const std::filesystem::path& filename,
unsigned int sampleRate,
unsigned int channelCount,
const std::vector<SoundChannel>& channelMap);
////////////////////////////////////////////////////////////
/// \brief Open the sound file from the disk for writing
///
@ -76,25 +93,6 @@ public:
unsigned int channelCount,
const std::vector<SoundChannel>& channelMap);
////////////////////////////////////////////////////////////
/// \brief Create the sound file from the disk for writing
///
/// The supported audio formats are: WAV, OGG/Vorbis, FLAC.
///
/// \param filename Path of the sound file to write
/// \param sampleRate Sample rate of the sound
/// \param channelCount Number of channels in the sound
/// \param channelMap Map of position in sample frame to sound channel
///
/// \return Output sound file if the file was successfully opened
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<OutputSoundFile> createFromFile(
const std::filesystem::path& filename,
unsigned int sampleRate,
unsigned int channelCount,
const std::vector<SoundChannel>& channelMap);
////////////////////////////////////////////////////////////
/// \brief Write audio samples to the file
///
@ -132,7 +130,7 @@ private:
/// Usage example:
/// \code
/// // Create a sound file, ogg/vorbis format, 44100 Hz, stereo
/// auto file = sf::OutputSoundFile::createFromFile("music.ogg", 44100, 2).value();
/// sf::OutputSoundFile file("music.ogg", 44100, 2, {sf::SoundChannel::FrontLeft, sf::SoundChannel::FrontRight});
///
/// while (...)
/// {

View File

@ -274,7 +274,7 @@ private:
///
/// Usage example:
/// \code
/// const auto buffer = sf::SoundBuffer::createFromFile("sound.wav").value();
/// const sf::SoundBuffer buffer("sound.wav");
/// sf::Sound sound(buffer);
/// sound.play();
/// \endcode

View File

@ -34,7 +34,6 @@
#include <SFML/System/Time.hpp>
#include <filesystem>
#include <optional>
#include <unordered_set>
#include <vector>
@ -72,6 +71,74 @@ public:
////////////////////////////////////////////////////////////
SoundBuffer(const SoundBuffer& copy);
////////////////////////////////////////////////////////////
/// \brief Construct the sound buffer from a file
///
/// See the documentation of sf::InputSoundFile for the list
/// of supported formats.
///
/// \param filename Path of the sound file to load
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see loadFromMemory, loadFromStream, loadFromSamples, saveToFile
///
////////////////////////////////////////////////////////////
SoundBuffer(const std::filesystem::path& filename);
////////////////////////////////////////////////////////////
/// \brief Construct the sound buffer from a file in memory
///
/// See the documentation of sf::InputSoundFile for the list
/// of supported formats.
///
/// \param data Pointer to the file data in memory
/// \param sizeInBytes Size of the data to load, in bytes
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see loadFromFile, loadFromStream, loadFromSamples
///
////////////////////////////////////////////////////////////
SoundBuffer(const void* data, std::size_t sizeInBytes);
////////////////////////////////////////////////////////////
/// \brief Construct the sound buffer from a custom stream
///
/// See the documentation of sf::InputSoundFile for the list
/// of supported formats.
///
/// \param stream Source stream to read from
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see loadFromFile, loadFromMemory, loadFromSamples
///
////////////////////////////////////////////////////////////
SoundBuffer(InputStream& stream);
////////////////////////////////////////////////////////////
/// \brief Construct the sound buffer from an array of audio samples
///
/// The assumed format of the audio samples is 16 bit signed integer.
///
/// \param samples Pointer to the array of samples in memory
/// \param sampleCount Number of samples in the array
/// \param channelCount Number of channels (1 = mono, 2 = stereo, ...)
/// \param sampleRate Sample rate (number of samples to play per second)
/// \param channelMap Map of position in sample frame to sound channel
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see loadFromFile, loadFromMemory, saveToFile
///
////////////////////////////////////////////////////////////
SoundBuffer(const std::int16_t* samples,
std::uint64_t sampleCount,
unsigned int channelCount,
unsigned int sampleRate,
const std::vector<SoundChannel>& channelMap);
////////////////////////////////////////////////////////////
/// \brief Destructor
///
@ -146,75 +213,6 @@ public:
unsigned int sampleRate,
const std::vector<SoundChannel>& channelMap);
////////////////////////////////////////////////////////////
/// \brief Create the sound buffer from a file
///
/// See the documentation of sf::InputSoundFile for the list
/// of supported formats.
///
/// \param filename Path of the sound file to load
///
/// \return Sound buffer if loading succeeded, `std::nullopt` if it failed
///
/// \see createFromMemory, createFromStream, createFromSamples, saveToFile
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<SoundBuffer> createFromFile(const std::filesystem::path& filename);
////////////////////////////////////////////////////////////
/// \brief Create the sound buffer from a file in memory
///
/// See the documentation of sf::InputSoundFile for the list
/// of supported formats.
///
/// \param data Pointer to the file data in memory
/// \param sizeInBytes Size of the data to load, in bytes
///
/// \return Sound buffer if loading succeeded, `std::nullopt` if it failed
///
/// \see createFromFile, createFromStream, createFromSamples
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<SoundBuffer> createFromMemory(const void* data, std::size_t sizeInBytes);
////////////////////////////////////////////////////////////
/// \brief Create the sound buffer from a custom stream
///
/// See the documentation of sf::InputSoundFile for the list
/// of supported formats.
///
/// \param stream Source stream to read from
///
/// \return Sound buffer if loading succeeded, `std::nullopt` if it failed
///
/// \see createFromFile, createFromMemory, createFromSamples
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<SoundBuffer> createFromStream(InputStream& stream);
////////////////////////////////////////////////////////////
/// \brief Create the sound buffer from an array of audio samples
///
/// The assumed format of the audio samples is 16 bits signed integer.
///
/// \param samples Pointer to the array of samples in memory
/// \param sampleCount Number of samples in the array
/// \param channelCount Number of channels (1 = mono, 2 = stereo, ...)
/// \param sampleRate Sample rate (number of samples to play per second)
/// \param channelMap Map of position in sample frame to sound channel
///
/// \return Sound buffer if loading succeeded, `std::nullopt` if it failed
///
/// \see createFromFile, createFromMemory, saveToFile
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<SoundBuffer> createFromSamples(
const std::int16_t* samples,
std::uint64_t sampleCount,
unsigned int channelCount,
unsigned int sampleRate,
const std::vector<SoundChannel>& channelMap);
////////////////////////////////////////////////////////////
/// \brief Save the sound buffer to an audio file
///
@ -225,8 +223,6 @@ public:
///
/// \return True if saving succeeded, false if it failed
///
/// \see createFromFile, createFromMemory, createFromSamples
///
////////////////////////////////////////////////////////////
[[nodiscard]] bool saveToFile(const std::filesystem::path& filename) const;
@ -389,8 +385,7 @@ private:
/// are like texture pixels, and a sf::SoundBuffer is similar to
/// a sf::Texture.
///
/// A sound buffer can be loaded from a file (see createFromFile()
/// for the complete list of supported formats), from memory, from
/// A sound buffer can be loaded from a file, from memory, from
/// a custom stream (see sf::InputStream) or directly from an array
/// of samples. It can also be saved back to a file.
///
@ -415,7 +410,7 @@ private:
/// Usage example:
/// \code
/// // Load a new sound buffer from a file
/// const auto buffer = sf::SoundBuffer::createFromFile("sound.wav").value();
/// const sf::SoundBuffer buffer("sound.wav");
///
/// // Create a sound source bound to the buffer
/// sf::Sound sound1(buffer);

View File

@ -37,7 +37,6 @@
#include <filesystem>
#include <memory>
#include <optional>
#include <string>
#include <unordered_map>
#include <vector>
@ -81,6 +80,71 @@ public:
////////////////////////////////////////////////////////////
Font() = default;
////////////////////////////////////////////////////////////
/// \brief Construct the font from a file
///
/// The supported font formats are: TrueType, Type 1, CFF,
/// OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42.
/// Note that this function knows nothing about the standard
/// fonts installed on the user's system, thus you can't
/// load them directly.
///
/// \warning SFML cannot preload all the font data in this
/// function, so the file has to remain accessible until
/// the sf::Font object opens a new font or is destroyed.
///
/// \param filename Path of the font file to open
///
/// \throws std::runtime_error if opening was unsuccessful
///
/// \see openFromFile, openFromMemory, openFromStream
///
////////////////////////////////////////////////////////////
Font(const std::filesystem::path& filename);
////////////////////////////////////////////////////////////
/// \brief Construct the font from a file in memory
///
/// The supported font formats are: TrueType, Type 1, CFF,
/// OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42.
///
/// \warning SFML cannot preload all the font data in this
/// function, so the buffer pointed by \a data has to remain
/// valid until the sf::Font object opens a new font or
/// is destroyed.
///
/// \param data Pointer to the file data in memory
/// \param sizeInBytes Size of the data to load, in bytes
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see openFromFile, openFromMemory, openFromStream
///
////////////////////////////////////////////////////////////
Font(const void* data, std::size_t sizeInBytes);
////////////////////////////////////////////////////////////
/// \brief Construct the font from a custom stream
///
/// The supported font formats are: TrueType, Type 1, CFF,
/// OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42.
/// Warning: SFML cannot preload all the font data in this
/// function, so the contents of \a stream have to remain
/// valid as long as the font is used.
///
/// \warning SFML cannot preload all the font data in this
/// function, so the stream has to remain accessible until
/// the sf::Font object opens a new font or is destroyed.
///
/// \param stream Source stream to read from
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see openFromFile, openFromMemory, openFromStream
///
////////////////////////////////////////////////////////////
Font(InputStream& stream);
////////////////////////////////////////////////////////////
/// \brief Open the font from a file
///
@ -92,11 +156,11 @@ public:
///
/// \warning SFML cannot preload all the font data in this
/// function, so the file has to remain accessible until
/// the sf::Font object loads a new font or is destroyed.
/// the sf::Font object opens a new font or is destroyed.
///
/// \param filename Path of the font file to load
///
/// \return True if loading succeeded, false if it failed
/// \return True if opening succeeded, false if it failed
///
/// \see openFromMemory, openFromStream
///
@ -111,13 +175,13 @@ public:
///
/// \warning SFML cannot preload all the font data in this
/// function, so the buffer pointed by \a data has to remain
/// valid until the sf::Font object loads a new font or
/// valid until the sf::Font object opens a new font or
/// is destroyed.
///
/// \param data Pointer to the file data in memory
/// \param sizeInBytes Size of the data to load, in bytes
///
/// \return True if loading succeeded, false if it failed
/// \return True if opening succeeded, false if it failed
///
/// \see openFromFile, openFromStream
///
@ -129,84 +193,20 @@ public:
///
/// The supported font formats are: TrueType, Type 1, CFF,
/// OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42.
/// Warning: SFML cannot preload all the font data in this
/// function, so the contents of \a stream have to remain
/// valid as long as the font is used.
///
/// \warning SFML cannot preload all the font data in this
/// function, so the stream has to remain accessible until
/// the sf::Font object loads a new font or is destroyed.
/// the sf::Font object opens a new font or is destroyed.
///
/// \param stream Source stream to read from
///
/// \return True if loading succeeded, false if it failed
/// \return True if opening succeeded, false if it failed
///
/// \see openFromFile, openFromMemory
///
////////////////////////////////////////////////////////////
[[nodiscard]] bool openFromStream(InputStream& stream);
////////////////////////////////////////////////////////////
/// \brief Create the font from a file
///
/// The supported font formats are: TrueType, Type 1, CFF,
/// OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42.
/// Note that this function knows nothing about the standard
/// fonts installed on the user's system, thus you can't
/// load them directly.
///
/// \warning SFML cannot preload all the font data in this
/// function, so the file has to remain accessible until
/// the sf::Font object is destroyed.
///
/// \param filename Path of the font file to load
///
/// \return Font if opening succeeded, `std::nullopt` if it failed
///
/// \see createFromMemory, createFromStream
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Font> createFromFile(const std::filesystem::path& filename);
////////////////////////////////////////////////////////////
/// \brief Create the font from a file in memory
///
/// The supported font formats are: TrueType, Type 1, CFF,
/// OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42.
///
/// \warning SFML cannot preload all the font data in this
/// function, so the buffer pointed by \a data has to remain
/// valid until the sf::Font object is destroyed.
///
/// \param data Pointer to the file data in memory
/// \param sizeInBytes Size of the data to load, in bytes
///
/// \return Font if opening succeeded, `std::nullopt` if it failed
///
/// \see createFromFile, createFromStream
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Font> createFromMemory(const void* data, std::size_t sizeInBytes);
////////////////////////////////////////////////////////////
/// \brief Create the font from a custom stream
///
/// The supported font formats are: TrueType, Type 1, CFF,
/// OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42.
///
/// \warning SFML cannot preload all the font data in this
/// function, so the stream has to remain accessible until
/// the sf::Font object is destroyed.
///
/// \param stream Source stream to read from
///
/// \return Font if opening succeeded, `std::nullopt` if it failed
///
/// \see createFromFile, createFromMemory
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Font> createFromStream(InputStream& stream);
////////////////////////////////////////////////////////////
/// \brief Get the font information
///
@ -474,7 +474,7 @@ private:
///
/// Fonts can be opened from a file, from memory or from a custom
/// stream, and supports the most common types of fonts. See
/// the createFromFile function for the complete list of supported formats.
/// the openFromFile function for the complete list of supported formats.
///
/// Once it is opened, a sf::Font instance provides three
/// types of information about the font:
@ -505,7 +505,7 @@ private:
/// Usage example:
/// \code
/// // Open a new font
/// const auto font = sf::Font::createFromFile("arial.ttf").value();
/// const sf::Font font("arial.ttf");
///
/// // Create a text which uses our font
/// sf::Text text1(font);

View File

@ -59,6 +59,8 @@ public:
///
/// Constructs an image with width 0 and height 0.
///
/// \see resize
///
////////////////////////////////////////////////////////////
Image() = default;
@ -85,6 +87,55 @@ public:
////////////////////////////////////////////////////////////
Image(Vector2u size, const std::uint8_t* pixels);
////////////////////////////////////////////////////////////
/// \brief Construct the image from a file on disk
///
/// The supported image formats are bmp, png, tga, jpg, gif,
/// psd, hdr, pic and pnm. Some format options are not supported,
/// like jpeg with arithmetic coding or ASCII pnm.
///
/// \param filename Path of the image file to load
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see loadFromFile, loadFromMemory, loadFromStream
///
////////////////////////////////////////////////////////////
explicit Image(const std::filesystem::path& filename);
////////////////////////////////////////////////////////////
/// \brief Construct the image from a file in memory
///
/// The supported image formats are bmp, png, tga, jpg, gif,
/// psd, hdr, pic and pnm. Some format options are not supported,
/// like jpeg with arithmetic coding or ASCII pnm.
///
/// \param data Pointer to the file data in memory
/// \param size Size of the data to load, in bytes
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see loadFromFile, loadFromMemory, loadFromStream
///
////////////////////////////////////////////////////////////
Image(const void* data, std::size_t size);
////////////////////////////////////////////////////////////
/// \brief Construct the image from a custom stream
///
/// The supported image formats are bmp, png, tga, jpg, gif,
/// psd, hdr, pic and pnm. Some format options are not supported,
/// like jpeg with arithmetic coding or ASCII pnm.
///
/// \param stream Source stream to read from
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see loadFromFile, loadFromMemory, loadFromStream
///
////////////////////////////////////////////////////////////
explicit Image(InputStream& stream);
////////////////////////////////////////////////////////////
/// \brief Resize the image and fill it with a unique color
///
@ -138,7 +189,7 @@ public:
///
/// \return True if loading was successful
///
/// \see loadFromFile, loadFromStream
/// \see loadFromFile, loadFromStream, saveToMemory
///
////////////////////////////////////////////////////////////
[[nodiscard]] bool loadFromMemory(const void* data, std::size_t size);
@ -160,58 +211,6 @@ public:
////////////////////////////////////////////////////////////
[[nodiscard]] bool loadFromStream(InputStream& stream);
////////////////////////////////////////////////////////////
/// \brief Load the image from a file on disk
///
/// The supported image formats are bmp, png, tga, jpg, gif,
/// psd, hdr, pic and pnm. Some format options are not supported,
/// like jpeg with arithmetic coding or ASCII pnm.
/// If this function fails, the image is left unchanged.
///
/// \param filename Path of the image file to load
///
/// \return Image if loading was successful, `std::nullopt` otherwise
///
/// \see createFromMemory, createFromStream, saveToFile
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Image> createFromFile(const std::filesystem::path& filename);
////////////////////////////////////////////////////////////
/// \brief Load the image from a file in memory
///
/// The supported image formats are bmp, png, tga, jpg, gif,
/// psd, hdr, pic and pnm. Some format options are not supported,
/// like jpeg with arithmetic coding or ASCII pnm.
/// If this function fails, the image is left unchanged.
///
/// \param data Pointer to the file data in memory
/// \param size Size of the data to load, in bytes
///
/// \return Image if loading was successful, `std::nullopt` otherwise
///
/// \see createFromFile, createFromStream
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Image> createFromMemory(const void* data, std::size_t size);
////////////////////////////////////////////////////////////
/// \brief Load the image from a custom stream
///
/// The supported image formats are bmp, png, tga, jpg, gif,
/// psd, hdr, pic and pnm. Some format options are not supported,
/// like jpeg with arithmetic coding or ASCII pnm.
/// If this function fails, the image is left unchanged.
///
/// \param stream Source stream to read from
///
/// \return Image if loading was successful, `std::nullopt` otherwise
///
/// \see createFromFile, createFromMemory
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Image> createFromStream(InputStream& stream);
////////////////////////////////////////////////////////////
/// \brief Save the image to a file on disk
///
@ -224,7 +223,7 @@ public:
///
/// \return True if saving was successful
///
/// \see create, createFromFile, createFromMemory
/// \see saveToMemory, loadFromFile
///
////////////////////////////////////////////////////////////
[[nodiscard]] bool saveToFile(const std::filesystem::path& filename) const;
@ -242,7 +241,7 @@ public:
/// \return Buffer with encoded data if saving was successful,
/// otherwise std::nullopt
///
/// \see create, createFromFile, createFromMemory, saveToFile
/// \see saveToFile, loadFromMemory
///
////////////////////////////////////////////////////////////
[[nodiscard]] std::optional<std::vector<std::uint8_t>> saveToMemory(std::string_view format) const;
@ -386,7 +385,7 @@ private:
/// channels -- just like a sf::Color.
/// All the functions that return an array of pixels follow
/// this rule, and all parameters that you pass to sf::Image
/// functions (such as createFromMemory) must use this
/// functions (such as loadFromMemory) must use this
/// representation as well.
///
/// A sf::Image can be copied, but it is a heavy resource and
@ -396,7 +395,7 @@ private:
/// Usage example:
/// \code
/// // Load an image file from a file
/// const auto background = sf::Image::createFromFile("background.jpg").value();
/// const sf::Image background("background.jpg");
///
/// // Create a 20x20 image filled with black color
/// sf::Image image({20, 20}, sf::Color::Black);

View File

@ -37,7 +37,6 @@
#include <SFML/System/Vector2.hpp>
#include <memory>
#include <optional>
namespace sf
@ -64,6 +63,25 @@ public:
////////////////////////////////////////////////////////////
RenderTexture();
////////////////////////////////////////////////////////////
/// \brief Construct a render-texture
///
/// The last parameter, \a settings, is useful if you want to enable
/// multi-sampling or use the render-texture for OpenGL rendering that
/// requires a depth or stencil buffer. Otherwise it is unnecessary, and
/// you should leave this parameter at its default value.
///
/// After creation, the contents of the render-texture are undefined.
/// Call `RenderTexture::clear` first to ensure a single color fill.
///
/// \param size Width and height of the render-texture
/// \param settings Additional settings for the underlying OpenGL texture and context
///
/// \throws std::runtime_error if creation was unsuccessful
///
////////////////////////////////////////////////////////////
RenderTexture(Vector2u size, const ContextSettings& settings = {});
////////////////////////////////////////////////////////////
/// \brief Destructor
///
@ -108,29 +126,10 @@ public:
/// \param size Width and height of the render-texture
/// \param settings Additional settings for the underlying OpenGL texture and context
///
/// \return True if resizing has been successful
/// \return True if resizing has been successful, false if it failed
///
////////////////////////////////////////////////////////////
[[nodiscard]] bool resize(Vector2u size, const ContextSettings& settings = ContextSettings());
////////////////////////////////////////////////////////////
/// \brief Create the render-texture
///
/// The last parameter, \a settings, is useful if you want to enable
/// multi-sampling or use the render-texture for OpenGL rendering that
/// requires a depth or stencil buffer. Otherwise it is unnecessary, and
/// you should leave this parameter at its default value.
///
/// After creation, the contents of the render-texture are undefined.
/// Call `RenderTexture::clear` first to ensure a single color fill.
///
/// \param size Width and height of the render-texture
/// \param settings Additional settings for the underlying OpenGL texture and context
///
/// \return Render texture if creation has been successful, otherwise `std::nullopt`
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<RenderTexture> create(Vector2u size, const ContextSettings& settings = {});
[[nodiscard]] bool resize(Vector2u size, const ContextSettings& settings = {});
////////////////////////////////////////////////////////////
/// \brief Get the maximum anti-aliasing level supported by the system
@ -302,7 +301,7 @@ private:
/// sf::RenderWindow window(sf::VideoMode({800, 600}), "SFML window");
///
/// // Create a new render-texture
/// auto texture = sf::RenderTexture::create({500, 500}).value();
/// sf::RenderTexture texture({500, 500});
///
/// // The main loop
/// while (window.isOpen())

View File

@ -87,7 +87,7 @@ public:
const String& title,
std::uint32_t style = Style::Default,
State state = State::Windowed,
const ContextSettings& settings = ContextSettings());
const ContextSettings& settings = {});
////////////////////////////////////////////////////////////
/// \brief Construct a new window
@ -106,7 +106,7 @@ public:
/// \param settings Additional settings for the underlying OpenGL context
///
////////////////////////////////////////////////////////////
RenderWindow(VideoMode mode, const String& title, State state, const ContextSettings& settings = ContextSettings());
RenderWindow(VideoMode mode, const String& title, State state, const ContextSettings& settings = {});
////////////////////////////////////////////////////////////
/// \brief Construct the window from an existing control
@ -124,7 +124,7 @@ public:
/// \param settings Additional settings for the underlying OpenGL context
///
////////////////////////////////////////////////////////////
explicit RenderWindow(WindowHandle handle, const ContextSettings& settings = ContextSettings());
explicit RenderWindow(WindowHandle handle, const ContextSettings& settings = {});
////////////////////////////////////////////////////////////
/// \brief Get the size of the rendering region of the window
@ -266,9 +266,9 @@ private:
/// sf::RenderWindow window(sf::VideoMode({800, 600}), "SFML OpenGL");
///
/// // Create a sprite and a text to display
/// const auto texture = sf::Texture::createFromFile("circle.png").value();
/// const sf::Texture texture("circle.png");
/// sf::Sprite sprite(texture);
/// const auto font = sf::Font::createFromFile("arial.ttf").value();
/// const sf::Font font("arial.ttf");
/// sf::Text text(font);
/// ...
///

View File

@ -34,7 +34,6 @@
#include <SFML/Window/GlResource.hpp>
#include <filesystem>
#include <optional>
#include <string>
#include <string_view>
#include <unordered_map>
@ -126,6 +125,198 @@ public:
////////////////////////////////////////////////////////////
Shader& operator=(Shader&& right) noexcept;
////////////////////////////////////////////////////////////
/// \brief Construct from a shader file
///
/// This constructor loads a single shader, vertex, geometry or
/// fragment, identified by the second argument.
/// The source must be a text file containing a valid
/// shader in GLSL language. GLSL is a C-like language
/// dedicated to OpenGL shaders; you'll probably need to
/// read a good documentation for it before writing your
/// own shaders.
///
/// \param filename Path of the vertex, geometry or fragment shader file to load
/// \param type Type of shader (vertex, geometry or fragment)
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see loadFromFile, loadFromMemory, loadFromStream
///
////////////////////////////////////////////////////////////
Shader(const std::filesystem::path& filename, Type type);
////////////////////////////////////////////////////////////
/// \brief Construct from vertex and fragment shader files
///
/// This constructor loads both the vertex and the fragment
/// shaders. If one of them fails to load, the shader is left
/// empty (the valid shader is unloaded).
/// The sources must be text files containing valid shaders
/// in GLSL language. GLSL is a C-like language dedicated to
/// OpenGL shaders; you'll probably need to read a good documentation
/// for it before writing your own shaders.
///
/// \param vertexShaderFilename Path of the vertex shader file to load
/// \param fragmentShaderFilename Path of the fragment shader file to load
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see loadFromFile, loadFromMemory, loadFromStream
///
////////////////////////////////////////////////////////////
Shader(const std::filesystem::path& vertexShaderFilename, const std::filesystem::path& fragmentShaderFilename);
////////////////////////////////////////////////////////////
/// \brief Construct from vertex, geometry and fragment shader files
///
/// This constructor loads the vertex, geometry and fragment
/// shaders. If one of them fails to load, the shader is left
/// empty (the valid shader is unloaded).
/// The sources must be text files containing valid shaders
/// in GLSL language. GLSL is a C-like language dedicated to
/// OpenGL shaders; you'll probably need to read a good documentation
/// for it before writing your own shaders.
///
/// \param vertexShaderFilename Path of the vertex shader file to load
/// \param geometryShaderFilename Path of the geometry shader file to load
/// \param fragmentShaderFilename Path of the fragment shader file to load
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see loadFromFile, loadFromMemory, loadFromStream
///
////////////////////////////////////////////////////////////
Shader(const std::filesystem::path& vertexShaderFilename,
const std::filesystem::path& geometryShaderFilename,
const std::filesystem::path& fragmentShaderFilename);
////////////////////////////////////////////////////////////
/// \brief Construct from shader in memory
///
/// This constructor loads a single shader, vertex, geometry
/// or fragment, identified by the second argument.
/// The source code must be a valid shader in GLSL language.
/// GLSL is a C-like language dedicated to OpenGL shaders;
/// you'll probably need to read a good documentation for
/// it before writing your own shaders.
///
/// \param shader String containing the source code of the shader
/// \param type Type of shader (vertex, geometry or fragment)
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see loadFromFile, loadFromMemory, loadFromStream
///
////////////////////////////////////////////////////////////
Shader(std::string_view shader, Type type);
////////////////////////////////////////////////////////////
/// \brief Construct from vertex and fragment shaders in memory
///
/// This constructor loads both the vertex and the fragment
/// shaders. If one of them fails to load, the shader is left
/// empty (the valid shader is unloaded).
/// The sources must be valid shaders in GLSL language. GLSL is
/// a C-like language dedicated to OpenGL shaders; you'll
/// probably need to read a good documentation for it before
/// writing your own shaders.
///
/// \param vertexShader String containing the source code of the vertex shader
/// \param fragmentShader String containing the source code of the fragment shader
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see loadFromFile, loadFromMemory, loadFromStream
///
////////////////////////////////////////////////////////////
Shader(std::string_view vertexShader, std::string_view fragmentShader);
////////////////////////////////////////////////////////////
/// \brief Construct from vertex, geometry and fragment shaders in memory
///
/// This constructor loads the vertex, geometry and fragment
/// shaders. If one of them fails to load, the shader is left
/// empty (the valid shader is unloaded).
/// The sources must be valid shaders in GLSL language. GLSL is
/// a C-like language dedicated to OpenGL shaders; you'll
/// probably need to read a good documentation for it before
/// writing your own shaders.
///
/// \param vertexShader String containing the source code of the vertex shader
/// \param geometryShader String containing the source code of the geometry shader
/// \param fragmentShader String containing the source code of the fragment shader
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see loadFromFile, loadFromMemory, loadFromStream
///
////////////////////////////////////////////////////////////
Shader(std::string_view vertexShader, std::string_view geometryShader, std::string_view fragmentShader);
////////////////////////////////////////////////////////////
/// \brief Construct from a shader stream
///
/// This constructor loads a single shader, vertex, geometry
/// or fragment, identified by the second argument.
/// The source code must be a valid shader in GLSL language.
/// GLSL is a C-like language dedicated to OpenGL shaders;
/// you'll probably need to read a good documentation for it
/// before writing your own shaders.
///
/// \param stream Source stream to read from
/// \param type Type of shader (vertex, geometry or fragment)
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see loadFromFile, loadFromMemory, loadFromStream
///
////////////////////////////////////////////////////////////
Shader(InputStream& stream, Type type);
////////////////////////////////////////////////////////////
/// \brief Construct from vertex and fragment shader streams
///
/// This constructor loads both the vertex and the fragment
/// shaders. If one of them fails to load, the shader is left
/// empty (the valid shader is unloaded).
/// The source codes must be valid shaders in GLSL language.
/// GLSL is a C-like language dedicated to OpenGL shaders;
/// you'll probably need to read a good documentation for
/// it before writing your own shaders.
///
/// \param vertexShaderStream Source stream to read the vertex shader from
/// \param fragmentShaderStream Source stream to read the fragment shader from
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see loadFromFile, loadFromMemory, loadFromStream
///
////////////////////////////////////////////////////////////
Shader(InputStream& vertexShaderStream, InputStream& fragmentShaderStream);
////////////////////////////////////////////////////////////
/// \brief Construct from vertex, geometry and fragment shader streams
///
/// This constructor loads the vertex, geometry and fragment
/// shaders. If one of them fails to load, the shader is left
/// empty (the valid shader is unloaded).
/// The source codes must be valid shaders in GLSL language.
/// GLSL is a C-like language dedicated to OpenGL shaders;
/// you'll probably need to read a good documentation for
/// it before writing your own shaders.
///
/// \param vertexShaderStream Source stream to read the vertex shader from
/// \param geometryShaderStream Source stream to read the geometry shader from
/// \param fragmentShaderStream Source stream to read the fragment shader from
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see loadFromFile, loadFromMemory, loadFromStream
///
////////////////////////////////////////////////////////////
Shader(InputStream& vertexShaderStream, InputStream& geometryShaderStream, InputStream& fragmentShaderStream);
////////////////////////////////////////////////////////////
/// \brief Load the vertex, geometry or fragment shader from a file
///
@ -323,204 +514,6 @@ public:
InputStream& geometryShaderStream,
InputStream& fragmentShaderStream);
////////////////////////////////////////////////////////////
/// \brief Load the vertex, geometry or fragment shader from a file
///
/// This function loads a single shader, vertex, geometry or
/// fragment, identified by the second argument.
/// The source must be a text file containing a valid
/// shader in GLSL language. GLSL is a C-like language
/// dedicated to OpenGL shaders; you'll probably need to
/// read a good documentation for it before writing your
/// own shaders.
///
/// \param filename Path of the vertex, geometry or fragment shader file to load
/// \param type Type of shader (vertex, geometry or fragment)
///
/// \return Shader if loading succeeded, `std::nullopt` if it failed
///
/// \see createFromMemory, createFromStream
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Shader> createFromFile(const std::filesystem::path& filename, Type type);
////////////////////////////////////////////////////////////
/// \brief Load both the vertex and fragment shaders from files
///
/// This function loads both the vertex and the fragment
/// shaders. If one of them fails to load, the shader is left
/// empty (the valid shader is unloaded).
/// The sources must be text files containing valid shaders
/// in GLSL language. GLSL is a C-like language dedicated to
/// OpenGL shaders; you'll probably need to read a good documentation
/// for it before writing your own shaders.
///
/// \param vertexShaderFilename Path of the vertex shader file to load
/// \param fragmentShaderFilename Path of the fragment shader file to load
///
/// \return Shader if loading succeeded, `std::nullopt` if it failed
///
/// \see createFromMemory, createFromStream
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Shader> createFromFile(const std::filesystem::path& vertexShaderFilename,
const std::filesystem::path& fragmentShaderFilename);
////////////////////////////////////////////////////////////
/// \brief Load the vertex, geometry and fragment shaders from files
///
/// This function loads the vertex, geometry and fragment
/// shaders. If one of them fails to load, the shader is left
/// empty (the valid shader is unloaded).
/// The sources must be text files containing valid shaders
/// in GLSL language. GLSL is a C-like language dedicated to
/// OpenGL shaders; you'll probably need to read a good documentation
/// for it before writing your own shaders.
///
/// \param vertexShaderFilename Path of the vertex shader file to load
/// \param geometryShaderFilename Path of the geometry shader file to load
/// \param fragmentShaderFilename Path of the fragment shader file to load
///
/// \return Shader if loading succeeded, `std::nullopt` if it failed
///
/// \see createFromMemory, createFromStream
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Shader> createFromFile(const std::filesystem::path& vertexShaderFilename,
const std::filesystem::path& geometryShaderFilename,
const std::filesystem::path& fragmentShaderFilename);
////////////////////////////////////////////////////////////
/// \brief Load the vertex, geometry or fragment shader from a source code in memory
///
/// This function loads a single shader, vertex, geometry
/// or fragment, identified by the second argument.
/// The source code must be a valid shader in GLSL language.
/// GLSL is a C-like language dedicated to OpenGL shaders;
/// you'll probably need to read a good documentation for
/// it before writing your own shaders.
///
/// \param shader String containing the source code of the shader
/// \param type Type of shader (vertex, geometry or fragment)
///
/// \return Shader if loading succeeded, `std::nullopt` if it failed
///
/// \see createFromFile, createFromStream
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Shader> createFromMemory(std::string_view shader, Type type);
////////////////////////////////////////////////////////////
/// \brief Load both the vertex and fragment shaders from source codes in memory
///
/// This function loads both the vertex and the fragment
/// shaders. If one of them fails to load, the shader is left
/// empty (the valid shader is unloaded).
/// The sources must be valid shaders in GLSL language. GLSL is
/// a C-like language dedicated to OpenGL shaders; you'll
/// probably need to read a good documentation for it before
/// writing your own shaders.
///
/// \param vertexShader String containing the source code of the vertex shader
/// \param fragmentShader String containing the source code of the fragment shader
///
/// \return Shader if loading succeeded, `std::nullopt` if it failed
///
/// \see createFromFile, createFromStream
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Shader> createFromMemory(std::string_view vertexShader, std::string_view fragmentShader);
////////////////////////////////////////////////////////////
/// \brief Load the vertex, geometry and fragment shaders from source codes in memory
///
/// This function loads the vertex, geometry and fragment
/// shaders. If one of them fails to load, the shader is left
/// empty (the valid shader is unloaded).
/// The sources must be valid shaders in GLSL language. GLSL is
/// a C-like language dedicated to OpenGL shaders; you'll
/// probably need to read a good documentation for it before
/// writing your own shaders.
///
/// \param vertexShader String containing the source code of the vertex shader
/// \param geometryShader String containing the source code of the geometry shader
/// \param fragmentShader String containing the source code of the fragment shader
///
/// \return Shader if loading succeeded, `std::nullopt` if it failed
///
/// \see createFromFile, createFromStream
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Shader> createFromMemory(std::string_view vertexShader,
std::string_view geometryShader,
std::string_view fragmentShader);
////////////////////////////////////////////////////////////
/// \brief Load the vertex, geometry or fragment shader from a custom stream
///
/// This function loads a single shader, vertex, geometry
/// or fragment, identified by the second argument.
/// The source code must be a valid shader in GLSL language.
/// GLSL is a C-like language dedicated to OpenGL shaders;
/// you'll probably need to read a good documentation for it
/// before writing your own shaders.
///
/// \param stream Source stream to read from
/// \param type Type of shader (vertex, geometry or fragment)
///
/// \return Shader if loading succeeded, `std::nullopt` if it failed
///
/// \see createFromFile, createFromMemory
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Shader> createFromStream(InputStream& stream, Type type);
////////////////////////////////////////////////////////////
/// \brief Load both the vertex and fragment shaders from custom streams
///
/// This function loads both the vertex and the fragment
/// shaders. If one of them fails to load, the shader is left
/// empty (the valid shader is unloaded).
/// The source codes must be valid shaders in GLSL language.
/// GLSL is a C-like language dedicated to OpenGL shaders;
/// you'll probably need to read a good documentation for
/// it before writing your own shaders.
///
/// \param vertexShaderStream Source stream to read the vertex shader from
/// \param fragmentShaderStream Source stream to read the fragment shader from
///
/// \return Shader if loading succeeded, `std::nullopt` if it failed
///
/// \see createFromFile, createFromMemory
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Shader> createFromStream(InputStream& vertexShaderStream,
InputStream& fragmentShaderStream);
////////////////////////////////////////////////////////////
/// \brief Load the vertex, geometry and fragment shaders from custom streams
///
/// This function loads the vertex, geometry and fragment
/// shaders. If one of them fails to load, the shader is left
/// empty (the valid shader is unloaded).
/// The source codes must be valid shaders in GLSL language.
/// GLSL is a C-like language dedicated to OpenGL shaders;
/// you'll probably need to read a good documentation for
/// it before writing your own shaders.
///
/// \param vertexShaderStream Source stream to read the vertex shader from
/// \param geometryShaderStream Source stream to read the geometry shader from
/// \param fragmentShaderStream Source stream to read the fragment shader from
///
/// \return Shader if loading succeeded, `std::nullopt` if it failed
///
/// \see createFromFile, createFromMemory
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Shader> createFromStream(InputStream& vertexShaderStream,
InputStream& geometryShaderStream,
InputStream& fragmentShaderStream);
////////////////////////////////////////////////////////////
/// \brief Specify value for \p float uniform
///

View File

@ -261,7 +261,7 @@ private:
/// Usage example:
/// \code
/// // Load a texture
/// const auto texture = sf::Texture::createFromFile("texture.png").value();
/// const sf::Texture texture("texture.png");
///
/// // Create a sprite
/// sf::Sprite sprite(texture);

View File

@ -469,7 +469,7 @@ private:
/// Usage example:
/// \code
/// // Open a font
/// const auto font = sf::Font::createFromFile("arial.ttf").value();
/// const sf::Font font("arial.ttf");
///
/// // Create a text
/// sf::Text text(font, "hello");

View File

@ -37,7 +37,6 @@
#include <SFML/System/Vector2.hpp>
#include <filesystem>
#include <optional>
#include <cstddef>
#include <cstdint>
@ -61,6 +60,8 @@ public:
///
/// Creates a texture with width 0 and height 0.
///
/// \see resize
///
////////////////////////////////////////////////////////////
Texture();
@ -96,6 +97,174 @@ public:
////////////////////////////////////////////////////////////
Texture& operator=(Texture&&) noexcept;
////////////////////////////////////////////////////////////
/// \brief Construct the texture from a file on disk
///
/// The maximum size for a texture depends on the graphics
/// driver and can be retrieved with the getMaximumSize function.
///
/// \param filename Path of the image file to load
/// \param sRgb True to enable sRGB conversion, false to disable it
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see loadFromFile, loadFromMemory, loadFromStream, loadFromImage
///
////////////////////////////////////////////////////////////
explicit Texture(const std::filesystem::path& filename, bool sRgb = false);
////////////////////////////////////////////////////////////
/// \brief Construct the texture from a sub-rectangle of a file on disk
///
/// 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
/// the default value (which is an empty IntRect).
/// If the \a area rectangle crosses the bounds of the image, it
/// is adjusted to fit the image size.
///
/// The maximum size for a texture depends on the graphics
/// driver and can be retrieved with the getMaximumSize function.
///
/// \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
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see loadFromFile, loadFromMemory, loadFromStream, loadFromImage
///
////////////////////////////////////////////////////////////
Texture(const std::filesystem::path& filename, bool sRgb, const IntRect& area);
////////////////////////////////////////////////////////////
/// \brief Construct the texture from a file in memory
///
/// The maximum size for a texture depends on the graphics
/// driver and can be retrieved with the getMaximumSize function.
///
/// \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
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see loadFromFile, loadFromMemory, loadFromStream, loadFromImage
///
////////////////////////////////////////////////////////////
Texture(const void* data, std::size_t size, bool sRgb = false);
////////////////////////////////////////////////////////////
/// \brief Construct the texture from a sub-rectangle of a file in memory
///
/// 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
/// the default value (which is an empty IntRect).
/// If the \a area rectangle crosses the bounds of the image, it
/// is adjusted to fit the image size.
///
/// The maximum size for a texture depends on the graphics
/// driver and can be retrieved with the getMaximumSize function.
///
/// \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
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see loadFromFile, loadFromMemory, loadFromStream, loadFromImage
///
////////////////////////////////////////////////////////////
Texture(const void* data, std::size_t size, bool sRgb, const IntRect& area);
////////////////////////////////////////////////////////////
/// \brief Construct the texture from a custom stream
///
/// The maximum size for a texture depends on the graphics
/// driver and can be retrieved with the getMaximumSize function.
///
/// \param stream Source stream to read from
/// \param sRgb True to enable sRGB conversion, false to disable it
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see loadFromFile, loadFromMemory, loadFromStream, loadFromImage
///
////////////////////////////////////////////////////////////
explicit Texture(InputStream& stream, bool sRgb = false);
////////////////////////////////////////////////////////////
/// \brief Construct the texture from a sub-rectangle of a custom stream
///
/// 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
/// the default value (which is an empty IntRect).
/// If the \a area rectangle crosses the bounds of the image, it
/// is adjusted to fit the image size.
///
/// The maximum size for a texture depends on the graphics
/// driver and can be retrieved with the getMaximumSize function.
///
/// \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
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see loadFromFile, loadFromMemory, loadFromStream, loadFromImage
///
////////////////////////////////////////////////////////////
Texture(InputStream& stream, bool sRgb, const IntRect& area);
////////////////////////////////////////////////////////////
/// \brief Construct the texture from an image
///
/// The maximum size for a texture depends on the graphics
/// driver and can be retrieved with the getMaximumSize function.
///
/// \param image Image to load into the texture
/// \param sRgb True to enable sRGB conversion, false to disable it
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see loadFromFile, loadFromMemory, loadFromStream, loadFromImage
///
////////////////////////////////////////////////////////////
explicit Texture(const Image& image, bool sRgb = false);
////////////////////////////////////////////////////////////
/// \brief Construct the texture from a sub-rectangle of an image
///
/// The \a area argument is used to load only a sub-rectangle
/// of the whole image.
/// If the \a area rectangle crosses the bounds of the image, it
/// is adjusted to fit the image size.
///
/// The maximum size for a texture depends on the graphics
/// driver and can be retrieved with the getMaximumSize function.
///
/// \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
///
/// \throws std::runtime_error if loading was unsuccessful
///
/// \see loadFromFile, loadFromMemory, loadFromStream, loadFromImage
///
////////////////////////////////////////////////////////////
Texture(const Image& image, bool sRgb, const IntRect& area);
////////////////////////////////////////////////////////////
/// \brief Construct the texture with a given size
///
/// \param size Width and height of the texture
/// \param sRgb True to enable sRGB conversion, false to disable it
///
/// \throws std::runtime_error if construction was unsuccessful
///
////////////////////////////////////////////////////////////
explicit Texture(Vector2u size, bool sRgb = false);
////////////////////////////////////////////////////////////
/// \brief Resize the texture
///
@ -104,7 +273,7 @@ public:
/// \param size Width and height of the texture
/// \param sRgb True to enable sRGB conversion, false to disable it
///
/// \return True if resizing was successful
/// \return True if resizing was successful, false if it failed
///
////////////////////////////////////////////////////////////
[[nodiscard]] bool resize(Vector2u size, bool sRgb = false);
@ -112,15 +281,6 @@ public:
////////////////////////////////////////////////////////////
/// \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
/// of the whole image. If you want the entire image then leave
/// the default value (which is an empty IntRect).
@ -136,25 +296,16 @@ public:
/// \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 True if loading was successful, false if it failed
///
/// \see loadFromMemory, loadFromStream, loadFromImage
///
////////////////////////////////////////////////////////////
[[nodiscard]] bool loadFromFile(const std::filesystem::path& filename, bool sRgb = false, const IntRect& area = IntRect());
[[nodiscard]] bool loadFromFile(const std::filesystem::path& filename, bool sRgb = false, const IntRect& area = {});
////////////////////////////////////////////////////////////
/// \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
/// of the whole image. If you want the entire image then leave
/// the default value (which is an empty IntRect).
@ -171,25 +322,16 @@ public:
/// \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 True if loading was successful, false if it failed
///
/// \see loadFromFile, loadFromStream, loadFromImage
///
////////////////////////////////////////////////////////////
[[nodiscard]] bool loadFromMemory(const void* data, std::size_t size, bool sRgb = false, const IntRect& area = IntRect());
[[nodiscard]] bool loadFromMemory(const void* data, std::size_t size, bool sRgb = false, const IntRect& area = {});
////////////////////////////////////////////////////////////
/// \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
/// of the whole image. If you want the entire image then leave
/// the default value (which is an empty IntRect).
@ -205,12 +347,12 @@ public:
/// \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 True if loading was successful, false if it failed
///
/// \see loadFromFile, loadFromMemory, loadFromImage
///
////////////////////////////////////////////////////////////
[[nodiscard]] bool loadFromStream(InputStream& stream, bool sRgb = false, const IntRect& area = IntRect());
[[nodiscard]] bool loadFromStream(InputStream& stream, bool sRgb = false, const IntRect& area = {});
////////////////////////////////////////////////////////////
/// \brief Load the texture from an image
@ -230,132 +372,12 @@ public:
/// \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 True if loading was successful, false if it failed
///
/// \see loadFromFile, loadFromMemory
///
////////////////////////////////////////////////////////////
[[nodiscard]] bool loadFromImage(const Image& image, bool sRgb = false, const IntRect& area = IntRect());
////////////////////////////////////////////////////////////
/// \brief Create a texture
///
/// \param size Width and height of the texture
/// \param sRgb True to enable sRGB conversion, false to disable it
///
/// \return Texture if creation was successful, otherwise `std::nullopt`
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Texture> create(Vector2u size, bool sRgb = false);
////////////////////////////////////////////////////////////
/// \brief Load the texture from a file on disk
///
/// 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
/// the default value (which is an empty IntRect).
/// If the \a area rectangle crosses the bounds of the image, it
/// is adjusted to fit the image size.
///
/// The maximum size for a texture depends on the graphics
/// driver and can be retrieved with the getMaximumSize function.
///
/// 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 Texture if loading was successful, otherwise `std::nullopt`
///
/// \see createFromMemory, createFromStream, createFromImage
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Texture> createFromFile(const std::filesystem::path& filename,
bool sRgb = false,
const IntRect& area = {});
////////////////////////////////////////////////////////////
/// \brief Load the texture from a file in memory
///
/// 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
/// the default value (which is an empty IntRect).
/// If the \a area rectangle crosses the bounds of the image, it
/// is adjusted to fit the image size.
///
/// The maximum size for a texture depends on the graphics
/// driver and can be retrieved with the getMaximumSize function.
///
/// If this function fails, the texture is left unchanged.
///
/// \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 Texture if loading was successful, otherwise `std::nullopt`
///
/// \see createFromFile, createFromStream, createFromImage
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Texture> createFromMemory(
const void* data,
std::size_t size,
bool sRgb = false,
const IntRect& area = {});
////////////////////////////////////////////////////////////
/// \brief Load the texture from a custom stream
///
/// 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
/// the default value (which is an empty IntRect).
/// If the \a area rectangle crosses the bounds of the image, it
/// is adjusted to fit the image size.
///
/// The maximum size for a texture depends on the graphics
/// driver and can be retrieved with the getMaximumSize function.
///
/// 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 Texture if loading was successful, otherwise `std::nullopt`
///
/// \see createFromFile, createFromMemory, createFromImage
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Texture> createFromStream(InputStream& stream,
bool sRgb = false,
const IntRect& area = {});
////////////////////////////////////////////////////////////
/// \brief Load the texture from an image
///
/// 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
/// the default value (which is an empty IntRect).
/// If the \a area rectangle crosses the bounds of the image, it
/// is adjusted to fit the image size.
///
/// The maximum size for a texture depends on the graphics
/// driver and can be retrieved with the getMaximumSize function.
///
/// 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 Texture if loading was successful, otherwise `std::nullopt`
///
/// \see createFromFile, createFromMemory
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<Texture> createFromImage(const Image& image, bool sRgb = false, const IntRect& area = {});
[[nodiscard]] bool loadFromImage(const Image& image, bool sRgb = false, const IntRect& area = {});
////////////////////////////////////////////////////////////
/// \brief Return the size of the texture
@ -375,7 +397,7 @@ public:
///
/// \return Image containing the texture's pixels
///
/// \see createFromImage
/// \see loadFromImage
///
////////////////////////////////////////////////////////////
[[nodiscard]] Image copyToImage() const;
@ -771,7 +793,7 @@ SFML_GRAPHICS_API void swap(Texture& left, Texture& right) noexcept;
/// However, if you want to perform some modifications on the pixels
/// before creating the final texture, you can load your file to a
/// sf::Image, do whatever you need with the pixels, and then call
/// Texture::createFromImage.
/// Texture(const Image&).
///
/// Since they live in the graphics card memory, the pixels of a texture
/// cannot be accessed without a slow copy first. And they cannot be
@ -803,7 +825,7 @@ SFML_GRAPHICS_API void swap(Texture& left, Texture& right) noexcept;
/// // drawing a sprite
///
/// // Load a texture from a file
/// const auto texture = sf::Texture::createFromFile("texture.png").value();
/// const sf::Texture texture("texture.png");
///
/// // Assign it to a sprite
/// sf::Sprite sprite(texture);
@ -817,7 +839,7 @@ SFML_GRAPHICS_API void swap(Texture& left, Texture& right) noexcept;
/// // streaming real-time data, like video frames
///
/// // Create an empty texture
/// auto texture = sf::Texture::create({640, 480}).value();
/// sf::Texture texture({640, 480});
///
/// // Create a sprite that will display the texture
/// sf::Sprite sprite(texture);

View File

@ -95,6 +95,16 @@ public:
////////////////////////////////////////////////////////////
FileInputStream& operator=(FileInputStream&&) noexcept;
////////////////////////////////////////////////////////////
/// \brief Construct the stream from a file path
///
/// \param filename Name of the file to open
///
/// \throws std::runtime_error on error
///
////////////////////////////////////////////////////////////
explicit FileInputStream(const std::filesystem::path& filename);
////////////////////////////////////////////////////////////
/// \brief Open the stream from a file path
///
@ -105,16 +115,6 @@ public:
////////////////////////////////////////////////////////////
[[nodiscard]] bool open(const std::filesystem::path& filename);
////////////////////////////////////////////////////////////
/// \brief Create the stream from a file path
///
/// \param filename Name of the file to open
///
/// \return File input stream on success, `std::nullopt` on error
///
////////////////////////////////////////////////////////////
[[nodiscard]] static std::optional<FileInputStream> create(const std::filesystem::path& filename);
////////////////////////////////////////////////////////////
/// \brief Read data from the stream
///

View File

@ -103,12 +103,12 @@ public:
/// from which SFML can load resources.
///
/// SFML resource classes like sf::Texture and
/// sf::SoundBuffer provide createFromFile and createFromMemory functions,
/// sf::SoundBuffer provide loadFromFile and loadFromMemory functions,
/// which read data from conventional sources. However, if you
/// have data coming from a different source (over a network,
/// embedded, encrypted, compressed, etc) you can derive your
/// own class from sf::InputStream and load SFML resources with
/// their createFromStream function.
/// their loadFromStream function.
///
/// Usage example:
/// \code
@ -142,7 +142,7 @@ public:
/// // Handle error...
/// }
///
/// const auto texture = sf::Texture::createFromStream(stream).value();
/// const sf::Texture texture(stream);
///
/// // musics...
/// sf::Music music;

View File

@ -55,15 +55,6 @@ public:
////////////////////////////////////////////////////////////
MemoryInputStream(const void* data, std::size_t sizeInBytes);
////////////////////////////////////////////////////////////
/// \brief Open the stream from its data
///
/// \param data Pointer to the data in memory
/// \param sizeInBytes Size of the data, in bytes
///
////////////////////////////////////////////////////////////
void open(const void* data, std::size_t sizeInBytes);
////////////////////////////////////////////////////////////
/// \brief Read data from the stream
///

View File

@ -144,6 +144,55 @@ public:
////////////////////////////////////////////////////////////
Cursor& operator=(Cursor&&) noexcept;
////////////////////////////////////////////////////////////
/// \brief Construct a cursor with the provided image
///
/// \a pixels must be an array of \a width by \a height pixels
/// in 32-bit RGBA format. If not, this will cause undefined behavior.
///
/// If \a pixels is null or either \a width or \a height are 0,
/// the current cursor is left unchanged and the function will
/// return false.
///
/// In addition to specifying the pixel data, you can also
/// specify the location of the hotspot of the cursor. The
/// hotspot is the pixel coordinate within the cursor image
/// which will be located exactly where the mouse pointer
/// position is. Any mouse actions that are performed will
/// return the window/screen location of the hotspot.
///
/// \warning On Unix platforms which do not support colored
/// cursors, the pixels are mapped into a monochrome
/// bitmap: pixels with an alpha channel to 0 are
/// transparent, black if the RGB channel are close
/// to zero, and white otherwise.
///
/// \param pixels Array of pixels of the image
/// \param size Width and height of the image
/// \param hotspot (x,y) location of the hotspot
///
/// \throws std::runtime_error if the cursor could not be constructed
///
////////////////////////////////////////////////////////////
Cursor(const std::uint8_t* pixels, Vector2u size, Vector2u hotspot);
////////////////////////////////////////////////////////////
/// \brief Create a native system cursor
///
/// Refer to the list of cursor available on each system
/// (see sf::Cursor::Type) to know whether a given cursor is
/// expected to load successfully or is not supported by
/// the operating system.
///
/// \param type Native system cursor type
///
/// \throws std::runtime_error if the corresponding cursor
/// is not natively supported by the operating
/// system
///
////////////////////////////////////////////////////////////
explicit Cursor(Type type);
////////////////////////////////////////////////////////////
/// \brief Create a cursor with the provided image
///

View File

@ -89,7 +89,7 @@ public:
const String& title,
std::uint32_t style = Style::Default,
State state = State::Windowed,
const ContextSettings& settings = ContextSettings());
const ContextSettings& settings = {});
////////////////////////////////////////////////////////////
/// \brief Construct a new window
@ -108,7 +108,7 @@ public:
/// \param settings Additional settings for the underlying OpenGL context
///
////////////////////////////////////////////////////////////
Window(VideoMode mode, const String& title, State state, const ContextSettings& settings = ContextSettings());
Window(VideoMode mode, const String& title, State state, const ContextSettings& settings = {});
////////////////////////////////////////////////////////////
/// \brief Construct the window from an existing control
@ -124,7 +124,7 @@ public:
/// \param settings Additional settings for the underlying OpenGL context
///
////////////////////////////////////////////////////////////
explicit Window(WindowHandle handle, const ContextSettings& settings = ContextSettings());
explicit Window(WindowHandle handle, const ContextSettings& settings = {});
////////////////////////////////////////////////////////////
/// \brief Destructor

View File

@ -66,6 +66,30 @@ void InputSoundFile::StreamDeleter::operator()(InputStream* ptr) const
}
////////////////////////////////////////////////////////////
InputSoundFile::InputSoundFile(const std::filesystem::path& filename)
{
if (!openFromFile(filename))
throw std::runtime_error("Failed to open input sound file");
}
////////////////////////////////////////////////////////////
InputSoundFile::InputSoundFile(const void* data, std::size_t sizeInBytes)
{
if (!openFromMemory(data, sizeInBytes))
throw std::runtime_error("Failed to open input sound file from memory");
}
////////////////////////////////////////////////////////////
InputSoundFile::InputSoundFile(InputStream& stream)
{
if (!openFromStream(stream))
throw std::runtime_error("Failed to open input sound file from stream");
}
////////////////////////////////////////////////////////////
bool InputSoundFile::openFromFile(const std::filesystem::path& filename)
{
@ -192,42 +216,6 @@ bool InputSoundFile::openFromStream(InputStream& stream)
}
////////////////////////////////////////////////////////////
std::optional<InputSoundFile> InputSoundFile::createFromFile(const std::filesystem::path& filename)
{
auto inputSoundFile = std::make_optional<InputSoundFile>();
if (!inputSoundFile->openFromFile(filename))
return std::nullopt;
return inputSoundFile;
}
////////////////////////////////////////////////////////////
std::optional<InputSoundFile> InputSoundFile::createFromMemory(const void* data, std::size_t sizeInBytes)
{
auto inputSoundFile = std::make_optional<InputSoundFile>();
if (!inputSoundFile->openFromMemory(data, sizeInBytes))
return std::nullopt;
return inputSoundFile;
}
////////////////////////////////////////////////////////////
std::optional<InputSoundFile> InputSoundFile::createFromStream(InputStream& stream)
{
auto inputSoundFile = std::make_optional<InputSoundFile>();
if (!inputSoundFile->openFromStream(stream))
return std::nullopt;
return inputSoundFile;
}
////////////////////////////////////////////////////////////
std::uint64_t InputSoundFile::getSampleCount() const
{

View File

@ -64,6 +64,30 @@ Music::Music() : m_impl(std::make_unique<Impl>())
}
////////////////////////////////////////////////////////////
Music::Music(const std::filesystem::path& filename) : Music()
{
if (!openFromFile(filename))
throw std::runtime_error("Failed to open music from file");
}
////////////////////////////////////////////////////////////
Music::Music(const void* data, std::size_t sizeInBytes) : Music()
{
if (!openFromMemory(data, sizeInBytes))
throw std::runtime_error("Failed to open music from memory");
}
////////////////////////////////////////////////////////////
Music::Music(InputStream& stream) : Music()
{
if (!openFromStream(stream))
throw std::runtime_error("Failed to open music from stream");
}
////////////////////////////////////////////////////////////
Music::~Music()
{
@ -152,42 +176,6 @@ bool Music::openFromStream(InputStream& stream)
}
////////////////////////////////////////////////////////////
std::optional<Music> Music::createFromFile(const std::filesystem::path& filename)
{
auto music = std::make_optional<Music>();
if (!music->openFromFile(filename))
return std::nullopt;
return music;
}
////////////////////////////////////////////////////////////
std::optional<Music> Music::createFromMemory(const void* data, std::size_t sizeInBytes)
{
auto music = std::make_optional<Music>();
if (!music->openFromMemory(data, sizeInBytes))
return std::nullopt;
return music;
}
////////////////////////////////////////////////////////////
std::optional<Music> Music::createFromStream(InputStream& stream)
{
auto music = std::make_optional<Music>();
if (!music->openFromStream(stream))
return std::nullopt;
return music;
}
////////////////////////////////////////////////////////////
Time Music::getDuration() const
{

View File

@ -36,6 +36,17 @@
namespace sf
{
////////////////////////////////////////////////////////////
OutputSoundFile::OutputSoundFile(const std::filesystem::path& filename,
unsigned int sampleRate,
unsigned int channelCount,
const std::vector<SoundChannel>& channelMap)
{
if (!openFromFile(filename, sampleRate, channelCount, channelMap))
throw std::runtime_error("Failed to open output sound file");
}
////////////////////////////////////////////////////////////
bool OutputSoundFile::openFromFile(const std::filesystem::path& filename,
unsigned int sampleRate,
@ -65,22 +76,6 @@ bool OutputSoundFile::openFromFile(const std::filesystem::path& filename,
}
////////////////////////////////////////////////////////////
std::optional<OutputSoundFile> OutputSoundFile::createFromFile(
const std::filesystem::path& filename,
unsigned int sampleRate,
unsigned int channelCount,
const std::vector<SoundChannel>& channelMap)
{
auto outputSoundFile = std::make_optional<OutputSoundFile>();
if (!outputSoundFile->openFromFile(filename, sampleRate, channelCount, channelMap))
return std::nullopt;
return outputSoundFile;
}
////////////////////////////////////////////////////////////
void OutputSoundFile::write(const std::int16_t* samples, std::uint64_t count)
{

View File

@ -39,6 +39,42 @@
namespace sf
{
////////////////////////////////////////////////////////////
SoundBuffer::SoundBuffer(const std::filesystem::path& filename)
{
if (!loadFromFile(filename))
throw std::runtime_error("Failed to open sound buffer from file");
}
////////////////////////////////////////////////////////////
SoundBuffer::SoundBuffer(const void* data, std::size_t sizeInBytes)
{
if (!loadFromMemory(data, sizeInBytes))
throw std::runtime_error("Failed to open sound buffer from memory");
}
////////////////////////////////////////////////////////////
SoundBuffer::SoundBuffer(InputStream& stream)
{
if (!loadFromStream(stream))
throw std::runtime_error("Failed to open sound buffer from stream");
}
////////////////////////////////////////////////////////////
SoundBuffer::SoundBuffer(const std::int16_t* samples,
std::uint64_t sampleCount,
unsigned int channelCount,
unsigned int sampleRate,
const std::vector<SoundChannel>& channelMap)
{
if (!loadFromSamples(samples, sampleCount, channelCount, sampleRate, channelMap))
throw std::runtime_error("Failed to open sound buffer from samples");
}
////////////////////////////////////////////////////////////
SoundBuffer::SoundBuffer(const SoundBuffer& copy)
{
@ -130,59 +166,6 @@ bool SoundBuffer::loadFromSamples(const std::int16_t* samples,
}
////////////////////////////////////////////////////////////
std::optional<SoundBuffer> SoundBuffer::createFromFile(const std::filesystem::path& filename)
{
auto soundBuffer = std::make_optional<SoundBuffer>();
if (!soundBuffer->loadFromFile(filename))
return std::nullopt;
return soundBuffer;
}
////////////////////////////////////////////////////////////
std::optional<SoundBuffer> SoundBuffer::createFromMemory(const void* data, std::size_t sizeInBytes)
{
auto soundBuffer = std::make_optional<SoundBuffer>();
if (!soundBuffer->loadFromMemory(data, sizeInBytes))
return std::nullopt;
return soundBuffer;
}
////////////////////////////////////////////////////////////
std::optional<SoundBuffer> SoundBuffer::createFromStream(InputStream& stream)
{
auto soundBuffer = std::make_optional<SoundBuffer>();
if (!soundBuffer->loadFromStream(stream))
return std::nullopt;
return soundBuffer;
}
////////////////////////////////////////////////////////////
std::optional<SoundBuffer> SoundBuffer::createFromSamples(
const std::int16_t* samples,
std::uint64_t sampleCount,
unsigned int channelCount,
unsigned int sampleRate,
const std::vector<SoundChannel>& channelMap)
{
auto soundBuffer = std::make_optional<SoundBuffer>();
if (!soundBuffer->loadFromSamples(samples, sampleCount, channelCount, sampleRate, channelMap))
return std::nullopt;
return soundBuffer;
}
////////////////////////////////////////////////////////////
bool SoundBuffer::saveToFile(const std::filesystem::path& filename) const
{

View File

@ -48,7 +48,7 @@ SoundBufferRecorder::~SoundBufferRecorder()
bool SoundBufferRecorder::onStart()
{
m_samples.clear();
m_buffer = SoundBuffer();
m_buffer = {};
return true;
}

View File

@ -120,6 +120,30 @@ struct Font::FontHandles
};
////////////////////////////////////////////////////////////
Font::Font(const std::filesystem::path& filename)
{
if (!openFromFile(filename))
throw std::runtime_error("Failed to open font from file");
}
////////////////////////////////////////////////////////////
Font::Font(const void* data, std::size_t sizeInBytes)
{
if (!openFromMemory(data, sizeInBytes))
throw std::runtime_error("Failed to open font from memory");
}
////////////////////////////////////////////////////////////
Font::Font(InputStream& stream)
{
if (!openFromStream(stream))
throw std::runtime_error("Failed to open font from stream");
}
////////////////////////////////////////////////////////////
bool Font::openFromFile(const std::filesystem::path& filename)
{
@ -252,7 +276,7 @@ bool Font::openFromStream(InputStream& stream)
}
// Make sure that the stream's reading position is at the beginning
if (!stream.seek(0))
if (!stream.seek(0).has_value())
{
err() << "Failed to seek font stream" << std::endl;
return false;
@ -305,42 +329,6 @@ bool Font::openFromStream(InputStream& stream)
}
////////////////////////////////////////////////////////////
std::optional<Font> Font::createFromFile(const std::filesystem::path& filename)
{
auto font = std::make_optional<Font>();
if (!font->openFromFile(filename))
return std::nullopt;
return font;
}
////////////////////////////////////////////////////////////
std::optional<Font> Font::createFromMemory(const void* data, std::size_t sizeInBytes)
{
auto font = std::make_optional<Font>();
if (!font->openFromMemory(data, sizeInBytes))
return std::nullopt;
return font;
}
////////////////////////////////////////////////////////////
std::optional<Font> Font::createFromStream(InputStream& stream)
{
auto font = std::make_optional<Font>();
if (!font->openFromStream(stream))
return std::nullopt;
return font;
}
////////////////////////////////////////////////////////////
const Font::Info& Font::getInfo() const
{
@ -409,8 +397,7 @@ float Font::getKerning(std::uint32_t first, std::uint32_t second, unsigned int c
// Combine kerning with compensation deltas and return the X advance
// Flooring is required as we use FT_KERNING_UNFITTED flag which is not quantized in 64 based grid
return std::floor(
(secondLsbDelta - firstRsbDelta + static_cast<float>(kerning.x) + 32) / static_cast<float>(1 << 6));
return std::floor((secondLsbDelta - firstRsbDelta + static_cast<float>(kerning.x) + 32) / float{1 << 6});
}
// Invalid font
@ -425,7 +412,7 @@ float Font::getLineSpacing(unsigned int characterSize) const
if (face && setCurrentSize(characterSize))
{
return static_cast<float>(face->size->metrics.height) / static_cast<float>(1 << 6);
return static_cast<float>(face->size->metrics.height) / float{1 << 6};
}
return 0.f;
@ -443,8 +430,7 @@ float Font::getUnderlinePosition(unsigned int characterSize) const
if (!FT_IS_SCALABLE(face))
return static_cast<float>(characterSize) / 10.f;
return -static_cast<float>(FT_MulFix(face->underline_position, face->size->metrics.y_scale)) /
static_cast<float>(1 << 6);
return -static_cast<float>(FT_MulFix(face->underline_position, face->size->metrics.y_scale)) / float{1 << 6};
}
return 0.f;
@ -462,8 +448,7 @@ float Font::getUnderlineThickness(unsigned int characterSize) const
if (!FT_IS_SCALABLE(face))
return static_cast<float>(characterSize) / 14.f;
return static_cast<float>(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale)) /
static_cast<float>(1 << 6);
return static_cast<float>(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale)) / float{1 << 6};
}
return 0.f;
@ -563,7 +548,7 @@ Glyph Font::loadGlyph(std::uint32_t codePoint, unsigned int characterSize, bool
FT_Stroker stroker = m_fontHandles->stroker;
FT_Stroker_Set(stroker,
static_cast<FT_Fixed>(outlineThickness * static_cast<float>(1 << 6)),
static_cast<FT_Fixed>(outlineThickness * float{1 << 6}),
FT_STROKER_LINECAP_ROUND,
FT_STROKER_LINEJOIN_ROUND,
0);
@ -591,47 +576,41 @@ Glyph Font::loadGlyph(std::uint32_t codePoint, unsigned int characterSize, bool
// Compute the glyph's advance offset
glyph.advance = static_cast<float>(bitmapGlyph->root.advance.x >> 16);
if (bold)
glyph.advance += static_cast<float>(weight) / static_cast<float>(1 << 6);
glyph.advance += static_cast<float>(weight) / float{1 << 6};
glyph.lsbDelta = static_cast<int>(face->glyph->lsb_delta);
glyph.rsbDelta = static_cast<int>(face->glyph->rsb_delta);
unsigned int width = bitmap.width;
unsigned int height = bitmap.rows;
Vector2u size(bitmap.width, bitmap.rows);
if ((width > 0) && (height > 0))
if ((size.x > 0) && (size.y > 0))
{
// Leave a small padding around characters, so that filtering doesn't
// pollute them with pixels from neighbors
const unsigned int padding = 2;
width += 2 * padding;
height += 2 * padding;
size += 2u * Vector2u(padding, padding);
// Get the glyphs page corresponding to the character size
Page& page = loadPage(characterSize);
// Find a good position for the new glyph into the texture
glyph.textureRect = findGlyphRect(page, {width, height});
glyph.textureRect = findGlyphRect(page, size);
// Make sure the texture data is positioned in the center
// of the allocated texture rectangle
glyph.textureRect.position.x += static_cast<int>(padding);
glyph.textureRect.position.y += static_cast<int>(padding);
glyph.textureRect.size.x -= static_cast<int>(2 * padding);
glyph.textureRect.size.y -= static_cast<int>(2 * padding);
glyph.textureRect.position += Vector2i(padding, padding);
glyph.textureRect.size -= 2 * Vector2i(padding, padding);
// Compute the glyph's bounding box
glyph.bounds.position.x = static_cast<float>(bitmapGlyph->left);
glyph.bounds.position.y = static_cast<float>(-bitmapGlyph->top);
glyph.bounds.size.x = static_cast<float>(bitmap.width);
glyph.bounds.size.y = static_cast<float>(bitmap.rows);
glyph.bounds.position = Vector2f(Vector2i(bitmapGlyph->left, -bitmapGlyph->top));
glyph.bounds.size = Vector2f(Vector2u(bitmap.width, bitmap.rows));
// Resize the pixel buffer to the new size and fill it with transparent white pixels
m_pixelBuffer.resize(static_cast<std::size_t>(width) * static_cast<std::size_t>(height) * 4);
m_pixelBuffer.resize(static_cast<std::size_t>(size.x) * static_cast<std::size_t>(size.y) * 4);
std::uint8_t* current = m_pixelBuffer.data();
std::uint8_t* end = current + width * height * 4;
std::uint8_t* end = current + size.x * size.y * 4;
while (current != end)
{
@ -646,12 +625,12 @@ Glyph Font::loadGlyph(std::uint32_t codePoint, unsigned int characterSize, bool
if (bitmap.pixel_mode == FT_PIXEL_MODE_MONO)
{
// Pixels are 1 bit monochrome values
for (unsigned int y = padding; y < height - padding; ++y)
for (unsigned int y = padding; y < size.y - padding; ++y)
{
for (unsigned int x = padding; x < width - padding; ++x)
for (unsigned int x = padding; x < size.x - padding; ++x)
{
// The color channels remain white, just fill the alpha channel
const std::size_t index = x + y * width;
const std::size_t index = x + y * size.x;
m_pixelBuffer[index * 4 + 3] = ((pixels[(x - padding) / 8]) & (1 << (7 - ((x - padding) % 8)))) ? 255 : 0;
}
pixels += bitmap.pitch;
@ -659,13 +638,13 @@ Glyph Font::loadGlyph(std::uint32_t codePoint, unsigned int characterSize, bool
}
else
{
// Pixels are 8 bits gray levels
for (unsigned int y = padding; y < height - padding; ++y)
// Pixels are 8 bit gray levels
for (unsigned int y = padding; y < size.y - padding; ++y)
{
for (unsigned int x = padding; x < width - padding; ++x)
for (unsigned int x = padding; x < size.x - padding; ++x)
{
// The color channels remain white, just fill the alpha channel
const std::size_t index = x + y * width;
const std::size_t index = x + y * size.x;
m_pixelBuffer[index * 4 + 3] = pixels[x - padding];
}
pixels += bitmap.pitch;
@ -673,11 +652,9 @@ Glyph Font::loadGlyph(std::uint32_t codePoint, unsigned int characterSize, bool
}
// Write the pixels to the texture
const unsigned int x = static_cast<unsigned int>(glyph.textureRect.position.x) - padding;
const unsigned int y = static_cast<unsigned int>(glyph.textureRect.position.y) - padding;
const unsigned int w = static_cast<unsigned int>(glyph.textureRect.size.x) + 2 * padding;
const unsigned int h = static_cast<unsigned int>(glyph.textureRect.size.y) + 2 * padding;
page.texture.update(m_pixelBuffer.data(), {w, h}, {x, y});
const auto dest = Vector2u(glyph.textureRect.position) - Vector2u(padding, padding);
const auto updateSize = Vector2u(glyph.textureRect.size) + 2u * Vector2u(padding, padding);
page.texture.update(m_pixelBuffer.data(), updateSize, dest);
}
// Delete the FT glyph

View File

@ -109,6 +109,30 @@ Image::Image(Vector2u size, const std::uint8_t* pixels)
}
////////////////////////////////////////////////////////////
Image::Image(const std::filesystem::path& filename)
{
if (!loadFromFile(filename))
throw std::runtime_error("Failed to open image from file");
}
////////////////////////////////////////////////////////////
Image::Image(const void* data, std::size_t size)
{
if (!loadFromMemory(data, size))
throw std::runtime_error("Failed to open image from memory");
}
////////////////////////////////////////////////////////////
Image::Image(InputStream& stream)
{
if (!loadFromStream(stream))
throw std::runtime_error("Failed to open image from stream");
}
////////////////////////////////////////////////////////////
void Image::resize(Vector2u size, Color color)
{
@ -257,7 +281,7 @@ bool Image::loadFromStream(InputStream& stream)
m_pixels.clear();
// Make sure that the stream's reading position is at the beginning
if (!stream.seek(0))
if (!stream.seek(0).has_value())
{
err() << "Failed to seek image stream" << std::endl;
return false;
@ -292,42 +316,6 @@ bool Image::loadFromStream(InputStream& stream)
}
////////////////////////////////////////////////////////////
std::optional<Image> Image::createFromFile(const std::filesystem::path& filename)
{
auto image = std::make_optional<Image>();
if (!image->loadFromFile(filename))
return std::nullopt;
return image;
}
////////////////////////////////////////////////////////////
std::optional<Image> Image::createFromMemory(const void* data, std::size_t size)
{
auto image = std::make_optional<Image>();
if (!image->loadFromMemory(data, size))
return std::nullopt;
return image;
}
////////////////////////////////////////////////////////////
std::optional<Image> Image::createFromStream(InputStream& stream)
{
auto image = std::make_optional<Image>();
if (!image->loadFromStream(stream))
return std::nullopt;
return image;
}
////////////////////////////////////////////////////////////
bool Image::saveToFile(const std::filesystem::path& filename) const
{

View File

@ -43,6 +43,14 @@ namespace sf
RenderTexture::RenderTexture() = default;
////////////////////////////////////////////////////////////
RenderTexture::RenderTexture(Vector2u size, const ContextSettings& settings)
{
if (!resize(size, settings))
throw std::runtime_error("Failed to create render texture");
}
////////////////////////////////////////////////////////////
RenderTexture::~RenderTexture() = default;
@ -96,18 +104,6 @@ bool RenderTexture::resize(Vector2u size, const ContextSettings& settings)
}
////////////////////////////////////////////////////////////
std::optional<RenderTexture> RenderTexture::create(Vector2u size, const ContextSettings& settings)
{
auto renderTexture = std::make_optional<RenderTexture>();
if (!renderTexture->resize(size, settings))
return std::nullopt;
return renderTexture;
}
////////////////////////////////////////////////////////////
unsigned int RenderTexture::getMaximumAntialiasingLevel()
{
@ -169,26 +165,26 @@ bool RenderTexture::setActive(bool active)
////////////////////////////////////////////////////////////
void RenderTexture::display()
{
if (m_impl)
{
if (priv::RenderTextureImplFBO::isAvailable())
{
// Perform a RenderTarget-only activation if we are using FBOs
if (!RenderTarget::setActive())
return;
}
else
{
// Perform a full activation if we are not using FBOs
if (!setActive())
return;
}
if (!m_impl)
return;
// Update the target texture
m_impl->updateTexture(m_texture.m_texture);
m_texture.m_pixelsFlipped = true;
m_texture.invalidateMipmap();
if (priv::RenderTextureImplFBO::isAvailable())
{
// Perform a RenderTarget-only activation if we are using FBOs
if (!RenderTarget::setActive())
return;
}
else
{
// Perform a full activation if we are not using FBOs
if (!setActive())
return;
}
// Update the target texture
m_impl->updateTexture(m_texture.m_texture);
m_texture.m_pixelsFlipped = true;
m_texture.invalidateMipmap();
}
@ -202,7 +198,7 @@ Vector2u RenderTexture::getSize() const
////////////////////////////////////////////////////////////
bool RenderTexture::isSrgb() const
{
assert(m_impl && "Must call RenderTexture::create first");
assert(m_impl && "RenderTexture::isSrgb() Must first initialize render texture");
return m_impl->isSrgb();
}

View File

@ -223,6 +223,80 @@ struct Shader::UniformBinder
};
////////////////////////////////////////////////////////////
Shader::Shader(const std::filesystem::path& filename, Type type)
{
if (!loadFromFile(filename, type))
throw std::runtime_error("Failed to load shader from file");
}
////////////////////////////////////////////////////////////
Shader::Shader(const std::filesystem::path& vertexShaderFilename, const std::filesystem::path& fragmentShaderFilename)
{
if (!loadFromFile(vertexShaderFilename, fragmentShaderFilename))
throw std::runtime_error("Failed to load shader from files");
}
////////////////////////////////////////////////////////////
Shader::Shader(const std::filesystem::path& vertexShaderFilename,
const std::filesystem::path& geometryShaderFilename,
const std::filesystem::path& fragmentShaderFilename)
{
if (!loadFromFile(vertexShaderFilename, geometryShaderFilename, fragmentShaderFilename))
throw std::runtime_error("Failed to load shader from files");
}
////////////////////////////////////////////////////////////
Shader::Shader(std::string_view shader, Type type)
{
if (!loadFromMemory(shader, type))
throw std::runtime_error("Failed to load shader from memory");
}
////////////////////////////////////////////////////////////
Shader::Shader(std::string_view vertexShader, std::string_view fragmentShader)
{
if (!loadFromMemory(vertexShader, fragmentShader))
throw std::runtime_error("Failed to load shader from memory");
}
////////////////////////////////////////////////////////////
Shader::Shader(std::string_view vertexShader, std::string_view geometryShader, std::string_view fragmentShader)
{
if (!loadFromMemory(vertexShader, geometryShader, fragmentShader))
throw std::runtime_error("Failed to load shader from memory");
}
////////////////////////////////////////////////////////////
Shader::Shader(InputStream& stream, Type type)
{
if (!loadFromStream(stream, type))
throw std::runtime_error("Failed to load shader from stream");
}
////////////////////////////////////////////////////////////
Shader::Shader(InputStream& vertexShaderStream, InputStream& fragmentShaderStream)
{
if (!loadFromStream(vertexShaderStream, fragmentShaderStream))
throw std::runtime_error("Failed to load shader from streams");
}
////////////////////////////////////////////////////////////
Shader::Shader(InputStream& vertexShaderStream, InputStream& geometryShaderStream, InputStream& fragmentShaderStream)
{
if (!loadFromStream(vertexShaderStream, geometryShaderStream, fragmentShaderStream))
throw std::runtime_error("Failed to load shader from streams");
}
////////////////////////////////////////////////////////////
Shader::~Shader()
{
@ -455,121 +529,6 @@ bool Shader::loadFromStream(InputStream& vertexShaderStream, InputStream& geomet
}
////////////////////////////////////////////////////////////
std::optional<Shader> Shader::createFromFile(const std::filesystem::path& filename, Type type)
{
auto shader = std::make_optional<Shader>();
if (!shader->loadFromFile(filename, type))
return std::nullopt;
return shader;
}
////////////////////////////////////////////////////////////
std::optional<Shader> Shader::createFromFile(const std::filesystem::path& vertexShaderFilename,
const std::filesystem::path& fragmentShaderFilename)
{
auto shader = std::make_optional<Shader>();
if (!shader->loadFromFile(vertexShaderFilename, fragmentShaderFilename))
return std::nullopt;
return shader;
}
////////////////////////////////////////////////////////////
std::optional<Shader> Shader::createFromFile(const std::filesystem::path& vertexShaderFilename,
const std::filesystem::path& geometryShaderFilename,
const std::filesystem::path& fragmentShaderFilename)
{
auto shader = std::make_optional<Shader>();
if (!shader->loadFromFile(vertexShaderFilename, geometryShaderFilename, fragmentShaderFilename))
return std::nullopt;
return shader;
}
////////////////////////////////////////////////////////////
std::optional<Shader> Shader::createFromMemory(std::string_view shader, Type type)
{
auto newShader = std::make_optional<Shader>();
if (!newShader->loadFromMemory(shader, type))
return std::nullopt;
return newShader;
}
////////////////////////////////////////////////////////////
std::optional<Shader> Shader::createFromMemory(std::string_view vertexShader, std::string_view fragmentShader)
{
auto shader = std::make_optional<Shader>();
if (!shader->loadFromMemory(vertexShader, fragmentShader))
return std::nullopt;
return shader;
}
////////////////////////////////////////////////////////////
std::optional<Shader> Shader::createFromMemory(std::string_view vertexShader,
std::string_view geometryShader,
std::string_view fragmentShader)
{
auto shader = std::make_optional<Shader>();
if (!shader->loadFromMemory(vertexShader, geometryShader, fragmentShader))
return std::nullopt;
return shader;
}
////////////////////////////////////////////////////////////
std::optional<Shader> Shader::createFromStream(InputStream& stream, Type type)
{
auto shader = std::make_optional<Shader>();
if (!shader->loadFromStream(stream, type))
return std::nullopt;
return shader;
}
////////////////////////////////////////////////////////////
std::optional<Shader> Shader::createFromStream(InputStream& vertexShaderStream, InputStream& fragmentShaderStream)
{
auto shader = std::make_optional<Shader>();
if (!shader->loadFromStream(vertexShaderStream, fragmentShaderStream))
return std::nullopt;
return shader;
}
////////////////////////////////////////////////////////////
std::optional<Shader> Shader::createFromStream(InputStream& vertexShaderStream,
InputStream& geometryShaderStream,
InputStream& fragmentShaderStream)
{
auto shader = std::make_optional<Shader>();
if (!shader->loadFromStream(vertexShaderStream, geometryShaderStream, fragmentShaderStream))
return std::nullopt;
return shader;
}
////////////////////////////////////////////////////////////
void Shader::setUniform(const std::string& name, float x)
{
@ -691,33 +650,33 @@ void Shader::setUniform(const std::string& name, const Glsl::Mat4& matrix)
////////////////////////////////////////////////////////////
void Shader::setUniform(const std::string& name, const Texture& texture)
{
if (m_shaderProgram)
if (!m_shaderProgram)
return;
const TransientContextLock lock;
// Find the location of the variable in the shader
const int location = getUniformLocation(name);
if (location != -1)
{
const TransientContextLock lock;
// Find the location of the variable in the shader
const int location = getUniformLocation(name);
if (location != -1)
// Store the location -> texture mapping
const auto it = m_textures.find(location);
if (it == m_textures.end())
{
// Store the location -> texture mapping
const auto it = m_textures.find(location);
if (it == m_textures.end())
// New entry, make sure there are enough texture units
if (m_textures.size() + 1 >= getMaxTextureUnits())
{
// New entry, make sure there are enough texture units
if (m_textures.size() + 1 >= getMaxTextureUnits())
{
err() << "Impossible to use texture " << std::quoted(name)
<< " for shader: all available texture units are used" << std::endl;
return;
}
err() << "Impossible to use texture " << std::quoted(name)
<< " for shader: all available texture units are used" << std::endl;
return;
}
m_textures[location] = &texture;
}
else
{
// Location already used, just replace the texture
it->second = &texture;
}
m_textures[location] = &texture;
}
else
{
// Location already used, just replace the texture
it->second = &texture;
}
}
}
@ -726,13 +685,13 @@ void Shader::setUniform(const std::string& name, const Texture& texture)
////////////////////////////////////////////////////////////
void Shader::setUniform(const std::string& name, CurrentTextureType)
{
if (m_shaderProgram)
{
const TransientContextLock lock;
if (!m_shaderProgram)
return;
// Find the location of the variable in the shader
m_currentTexture = getUniformLocation(name);
}
const TransientContextLock lock;
// Find the location of the variable in the shader
m_currentTexture = getUniformLocation(name);
}
@ -1077,6 +1036,74 @@ int Shader::getUniformLocation(const std::string& name)
namespace sf
{
////////////////////////////////////////////////////////////
Shader::Shader(const std::filesystem::path& /* filename */, Type /* type */)
{
throw std::runtime_error("Shaders are not supported with OpenGL ES 1");
}
////////////////////////////////////////////////////////////
Shader::Shader(const std::filesystem::path& /* vertexShaderFilename */,
const std::filesystem::path& /* fragmentShaderFilename */)
{
throw std::runtime_error("Shaders are not supported with OpenGL ES 1");
}
////////////////////////////////////////////////////////////
Shader::Shader(const std::filesystem::path& /* vertexShaderFilename */,
const std::filesystem::path& /* geometryShaderFilename */,
const std::filesystem::path& /* fragmentShaderFilename */)
{
throw std::runtime_error("Shaders are not supported with OpenGL ES 1");
}
////////////////////////////////////////////////////////////
Shader::Shader(std::string_view /* shader */, Type /* type */)
{
throw std::runtime_error("Shaders are not supported with OpenGL ES 1");
}
////////////////////////////////////////////////////////////
Shader::Shader(std::string_view /* vertexShader */, std::string_view /* fragmentShader */)
{
throw std::runtime_error("Shaders are not supported with OpenGL ES 1");
}
////////////////////////////////////////////////////////////
Shader::Shader(std::string_view /* vertexShader */, std::string_view /* geometryShader */, std::string_view /* fragmentShader */)
{
throw std::runtime_error("Shaders are not supported with OpenGL ES 1");
}
////////////////////////////////////////////////////////////
Shader::Shader(InputStream& /* stream */, Type /* type */)
{
throw std::runtime_error("Shaders are not supported with OpenGL ES 1");
}
////////////////////////////////////////////////////////////
Shader::Shader(InputStream& /* vertexShaderStream */, InputStream& /* fragmentShaderStream */)
{
throw std::runtime_error("Shaders are not supported with OpenGL ES 1");
}
////////////////////////////////////////////////////////////
Shader::Shader(InputStream& /* vertexShaderStream */,
InputStream& /* geometryShaderStream */,
InputStream& /* fragmentShaderStream */)
{
throw std::runtime_error("Shaders are not supported with OpenGL ES 1");
}
////////////////////////////////////////////////////////////
Shader::~Shader() = default;
@ -1159,76 +1186,6 @@ bool Shader::loadFromStream(InputStream& /* vertexShaderStream */,
}
////////////////////////////////////////////////////////////
std::optional<Shader> Shader::createFromFile(const std::filesystem::path& /* filename */, Type /* type */)
{
return std::nullopt;
}
////////////////////////////////////////////////////////////
std::optional<Shader> Shader::createFromFile(const std::filesystem::path& /* vertexShaderFilename */,
const std::filesystem::path& /* fragmentShaderFilename */)
{
return std::nullopt;
}
////////////////////////////////////////////////////////////
std::optional<Shader> Shader::createFromFile(const std::filesystem::path& /* vertexShaderFilename */,
const std::filesystem::path& /* geometryShaderFilename */,
const std::filesystem::path& /* fragmentShaderFilename */)
{
return std::nullopt;
}
////////////////////////////////////////////////////////////
std::optional<Shader> Shader::createFromMemory(std::string_view /* shader */, Type /* type */)
{
return std::nullopt;
}
////////////////////////////////////////////////////////////
std::optional<Shader> Shader::createFromMemory(std::string_view /* vertexShader */, std::string_view /* fragmentShader */)
{
return std::nullopt;
}
////////////////////////////////////////////////////////////
std::optional<Shader> Shader::createFromMemory(std::string_view /* vertexShader */,
std::string_view /* geometryShader */,
std::string_view /* fragmentShader */)
{
return std::nullopt;
}
////////////////////////////////////////////////////////////
std::optional<Shader> Shader::createFromStream(InputStream& /* stream */, Type /* type */)
{
return std::nullopt;
}
////////////////////////////////////////////////////////////
std::optional<Shader> Shader::createFromStream(InputStream& /* vertexShaderStream */, InputStream& /* fragmentShaderStream */)
{
return std::nullopt;
}
////////////////////////////////////////////////////////////
std::optional<Shader> Shader::createFromStream(InputStream& /* vertexShaderStream */,
InputStream& /* geometryShaderStream */,
InputStream& /* fragmentShaderStream */)
{
return std::nullopt;
}
////////////////////////////////////////////////////////////
void Shader::setUniform(const std::string& /* name */, float)
{

View File

@ -71,6 +71,78 @@ Texture::Texture() : m_cacheId(TextureImpl::getUniqueId())
}
////////////////////////////////////////////////////////////
Texture::Texture(const std::filesystem::path& filename, bool sRgb) : Texture()
{
if (!loadFromFile(filename, sRgb))
throw std::runtime_error("Failed to load texture from file");
}
////////////////////////////////////////////////////////////
Texture::Texture(const std::filesystem::path& filename, bool sRgb, const IntRect& area) : Texture()
{
if (!loadFromFile(filename, sRgb, area))
throw std::runtime_error("Failed to load texture from file");
}
////////////////////////////////////////////////////////////
Texture::Texture(const void* data, std::size_t size, bool sRgb) : Texture()
{
if (!loadFromMemory(data, size, sRgb))
throw std::runtime_error("Failed to load texture from memory");
}
////////////////////////////////////////////////////////////
Texture::Texture(const void* data, std::size_t size, bool sRgb, const IntRect& area) : Texture()
{
if (!loadFromMemory(data, size, sRgb, area))
throw std::runtime_error("Failed to load texture from memory");
}
////////////////////////////////////////////////////////////
Texture::Texture(InputStream& stream, bool sRgb) : Texture()
{
if (!loadFromStream(stream, sRgb))
throw std::runtime_error("Failed to load texture from stream");
}
////////////////////////////////////////////////////////////
Texture::Texture(InputStream& stream, bool sRgb, const IntRect& area) : Texture()
{
if (!loadFromStream(stream, sRgb, area))
throw std::runtime_error("Failed to load texture from stream");
}
////////////////////////////////////////////////////////////
Texture::Texture(const Image& image, bool sRgb) : Texture()
{
if (!loadFromImage(image, sRgb))
throw std::runtime_error("Failed to load texture from image");
}
////////////////////////////////////////////////////////////
Texture::Texture(const Image& image, bool sRgb, const IntRect& area) : Texture()
{
if (!loadFromImage(image, sRgb, area))
throw std::runtime_error("Failed to load texture from image");
}
////////////////////////////////////////////////////////////
Texture::Texture(Vector2u size, bool sRgb) : Texture()
{
if (!resize(size, sRgb))
throw std::runtime_error("Failed to create texture");
}
////////////////////////////////////////////////////////////
Texture::Texture(const Texture& copy) :
GlResource(copy),
@ -361,66 +433,6 @@ bool Texture::loadFromImage(const Image& image, bool sRgb, const IntRect& area)
}
////////////////////////////////////////////////////////////
std::optional<Texture> Texture::create(Vector2u size, bool sRgb)
{
auto texture = std::make_optional<Texture>();
if (!texture->resize(size, sRgb))
return std::nullopt;
return texture;
}
////////////////////////////////////////////////////////////
std::optional<Texture> Texture::createFromFile(const std::filesystem::path& filename, bool sRgb, const IntRect& area)
{
auto texture = std::make_optional<Texture>();
if (!texture->loadFromFile(filename, sRgb, area))
return std::nullopt;
return texture;
}
////////////////////////////////////////////////////////////
std::optional<Texture> Texture::createFromMemory(const void* data, std::size_t size, bool sRgb, const IntRect& area)
{
auto texture = std::make_optional<Texture>();
if (!texture->loadFromMemory(data, size, sRgb, area))
return std::nullopt;
return texture;
}
////////////////////////////////////////////////////////////
std::optional<Texture> Texture::createFromStream(InputStream& stream, bool sRgb, const IntRect& area)
{
auto texture = std::make_optional<Texture>();
if (!texture->loadFromStream(stream, sRgb, area))
return std::nullopt;
return texture;
}
////////////////////////////////////////////////////////////
std::optional<Texture> Texture::createFromImage(const Image& image, bool sRgb, const IntRect& area)
{
auto texture = std::make_optional<Texture>();
if (!texture->loadFromImage(image, sRgb, area))
return std::nullopt;
return texture;
}
////////////////////////////////////////////////////////////
Vector2u Texture::getSize() const
{

View File

@ -47,6 +47,14 @@ void FileInputStream::FileCloser::operator()(std::FILE* file)
FileInputStream::FileInputStream() = default;
////////////////////////////////////////////////////////////
FileInputStream::FileInputStream(const std::filesystem::path& filename)
{
if (!open(filename))
throw std::runtime_error("Failed to open file input stream");
}
////////////////////////////////////////////////////////////
FileInputStream::~FileInputStream() = default;
@ -78,18 +86,6 @@ bool FileInputStream::open(const std::filesystem::path& filename)
}
////////////////////////////////////////////////////////////
std::optional<FileInputStream> FileInputStream::create(const std::filesystem::path& filename)
{
auto fileInputStream = std::make_optional<FileInputStream>();
if (!fileInputStream->open(filename))
return std::nullopt;
return fileInputStream;
}
////////////////////////////////////////////////////////////
std::optional<std::size_t> FileInputStream::read(void* data, std::size_t size)
{

View File

@ -35,18 +35,10 @@
namespace sf
{
////////////////////////////////////////////////////////////
MemoryInputStream::MemoryInputStream(const void* data, std::size_t sizeInBytes)
MemoryInputStream::MemoryInputStream(const void* data, std::size_t sizeInBytes) :
m_data(static_cast<const std::byte*>(data)),
m_size(sizeInBytes)
{
open(data, sizeInBytes);
}
////////////////////////////////////////////////////////////
void MemoryInputStream::open(const void* data, std::size_t sizeInBytes)
{
m_data = static_cast<const std::byte*>(data);
m_size = sizeInBytes;
m_offset = 0;
}

View File

@ -43,6 +43,25 @@ Cursor::Cursor() : m_impl(std::make_unique<priv::CursorImpl>())
}
////////////////////////////////////////////////////////////
Cursor::Cursor(const std::uint8_t* pixels, Vector2u size, Vector2u hotspot) : Cursor()
{
if ((pixels == nullptr) || (size.x == 0) || (size.y == 0))
throw std::runtime_error("Failed to create cursor from pixels (invalid arguments)");
if (!m_impl->loadFromPixels(pixels, size, hotspot))
throw std::runtime_error("Failed to create cursor from pixels");
}
////////////////////////////////////////////////////////////
Cursor::Cursor(Type type) : Cursor()
{
if (!m_impl->loadFromSystem(type))
throw std::runtime_error("Failed to create cursor from type");
}
////////////////////////////////////////////////////////////
Cursor::~Cursor() = default;

View File

@ -23,13 +23,131 @@ TEST_CASE("[Audio] sf::InputSoundFile")
SECTION("Construction")
{
const sf::InputSoundFile inputSoundFile;
CHECK(inputSoundFile.getSampleCount() == 0);
CHECK(inputSoundFile.getChannelCount() == 0);
CHECK(inputSoundFile.getSampleRate() == 0);
CHECK(inputSoundFile.getDuration() == sf::Time::Zero);
CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero);
CHECK(inputSoundFile.getSampleOffset() == 0);
SECTION("Default constructor")
{
const sf::InputSoundFile inputSoundFile;
CHECK(inputSoundFile.getSampleCount() == 0);
CHECK(inputSoundFile.getChannelCount() == 0);
CHECK(inputSoundFile.getSampleRate() == 0);
CHECK(inputSoundFile.getDuration() == sf::Time::Zero);
CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero);
CHECK(inputSoundFile.getSampleOffset() == 0);
}
SECTION("Invalid file")
{
CHECK_THROWS_AS(sf::InputSoundFile("does/not/exist.wav"), std::runtime_error);
}
SECTION("Valid file")
{
SECTION("flac")
{
const sf::InputSoundFile inputSoundFile("Audio/ding.flac");
CHECK(inputSoundFile.getSampleCount() == 87'798);
CHECK(inputSoundFile.getChannelCount() == 1);
CHECK(inputSoundFile.getSampleRate() == 44'100);
CHECK(inputSoundFile.getDuration() == sf::microseconds(1'990'884));
CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero);
CHECK(inputSoundFile.getSampleOffset() == 0);
}
SECTION("mp3")
{
const sf::InputSoundFile inputSoundFile("Audio/ding.mp3");
CHECK(inputSoundFile.getSampleCount() == 87'798);
CHECK(inputSoundFile.getChannelCount() == 1);
CHECK(inputSoundFile.getSampleRate() == 44'100);
CHECK(inputSoundFile.getDuration() == sf::microseconds(1'990'884));
CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero);
CHECK(inputSoundFile.getSampleOffset() == 0);
}
SECTION("ogg")
{
const sf::InputSoundFile inputSoundFile("Audio/doodle_pop.ogg");
CHECK(inputSoundFile.getSampleCount() == 2'116'992);
CHECK(inputSoundFile.getChannelCount() == 2);
CHECK(inputSoundFile.getSampleRate() == 44'100);
CHECK(inputSoundFile.getDuration() == sf::microseconds(24'002'176));
CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero);
CHECK(inputSoundFile.getSampleOffset() == 0);
}
SECTION("wav")
{
const sf::InputSoundFile inputSoundFile("Audio/killdeer.wav");
CHECK(inputSoundFile.getSampleCount() == 112'941);
CHECK(inputSoundFile.getChannelCount() == 1);
CHECK(inputSoundFile.getSampleRate() == 22'050);
CHECK(inputSoundFile.getDuration() == sf::microseconds(5'122'040));
CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero);
CHECK(inputSoundFile.getSampleOffset() == 0);
}
}
SECTION("Memory")
{
const auto memory = loadIntoMemory("Audio/killdeer.wav");
const sf::InputSoundFile inputSoundFile(memory.data(), memory.size());
CHECK(inputSoundFile.getSampleCount() == 112'941);
CHECK(inputSoundFile.getChannelCount() == 1);
CHECK(inputSoundFile.getSampleRate() == 22'050);
CHECK(inputSoundFile.getDuration() == sf::microseconds(5'122'040));
CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero);
CHECK(inputSoundFile.getSampleOffset() == 0);
}
SECTION("Stream")
{
SECTION("flac")
{
sf::FileInputStream stream("Audio/ding.flac");
const sf::InputSoundFile inputSoundFile(stream);
CHECK(inputSoundFile.getSampleCount() == 87'798);
CHECK(inputSoundFile.getChannelCount() == 1);
CHECK(inputSoundFile.getSampleRate() == 44'100);
CHECK(inputSoundFile.getDuration() == sf::microseconds(1'990'884));
CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero);
CHECK(inputSoundFile.getSampleOffset() == 0);
}
SECTION("mp3")
{
sf::FileInputStream stream("Audio/ding.mp3");
const sf::InputSoundFile inputSoundFile(stream);
CHECK(inputSoundFile.getSampleCount() == 87'798);
CHECK(inputSoundFile.getChannelCount() == 1);
CHECK(inputSoundFile.getSampleRate() == 44'100);
CHECK(inputSoundFile.getDuration() == sf::microseconds(1'990'884));
CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero);
CHECK(inputSoundFile.getSampleOffset() == 0);
}
SECTION("ogg")
{
sf::FileInputStream stream("Audio/doodle_pop.ogg");
const sf::InputSoundFile inputSoundFile(stream);
CHECK(inputSoundFile.getSampleCount() == 2'116'992);
CHECK(inputSoundFile.getChannelCount() == 2);
CHECK(inputSoundFile.getSampleRate() == 44'100);
CHECK(inputSoundFile.getDuration() == sf::microseconds(24'002'176));
CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero);
CHECK(inputSoundFile.getSampleOffset() == 0);
}
SECTION("wav")
{
sf::FileInputStream stream("Audio/killdeer.wav");
const sf::InputSoundFile inputSoundFile(stream);
CHECK(inputSoundFile.getSampleCount() == 112'941);
CHECK(inputSoundFile.getChannelCount() == 1);
CHECK(inputSoundFile.getSampleRate() == 22'050);
CHECK(inputSoundFile.getDuration() == sf::microseconds(5'122'040));
CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero);
CHECK(inputSoundFile.getSampleOffset() == 0);
}
}
}
SECTION("openFromFile()")
@ -164,129 +282,11 @@ TEST_CASE("[Audio] sf::InputSoundFile")
}
}
SECTION("createFromFile()")
{
SECTION("Invalid file")
{
CHECK(!sf::InputSoundFile::createFromFile("does/not/exist.wav"));
}
SECTION("Valid file")
{
SECTION("flac")
{
const auto inputSoundFile = sf::InputSoundFile::createFromFile("Audio/ding.flac").value();
CHECK(inputSoundFile.getSampleCount() == 87'798);
CHECK(inputSoundFile.getChannelCount() == 1);
CHECK(inputSoundFile.getSampleRate() == 44'100);
CHECK(inputSoundFile.getDuration() == sf::microseconds(1'990'884));
CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero);
CHECK(inputSoundFile.getSampleOffset() == 0);
}
SECTION("mp3")
{
const auto inputSoundFile = sf::InputSoundFile::createFromFile("Audio/ding.mp3").value();
CHECK(inputSoundFile.getSampleCount() == 87'798);
CHECK(inputSoundFile.getChannelCount() == 1);
CHECK(inputSoundFile.getSampleRate() == 44'100);
CHECK(inputSoundFile.getDuration() == sf::microseconds(1'990'884));
CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero);
CHECK(inputSoundFile.getSampleOffset() == 0);
}
SECTION("ogg")
{
const auto inputSoundFile = sf::InputSoundFile::createFromFile("Audio/doodle_pop.ogg").value();
CHECK(inputSoundFile.getSampleCount() == 2'116'992);
CHECK(inputSoundFile.getChannelCount() == 2);
CHECK(inputSoundFile.getSampleRate() == 44'100);
CHECK(inputSoundFile.getDuration() == sf::microseconds(24'002'176));
CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero);
CHECK(inputSoundFile.getSampleOffset() == 0);
}
SECTION("wav")
{
const auto inputSoundFile = sf::InputSoundFile::createFromFile("Audio/killdeer.wav").value();
CHECK(inputSoundFile.getSampleCount() == 112'941);
CHECK(inputSoundFile.getChannelCount() == 1);
CHECK(inputSoundFile.getSampleRate() == 22'050);
CHECK(inputSoundFile.getDuration() == sf::microseconds(5'122'040));
CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero);
CHECK(inputSoundFile.getSampleOffset() == 0);
}
}
}
SECTION("createFromMemory()")
{
const auto memory = loadIntoMemory("Audio/killdeer.wav");
const auto inputSoundFile = sf::InputSoundFile::createFromMemory(memory.data(), memory.size()).value();
CHECK(inputSoundFile.getSampleCount() == 112'941);
CHECK(inputSoundFile.getChannelCount() == 1);
CHECK(inputSoundFile.getSampleRate() == 22'050);
CHECK(inputSoundFile.getDuration() == sf::microseconds(5'122'040));
CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero);
CHECK(inputSoundFile.getSampleOffset() == 0);
}
SECTION("createFromStream()")
{
SECTION("flac")
{
auto stream = sf::FileInputStream::create("Audio/ding.flac").value();
const auto inputSoundFile = sf::InputSoundFile::createFromStream(stream).value();
CHECK(inputSoundFile.getSampleCount() == 87'798);
CHECK(inputSoundFile.getChannelCount() == 1);
CHECK(inputSoundFile.getSampleRate() == 44'100);
CHECK(inputSoundFile.getDuration() == sf::microseconds(1'990'884));
CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero);
CHECK(inputSoundFile.getSampleOffset() == 0);
}
SECTION("mp3")
{
auto stream = sf::FileInputStream::create("Audio/ding.mp3").value();
const auto inputSoundFile = sf::InputSoundFile::createFromStream(stream).value();
CHECK(inputSoundFile.getSampleCount() == 87'798);
CHECK(inputSoundFile.getChannelCount() == 1);
CHECK(inputSoundFile.getSampleRate() == 44'100);
CHECK(inputSoundFile.getDuration() == sf::microseconds(1'990'884));
CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero);
CHECK(inputSoundFile.getSampleOffset() == 0);
}
SECTION("ogg")
{
auto stream = sf::FileInputStream::create("Audio/doodle_pop.ogg").value();
const auto inputSoundFile = sf::InputSoundFile::createFromStream(stream).value();
CHECK(inputSoundFile.getSampleCount() == 2'116'992);
CHECK(inputSoundFile.getChannelCount() == 2);
CHECK(inputSoundFile.getSampleRate() == 44'100);
CHECK(inputSoundFile.getDuration() == sf::microseconds(24'002'176));
CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero);
CHECK(inputSoundFile.getSampleOffset() == 0);
}
SECTION("wav")
{
auto stream = sf::FileInputStream::create("Audio/killdeer.wav").value();
const auto inputSoundFile = sf::InputSoundFile::createFromStream(stream).value();
CHECK(inputSoundFile.getSampleCount() == 112'941);
CHECK(inputSoundFile.getChannelCount() == 1);
CHECK(inputSoundFile.getSampleRate() == 22'050);
CHECK(inputSoundFile.getDuration() == sf::microseconds(5'122'040));
CHECK(inputSoundFile.getTimeOffset() == sf::Time::Zero);
CHECK(inputSoundFile.getSampleOffset() == 0);
}
}
SECTION("seek(std::uint64_t)")
{
SECTION("flac")
{
auto inputSoundFile = sf::InputSoundFile::createFromFile("Audio/ding.flac").value();
sf::InputSoundFile inputSoundFile("Audio/ding.flac");
inputSoundFile.seek(1'000);
CHECK(inputSoundFile.getTimeOffset() == sf::microseconds(22'675));
CHECK(inputSoundFile.getSampleOffset() == 1'000);
@ -294,7 +294,7 @@ TEST_CASE("[Audio] sf::InputSoundFile")
SECTION("mp3")
{
auto inputSoundFile = sf::InputSoundFile::createFromFile("Audio/ding.mp3").value();
sf::InputSoundFile inputSoundFile("Audio/ding.mp3");
inputSoundFile.seek(1'000);
CHECK(inputSoundFile.getTimeOffset() == sf::microseconds(22'675));
CHECK(inputSoundFile.getSampleOffset() == 1'000);
@ -302,7 +302,7 @@ TEST_CASE("[Audio] sf::InputSoundFile")
SECTION("ogg")
{
auto inputSoundFile = sf::InputSoundFile::createFromFile("Audio/doodle_pop.ogg").value();
sf::InputSoundFile inputSoundFile("Audio/doodle_pop.ogg");
inputSoundFile.seek(1'000);
CHECK(inputSoundFile.getTimeOffset() == sf::microseconds(11'337));
CHECK(inputSoundFile.getSampleOffset() == 1'000);
@ -310,7 +310,7 @@ TEST_CASE("[Audio] sf::InputSoundFile")
SECTION("wav")
{
auto inputSoundFile = sf::InputSoundFile::createFromFile("Audio/killdeer.wav").value();
sf::InputSoundFile inputSoundFile("Audio/killdeer.wav");
inputSoundFile.seek(1'000);
CHECK(inputSoundFile.getTimeOffset() == sf::microseconds(45'351));
CHECK(inputSoundFile.getSampleOffset() == 1'000);
@ -319,7 +319,7 @@ TEST_CASE("[Audio] sf::InputSoundFile")
SECTION("seek(Time)")
{
auto inputSoundFile = sf::InputSoundFile::createFromFile("Audio/ding.flac").value();
sf::InputSoundFile inputSoundFile("Audio/ding.flac");
inputSoundFile.seek(sf::milliseconds(100));
CHECK(inputSoundFile.getSampleCount() == 87'798);
CHECK(inputSoundFile.getChannelCount() == 1);
@ -331,7 +331,7 @@ TEST_CASE("[Audio] sf::InputSoundFile")
SECTION("read()")
{
auto inputSoundFile = sf::InputSoundFile::createFromFile("Audio/ding.flac").value();
sf::InputSoundFile inputSoundFile("Audio/ding.flac");
SECTION("Null address")
{
@ -349,7 +349,7 @@ TEST_CASE("[Audio] sf::InputSoundFile")
{
SECTION("flac")
{
inputSoundFile = sf::InputSoundFile::createFromFile("Audio/ding.flac").value();
inputSoundFile = sf::InputSoundFile("Audio/ding.flac");
CHECK(inputSoundFile.read(samples.data(), samples.size()) == 4);
CHECK(samples == std::array<std::int16_t, 4>{0, 1, -1, 4});
CHECK(inputSoundFile.read(samples.data(), samples.size()) == 4);
@ -358,7 +358,7 @@ TEST_CASE("[Audio] sf::InputSoundFile")
SECTION("mp3")
{
inputSoundFile = sf::InputSoundFile::createFromFile("Audio/ding.mp3").value();
inputSoundFile = sf::InputSoundFile("Audio/ding.mp3");
CHECK(inputSoundFile.read(samples.data(), samples.size()) == 4);
CHECK(samples == std::array<std::int16_t, 4>{0, -2, 0, 2});
CHECK(inputSoundFile.read(samples.data(), samples.size()) == 4);
@ -367,7 +367,7 @@ TEST_CASE("[Audio] sf::InputSoundFile")
SECTION("ogg")
{
inputSoundFile = sf::InputSoundFile::createFromFile("Audio/doodle_pop.ogg").value();
inputSoundFile = sf::InputSoundFile("Audio/doodle_pop.ogg");
CHECK(inputSoundFile.read(samples.data(), samples.size()) == 4);
CHECK(samples == std::array<std::int16_t, 4>{-827, -985, -1168, -1319});
CHECK(inputSoundFile.read(samples.data(), samples.size()) == 4);
@ -383,7 +383,7 @@ TEST_CASE("[Audio] sf::InputSoundFile")
SECTION("close()")
{
auto inputSoundFile = sf::InputSoundFile::createFromFile("Audio/ding.flac").value();
sf::InputSoundFile inputSoundFile("Audio/ding.flac");
inputSoundFile.close();
CHECK(inputSoundFile.getSampleCount() == 0);
CHECK(inputSoundFile.getChannelCount() == 0);

View File

@ -32,18 +32,84 @@ TEST_CASE("[Audio] sf::Music", runAudioDeviceTests())
CHECK(timeSpan.length == sf::Time::Zero);
}
SECTION("Construction")
SECTION("Constructor")
{
const sf::Music music;
CHECK(music.getDuration() == sf::Time::Zero);
const auto [offset, length] = music.getLoopPoints();
CHECK(offset == sf::Time::Zero);
CHECK(length == sf::Time::Zero);
CHECK(music.getChannelCount() == 0);
CHECK(music.getSampleRate() == 0);
CHECK(music.getStatus() == sf::Music::Status::Stopped);
CHECK(music.getPlayingOffset() == sf::Time::Zero);
CHECK(!music.getLoop());
SECTION("Default constructor")
{
const sf::Music music;
CHECK(music.getDuration() == sf::Time::Zero);
const auto [offset, length] = music.getLoopPoints();
CHECK(offset == sf::Time::Zero);
CHECK(length == sf::Time::Zero);
CHECK(music.getChannelCount() == 0);
CHECK(music.getSampleRate() == 0);
CHECK(music.getStatus() == sf::Music::Status::Stopped);
CHECK(music.getPlayingOffset() == sf::Time::Zero);
CHECK(!music.getLoop());
}
SECTION("File")
{
SECTION("Invalid file")
{
CHECK_THROWS_AS(sf::Music("does/not/exist.wav"), std::runtime_error);
}
SECTION("Valid file")
{
const sf::Music music("Audio/ding.mp3");
CHECK(music.getDuration() == sf::microseconds(1990884));
const auto [offset, length] = music.getLoopPoints();
CHECK(offset == sf::Time::Zero);
CHECK(length == sf::microseconds(1990884));
CHECK(music.getChannelCount() == 1);
CHECK(music.getSampleRate() == 44100);
CHECK(music.getStatus() == sf::Music::Status::Stopped);
CHECK(music.getPlayingOffset() == sf::Time::Zero);
CHECK(!music.getLoop());
}
}
SECTION("Memory")
{
std::vector<std::byte> memory(10, std::byte{0xCA});
SECTION("Invalid buffer")
{
CHECK_THROWS_AS(sf::Music(memory.data(), memory.size()), std::runtime_error);
}
SECTION("Valid buffer")
{
memory = loadIntoMemory("Audio/ding.flac");
const sf::Music music(memory.data(), memory.size());
CHECK(music.getDuration() == sf::microseconds(1990884));
const auto [offset, length] = music.getLoopPoints();
CHECK(offset == sf::Time::Zero);
CHECK(length == sf::microseconds(1990884));
CHECK(music.getChannelCount() == 1);
CHECK(music.getSampleRate() == 44100);
CHECK(music.getStatus() == sf::Music::Status::Stopped);
CHECK(music.getPlayingOffset() == sf::Time::Zero);
CHECK(!music.getLoop());
}
}
SECTION("Stream")
{
sf::FileInputStream stream("Audio/doodle_pop.ogg");
const sf::Music music(stream);
CHECK(music.getDuration() == sf::microseconds(24002176));
const auto [offset, length] = music.getLoopPoints();
CHECK(offset == sf::Time::Zero);
CHECK(length == sf::microseconds(24002176));
CHECK(music.getChannelCount() == 2);
CHECK(music.getSampleRate() == 44100);
CHECK(music.getStatus() == sf::Music::Status::Stopped);
CHECK(music.getPlayingOffset() == sf::Time::Zero);
CHECK(!music.getLoop());
}
}
SECTION("openFromFile()")
@ -149,72 +215,9 @@ TEST_CASE("[Audio] sf::Music", runAudioDeviceTests())
}
}
SECTION("createFromFile()")
{
SECTION("Invalid file")
{
CHECK(!sf::Music::createFromFile("does/not/exist.wav"));
}
SECTION("Valid file")
{
const auto music = sf::Music::createFromFile("Audio/ding.mp3").value();
CHECK(music.getDuration() == sf::microseconds(1990884));
const auto [offset, length] = music.getLoopPoints();
CHECK(offset == sf::Time::Zero);
CHECK(length == sf::microseconds(1990884));
CHECK(music.getChannelCount() == 1);
CHECK(music.getSampleRate() == 44100);
CHECK(music.getStatus() == sf::Music::Status::Stopped);
CHECK(music.getPlayingOffset() == sf::Time::Zero);
CHECK(!music.getLoop());
}
}
SECTION("createFromMemory()")
{
std::vector<std::byte> memory(10, std::byte{0xCA});
SECTION("Invalid buffer")
{
CHECK(!sf::Music::createFromMemory(memory.data(), memory.size()));
}
SECTION("Valid buffer")
{
memory = loadIntoMemory("Audio/ding.flac");
const auto music = sf::Music::createFromMemory(memory.data(), memory.size()).value();
CHECK(music.getDuration() == sf::microseconds(1990884));
const auto [offset, length] = music.getLoopPoints();
CHECK(offset == sf::Time::Zero);
CHECK(length == sf::microseconds(1990884));
CHECK(music.getChannelCount() == 1);
CHECK(music.getSampleRate() == 44100);
CHECK(music.getStatus() == sf::Music::Status::Stopped);
CHECK(music.getPlayingOffset() == sf::Time::Zero);
CHECK(!music.getLoop());
}
}
SECTION("createFromStream()")
{
auto stream = sf::FileInputStream::create("Audio/doodle_pop.ogg").value();
const auto music = sf::Music::createFromStream(stream).value();
CHECK(music.getDuration() == sf::microseconds(24002176));
const auto [offset, length] = music.getLoopPoints();
CHECK(offset == sf::Time::Zero);
CHECK(length == sf::microseconds(24002176));
CHECK(music.getChannelCount() == 2);
CHECK(music.getSampleRate() == 44100);
CHECK(music.getStatus() == sf::Music::Status::Stopped);
CHECK(music.getPlayingOffset() == sf::Time::Zero);
CHECK(!music.getLoop());
}
SECTION("play/pause/stop")
{
auto music = sf::Music::createFromFile("Audio/ding.mp3").value();
sf::Music music("Audio/ding.mp3");
// Wait for background thread to start
music.play();
@ -237,7 +240,7 @@ TEST_CASE("[Audio] sf::Music", runAudioDeviceTests())
SECTION("setLoopPoints()")
{
auto music = sf::Music::createFromFile("Audio/killdeer.wav").value();
sf::Music music("Audio/killdeer.wav");
music.setLoopPoints({sf::seconds(1), sf::seconds(2)});
const auto [offset, length] = music.getLoopPoints();
CHECK(offset == sf::seconds(1));

View File

@ -2,6 +2,7 @@
#include <type_traits>
static_assert(std::is_default_constructible_v<sf::OutputSoundFile>);
static_assert(!std::is_copy_constructible_v<sf::OutputSoundFile>);
static_assert(!std::is_copy_assignable_v<sf::OutputSoundFile>);
static_assert(std::is_nothrow_move_constructible_v<sf::OutputSoundFile>);

View File

@ -26,7 +26,7 @@ TEST_CASE("[Audio] sf::Sound", runAudioDeviceTests())
STATIC_CHECK(std::has_virtual_destructor_v<sf::Sound>);
}
const auto soundBuffer = sf::SoundBuffer::createFromFile("Audio/ding.flac").value();
const sf::SoundBuffer soundBuffer("Audio/ding.flac");
SECTION("Construction")
{
@ -52,7 +52,7 @@ TEST_CASE("[Audio] sf::Sound", runAudioDeviceTests())
SECTION("Assignment")
{
const sf::SoundBuffer otherSoundBuffer = sf::SoundBuffer::createFromFile("Audio/ding.flac").value();
const sf::SoundBuffer otherSoundBuffer("Audio/ding.flac");
sf::Sound soundCopy(otherSoundBuffer);
soundCopy = sound;
CHECK(&soundCopy.getBuffer() == &soundBuffer);
@ -64,7 +64,7 @@ TEST_CASE("[Audio] sf::Sound", runAudioDeviceTests())
SECTION("Set/get buffer")
{
const sf::SoundBuffer otherSoundBuffer = sf::SoundBuffer::createFromFile("Audio/ding.flac").value();
const sf::SoundBuffer otherSoundBuffer("Audio/ding.flac");
sf::Sound sound(soundBuffer);
sound.setBuffer(otherSoundBuffer);
CHECK(&sound.getBuffer() == &otherSoundBuffer);

View File

@ -24,17 +24,69 @@ TEST_CASE("[Audio] sf::SoundBuffer", runAudioDeviceTests())
SECTION("Construction")
{
const sf::SoundBuffer soundBuffer;
CHECK(soundBuffer.getSamples() == nullptr);
CHECK(soundBuffer.getSampleCount() == 0);
CHECK(soundBuffer.getSampleRate() == 44100);
CHECK(soundBuffer.getChannelCount() == 1);
CHECK(soundBuffer.getDuration() == sf::Time::Zero);
SECTION("Default constructor")
{
const sf::SoundBuffer soundBuffer;
CHECK(soundBuffer.getSamples() == nullptr);
CHECK(soundBuffer.getSampleCount() == 0);
CHECK(soundBuffer.getSampleRate() == 44100);
CHECK(soundBuffer.getChannelCount() == 1);
CHECK(soundBuffer.getDuration() == sf::Time::Zero);
}
SECTION("File")
{
SECTION("Invalid filename")
{
CHECK_THROWS_AS(sf::SoundBuffer("does/not/exist.wav"), std::runtime_error);
}
SECTION("Valid file")
{
const sf::SoundBuffer soundBuffer("Audio/ding.flac");
CHECK(soundBuffer.getSamples() != nullptr);
CHECK(soundBuffer.getSampleCount() == 87798);
CHECK(soundBuffer.getSampleRate() == 44100);
CHECK(soundBuffer.getChannelCount() == 1);
CHECK(soundBuffer.getDuration() == sf::microseconds(1990884));
}
}
SECTION("Memory")
{
SECTION("Invalid memory")
{
constexpr std::array<std::byte, 5> memory{};
CHECK_THROWS_AS(sf::SoundBuffer(memory.data(), memory.size()), std::runtime_error);
}
SECTION("Valid memory")
{
const auto memory = loadIntoMemory("Audio/ding.flac");
const sf::SoundBuffer soundBuffer(memory.data(), memory.size());
CHECK(soundBuffer.getSamples() != nullptr);
CHECK(soundBuffer.getSampleCount() == 87798);
CHECK(soundBuffer.getSampleRate() == 44100);
CHECK(soundBuffer.getChannelCount() == 1);
CHECK(soundBuffer.getDuration() == sf::microseconds(1990884));
}
}
SECTION("Stream")
{
sf::FileInputStream stream("Audio/ding.flac");
const sf::SoundBuffer soundBuffer(stream);
CHECK(soundBuffer.getSamples() != nullptr);
CHECK(soundBuffer.getSampleCount() == 87798);
CHECK(soundBuffer.getSampleRate() == 44100);
CHECK(soundBuffer.getChannelCount() == 1);
CHECK(soundBuffer.getDuration() == sf::microseconds(1990884));
}
}
SECTION("Copy semantics")
{
const auto soundBuffer = sf::SoundBuffer::createFromFile("Audio/ding.flac").value();
const sf::SoundBuffer soundBuffer("Audio/ding.flac");
SECTION("Construction")
{
@ -48,8 +100,8 @@ TEST_CASE("[Audio] sf::SoundBuffer", runAudioDeviceTests())
SECTION("Assignment")
{
sf::SoundBuffer soundBufferCopy = sf::SoundBuffer::createFromFile("Audio/doodle_pop.ogg").value();
soundBufferCopy = soundBuffer;
sf::SoundBuffer soundBufferCopy("Audio/doodle_pop.ogg");
soundBufferCopy = soundBuffer;
CHECK(soundBufferCopy.getSamples() != nullptr);
CHECK(soundBufferCopy.getSampleCount() == 87798);
CHECK(soundBufferCopy.getSampleRate() == 44100);
@ -123,65 +175,16 @@ TEST_CASE("[Audio] sf::SoundBuffer", runAudioDeviceTests())
}
}
SECTION("createFromFile()")
{
SECTION("Invalid filename")
{
CHECK(!sf::SoundBuffer::createFromFile("does/not/exist.wav"));
}
SECTION("Valid file")
{
const auto soundBuffer = sf::SoundBuffer::createFromFile("Audio/ding.flac").value();
CHECK(soundBuffer.getSamples() != nullptr);
CHECK(soundBuffer.getSampleCount() == 87798);
CHECK(soundBuffer.getSampleRate() == 44100);
CHECK(soundBuffer.getChannelCount() == 1);
CHECK(soundBuffer.getDuration() == sf::microseconds(1990884));
}
}
SECTION("createFromMemory()")
{
SECTION("Invalid memory")
{
constexpr std::array<std::byte, 5> memory{};
CHECK(!sf::SoundBuffer::createFromMemory(memory.data(), memory.size()));
}
SECTION("Valid memory")
{
const auto memory = loadIntoMemory("Audio/ding.flac");
const auto soundBuffer = sf::SoundBuffer::createFromMemory(memory.data(), memory.size()).value();
CHECK(soundBuffer.getSamples() != nullptr);
CHECK(soundBuffer.getSampleCount() == 87798);
CHECK(soundBuffer.getSampleRate() == 44100);
CHECK(soundBuffer.getChannelCount() == 1);
CHECK(soundBuffer.getDuration() == sf::microseconds(1990884));
}
}
SECTION("createFromStream()")
{
auto stream = sf::FileInputStream::create("Audio/ding.flac").value();
const auto soundBuffer = sf::SoundBuffer::createFromStream(stream).value();
CHECK(soundBuffer.getSamples() != nullptr);
CHECK(soundBuffer.getSampleCount() == 87798);
CHECK(soundBuffer.getSampleRate() == 44100);
CHECK(soundBuffer.getChannelCount() == 1);
CHECK(soundBuffer.getDuration() == sf::microseconds(1990884));
}
SECTION("saveToFile()")
{
const auto filename = std::filesystem::temp_directory_path() / "ding.flac";
{
const auto soundBuffer = sf::SoundBuffer::createFromFile("Audio/ding.flac").value();
const sf::SoundBuffer soundBuffer("Audio/ding.flac");
REQUIRE(soundBuffer.saveToFile(filename));
}
const auto soundBuffer = sf::SoundBuffer::createFromFile(filename).value();
const sf::SoundBuffer soundBuffer(filename);
CHECK(soundBuffer.getSamples() != nullptr);
CHECK(soundBuffer.getSampleCount() == 87798);
CHECK(soundBuffer.getSampleRate() == 44100);

View File

@ -11,7 +11,6 @@
#include <catch2/catch_test_macros.hpp>
#include <filesystem>
#include <optional>
#include <type_traits>
#include <cstdint>
@ -110,30 +109,29 @@ TEST_CASE("[Audio] sf::SoundFileFactory")
SECTION("createReaderFromStream()")
{
std::optional<sf::FileInputStream> stream;
sf::FileInputStream stream;
SECTION("flac")
{
stream = sf::FileInputStream::create("Audio/ding.flac");
REQUIRE(stream.open("Audio/ding.flac"));
}
SECTION("mp3")
{
stream = sf::FileInputStream::create("Audio/ding.mp3");
REQUIRE(stream.open("Audio/ding.mp3"));
}
SECTION("ogg")
{
stream = sf::FileInputStream::create("Audio/doodle_pop.ogg");
REQUIRE(stream.open("Audio/doodle_pop.ogg"));
}
SECTION("wav")
{
stream = sf::FileInputStream::create("Audio/killdeer.wav");
REQUIRE(stream.open("Audio/killdeer.wav"));
}
REQUIRE(stream);
CHECK(sf::SoundFileFactory::createReaderFromStream(*stream));
CHECK(sf::SoundFileFactory::createReaderFromStream(stream));
}
SECTION("createWriterFromFilename()")

View File

@ -46,7 +46,7 @@ TEST_CASE("[Graphics] sf::Drawable", runDisplayTests())
SECTION("draw()")
{
const DrawableTest drawableTest;
auto renderTexture = sf::RenderTexture::create({32, 32}).value();
sf::RenderTexture renderTexture({32, 32});
CHECK(drawableTest.callCount() == 0);
renderTexture.draw(drawableTest);
CHECK(drawableTest.callCount() == 1);

View File

@ -23,13 +23,114 @@ TEST_CASE("[Graphics] sf::Font", runDisplayTests())
SECTION("Construction")
{
const sf::Font font;
CHECK(font.getInfo().family.empty());
CHECK(!font.hasGlyph(0));
CHECK(font.getLineSpacing(0) == 0);
CHECK(font.getUnderlinePosition(0) == 0);
CHECK(font.getUnderlineThickness(0) == 0);
CHECK(font.isSmooth());
SECTION("Default constructor")
{
const sf::Font font;
CHECK(font.getInfo().family.empty());
CHECK(!font.hasGlyph(0));
CHECK(font.getLineSpacing(0) == 0);
CHECK(font.getUnderlinePosition(0) == 0);
CHECK(font.getUnderlineThickness(0) == 0);
CHECK(font.isSmooth());
}
SECTION("File")
{
SECTION("Invalid filename")
{
CHECK_THROWS_AS(sf::Font("does/not/exist.ttf"), std::runtime_error);
}
SECTION("Successful load")
{
const sf::Font font("Graphics/tuffy.ttf");
CHECK(font.getInfo().family == "Tuffy");
const auto& glyph = font.getGlyph(0x45, 16, false);
CHECK(glyph.advance == 9);
CHECK(glyph.lsbDelta == 9);
CHECK(glyph.rsbDelta == 16);
CHECK(glyph.bounds == sf::FloatRect({0, -12}, {8, 12}));
CHECK(glyph.textureRect == sf::IntRect({2, 5}, {8, 12}));
CHECK(font.hasGlyph(0x41));
CHECK(font.hasGlyph(0xC0));
CHECK(font.getKerning(0x41, 0x42, 12) == -1);
CHECK(font.getKerning(0x43, 0x44, 24, true) == 0);
CHECK(font.getLineSpacing(24) == 30);
CHECK(font.getUnderlinePosition(36) == Approx(2.20312f));
CHECK(font.getUnderlineThickness(48) == Approx(1.17188f));
const auto& texture = font.getTexture(10);
CHECK(texture.getSize() == sf::Vector2u(128, 128));
CHECK(texture.isSmooth());
CHECK(!texture.isSrgb());
CHECK(!texture.isRepeated());
CHECK(texture.getNativeHandle() != 0);
CHECK(font.isSmooth());
}
}
SECTION("Memory")
{
SECTION("Invalid data and size")
{
CHECK_THROWS_AS(sf::Font(nullptr, 1), std::runtime_error);
const std::byte testByte{0xCD};
CHECK_THROWS_AS(sf::Font(&testByte, 0), std::runtime_error);
}
SECTION("Successful load")
{
const auto memory = loadIntoMemory("Graphics/tuffy.ttf");
const sf::Font font(memory.data(), memory.size());
CHECK(font.getInfo().family == "Tuffy");
const auto& glyph = font.getGlyph(0x45, 16, false);
CHECK(glyph.advance == 9);
CHECK(glyph.lsbDelta == 9);
CHECK(glyph.rsbDelta == 16);
CHECK(glyph.bounds == sf::FloatRect({0, -12}, {8, 12}));
CHECK(glyph.textureRect == sf::IntRect({2, 5}, {8, 12}));
CHECK(font.hasGlyph(0x41));
CHECK(font.hasGlyph(0xC0));
CHECK(font.getKerning(0x41, 0x42, 12) == -1);
CHECK(font.getKerning(0x43, 0x44, 24, true) == 0);
CHECK(font.getLineSpacing(24) == 30);
CHECK(font.getUnderlinePosition(36) == Approx(2.20312f));
CHECK(font.getUnderlineThickness(48) == Approx(1.17188f));
const auto& texture = font.getTexture(10);
CHECK(texture.getSize() == sf::Vector2u(128, 128));
CHECK(texture.isSmooth());
CHECK(!texture.isSrgb());
CHECK(!texture.isRepeated());
CHECK(texture.getNativeHandle() != 0);
CHECK(font.isSmooth());
}
}
SECTION("Stream")
{
sf::FileInputStream stream("Graphics/tuffy.ttf");
const sf::Font font(stream);
CHECK(font.getInfo().family == "Tuffy");
const auto& glyph = font.getGlyph(0x45, 16, false);
CHECK(glyph.advance == 9);
CHECK(glyph.lsbDelta == 9);
CHECK(glyph.rsbDelta == 16);
CHECK(glyph.bounds == sf::FloatRect({0, -12}, {8, 12}));
CHECK(glyph.textureRect == sf::IntRect({2, 5}, {8, 12}));
CHECK(font.hasGlyph(0x41));
CHECK(font.hasGlyph(0xC0));
CHECK(font.getKerning(0x41, 0x42, 12) == -1);
CHECK(font.getKerning(0x43, 0x44, 24, true) == 0);
CHECK(font.getLineSpacing(24) == 30);
CHECK(font.getUnderlinePosition(36) == Approx(2.20312f));
CHECK(font.getUnderlineThickness(48) == Approx(1.17188f));
const auto& texture = font.getTexture(10);
CHECK(texture.getSize() == sf::Vector2u(128, 128));
CHECK(texture.isSmooth());
CHECK(!texture.isSrgb());
CHECK(!texture.isRepeated());
CHECK(texture.getNativeHandle() != 0);
CHECK(font.isSmooth());
}
}
SECTION("openFromFile()")
@ -145,107 +246,9 @@ TEST_CASE("[Graphics] sf::Font", runDisplayTests())
}
}
SECTION("createFromFile()")
{
SECTION("Invalid filename")
{
CHECK(!sf::Font::createFromFile("does/not/exist.ttf"));
}
SECTION("Valid file")
{
const auto font = sf::Font::createFromFile("Graphics/tuffy.ttf").value();
CHECK(font.getInfo().family == "Tuffy");
const auto& glyph = font.getGlyph(0x45, 16, false);
CHECK(glyph.advance == 9);
CHECK(glyph.lsbDelta == 9);
CHECK(glyph.rsbDelta == 16);
CHECK(glyph.bounds == sf::FloatRect({0, -12}, {8, 12}));
CHECK(glyph.textureRect == sf::IntRect({2, 5}, {8, 12}));
CHECK(font.hasGlyph(0x41));
CHECK(font.hasGlyph(0xC0));
CHECK(font.getKerning(0x41, 0x42, 12) == -1);
CHECK(font.getKerning(0x43, 0x44, 24, true) == 0);
CHECK(font.getLineSpacing(24) == 30);
CHECK(font.getUnderlinePosition(36) == Approx(2.20312f));
CHECK(font.getUnderlineThickness(48) == Approx(1.17188f));
const auto& texture = font.getTexture(10);
CHECK(texture.getSize() == sf::Vector2u(128, 128));
CHECK(texture.isSmooth());
CHECK(!texture.isSrgb());
CHECK(!texture.isRepeated());
CHECK(texture.getNativeHandle() != 0);
CHECK(font.isSmooth());
}
}
SECTION("createFromMemory()")
{
SECTION("Invalid data and size")
{
CHECK(!sf::Font::createFromMemory(nullptr, 1));
const std::byte testByte{0xCD};
CHECK(!sf::Font::createFromMemory(&testByte, 0));
}
SECTION("Valid data")
{
const auto memory = loadIntoMemory("Graphics/tuffy.ttf");
const auto font = sf::Font::createFromMemory(memory.data(), memory.size()).value();
CHECK(font.getInfo().family == "Tuffy");
const auto& glyph = font.getGlyph(0x45, 16, false);
CHECK(glyph.advance == 9);
CHECK(glyph.lsbDelta == 9);
CHECK(glyph.rsbDelta == 16);
CHECK(glyph.bounds == sf::FloatRect({0, -12}, {8, 12}));
CHECK(glyph.textureRect == sf::IntRect({2, 5}, {8, 12}));
CHECK(font.hasGlyph(0x41));
CHECK(font.hasGlyph(0xC0));
CHECK(font.getKerning(0x41, 0x42, 12) == -1);
CHECK(font.getKerning(0x43, 0x44, 24, true) == 0);
CHECK(font.getLineSpacing(24) == 30);
CHECK(font.getUnderlinePosition(36) == Approx(2.20312f));
CHECK(font.getUnderlineThickness(48) == Approx(1.17188f));
const auto& texture = font.getTexture(10);
CHECK(texture.getSize() == sf::Vector2u(128, 128));
CHECK(texture.isSmooth());
CHECK(!texture.isSrgb());
CHECK(!texture.isRepeated());
CHECK(texture.getNativeHandle() != 0);
CHECK(font.isSmooth());
}
}
SECTION("createFromStream()")
{
auto stream = sf::FileInputStream::create("Graphics/tuffy.ttf").value();
const auto font = sf::Font::createFromStream(stream).value();
CHECK(font.getInfo().family == "Tuffy");
const auto& glyph = font.getGlyph(0x45, 16, false);
CHECK(glyph.advance == 9);
CHECK(glyph.lsbDelta == 9);
CHECK(glyph.rsbDelta == 16);
CHECK(glyph.bounds == sf::FloatRect({0, -12}, {8, 12}));
CHECK(glyph.textureRect == sf::IntRect({2, 5}, {8, 12}));
CHECK(font.hasGlyph(0x41));
CHECK(font.hasGlyph(0xC0));
CHECK(font.getKerning(0x41, 0x42, 12) == -1);
CHECK(font.getKerning(0x43, 0x44, 24, true) == 0);
CHECK(font.getLineSpacing(24) == 30);
CHECK(font.getUnderlinePosition(36) == Approx(2.20312f));
CHECK(font.getUnderlineThickness(48) == Approx(1.17188f));
const auto& texture = font.getTexture(10);
CHECK(texture.getSize() == sf::Vector2u(128, 128));
CHECK(texture.isSmooth());
CHECK(!texture.isSrgb());
CHECK(!texture.isRepeated());
CHECK(texture.getNativeHandle() != 0);
CHECK(font.isSmooth());
}
SECTION("Set/get smooth")
{
auto font = sf::Font::createFromFile("Graphics/tuffy.ttf").value();
sf::Font font("Graphics/tuffy.ttf");
font.setSmooth(false);
CHECK(!font.isSmooth());
}

View File

@ -19,15 +19,123 @@ TEST_CASE("[Graphics] sf::Image")
STATIC_CHECK(std::is_nothrow_move_assignable_v<sf::Image>);
}
SECTION("Default constructor")
{
const sf::Image image;
CHECK(image.getSize() == sf::Vector2u());
CHECK(image.getPixelsPtr() == nullptr);
}
SECTION("Construction")
{
SECTION("Default constructor")
{
const sf::Image image;
CHECK(image.getSize() == sf::Vector2u());
CHECK(image.getPixelsPtr() == nullptr);
}
SECTION("File constructor")
{
SECTION("Invalid file")
{
CHECK_THROWS_AS(sf::Image("."), std::runtime_error);
CHECK_THROWS_AS(sf::Image("this/does/not/exist.jpg"), std::runtime_error);
}
SECTION("Successful load")
{
SECTION("bmp")
{
const sf::Image image("Graphics/sfml-logo-big.bmp");
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.getPixelsPtr() != nullptr);
}
SECTION("png")
{
const sf::Image image("Graphics/sfml-logo-big.png");
CHECK(image.getPixel({0, 0}) == sf::Color(255, 255, 255, 0));
CHECK(image.getPixel({200, 150}) == sf::Color(144, 208, 62));
CHECK(image.getSize() == sf::Vector2u(1001, 304));
CHECK(image.getPixelsPtr() != nullptr);
}
SECTION("jpg")
{
const sf::Image image("Graphics/sfml-logo-big.jpg");
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.getPixelsPtr() != nullptr);
}
SECTION("gif")
{
const sf::Image image("Graphics/sfml-logo-big.gif");
CHECK(image.getPixel({0, 0}) == sf::Color::White);
CHECK(image.getPixel({200, 150}) == sf::Color(146, 210, 62));
CHECK(image.getSize() == sf::Vector2u(1001, 304));
CHECK(image.getPixelsPtr() != nullptr);
}
SECTION("psd")
{
const sf::Image image("Graphics/sfml-logo-big.psd");
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.getPixelsPtr() != nullptr);
}
}
}
SECTION("Memory constructor")
{
SECTION("Invalid pointer")
{
CHECK_THROWS_AS(sf::Image(nullptr, 1), std::runtime_error);
}
SECTION("Invalid size")
{
const std::byte testByte{0xAB};
CHECK_THROWS_AS(sf::Image(&testByte, 0), std::runtime_error);
}
SECTION("Failed load")
{
std::vector<std::uint8_t> memory;
SECTION("Empty")
{
memory.clear();
}
SECTION("Junk data")
{
memory = {1, 2, 3, 4};
}
CHECK_THROWS_AS(sf::Image(memory.data(), memory.size()), std::runtime_error);
}
SECTION("Successful load")
{
const auto memory = sf::Image({24, 24}, sf::Color::Green).saveToMemory("png").value();
const sf::Image image(memory.data(), memory.size());
CHECK(image.getSize() == sf::Vector2u(24, 24));
CHECK(image.getPixelsPtr() != nullptr);
CHECK(image.getPixel({0, 0}) == sf::Color::Green);
CHECK(image.getPixel({23, 23}) == sf::Color::Green);
}
}
SECTION("Stream constructor")
{
sf::FileInputStream stream("Graphics/sfml-logo-big.png");
const sf::Image image(stream);
CHECK(image.getSize() == sf::Vector2u(1001, 304));
CHECK(image.getPixelsPtr() != nullptr);
CHECK(image.getPixel({0, 0}) == sf::Color(255, 255, 255, 0));
CHECK(image.getPixel({200, 150}) == sf::Color(144, 208, 62));
}
SECTION("Vector2 constructor")
{
const sf::Image image(sf::Vector2u(10, 10));
@ -272,114 +380,6 @@ TEST_CASE("[Graphics] sf::Image")
}
}
SECTION("createFromFile()")
{
SECTION("Invalid file")
{
CHECK(!sf::Image::createFromFile("."));
CHECK(!sf::Image::createFromFile("this/does/not/exist.jpg"));
}
SECTION("Successful load")
{
std::optional<sf::Image> image;
SECTION("bmp")
{
image = sf::Image::createFromFile("Graphics/sfml-logo-big.bmp").value();
REQUIRE(image.has_value());
CHECK(image->getPixel({0, 0}) == sf::Color::White);
CHECK(image->getPixel({200, 150}) == sf::Color(144, 208, 62));
}
SECTION("png")
{
image = sf::Image::createFromFile("Graphics/sfml-logo-big.png").value();
REQUIRE(image.has_value());
CHECK(image->getPixel({0, 0}) == sf::Color(255, 255, 255, 0));
CHECK(image->getPixel({200, 150}) == sf::Color(144, 208, 62));
}
SECTION("jpg")
{
image = sf::Image::createFromFile("Graphics/sfml-logo-big.jpg").value();
REQUIRE(image.has_value());
CHECK(image->getPixel({0, 0}) == sf::Color::White);
CHECK(image->getPixel({200, 150}) == sf::Color(144, 208, 62));
}
SECTION("gif")
{
image = sf::Image::createFromFile("Graphics/sfml-logo-big.gif").value();
REQUIRE(image.has_value());
CHECK(image->getPixel({0, 0}) == sf::Color::White);
CHECK(image->getPixel({200, 150}) == sf::Color(146, 210, 62));
}
SECTION("psd")
{
image = sf::Image::createFromFile("Graphics/sfml-logo-big.psd").value();
REQUIRE(image.has_value());
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->getPixelsPtr() != nullptr);
}
}
SECTION("createFromMemory()")
{
SECTION("Invalid pointer")
{
CHECK(!sf::Image::createFromMemory(nullptr, 1));
}
SECTION("Invalid size")
{
const std::byte testByte{0xAB};
CHECK(!sf::Image::createFromMemory(&testByte, 0));
}
SECTION("Failed load")
{
std::vector<std::uint8_t> memory;
SECTION("Empty")
{
memory.clear();
}
SECTION("Junk data")
{
memory = {1, 2, 3, 4};
}
CHECK(!sf::Image::createFromMemory(memory.data(), memory.size()));
}
SECTION("Successful load")
{
const auto memory = sf::Image({24, 24}, sf::Color::Green).saveToMemory("png").value();
const auto image = sf::Image::createFromMemory(memory.data(), memory.size()).value();
CHECK(image.getSize() == sf::Vector2u(24, 24));
CHECK(image.getPixelsPtr() != nullptr);
CHECK(image.getPixel({0, 0}) == sf::Color::Green);
CHECK(image.getPixel({23, 23}) == sf::Color::Green);
}
}
SECTION("createFromStream()")
{
auto stream = sf::FileInputStream::create("Graphics/sfml-logo-big.png").value();
const auto image = sf::Image::createFromStream(stream).value();
CHECK(image.getSize() == sf::Vector2u(1001, 304));
CHECK(image.getPixelsPtr() != nullptr);
CHECK(image.getPixel({0, 0}) == sf::Color(255, 255, 255, 0));
CHECK(image.getPixel({200, 150}) == sf::Color(144, 208, 62));
}
SECTION("saveToFile()")
{
SECTION("Invalid size")
@ -426,7 +426,7 @@ TEST_CASE("[Graphics] sf::Image")
// Cannot test JPEG encoding due to it triggering UB in stbiw__jpg_writeBits
const auto loadedImage = sf::Image::createFromFile(filename).value();
const sf::Image loadedImage(filename);
CHECK(loadedImage.getSize() == sf::Vector2u(256, 256));
CHECK(loadedImage.getPixelsPtr() != nullptr);

View File

@ -12,9 +12,7 @@ TEST_CASE("[Graphics] Render Tests", runDisplayTests())
{
SECTION("Stencil Tests")
{
auto renderTexture = sf::RenderTexture::create({100, 100}, sf::ContextSettings{0 /* depthBits */, 8 /* stencilBits */})
.value();
sf::RenderTexture renderTexture({100, 100}, sf::ContextSettings{0 /* depthBits */, 8 /* stencilBits */});
renderTexture.clear(sf::Color::Red, 127);
sf::RectangleShape shape1({100, 100});

View File

@ -17,20 +17,45 @@ TEST_CASE("[Graphics] sf::RenderTexture", runDisplayTests())
SECTION("Construction")
{
const sf::RenderTexture renderTexture;
CHECK(!renderTexture.isSmooth());
CHECK(!renderTexture.isRepeated());
CHECK(renderTexture.getSize() == sf::Vector2u(0, 0));
SECTION("Default constructor")
{
const sf::RenderTexture renderTexture;
CHECK(!renderTexture.isSmooth());
CHECK(!renderTexture.isRepeated());
CHECK(renderTexture.getSize() == sf::Vector2u(0, 0));
}
SECTION("2 parameter constructor")
{
CHECK_THROWS_AS(sf::RenderTexture({1'000'000, 1'000'000}), std::runtime_error);
CHECK_NOTHROW(sf::RenderTexture({100, 100}, sf::ContextSettings{8 /* depthBits */, 0 /* stencilBits */}));
CHECK_NOTHROW(sf::RenderTexture({100, 100}, sf::ContextSettings{0 /* depthBits */, 8 /* stencilBits */}));
const sf::RenderTexture renderTexture({360, 480});
CHECK(renderTexture.getSize() == sf::Vector2u(360, 480));
CHECK(!renderTexture.isSmooth());
CHECK(!renderTexture.isRepeated());
CHECK(!renderTexture.isSrgb());
const auto& texture = renderTexture.getTexture();
CHECK(texture.getSize() == sf::Vector2u(360, 480));
CHECK(!texture.isSmooth());
CHECK(!texture.isSrgb());
CHECK(!texture.isRepeated());
CHECK(texture.getNativeHandle() != 0);
}
}
SECTION("create()")
SECTION("resize()")
{
CHECK(!sf::RenderTexture::create({1'000'000, 1'000'000}));
sf::RenderTexture renderTexture;
CHECK(!renderTexture.resize({1'000'000, 1'000'000}));
CHECK(sf::RenderTexture::create({100, 100}, sf::ContextSettings{8 /* depthBits */, 0 /* stencilBits */}));
CHECK(sf::RenderTexture::create({100, 100}, sf::ContextSettings{0 /* depthBits */, 8 /* stencilBits */}));
CHECK(renderTexture.resize({100, 100}, sf::ContextSettings{8 /* depthBits */, 0 /* stencilBits */}));
CHECK(renderTexture.resize({100, 100}, sf::ContextSettings{0 /* depthBits */, 8 /* stencilBits */}));
const auto renderTexture = sf::RenderTexture::create({360, 480}).value();
REQUIRE(renderTexture.resize({360, 480}));
CHECK(renderTexture.getSize() == sf::Vector2u(360, 480));
CHECK(!renderTexture.isSmooth());
CHECK(!renderTexture.isRepeated());
@ -66,27 +91,27 @@ TEST_CASE("[Graphics] sf::RenderTexture", runDisplayTests())
SECTION("Set/get smooth")
{
auto renderTexture = sf::RenderTexture::create({64, 64}).value();
sf::RenderTexture renderTexture({64, 64});
renderTexture.setSmooth(true);
CHECK(renderTexture.isSmooth());
}
SECTION("Set/get repeated")
{
auto renderTexture = sf::RenderTexture::create({64, 64}).value();
sf::RenderTexture renderTexture({64, 64});
renderTexture.setRepeated(true);
CHECK(renderTexture.isRepeated());
}
SECTION("generateMipmap()")
{
auto renderTexture = sf::RenderTexture::create({64, 64}).value();
sf::RenderTexture renderTexture({64, 64});
CHECK(renderTexture.generateMipmap());
}
SECTION("setActive()")
{
auto renderTexture = sf::RenderTexture::create({64, 64}).value();
sf::RenderTexture renderTexture({64, 64});
CHECK(renderTexture.setActive());
CHECK(renderTexture.setActive(false));
CHECK(renderTexture.setActive(true));
@ -94,7 +119,7 @@ TEST_CASE("[Graphics] sf::RenderTexture", runDisplayTests())
SECTION("getTexture()")
{
const auto renderTexture = sf::RenderTexture::create({64, 64}).value();
const sf::RenderTexture renderTexture({64, 64});
CHECK(renderTexture.getTexture().getSize() == sf::Vector2u(64, 64));
}
}

View File

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

View File

@ -145,6 +145,18 @@ TEST_CASE("[Graphics] sf::Shader (Dummy Implementation)", skipShaderDummyTests()
CHECK_FALSE(sf::Shader::isGeometryAvailable());
}
SECTION("Construct from memory")
{
CHECK_THROWS_AS(sf::Shader(std::string_view(vertexSource), sf::Shader::Type::Vertex), std::runtime_error);
CHECK_THROWS_AS(sf::Shader(std::string_view(geometrySource), sf::Shader::Type::Geometry), std::runtime_error);
CHECK_THROWS_AS(sf::Shader(std::string_view(fragmentSource), sf::Shader::Type::Fragment), std::runtime_error);
CHECK_THROWS_AS(sf::Shader(std::string_view(vertexSource), std::string_view(fragmentSource)), std::runtime_error);
CHECK_THROWS_AS(sf::Shader(std::string_view(vertexSource),
std::string_view(geometrySource),
std::string_view(fragmentSource)),
std::runtime_error);
}
SECTION("loadFromMemory()")
{
sf::Shader shader;
@ -154,15 +166,6 @@ TEST_CASE("[Graphics] sf::Shader (Dummy Implementation)", skipShaderDummyTests()
CHECK_FALSE(shader.loadFromMemory(vertexSource, fragmentSource));
CHECK_FALSE(shader.loadFromMemory(vertexSource, geometrySource, fragmentSource));
}
SECTION("createFromMemory()")
{
CHECK_FALSE(sf::Shader::createFromMemory(vertexSource, sf::Shader::Type::Vertex).has_value());
CHECK_FALSE(sf::Shader::createFromMemory(geometrySource, sf::Shader::Type::Geometry).has_value());
CHECK_FALSE(sf::Shader::createFromMemory(fragmentSource, sf::Shader::Type::Fragment).has_value());
CHECK_FALSE(sf::Shader::createFromMemory(vertexSource, fragmentSource).has_value());
CHECK_FALSE(sf::Shader::createFromMemory(vertexSource, geometrySource, fragmentSource).has_value());
}
}
TEST_CASE("[Graphics] sf::Shader", skipShaderFullTests())
@ -177,8 +180,181 @@ TEST_CASE("[Graphics] sf::Shader", skipShaderFullTests())
SECTION("Construction")
{
const sf::Shader shader;
CHECK(shader.getNativeHandle() == 0);
SECTION("Default constructor")
{
const sf::Shader shader;
CHECK(shader.getNativeHandle() == 0);
}
SECTION("File")
{
SECTION("One shader")
{
CHECK_THROWS_AS(sf::Shader(std::filesystem::path("does-not-exist.vert"), sf::Shader::Type::Vertex),
std::runtime_error);
if (sf::Shader::isAvailable())
{
CHECK(sf::Shader(std::filesystem::path("Graphics/shader.vert"), sf::Shader::Type::Vertex).getNativeHandle() !=
0);
CHECK(sf::Shader(std::filesystem::path("Graphics/shader.frag"), sf::Shader::Type::Fragment)
.getNativeHandle() != 0);
}
else
{
CHECK_THROWS_AS(sf::Shader(std::filesystem::path("Graphics/shader.vert"), sf::Shader::Type::Vertex),
std::runtime_error);
CHECK_THROWS_AS(sf::Shader(std::filesystem::path("Graphics/shader.frag"), sf::Shader::Type::Fragment),
std::runtime_error);
}
}
SECTION("Two shaders")
{
CHECK_THROWS_AS(sf::Shader(std::filesystem::path("does-not-exist.vert"),
std::filesystem::path("Graphics/shader.frag")),
std::runtime_error);
CHECK_THROWS_AS(sf::Shader(std::filesystem::path("Graphics/shader.vert"),
std::filesystem::path("does-not-exist.frag")),
std::runtime_error);
if (sf::Shader::isAvailable())
{
CHECK(sf::Shader(std::filesystem::path("Graphics/shader.vert"),
std::filesystem::path("Graphics/shader.frag"))
.getNativeHandle() != 0);
}
else
{
CHECK_THROWS_AS(sf::Shader(std::filesystem::path("Graphics/shader.vert"),
std::filesystem::path("Graphics/shader.frag")),
std::runtime_error);
}
}
SECTION("Three shaders")
{
CHECK_THROWS_AS(sf::Shader(std::filesystem::path("does-not-exist.vert"),
std::filesystem::path("Graphics/shader.geom"),
std::filesystem::path("Graphics/shader.frag")),
std::runtime_error);
CHECK_THROWS_AS(sf::Shader(std::filesystem::path("Graphics/shader.vert"),
std::filesystem::path("does-not-exist.geom"),
std::filesystem::path("Graphics/shader.frag")),
std::runtime_error);
CHECK_THROWS_AS(sf::Shader(std::filesystem::path("Graphics/shader.vert"),
std::filesystem::path("Graphics/shader.geom"),
std::filesystem::path("does-not-exist.frag")),
std::runtime_error);
if (sf::Shader::isGeometryAvailable())
{
CHECK(sf::Shader(std::filesystem::path("Graphics/shader.vert"),
std::filesystem::path("Graphics/shader.geom"),
std::filesystem::path("Graphics/shader.frag"))
.getNativeHandle() != 0);
}
else
{
CHECK_THROWS_AS(sf::Shader(std::filesystem::path("Graphics/shader.vert"),
std::filesystem::path("Graphics/shader.geom"),
std::filesystem::path("Graphics/shader.frag")),
std::runtime_error);
}
}
}
SECTION("Memory")
{
if (sf::Shader::isAvailable())
{
CHECK(sf::Shader(std::string_view(vertexSource), sf::Shader::Type::Vertex).getNativeHandle() != 0);
CHECK_THROWS_AS(sf::Shader(std::string_view(geometrySource), sf::Shader::Type::Geometry),
std::runtime_error);
CHECK(sf::Shader(std::string_view(fragmentSource), sf::Shader::Type::Fragment).getNativeHandle() != 0);
CHECK(sf::Shader(std::string_view(vertexSource), std::string_view(fragmentSource)).getNativeHandle() != 0);
}
else
{
CHECK_THROWS_AS(sf::Shader(std::string_view(vertexSource), sf::Shader::Type::Vertex), std::runtime_error);
CHECK_THROWS_AS(sf::Shader(std::string_view(geometrySource), sf::Shader::Type::Geometry),
std::runtime_error);
CHECK_THROWS_AS(sf::Shader(std::string_view(fragmentSource), sf::Shader::Type::Fragment),
std::runtime_error);
CHECK_THROWS_AS(sf::Shader(std::string_view(vertexSource), std::string_view(fragmentSource)),
std::runtime_error);
}
if (sf::Shader::isGeometryAvailable())
{
CHECK(sf::Shader(std::string_view(vertexSource), std::string_view(geometrySource), std::string_view(fragmentSource))
.getNativeHandle() != 0);
}
else
{
CHECK_THROWS_AS(sf::Shader(std::string_view(vertexSource),
std::string_view(geometrySource),
std::string_view(fragmentSource)),
std::runtime_error);
}
}
SECTION("Stream")
{
sf::FileInputStream vertexShaderStream("Graphics/shader.vert");
sf::FileInputStream fragmentShaderStream("Graphics/shader.frag");
sf::FileInputStream geometryShaderStream("Graphics/shader.geom");
sf::FileInputStream emptyStream("Graphics/invalid_shader.vert");
SECTION("One shader")
{
CHECK_THROWS_AS(sf::Shader(emptyStream, sf::Shader::Type::Vertex), std::runtime_error);
if (sf::Shader::isAvailable())
{
CHECK(sf::Shader(vertexShaderStream, sf::Shader::Type::Vertex).getNativeHandle() != 0);
CHECK(sf::Shader(fragmentShaderStream, sf::Shader::Type::Fragment).getNativeHandle() != 0);
}
else
{
CHECK_THROWS_AS(sf::Shader(vertexShaderStream, sf::Shader::Type::Vertex), std::runtime_error);
CHECK_THROWS_AS(sf::Shader(fragmentShaderStream, sf::Shader::Type::Fragment), std::runtime_error);
}
}
SECTION("Two shaders")
{
CHECK_THROWS_AS(sf::Shader(emptyStream, fragmentShaderStream), std::runtime_error);
CHECK_THROWS_AS(sf::Shader(vertexShaderStream, emptyStream), std::runtime_error);
if (sf::Shader::isAvailable())
{
CHECK(sf::Shader(vertexShaderStream, fragmentShaderStream).getNativeHandle() != 0);
}
else
{
CHECK_THROWS_AS(sf::Shader(vertexShaderStream, fragmentShaderStream), std::runtime_error);
}
}
SECTION("Three shaders")
{
CHECK_THROWS_AS(sf::Shader(emptyStream, geometryShaderStream, fragmentShaderStream), std::runtime_error);
CHECK_THROWS_AS(sf::Shader(vertexShaderStream, emptyStream, fragmentShaderStream), std::runtime_error);
CHECK_THROWS_AS(sf::Shader(vertexShaderStream, geometryShaderStream, emptyStream), std::runtime_error);
if (sf::Shader::isGeometryAvailable())
{
CHECK(sf::Shader(vertexShaderStream, geometryShaderStream, fragmentShaderStream).getNativeHandle() != 0);
}
else
{
CHECK_THROWS_AS(sf::Shader(vertexShaderStream, geometryShaderStream, fragmentShaderStream),
std::runtime_error);
}
}
}
}
SECTION("Move semantics")
@ -203,16 +379,16 @@ TEST_CASE("[Graphics] sf::Shader", skipShaderFullTests())
{
SECTION("Construction")
{
sf::Shader movedShader = sf::Shader::createFromFile("Graphics/shader.vert", sf::Shader::Type::Vertex).value();
sf::Shader movedShader(std::filesystem::path("Graphics/shader.vert"), sf::Shader::Type::Vertex);
const sf::Shader shader = std::move(movedShader);
CHECK(shader.getNativeHandle() != 0);
}
SECTION("Assignment")
{
sf::Shader movedShader = sf::Shader::createFromFile("Graphics/shader.vert", sf::Shader::Type::Vertex).value();
sf::Shader shader = sf::Shader::createFromFile("Graphics/shader.frag", sf::Shader::Type::Fragment).value();
shader = std::move(movedShader);
sf::Shader movedShader(std::filesystem::path("Graphics/shader.vert"), sf::Shader::Type::Vertex);
sf::Shader shader(std::filesystem::path("Graphics/shader.frag"), sf::Shader::Type::Fragment);
shader = std::move(movedShader);
CHECK(shader.getNativeHandle() != 0);
}
}
@ -255,7 +431,7 @@ TEST_CASE("[Graphics] sf::Shader", skipShaderFullTests())
{
sf::Shader shader;
CHECK(shader.loadFromMemory(vertexSource, sf::Shader::Type::Vertex) == sf::Shader::isAvailable());
CHECK_FALSE(shader.loadFromMemory(geometrySource, sf::Shader::Type::Geometry));
CHECK(!shader.loadFromMemory(geometrySource, sf::Shader::Type::Geometry));
CHECK(shader.loadFromMemory(fragmentSource, sf::Shader::Type::Fragment) == sf::Shader::isAvailable());
CHECK(shader.loadFromMemory(vertexSource, fragmentSource) == sf::Shader::isAvailable());
CHECK(shader.loadFromMemory(vertexSource, geometrySource, fragmentSource) == sf::Shader::isGeometryAvailable());
@ -300,100 +476,4 @@ TEST_CASE("[Graphics] sf::Shader", skipShaderFullTests())
CHECK(static_cast<bool>(shader.getNativeHandle()) == sf::Shader::isGeometryAvailable());
}
}
SECTION("createFromFile()")
{
SECTION("One shader")
{
CHECK(!sf::Shader::createFromFile("does-not-exist.vert", sf::Shader::Type::Vertex));
const auto vertexShader = sf::Shader::createFromFile("Graphics/shader.vert", sf::Shader::Type::Vertex);
CHECK(vertexShader.has_value() == sf::Shader::isAvailable());
if (vertexShader)
CHECK(static_cast<bool>(vertexShader->getNativeHandle()) == sf::Shader::isAvailable());
const auto fragmentShader = sf::Shader::createFromFile("Graphics/shader.frag", sf::Shader::Type::Fragment);
CHECK(fragmentShader.has_value() == sf::Shader::isAvailable());
if (fragmentShader)
CHECK(static_cast<bool>(fragmentShader->getNativeHandle()) == sf::Shader::isAvailable());
}
SECTION("Two shaders")
{
CHECK(!sf::Shader::createFromFile("does-not-exist.vert", "Graphics/shader.frag"));
CHECK(!sf::Shader::createFromFile("Graphics/shader.vert", "does-not-exist.frag"));
const auto shader = sf::Shader::createFromFile("Graphics/shader.vert", "Graphics/shader.frag");
CHECK(shader.has_value() == sf::Shader::isAvailable());
if (shader)
CHECK(static_cast<bool>(shader->getNativeHandle()) == sf::Shader::isAvailable());
}
SECTION("Three shaders")
{
CHECK(!sf::Shader::createFromFile("does-not-exist.vert", "Graphics/shader.geom", "Graphics/shader.frag"));
CHECK(!sf::Shader::createFromFile("Graphics/shader.vert", "does-not-exist.geom", "Graphics/shader.frag"));
CHECK(!sf::Shader::createFromFile("Graphics/shader.vert", "Graphics/shader.geom", "does-not-exist.frag"));
const auto shader = sf::Shader::createFromFile("Graphics/shader.vert",
"Graphics/shader.geom",
"Graphics/shader.frag");
CHECK(shader.has_value() == sf::Shader::isGeometryAvailable());
if (shader)
CHECK(static_cast<bool>(shader->getNativeHandle()) == sf::Shader::isGeometryAvailable());
}
}
SECTION("createFromMemory()")
{
CHECK(sf::Shader::createFromMemory(vertexSource, sf::Shader::Type::Vertex).has_value() ==
sf::Shader::isAvailable());
CHECK(!sf::Shader::createFromMemory(geometrySource, sf::Shader::Type::Geometry));
CHECK(sf::Shader::createFromMemory(fragmentSource, sf::Shader::Type::Fragment).has_value() ==
sf::Shader::isAvailable());
CHECK(sf::Shader::createFromMemory(vertexSource, fragmentSource).has_value() == sf::Shader::isAvailable());
const auto shader = sf::Shader::createFromMemory(vertexSource, geometrySource, fragmentSource);
CHECK(shader.has_value() == sf::Shader::isGeometryAvailable());
if (shader)
CHECK(static_cast<bool>(shader->getNativeHandle()) == sf::Shader::isAvailable());
}
SECTION("createFromStream()")
{
auto vertexShaderStream = sf::FileInputStream::create("Graphics/shader.vert").value();
auto fragmentShaderStream = sf::FileInputStream::create("Graphics/shader.frag").value();
auto geometryShaderStream = sf::FileInputStream::create("Graphics/shader.geom").value();
auto emptyStream = sf::FileInputStream::create("Graphics/invalid_shader.vert").value();
SECTION("One shader")
{
CHECK(!sf::Shader::createFromStream(emptyStream, sf::Shader::Type::Vertex));
CHECK(sf::Shader::createFromStream(vertexShaderStream, sf::Shader::Type::Vertex).has_value() ==
sf::Shader::isAvailable());
CHECK(sf::Shader::createFromStream(fragmentShaderStream, sf::Shader::Type::Fragment).has_value() ==
sf::Shader::isAvailable());
}
SECTION("Two shaders")
{
CHECK(!sf::Shader::createFromStream(emptyStream, fragmentShaderStream));
CHECK(!sf::Shader::createFromStream(vertexShaderStream, emptyStream));
CHECK(sf::Shader::createFromStream(vertexShaderStream, fragmentShaderStream).has_value() ==
sf::Shader::isAvailable());
}
SECTION("Three shaders")
{
CHECK(!sf::Shader::createFromStream(emptyStream, geometryShaderStream, fragmentShaderStream));
CHECK(!sf::Shader::createFromStream(vertexShaderStream, emptyStream, fragmentShaderStream));
CHECK(!sf::Shader::createFromStream(vertexShaderStream, geometryShaderStream, emptyStream));
const auto shader = sf::Shader::createFromStream(vertexShaderStream, geometryShaderStream, fragmentShaderStream);
CHECK(shader.has_value() == sf::Shader::isGeometryAvailable());
if (shader)
CHECK(static_cast<bool>(shader->getNativeHandle()) == sf::Shader::isGeometryAvailable());
}
}
}

View File

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

View File

@ -22,7 +22,7 @@ TEST_CASE("[Graphics] sf::Sprite", runDisplayTests())
STATIC_CHECK(std::is_nothrow_move_assignable_v<sf::Sprite>);
}
const auto texture = sf::Texture::create({64, 64}).value();
const sf::Texture texture(sf::Vector2u(64, 64));
SECTION("Construction")
{
@ -60,7 +60,7 @@ TEST_CASE("[Graphics] sf::Sprite", runDisplayTests())
SECTION("Set/get texture")
{
sf::Sprite sprite(texture);
const sf::Texture otherTexture = sf::Texture::create({64, 64}).value();
const sf::Texture otherTexture(sf::Vector2u(64, 64));
sprite.setTexture(otherTexture);
CHECK(&sprite.getTexture() == &otherTexture);
}

View File

@ -21,7 +21,7 @@ TEST_CASE("[Graphics] sf::Text", runDisplayTests())
STATIC_CHECK(std::is_nothrow_move_assignable_v<sf::Text>);
}
const auto font = sf::Font::createFromFile("Graphics/tuffy.ttf").value();
const sf::Font font("Graphics/tuffy.ttf");
SECTION("Construction")
{
@ -86,8 +86,8 @@ TEST_CASE("[Graphics] sf::Text", runDisplayTests())
SECTION("Set/get font")
{
sf::Text text(font);
const auto otherFont = sf::Font::createFromFile("Graphics/tuffy.ttf").value();
sf::Text text(font);
const sf::Font otherFont("Graphics/tuffy.ttf");
text.setFont(otherFont);
CHECK(&text.getFont() == &otherFont);
}

View File

@ -24,12 +24,99 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
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("Default constructor")
{
const sf::Texture texture;
CHECK(texture.getSize() == sf::Vector2u());
CHECK(!texture.isSmooth());
CHECK(!texture.isSrgb());
CHECK(!texture.isRepeated());
CHECK(texture.getNativeHandle() == 0);
}
SECTION("Vector")
{
SECTION("At least one zero dimension")
{
CHECK_THROWS_AS(sf::Texture(sf::Vector2u()), std::runtime_error);
CHECK_THROWS_AS(sf::Texture(sf::Vector2u(0, 1)), std::runtime_error);
CHECK_THROWS_AS(sf::Texture(sf::Vector2u(1, 0)), std::runtime_error);
}
SECTION("Valid size")
{
const sf::Texture texture(sf::Vector2u(100, 100));
CHECK(texture.getSize() == sf::Vector2u(100, 100));
CHECK(texture.getNativeHandle() != 0);
}
SECTION("Too large")
{
CHECK_THROWS_AS(sf::Texture(sf::Vector2u(100'000, 100'000)), std::runtime_error);
CHECK_THROWS_AS(sf::Texture(sf::Vector2u(1'000'000, 1'000'000)), std::runtime_error);
}
}
SECTION("File")
{
const sf::Texture texture("Graphics/sfml-logo-big.png");
CHECK(texture.getSize() == sf::Vector2u(1001, 304));
CHECK(!texture.isSmooth());
CHECK(!texture.isSrgb());
CHECK(!texture.isRepeated());
CHECK(texture.getNativeHandle() != 0);
}
SECTION("Memory")
{
const auto memory = loadIntoMemory("Graphics/sfml-logo-big.png");
const sf::Texture texture(memory.data(), memory.size());
CHECK(texture.getSize() == sf::Vector2u(1001, 304));
CHECK(!texture.isSmooth());
CHECK(!texture.isSrgb());
CHECK(!texture.isRepeated());
CHECK(texture.getNativeHandle() != 0);
}
SECTION("Stream")
{
sf::FileInputStream stream("Graphics/sfml-logo-big.png");
const sf::Texture texture(stream);
CHECK(texture.getSize() == sf::Vector2u(1001, 304));
CHECK(!texture.isSmooth());
CHECK(!texture.isSrgb());
CHECK(!texture.isRepeated());
CHECK(texture.getNativeHandle() != 0);
}
SECTION("Image")
{
SECTION("Subarea of image")
{
const sf::Image image(sf::Vector2u(10, 15));
SECTION("Non-truncated area")
{
const sf::Texture texture(image, false, {{0, 0}, {5, 10}});
CHECK(texture.getSize() == sf::Vector2u(5, 10));
CHECK(texture.getNativeHandle() != 0);
}
SECTION("Truncated area (negative position)")
{
const sf::Texture texture(image, false, {{-5, -5}, {4, 8}});
CHECK(texture.getSize() == sf::Vector2u(4, 8));
CHECK(texture.getNativeHandle() != 0);
}
SECTION("Truncated area (width/height too big)")
{
const sf::Texture texture(image, false, {{5, 5}, {12, 18}});
CHECK(texture.getSize() == sf::Vector2u(5, 10));
CHECK(texture.getNativeHandle() != 0);
}
}
}
}
SECTION("Move semantics")
@ -58,12 +145,12 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
}
}
SECTION("Move semantics (create)")
SECTION("Move semantics")
{
SECTION("Construction")
{
sf::Texture movedTexture = sf::Texture::create({64, 64}).value();
const sf::Texture texture = std::move(movedTexture);
sf::Texture movedTexture(sf::Vector2u(64, 64));
const sf::Texture texture = std::move(movedTexture);
CHECK(texture.getSize() == sf::Vector2u(64, 64));
CHECK(!texture.isSmooth());
CHECK(!texture.isSrgb());
@ -73,9 +160,9 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
SECTION("Assignment")
{
sf::Texture movedTexture = sf::Texture::create({64, 64}).value();
sf::Texture texture = sf::Texture::create({128, 128}).value();
texture = std::move(movedTexture);
sf::Texture movedTexture(sf::Vector2u(64, 64));
sf::Texture texture(sf::Vector2u(128, 128));
texture = std::move(movedTexture);
CHECK(texture.getSize() == sf::Vector2u(64, 64));
CHECK(!texture.isSmooth());
CHECK(!texture.isSrgb());
@ -84,29 +171,6 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
}
}
SECTION("create()")
{
SECTION("At least one zero dimension")
{
CHECK(!sf::Texture::create({}));
CHECK(!sf::Texture::create({0, 1}));
CHECK(!sf::Texture::create({1, 0}));
}
SECTION("Valid size")
{
const auto texture = sf::Texture::create({100, 100}).value();
CHECK(texture.getSize() == sf::Vector2u(100, 100));
CHECK(texture.getNativeHandle() != 0);
}
SECTION("Too large")
{
CHECK(!sf::Texture::create({100'000, 100'000}));
CHECK(!sf::Texture::create({1'000'000, 1'000'000}));
}
}
SECTION("resize()")
{
sf::Texture texture;
@ -206,72 +270,11 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
}
}
SECTION("createFromFile()")
{
const auto texture = sf::Texture::createFromFile("Graphics/sfml-logo-big.png").value();
CHECK(texture.getSize() == sf::Vector2u(1001, 304));
CHECK(!texture.isSmooth());
CHECK(!texture.isSrgb());
CHECK(!texture.isRepeated());
CHECK(texture.getNativeHandle() != 0);
}
SECTION("createFromMemory()")
{
const auto memory = loadIntoMemory("Graphics/sfml-logo-big.png");
const auto texture = sf::Texture::createFromMemory(memory.data(), memory.size()).value();
CHECK(texture.getSize() == sf::Vector2u(1001, 304));
CHECK(!texture.isSmooth());
CHECK(!texture.isSrgb());
CHECK(!texture.isRepeated());
CHECK(texture.getNativeHandle() != 0);
}
SECTION("createFromStream()")
{
auto stream = sf::FileInputStream::create("Graphics/sfml-logo-big.png").value();
const auto texture = sf::Texture::createFromStream(stream).value();
CHECK(texture.getSize() == sf::Vector2u(1001, 304));
CHECK(!texture.isSmooth());
CHECK(!texture.isSrgb());
CHECK(!texture.isRepeated());
CHECK(texture.getNativeHandle() != 0);
}
SECTION("createFromImage()")
{
SECTION("Subarea of image")
{
const sf::Image image(sf::Vector2u(10, 15));
SECTION("Non-truncated area")
{
const auto texture = sf::Texture::createFromImage(image, false, {{0, 0}, {5, 10}}).value();
CHECK(texture.getSize() == sf::Vector2u(5, 10));
CHECK(texture.getNativeHandle() != 0);
}
SECTION("Truncated area (negative position)")
{
const auto texture = sf::Texture::createFromImage(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)")
{
const auto texture = sf::Texture::createFromImage(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};
auto texture = sf::Texture::create({1, 2}).value();
sf::Texture texture(sf::Vector2u(1, 2));
texture.update(red);
SECTION("Construction")
@ -283,8 +286,8 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
SECTION("Assignment")
{
sf::Texture textureCopy = sf::Texture::create({64, 64}).value();
textureCopy = texture;
sf::Texture textureCopy(sf::Vector2u(64, 64));
textureCopy = texture;
REQUIRE(textureCopy.getSize() == sf::Vector2u(1, 2));
CHECK(textureCopy.copyToImage().getPixel(sf::Vector2u(0, 1)) == sf::Color::Red);
}
@ -297,14 +300,14 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
SECTION("Pixels")
{
auto texture = sf::Texture::create(sf::Vector2u(1, 1)).value();
sf::Texture texture(sf::Vector2u(1, 1));
texture.update(yellow);
CHECK(texture.copyToImage().getPixel(sf::Vector2u(0, 0)) == sf::Color::Yellow);
}
SECTION("Pixels, size and destination")
{
auto texture = sf::Texture::create(sf::Vector2u(2, 1)).value();
sf::Texture texture(sf::Vector2u(2, 1));
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);
@ -313,19 +316,19 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
SECTION("Another texture")
{
auto otherTexture = sf::Texture::create(sf::Vector2u(1, 1)).value();
sf::Texture otherTexture(sf::Vector2u(1, 1));
otherTexture.update(cyan);
auto texture = sf::Texture::create(sf::Vector2u(1, 1)).value();
sf::Texture texture(sf::Vector2u(1, 1));
texture.update(otherTexture);
CHECK(texture.copyToImage().getPixel(sf::Vector2u(0, 0)) == sf::Color::Cyan);
}
SECTION("Another texture and destination")
{
auto texture = sf::Texture::create(sf::Vector2u(2, 1)).value();
auto otherTexture1 = sf::Texture::create(sf::Vector2u(1, 1)).value();
sf::Texture texture(sf::Vector2u(2, 1));
sf::Texture otherTexture1(sf::Vector2u(1, 1));
otherTexture1.update(cyan);
auto otherTexture2 = sf::Texture::create(sf::Vector2u(1, 1)).value();
sf::Texture otherTexture2(sf::Vector2u(1, 1));
otherTexture2.update(yellow);
texture.update(otherTexture1, sf::Vector2u(0, 0));
texture.update(otherTexture2, sf::Vector2u(1, 0));
@ -335,7 +338,7 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
SECTION("Image")
{
auto texture = sf::Texture::create(sf::Vector2u(16, 32)).value();
sf::Texture texture(sf::Vector2u(16, 32));
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);
@ -343,7 +346,7 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
SECTION("Image and destination")
{
auto texture = sf::Texture::create(sf::Vector2u(16, 32)).value();
sf::Texture texture(sf::Vector2u(16, 32));
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);
@ -356,7 +359,7 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
SECTION("Set/get smooth")
{
sf::Texture texture = sf::Texture::create({64, 64}).value();
sf::Texture texture(sf::Vector2u(64, 64));
CHECK(!texture.isSmooth());
texture.setSmooth(true);
CHECK(texture.isSmooth());
@ -366,7 +369,7 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
SECTION("Set/get repeated")
{
sf::Texture texture = sf::Texture::create({64, 64}).value();
sf::Texture texture(sf::Vector2u(64, 64));
CHECK(!texture.isRepeated());
texture.setRepeated(true);
CHECK(texture.isRepeated());
@ -376,7 +379,7 @@ TEST_CASE("[Graphics] sf::Texture", runDisplayTests())
SECTION("generateMipmap()")
{
sf::Texture texture = sf::Texture::create({100, 100}).value();
sf::Texture texture(sf::Vector2u(100, 100));
CHECK(texture.generateMipmap());
}
@ -385,12 +388,12 @@ 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};
auto texture1 = sf::Texture::create(sf::Vector2u(1, 1), true).value();
sf::Texture texture1(sf::Vector2u(1, 1), true);
texture1.update(blue);
texture1.setSmooth(false);
texture1.setRepeated(true);
auto texture2 = sf::Texture::create(sf::Vector2u(2, 1), false).value();
sf::Texture texture2(sf::Vector2u(2, 1), false);
texture2.update(green);
texture2.setSmooth(true);
texture2.setRepeated(false);

View File

@ -72,24 +72,38 @@ TEST_CASE("[System] sf::FileInputStream")
STATIC_CHECK(std::is_nothrow_move_assignable_v<sf::FileInputStream>);
}
SECTION("Default constructor")
{
sf::FileInputStream fileInputStream;
CHECK(fileInputStream.read(nullptr, 0) == std::nullopt);
CHECK(fileInputStream.seek(0) == std::nullopt);
CHECK(fileInputStream.tell() == std::nullopt);
CHECK(fileInputStream.getSize() == std::nullopt);
}
const TemporaryFile temporaryFile("Hello world");
char buffer[32];
SECTION("Construction")
{
SECTION("Default constructor")
{
sf::FileInputStream fileInputStream;
CHECK(fileInputStream.read(nullptr, 0) == std::nullopt);
CHECK(fileInputStream.seek(0) == std::nullopt);
CHECK(fileInputStream.tell() == std::nullopt);
CHECK(fileInputStream.getSize() == std::nullopt);
}
SECTION("File path constructor")
{
sf::FileInputStream fileInputStream(temporaryFile.getPath());
CHECK(fileInputStream.read(buffer, 5) == 5);
CHECK(fileInputStream.tell() == 5);
CHECK(fileInputStream.getSize() == 11);
CHECK(std::string_view(buffer, 5) == "Hello"sv);
CHECK(fileInputStream.seek(6) == 6);
CHECK(fileInputStream.tell() == 6);
}
}
SECTION("Move semantics")
{
SECTION("Move constructor")
{
auto movedFileInputStream = sf::FileInputStream::create(temporaryFile.getPath()).value();
sf::FileInputStream fileInputStream = std::move(movedFileInputStream);
sf::FileInputStream movedFileInputStream(temporaryFile.getPath());
sf::FileInputStream fileInputStream = std::move(movedFileInputStream);
CHECK(fileInputStream.read(buffer, 6) == 6);
CHECK(fileInputStream.tell() == 6);
CHECK(fileInputStream.getSize() == 11);
@ -98,10 +112,10 @@ TEST_CASE("[System] sf::FileInputStream")
SECTION("Move assignment")
{
auto movedFileInputStream = sf::FileInputStream::create(temporaryFile.getPath()).value();
sf::FileInputStream movedFileInputStream(temporaryFile.getPath());
const TemporaryFile temporaryFile2("Hello world the sequel");
auto fileInputStream = sf::FileInputStream::create(temporaryFile2.getPath()).value();
fileInputStream = std::move(movedFileInputStream);
sf::FileInputStream fileInputStream(temporaryFile2.getPath());
fileInputStream = std::move(movedFileInputStream);
CHECK(fileInputStream.read(buffer, 6) == 6);
CHECK(fileInputStream.tell() == 6);
CHECK(fileInputStream.getSize() == 11);
@ -123,7 +137,7 @@ TEST_CASE("[System] sf::FileInputStream")
SECTION("Temporary file stream create")
{
auto fileInputStream = sf::FileInputStream::create(temporaryFile.getPath()).value();
sf::FileInputStream fileInputStream(temporaryFile.getPath());
CHECK(fileInputStream.read(buffer, 5) == 5);
CHECK(fileInputStream.tell() == 5);
CHECK(fileInputStream.getSize() == 11);

View File

@ -18,8 +18,17 @@ TEST_CASE("[System] sf::MemoryInputStream")
using namespace std::literals::string_view_literals;
SECTION("open()")
SECTION("Construction")
{
SECTION("Null data")
{
sf::MemoryInputStream memoryInputStream(nullptr, 0);
CHECK(memoryInputStream.read(nullptr, 0) == std::nullopt);
CHECK(memoryInputStream.seek(0) == std::nullopt);
CHECK(memoryInputStream.tell() == std::nullopt);
CHECK(memoryInputStream.getSize() == std::nullopt);
}
static constexpr auto input = "hello world"sv;
SECTION("Zero length")

View File

@ -17,6 +17,37 @@ TEST_CASE("[Window] sf::Cursor", runDisplayTests())
STATIC_CHECK(std::is_nothrow_move_assignable_v<sf::Cursor>);
}
SECTION("Constructor")
{
SECTION("Pixels")
{
static constexpr std::array<std::uint8_t, 4> pixels{};
CHECK_THROWS_AS(sf::Cursor(nullptr, {}, {}), std::runtime_error);
CHECK_THROWS_AS(sf::Cursor(pixels.data(), {0, 1}, {}), std::runtime_error);
CHECK_THROWS_AS(sf::Cursor(pixels.data(), {1, 0}, {}), std::runtime_error);
CHECK_NOTHROW(sf::Cursor(pixels.data(), {1, 1}, {}));
}
SECTION("System")
{
CHECK_NOTHROW(sf::Cursor(sf::Cursor::Type::Hand));
CHECK_NOTHROW(sf::Cursor(sf::Cursor::Type::SizeHorizontal));
CHECK_NOTHROW(sf::Cursor(sf::Cursor::Type::SizeVertical));
CHECK_NOTHROW(sf::Cursor(sf::Cursor::Type::SizeLeft));
CHECK_NOTHROW(sf::Cursor(sf::Cursor::Type::SizeRight));
CHECK_NOTHROW(sf::Cursor(sf::Cursor::Type::SizeTop));
CHECK_NOTHROW(sf::Cursor(sf::Cursor::Type::SizeBottom));
CHECK_NOTHROW(sf::Cursor(sf::Cursor::Type::SizeTopLeft));
CHECK_NOTHROW(sf::Cursor(sf::Cursor::Type::SizeTopRight));
CHECK_NOTHROW(sf::Cursor(sf::Cursor::Type::SizeBottomLeft));
CHECK_NOTHROW(sf::Cursor(sf::Cursor::Type::SizeBottomRight));
CHECK_NOTHROW(sf::Cursor(sf::Cursor::Type::Cross));
CHECK_NOTHROW(sf::Cursor(sf::Cursor::Type::Help));
CHECK_NOTHROW(sf::Cursor(sf::Cursor::Type::NotAllowed));
}
}
SECTION("loadFromPixels()")
{
static constexpr std::array<std::uint8_t, 4> pixels{};

View File

@ -26,16 +26,16 @@ int main()
sf::RenderWindow window(sf::VideoMode({800, 600}), "SFML window");
// Set the Icon
const auto icon = sf::Image::loadFromFile(resourcePath() / "icon.png").value();
const sf::Image icon(resourcePath() / "icon.png");
window.setIcon(icon);
// Load a sprite to display
const auto texture = sf::Texture::loadFromFile(resourcePath() / "background.jpg").value();
sf::Sprite sprite(texture);
const sf::Texture texture(resourcePath() / "background.jpg");
sf::Sprite sprite(texture);
// Create a graphical text to display
const auto font = sf::Font::openFromFile(resourcePath() / "tuffy.ttf").value();
sf::Text text(font, "Hello SFML", 50);
const sf::Font font(resourcePath() / "tuffy.ttf");
sf::Text text(font, "Hello SFML", 50);
text.setFillColor(sf::Color::Black);
// Load a music to play

View File

@ -24,16 +24,16 @@ int main()
sf::RenderWindow window(sf::VideoMode({800, 600}), "SFML window");
// Set the Icon
const auto icon = sf::Image::loadFromFile("icon.png").value();
const sf::Image icon("icon.png");
window.setIcon(icon);
// Load a sprite to display
const auto texture = sf::Texture::loadFromFile("background.jpg").value();
sf::Sprite sprite(texture);
const sf::Texture texture("background.jpg");
sf::Sprite sprite(texture);
// Create a graphical text to display
const auto font = sf::Font::openFromFile("tuffy.ttf").value();
sf::Text text(font, "Hello SFML", 50);
const sf::Font font("tuffy.ttf");
sf::Text text(font, "Hello SFML", 50);
text.setFillColor(sf::Color::Black);
// Load a music to play