From 6a4962817434e859354091e7815ebee11798e7ba Mon Sep 17 00:00:00 2001 From: Hartmut Seichter Date: Sun, 25 May 2025 23:14:14 +0200 Subject: [PATCH] WIP to get new structure working --- CONTRIBUTORS.md | 4 +- examples/quickwings/quickwings.cpp | 112 ++++++++++++++++++++++++- src/lib/include/paradiso/bitmap_io.hpp | 19 ++++- src/lib/src/bitmap_io.cpp | 89 ++++++++++---------- 4 files changed, 173 insertions(+), 51 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index f5d7881..3149482 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -1,6 +1,6 @@ # Contributors - Hartmut Seichter (dev lead) -- Robin Rottstädt (image loader) +- Robin Rottstädt (Flappy Bird, image loader) - Tim Gösselmann (Win32 fixes) -- Hannes Brothuhn (Flappy Bird clone) +- Hannes Brothuhn (Flappy Bird fixes) diff --git a/examples/quickwings/quickwings.cpp b/examples/quickwings/quickwings.cpp index dd51112..8564040 100644 --- a/examples/quickwings/quickwings.cpp +++ b/examples/quickwings/quickwings.cpp @@ -5,6 +5,7 @@ * */ +#include #include #include #include @@ -16,8 +17,104 @@ #include #include +#include #include +#include +#include +#include #include +#include +#include +#include + +namespace QuickWings { + +using SpriteName = std::tuple; +using SpriteMap = std::unordered_map; + +struct App { + SpriteMap sprites; + + static auto create() -> App { + + paradiso::BitmapIO::get().set_asset_path( + paradiso::get_executable_path().parent_path() / "assets"); + + auto assets = std::array{ + SpriteName{"background.bg", "background-day.png"}, + SpriteName{"background.fg", "base.png"}, + }; + + SpriteMap load_map{}; + + for (const auto& [name, filename] : assets) { + std::print("{} : {}", name, filename); + + if (auto bm = paradiso::BitmapIO::get().load(filename); + bm.has_value()) { + load_map[name] = bm.value(); + std::print(" ok!\n"); + } else { + std::print(" error!\n"); + } + } + return {.sprites{load_map}}; + } + + void run() { + auto window = paradiso::Window(); + + paradiso::Size size {.width = 640, .height = 480}; + + window + .set_size(size) // ... Grösse + .set_position( + paradiso::Point{.x = 1920 / 2 - 500 / 2, + .y = 1080 / 2 - 700 / 2}) // ... Position + .set_title("PardiSO.Quickwings") // ... Titel + .set_visible(true); // ... und jetzt anzeigen! + + // der Fenster Kontext + auto ctx = paradiso::Context{}; + + // ein Shader (Schattierungsprogramm) + auto shader = paradiso::Shader{}; + + // wir nutzen einen vorgefertigten shader + shader.load_preset(paradiso::Shader::Preset::Sprite); + + // ein viewport stellt die Sicht der Kamera dar, d.h. bei quadratischen + // Pixeln sollte hier auch eine dementsprechende Grösse eingestellt + // werden + ctx.set_viewport( + paradiso::Rectangle{.position = paradiso::Point{.x = 0, .y = 0}, + .size = window.size()}); + + // nothing beats a classic look + ctx.set_clearcolor(paradiso::RGBA::from_rgb(0x00, 0x00, 0x00)); + + while ( + window.update([&](paradiso::Window& w) -> bool { + ctx.set_viewport(paradiso::Rectangle{ + .position = paradiso::Point{.x = 0, .y = 0}, + .size = size, + }); + + // Quit + return !(w.keyboard_input().size() && + w.keyboard_input().top().key == 'Q'); + }){}; + + } + + } // namespace QuickWings + + auto main() -> int { + auto app = QuickWings::App::create(); + app.run(); + } + +#if 0 // TODO remove all hard coded 'magic' values! @@ -31,7 +128,12 @@ float risky_pos_top_y; float risky_pos_bottom_max_y; float risky_pos_top_max_y; + + struct Background { + + SpriteMap sprites; + paradiso::Sprite backgroundLeft; paradiso::Sprite backgroundRight; paradiso::Sprite grassLeft; @@ -44,7 +146,9 @@ struct Background { // TODO no constructors in rule of zero Background() { auto backgroundImage = - paradiso::BitmapIO::get().load("background-day.png"); + paradiso::BitmapIO::get().load("background-day.png").has_value() + ? paradiso::BitmapIO::get().load("background-day.png").value() + : paradiso::Bitmap(); backgroundLeft = paradiso::Sprite{ .bitmap = backgroundImage, .pivot = {paradiso::Vector2::make(0.0f, 0.16f)}, @@ -459,7 +563,7 @@ auto main() -> int { .set_size(size) // ... Grösse .set_position(paradiso::Point{.x = 1920 / 2 - 500 / 2, .y = 1080 / 2 - 700 / 2}) // ... Position - .set_title("PardiSO.FlappyBird") // ... Titel + .set_title("PardiSO.Quickwings") // ... Titel .set_visible(true); // ... und jetzt anzeigen! // der Fenster Kontext @@ -482,7 +586,8 @@ auto main() -> int { // Asset loader bekommt den Pfad - paradiso::BitmapIO::get().set_path("assets"); + paradiso::BitmapIO::get().set_asset_path( + paradiso::get_executable_path().parent_path() / "assets"); // Load auto background = Background{}; @@ -544,3 +649,4 @@ auto main() -> int { return 0; } +#endif diff --git a/src/lib/include/paradiso/bitmap_io.hpp b/src/lib/include/paradiso/bitmap_io.hpp index 1700bc1..1dd77b9 100644 --- a/src/lib/include/paradiso/bitmap_io.hpp +++ b/src/lib/include/paradiso/bitmap_io.hpp @@ -23,8 +23,11 @@ #ifndef PARADISO_BITMAP_IO_HPP #define PARADISO_BITMAP_IO_HPP +#include #include +#include +#include #include #include @@ -32,13 +35,23 @@ namespace paradiso { struct BitmapIO { + enum struct LoadError { + FileNotFound, + FileCorrupted, + FileNotBitmap, + }; + + using LoadResult = std::expected; + using path = std::filesystem::path; + static BitmapIO& get(); - Bitmap load(std::string_view filename, bool ignore_cache = false) const; + auto load(std::string_view filename, bool ignore_cache = false) const + -> LoadResult; - void set_path(std::string_view path); + void set_asset_path(path path_); - std::string path() const; + path asset_path() const; private: struct Impl; diff --git a/src/lib/src/bitmap_io.cpp b/src/lib/src/bitmap_io.cpp index b279244..35510e3 100644 --- a/src/lib/src/bitmap_io.cpp +++ b/src/lib/src/bitmap_io.cpp @@ -26,15 +26,14 @@ #include "paradiso/bitmap_io.hpp" #include "paradiso/bitmap.hpp" +#include +#include #include // STB image loading #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" -#include -#include - namespace paradiso { struct BitmapIO::Impl { @@ -45,7 +44,7 @@ struct BitmapIO::Impl { BitmapCacheType cache_; - static Bitmap read(std::string_view filename) { + static BitmapIO::LoadResult _read_bitmap(const path& filepath) { // Load with stb_image stbi_set_flip_vertically_on_load(true); // flip y axis for OpenGL @@ -54,16 +53,16 @@ struct BitmapIO::Impl { auto stb_free = [](uint8_t* data) { stbi_image_free(data); }; - if (std::unique_ptr image{ - stbi_load(filename.data(), &width, &height, &channels, 0)}; + if (std::unique_ptr image{stbi_load( + filepath.string().c_str(), &width, &height, &channels, 0)}; image.get()) { - int size = width * height; + const auto area = width * height; // Convert to Vector of RGBA std::vector rgba = - std::vector(size); - for (int i = 0; i < size; i++) { + std::vector(area); + for (int i = 0; i < area; i++) { // get rgba values int pos = i * 4; int r = image.get()[pos + 0]; @@ -72,47 +71,50 @@ struct BitmapIO::Impl { int a = image.get()[pos + 3]; // bug in from_rgba. it expects bgra, not rgba - auto val = paradiso::RGBA::from_rgba(b, g, r, a); - rgba[i] = val; + // auto val = paradiso::RGBA::from_rgba(b, g, r, a); + rgba[i] = paradiso::RGBA::from_rgba(r, g, b, a); } - - // rotate image by 90 degrees CW - std::vector rotated = - std::vector(size); - for (int x = 0; x < width; x++) { - for (int y = 0; y < height; y++) { - - int pos = y * width + x; - int pos_rotated = x * height + (height - y - 1); - rotated[pos_rotated] = rgba[pos]; - } - } - return paradiso::Bitmap::from_data( paradiso::Size{static_cast(height), static_cast(width)}, - rotated); + rgba); + + // rotate image by 90 degrees CW + // std::vector rotated = + // std::vector(size); + // for (int x = 0; x < width; x++) { + // for (int y = 0; y < height; y++) { + + // int pos = y * width + x; + // int pos_rotated = x * height + (height - y - 1); + // rotated[pos_rotated] = rgba[pos]; + // } + // } + + // return paradiso::Bitmap::from_data( + // paradiso::Size{static_cast(height), + // static_cast(width)}, + // rotated); } else { - std::cerr << "cannot load " << filename << '\n'; + return std::unexpected(BitmapIO::LoadError::FileNotFound); } return Bitmap(); // well, no exception ... } - Bitmap load(std::string_view filename) { - if (cache_.find(filename) == cache_.end()) { + auto load(std::string_view filename, bool ignore_cache) -> LoadResult { + // check cache first + if (cache_.find(filename) != cache_.end() && !ignore_cache) { + return cache_[filename.data()]; + } // construct file path + auto asset_filepath = asset_path_ / std::filesystem::path(filename); - auto asset_filepath = asset_path_ / std::filesystem::path(filename); + auto data = _read_bitmap(asset_filepath); - std::cout << "Loading " << asset_filepath << std::endl; - - // moving to C++23 this should be replaced with - // std::expected - auto data = read(asset_filepath.generic_string()); - - cache_[filename] = data; + if (data.has_value()) { + cache_[filename.data()] = *data; } - return cache_[filename.data()]; + return data; } }; @@ -123,14 +125,15 @@ BitmapIO& BitmapIO::get() { return instance; } -Bitmap BitmapIO::load(std::string_view filename, bool ignore_cache) const { - return impl_->load(filename); +auto BitmapIO::load(std::string_view filename, bool ignore_cache) const + -> BitmapIO::LoadResult { + return impl_->load(filename, ignore_cache); } -void BitmapIO::set_path(std::string_view path) { impl_->asset_path_ = path; } - -std::string BitmapIO::path() const { - return impl_->asset_path_.generic_string(); +void BitmapIO::set_asset_path(BitmapIO::path path_) { + impl_->asset_path_ = path_; } +BitmapIO::path BitmapIO::asset_path() const { return impl_->asset_path_; } + } // namespace paradiso