Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gfx/sfml: Implement pixel-drawing #727

Merged
merged 3 commits into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion gfx/canvas_command_saver.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,22 @@ struct DrawTextCmd {
[[nodiscard]] bool operator==(DrawTextCmd const &) const = default;
};

struct DrawPixelsCmd {
geom::Rect rect{};
std::vector<std::uint8_t> rgba_data{};

[[nodiscard]] bool operator==(DrawPixelsCmd const &) const = default;
};

using CanvasCommand = std::variant<SetViewportSizeCmd,
SetScaleCmd,
AddTranslationCmd,
ClearCmd,
FillRectCmd,
DrawRectCmd,
DrawTextWithFontOptionsCmd,
DrawTextCmd>;
DrawTextCmd,
DrawPixelsCmd>;

class CanvasCommandSaver : public ICanvas {
public:
Expand Down Expand Up @@ -124,6 +132,10 @@ class CanvasCommandSaver : public ICanvas {
cmds_.emplace_back(DrawTextCmd{position, std::string{text}, std::string{font.font}, size.px, style, color});
}

void draw_pixels(geom::Rect const &rect, std::span<std::uint8_t const> rgba_data) override {
cmds_.emplace_back(DrawPixelsCmd{rect, {rgba_data.begin(), rgba_data.end()}});
}

//
[[nodiscard]] std::vector<CanvasCommand> take_commands() { return std::exchange(cmds_, {}); }

Expand Down Expand Up @@ -156,6 +168,8 @@ class CanvasCommandVisitor {
canvas_.draw_text(cmd.position, cmd.text, {cmd.font}, {cmd.size}, cmd.style, cmd.color);
}

void operator()(DrawPixelsCmd const &cmd) { canvas_.draw_pixels(cmd.rect, cmd.rgba_data); }

private:
ICanvas &canvas_;
};
Expand Down
7 changes: 7 additions & 0 deletions gfx/canvas_command_saver_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ int main() {
{1, 2}, "hello!"s, {{"comic sans"}}, 11, FontStyle::Normal, {1, 2, 3}}});
});

etest::test("CanvasCommandSaver::draw_pixels", [] {
CanvasCommandSaver saver;
saver.draw_pixels({1, 2, 3, 4}, {{0x12, 0x34, 0x56, 0x78}});
expect_eq(saver.take_commands(), CanvasCommands{DrawPixelsCmd{{1, 2, 3, 4}, {0x12, 0x34, 0x56, 0x78}}});
});

