WIP to get new structure working

This commit is contained in:
Hartmut Seichter 2025-05-25 23:14:14 +02:00
parent 42a0d56173
commit 6a49628174
4 changed files with 173 additions and 51 deletions

View file

@ -1,6 +1,6 @@
# Contributors # Contributors
- Hartmut Seichter (dev lead) - Hartmut Seichter (dev lead)
- Robin Rottstädt (image loader) - Robin Rottstädt (Flappy Bird, image loader)
- Tim Gösselmann (Win32 fixes) - Tim Gösselmann (Win32 fixes)
- Hannes Brothuhn (Flappy Bird clone) - Hannes Brothuhn (Flappy Bird fixes)

View file

@ -5,6 +5,7 @@
* *
*/ */
#include <filesystem>
#include <paradiso/bitmap.hpp> #include <paradiso/bitmap.hpp>
#include <paradiso/bitmap_io.hpp> #include <paradiso/bitmap_io.hpp>
#include <paradiso/context.hpp> #include <paradiso/context.hpp>
@ -16,8 +17,104 @@
#include <paradiso/vector.hpp> #include <paradiso/vector.hpp>
#include <paradiso/window.hpp> #include <paradiso/window.hpp>
#include <array>
#include <chrono> #include <chrono>
#include <flat_map>
#include <print>
#include <string_view>
#include <thread> #include <thread>
#include <tuple>
#include <unordered_map>
#include <vector>
namespace QuickWings {
using SpriteName = std::tuple<std::string_view, std::string_view>;
using SpriteMap = std::unordered_map<std::string_view, paradiso::Bitmap>;
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! // 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_bottom_max_y;
float risky_pos_top_max_y; float risky_pos_top_max_y;
struct Background { struct Background {
SpriteMap sprites;
paradiso::Sprite backgroundLeft; paradiso::Sprite backgroundLeft;
paradiso::Sprite backgroundRight; paradiso::Sprite backgroundRight;
paradiso::Sprite grassLeft; paradiso::Sprite grassLeft;
@ -44,7 +146,9 @@ struct Background {
// TODO no constructors in rule of zero // TODO no constructors in rule of zero
Background() { Background() {
auto backgroundImage = 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{ backgroundLeft = paradiso::Sprite{
.bitmap = backgroundImage, .bitmap = backgroundImage,
.pivot = {paradiso::Vector2<float>::make(0.0f, 0.16f)}, .pivot = {paradiso::Vector2<float>::make(0.0f, 0.16f)},
@ -459,7 +563,7 @@ auto main() -> int {
.set_size(size) // ... Grösse .set_size(size) // ... Grösse
.set_position(paradiso::Point{.x = 1920 / 2 - 500 / 2, .set_position(paradiso::Point{.x = 1920 / 2 - 500 / 2,
.y = 1080 / 2 - 700 / 2}) // ... Position .y = 1080 / 2 - 700 / 2}) // ... Position
.set_title("PardiSO.FlappyBird") // ... Titel .set_title("PardiSO.Quickwings") // ... Titel
.set_visible(true); // ... und jetzt anzeigen! .set_visible(true); // ... und jetzt anzeigen!
// der Fenster Kontext // der Fenster Kontext
@ -482,7 +586,8 @@ auto main() -> int {
// Asset loader bekommt den Pfad // 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 // Load
auto background = Background{}; auto background = Background{};
@ -544,3 +649,4 @@ auto main() -> int {
return 0; return 0;
} }
#endif

View file

@ -23,8 +23,11 @@
#ifndef PARADISO_BITMAP_IO_HPP #ifndef PARADISO_BITMAP_IO_HPP
#define PARADISO_BITMAP_IO_HPP #define PARADISO_BITMAP_IO_HPP
#include <filesystem>
#include <paradiso/bitmap.hpp> #include <paradiso/bitmap.hpp>
#include <paradiso/utils.hpp>
#include <expected>
#include <memory> #include <memory>
#include <string_view> #include <string_view>
@ -32,13 +35,23 @@ namespace paradiso {
struct BitmapIO { struct BitmapIO {
enum struct LoadError {
FileNotFound,
FileCorrupted,
FileNotBitmap,
};
using LoadResult = std::expected<Bitmap, LoadError>;
using path = std::filesystem::path;
static BitmapIO& get(); 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: private:
struct Impl; struct Impl;

View file

@ -26,15 +26,14 @@
#include "paradiso/bitmap_io.hpp" #include "paradiso/bitmap_io.hpp"
#include "paradiso/bitmap.hpp" #include "paradiso/bitmap.hpp"
#include <filesystem>
#include <string>
#include <unordered_map> #include <unordered_map>
// STB image loading // STB image loading
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h" #include "stb_image.h"
#include <filesystem>
#include <iostream>
namespace paradiso { namespace paradiso {
struct BitmapIO::Impl { struct BitmapIO::Impl {
@ -45,7 +44,7 @@ struct BitmapIO::Impl {
BitmapCacheType cache_; BitmapCacheType cache_;
static Bitmap read(std::string_view filename) { static BitmapIO::LoadResult _read_bitmap(const path& filepath) {
// Load with stb_image // Load with stb_image
stbi_set_flip_vertically_on_load(true); // flip y axis for OpenGL 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); }; auto stb_free = [](uint8_t* data) { stbi_image_free(data); };
if (std::unique_ptr<uint8_t, decltype(stb_free)> image{ if (std::unique_ptr<uint8_t, decltype(stb_free)> image{stbi_load(
stbi_load(filename.data(), &width, &height, &channels, 0)}; filepath.string().c_str(), &width, &height, &channels, 0)};
image.get()) { image.get()) {
int size = width * height; const auto area = width * height;
// Convert to Vector of RGBA // Convert to Vector of RGBA
std::vector<paradiso::RGBA> rgba = std::vector<paradiso::RGBA> rgba =
std::vector<paradiso::RGBA>(size); std::vector<paradiso::RGBA>(area);
for (int i = 0; i < size; i++) { for (int i = 0; i < area; i++) {
// get rgba values // get rgba values
int pos = i * 4; int pos = i * 4;
int r = image.get()[pos + 0]; int r = image.get()[pos + 0];
@ -72,47 +71,50 @@ struct BitmapIO::Impl {
int a = image.get()[pos + 3]; int a = image.get()[pos + 3];
// bug in from_rgba. it expects bgra, not rgba // bug in from_rgba. it expects bgra, not rgba
auto val = paradiso::RGBA::from_rgba(b, g, r, a); // auto val = paradiso::RGBA::from_rgba(b, g, r, a);
rgba[i] = val; rgba[i] = paradiso::RGBA::from_rgba(r, g, b, a);
} }
// rotate image by 90 degrees CW
std::vector<paradiso::RGBA> rotated =
std::vector<paradiso::RGBA>(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( return paradiso::Bitmap::from_data(
paradiso::Size{static_cast<unsigned int>(height), paradiso::Size{static_cast<unsigned int>(height),
static_cast<unsigned int>(width)}, static_cast<unsigned int>(width)},
rotated); rgba);
// rotate image by 90 degrees CW
// std::vector<paradiso::RGBA> rotated =
// std::vector<paradiso::RGBA>(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<unsigned int>(height),
// static_cast<unsigned int>(width)},
// rotated);
} else { } else {
std::cerr << "cannot load " << filename << '\n'; return std::unexpected(BitmapIO::LoadError::FileNotFound);
} }
return Bitmap(); // well, no exception ... return Bitmap(); // well, no exception ...
} }
Bitmap load(std::string_view filename) { auto load(std::string_view filename, bool ignore_cache) -> LoadResult {
if (cache_.find(filename) == cache_.end()) { // 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; if (data.has_value()) {
cache_[filename.data()] = *data;
// moving to C++23 this should be replaced with
// std::expected
auto data = read(asset_filepath.generic_string());
cache_[filename] = data;
} }
return cache_[filename.data()]; return data;
} }
}; };
@ -123,14 +125,15 @@ BitmapIO& BitmapIO::get() {
return instance; return instance;
} }
Bitmap BitmapIO::load(std::string_view filename, bool ignore_cache) const { auto BitmapIO::load(std::string_view filename, bool ignore_cache) const
return impl_->load(filename); -> BitmapIO::LoadResult {
return impl_->load(filename, ignore_cache);
} }
void BitmapIO::set_path(std::string_view path) { impl_->asset_path_ = path; } void BitmapIO::set_asset_path(BitmapIO::path path_) {
impl_->asset_path_ = path_;
std::string BitmapIO::path() const {
return impl_->asset_path_.generic_string();
} }
BitmapIO::path BitmapIO::asset_path() const { return impl_->asset_path_; }
} // namespace paradiso } // namespace paradiso