etest::test("replay_commands", [] {
CanvasCommandSaver saver;
saver.clear(gfx::Color{});
Expand All @@ -110,6 +116,7 @@ int main() {
saver.draw_text({10, 10}, "beep beep boop!"sv, {"helvetica"}, {42}, FontStyle::Italic, {3, 2, 1});
saver.draw_text({1, 5}, "hello?"sv, {{{"font1"}, {"font2"}}}, {42}, FontStyle::Normal, {1, 2, 3});
saver.clear(gfx::Color{1, 2, 3});
saver.draw_pixels({1, 2, 3, 4}, {{0x12, 0x34, 0x56, 0x78}});
auto cmds = saver.take_commands();

CanvasCommandSaver replayed;
Expand Down
4 changes: 4 additions & 0 deletions gfx/gfx_example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Window/Event.hpp>

#include <array>
#include <memory>
#include <string_view>

Expand Down Expand Up @@ -78,6 +79,9 @@ int main(int argc, char **argv) {
gfx::FontStyle::Italic | gfx::FontStyle::Bold | gfx::FontStyle::Underlined
| gfx::FontStyle::Strikethrough,
kHotPink);
auto px = std::to_array<std::uint8_t>(
{100, 100, 100, 0xff, 200, 200, 200, 0xff, 50, 50, 50, 0xff, 200, 0, 0, 0xff});
canvas->draw_pixels({1, 1, 2, 2}, px);

window.display();
}
Expand Down
1 change: 1 addition & 0 deletions gfx/icanvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class ICanvas {
virtual void draw_rect(geom::Rect const &, Color const &, Borders const &, Corners const &) = 0;
virtual void draw_text(geom::Position, std::string_view, std::span<Font const>, FontSize, FontStyle, Color) = 0;
virtual void draw_text(geom::Position, std::string_view, Font, FontSize, FontStyle, Color) = 0;
virtual void draw_pixels(geom::Rect const &, std::span<std::uint8_t const> rgba_data) = 0;
};

} // namespace gfx
Expand Down
1 change: 1 addition & 0 deletions gfx/opengl_canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class OpenGLCanvas final : public ICanvas {
void draw_rect(geom::Rect const &, Color const &, Borders const &, Corners const &) override;
void draw_text(geom::Position, std::string_view, std::span<Font const>, FontSize, FontStyle, Color) override {}
void draw_text(geom::Position, std::string_view, Font, FontSize, FontStyle, Color) override {}
void draw_pixels(geom::Rect const &, std::span<std::uint8_t const>) override {}

private:
OpenGLShader border_shader_;
Expand Down
19 changes: 19 additions & 0 deletions gfx/sfml_canvas.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@

#include <SFML/Graphics/RectangleShape.hpp>
#include <SFML/Graphics/RenderTarget.hpp>
#include <SFML/Graphics/Sprite.hpp>
#include <SFML/Graphics/Text.hpp>
#include <SFML/Graphics/View.hpp>
#include <spdlog/spdlog.h>

#include <algorithm>
#include <cassert>
#include <filesystem>
#include <optional>
#include <string>
Expand Down Expand Up @@ -114,6 +116,7 @@ void SfmlCanvas::set_viewport_size(int width, int height) {

void SfmlCanvas::clear(Color c) {
target_.clear(sf::Color(c.as_rgba_u32()));
textures_.clear();
}

void SfmlCanvas::fill_rect(geom::Rect const &rect, Color color) {
Expand Down Expand Up @@ -238,4 +241,20 @@ void SfmlCanvas::draw_text(
target_.draw(drawable);
}

void SfmlCanvas::draw_pixels(geom::Rect const &rect, std::span<std::uint8_t const> rgba_data) {
assert(rgba_data.size() == static_cast<std::size_t>(rect.width * rect.height * 4));
sf::Image img;
// Textures need to be kept around while they're displayed. This will be
// cleared when the canvas is cleared.
sf::Texture &texture = textures_.emplace_back();
texture.create(static_cast<unsigned>(rect.width), static_cast<unsigned>(rect.height));
texture.update(rgba_data.data());
sf::Sprite sprite{texture};
sprite.setPosition(static_cast<float>(rect.x), static_cast<float>(rect.y));
target_.draw(sprite);
sf::RectangleShape shape{{static_cast<float>(rect.width), static_cast<float>(rect.height)}};
shape.setTexture(&texture);
target_.draw(shape);
}

} // namespace gfx
4 changes: 4 additions & 0 deletions gfx/sfml_canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
#include "gfx/icanvas.h"

#include <SFML/Graphics/Shader.hpp>
#include <SFML/Graphics/Texture.hpp>

#include <map>
#include <memory>
#include <vector>

namespace sf {
class Font;
Expand All @@ -36,11 +38,13 @@ class SfmlCanvas : public ICanvas {
void draw_rect(geom::Rect const &, Color const &, Borders const &, Corners const &) override;
void draw_text(geom::Position, std::string_view, std::span<Font const>, FontSize, FontStyle, Color) override;
void draw_text(geom::Position, std::string_view, Font, FontSize, FontStyle, Color) override;
void draw_pixels(geom::Rect const &, std::span<std::uint8_t const> rgba_data) override;

private:
sf::RenderTarget &target_;
sf::Shader border_shader_{};
std::map<std::string, std::shared_ptr<sf::Font>, std::less<>> font_cache_;
std::vector<sf::Texture> textures_;

int scale_{1};
int tx_{0};
Expand Down
1 change: 1 addition & 0 deletions img/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ cc_binary(
":gif",
":png",
":qoi",
"//gfx:sfml",
"@sfml//:graphics",
"@sfml//:window",
],
Expand Down
19 changes: 6 additions & 13 deletions img/img_example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@
#include "img/png.h"
#include "img/qoi.h"

#include <SFML/Graphics/Image.hpp>
#include "gfx/sfml_canvas.h"

#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Graphics/Sprite.hpp>
#include <SFML/Graphics/Texture.hpp>
#include <SFML/Window/Event.hpp>

#include <algorithm>
Expand Down Expand Up @@ -110,12 +109,7 @@ int main(int argc, char **argv) {
window.setVerticalSyncEnabled(true);
window.setActive(true);

sf::Image sf_image{};
sf_image.create(width, height, bytes.data());
sf::Texture texture{};
texture.loadFromImage(sf_image);
sf::Sprite sprite{};
sprite.setTexture(texture);
gfx::SfmlCanvas canvas{window};

bool running = true;
while (running) {
Expand All @@ -126,16 +120,15 @@ int main(int argc, char **argv) {
running = false;
break;
case sf::Event::Resized:
window.setView(sf::View{sf::FloatRect{
0, 0, static_cast<float>(event.size.width), static_cast<float>(event.size.height)}});
canvas.set_viewport_size(event.size.width, event.size.height);
break;
default:
break;
}
}

window.clear();
window.draw(sprite);
canvas.clear(gfx::Color{});
canvas.draw_pixels({0, 0, static_cast<int>(width), static_cast<int>(height)}, bytes);
window.display();
}
}