diff --git a/README.de.md b/README.de.md index de42551..274cee6 100644 --- a/README.de.md +++ b/README.de.md @@ -1,28 +1,41 @@ -# ParadisSO - eine minimale 2D-Grafikengine +# ParadiSO - eine minimale 2D-Grafikengine -**ParadiSO** wurde als stark abgespeckte 2D-Version meiner `pixwerx`-Engine konzipiert. *ParadiSO* verfolgt einen minimalistischen Ansatz für 2D-Grafik zu Bildungszwecken. Es verwendet modernes C++ und ein datengetriebenes Design, jedoch keine ECS (Entity Component System). +**ParadiSO** wurde als stark abgespeckte 2D-Version meiner `pixwerx`-Engine konzipiert. _ParadiSO_ verfolgt einen minimalistischen Ansatz für 2D-Grafik zu Bildungszwecken. Es verwendet modernes C++ und ein datengetriebenes Design, jedoch keine ECS (Entity Component System). ## Bildungszwecke -Einige Argumente für seinen Bildungsaspekt: +Einige Argumente für seinen Bildungsaspekt: -- Kombination verschiedener Konzepte und Paradigmen zur Erstellung ausdrucksstarker, aber knappen Codes -- Stark von Rust-Code inspiriert -- Für den mathematischen Code wird eine sofortige Auswertung verwendet (keine Expression-Templates), jedoch mit der Verwendung von `constexpr`, um eventuelle Performance-Overheads auszugleichen und optimale Vektorisierung zu erreichen. -- Versteckt alte `C`-APIs hinter einer modernisierten Fassade -- Es lehnt sich stark an die STL und ihre Algorithmen an +- Kombination verschiedener Konzepte und Paradigmen zur Erstellung ausdrucksstarker, aber knappen Codes +- Stark von Rust-Code inspiriert +- Für den mathematischen Code wird eine sofortige Auswertung verwendet (keine Expression-Templates), jedoch mit der Verwendung von `constexpr`, um eventuelle Performance-Overheads auszugleichen und optimale Vektorisierung zu erreichen. +- Versteckt alte `C`-APIs hinter einer modernisierten Fassade +- Es lehnt sich stark an die STL und ihre Algorithmen an ## Minimalistisch -Da diese Engine einige Muster und Designkonzepte zeigen soll, versucht sie, unnötigen Ballast zu vermeiden. +Da diese Engine einige Muster und Designkonzepte zeigen soll, versucht sie, unnötigen Ballast zu vermeiden. -## Abhängigkeiten +## Abhängigkeiten -ParadiSO wird mit den notwendigen Komponenten geliefert. Diese sollte jedoch hier erwähnt werden: +ParadiSO wird mit den notwendigen Komponenten geliefert. Diese sollte jedoch hier erwähnt werden: -- [GLFW 3.3.8](https://github.com/glfw/glfw) -- [GLAD](https://github.com/Dav1dde/glad) +- [GLFW 3.3.8](https://github.com/glfw/glfw) +- [GLAD](https://github.com/Dav1dde/glad) +- [STB image](https://github.com/nothings/stb) -## Zuarbeiten +## Toolchains -* [TimePlex](https://code.technotecture.net/Timeplex) \ No newline at end of file +ParadiSO kann auf verschiedenen Plattformen gebaut werden + +- Windows (Visual Studio Build Tools 2022) +- MacOS (clang 14 or later) +- Linux (clang 14 or later, gcc 13.2.1) + +Andere Kombinationen sind möglich aber nicht getestet. + +## Beiträge + +- [Tim Götzelmann](https://code.technotecture.net/Timeplex) Windows Build +- [Robin Rottstädt](https://code.technotecture.net/robin_rottstaedt) Flappy Bird Clone, Bitmap Loader +- [brxxh](https://code.technotecture.net/brxxh) Flappy Bird Clone diff --git a/README.md b/README.md index 2117b39..07828bc 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,41 @@ -# ParadisSO - a minimal 2D graphics engine +# ParadiSO - a minimal 2D graphics engine -**ParadiSO** was conceived as a heavily stripped down 2D version of my `pixwerx` engine. *ParadiSO* mimics a minimalistic approach to 2D graphics for educational purposes. It uses modern C++ and a data-driven design, but no ECS. +**ParadiSO** was conceived as a heavily stripped down 2D version of my `pixwerx` engine. _ParadiSO_ mimics a minimalistic approach to 2D graphics for educational purposes. It uses modern C++ and a data-driven design, but no ECS. ## Educational Some arguments for its educational side: -* mix and match of various concepts and paradigms to write expressive but concise code -* heavily inspired by Rust code -* math code is eager evaluation but `constexpr` to compensate overheads -* hides old-style `C` APIs behind a renovated facade -* it leans heavily on the STL and its algorithms +- mix and match of various concepts and paradigms to write expressive but concise code +- heavily inspired by Rust code +- math code is eager evaluation but `constexpr` to compensate overheads +- hides old-style `C` APIs behind a renovated facade +- it leans heavily on the STL and its algorithms ## Minimal -Because this engine should show some patterns and design concepts it tries to avoid adding unnecessary bloat. +Because this engine should show some patterns and design concepts it tries to avoid adding unnecessary bloat. ## Dependencies ParadiSO comes with batteries included. However, it should be mentioned here: -* [GLFW 3.3.8](https://github.com/glfw/glfw) -* [GLAD](https://github.com/Dav1dde/glad) +- [GLFW 3.3.8](https://github.com/glfw/glfw) +- [GLAD](https://github.com/Dav1dde/glad) +- [STB image](https://github.com/nothings/stb) + +## Toolchains + +ParadiSO is being developed to work on all major desktop systems. + +- Windows (Visual Studio Build Tools 2022) +- MacOS (clang 14 or later) +- Linux (clang 14 or later, gcc 13.2.1) + +Other combinations might work but are untested. ## Contributors -* [TimePlex](https://code.technotecture.net/Timeplex) \ No newline at end of file +- [Tim Götzelmann](https://code.technotecture.net/Timeplex) Windows Build +- [Robin Rottstädt](https://code.technotecture.net/robin_rottstaedt) Flappy Bird Clone, Bitmap Loader +- [brxxh](https://code.technotecture.net/brxxh) Flappy Bird Clone diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..64ecc08 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,50 @@ +# Todo + +Here some ideas for improving this tiny engine: + +## Rendering +- [ ] replace the OpenGL renderer with a Vulkan backend +- [ ] add animatable sprites (access to UV mapping and tiling) +- [ ] add a SDF based renderer (parametric tiles and font rendering) + +## Game Support +- [ ] audio! +- [ ] some minimal animation system with tweening with different f-curves + + +## System Level + +- [ ] add a `Asset` handler to load cache and manage assets +- [ ] introspection of file system if we load assset + +## Design + +- [ ] replace some of the 'unkown source' assets + +## Build / Dev Support +- [ ] add a test rig either with Snitch or Catch2 +- [ ] write some reasonable testcases +- [ ] add CPU and GPU benchmarks to address various issues + + +# Issues + + +```sh + Performance counter stats for 'bin/paradiso_pong': + + 555,35 msec task-clock:u # 0,042 CPUs utilized + 0 context-switches:u # 0,000 /sec + 0 cpu-migrations:u # 0,000 /sec + 4.072 page-faults:u # 7,332 K/sec + 319.484.735 cycles:u # 0,575 GHz + 358.165.995 instructions:u # 1,12 insn per cycle + 86.037.942 branches:u # 154,926 M/sec + 2.469.068 branch-misses:u # 2,87% of all branches + + 13,092775373 seconds time elapsed + + 0,311565000 seconds user + 0,247491000 seconds sys +``` +above run with `perf stat bin/paradiso_pong` shows some really bad performance issues. diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index f51da6f..9d4c49a 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,3 +1,3 @@ add_subdirectory(simple) add_subdirectory(pong) -add_subdirectory(flappy_bird) \ No newline at end of file +add_subdirectory(quickwings) \ No newline at end of file diff --git a/examples/flappy_bird/CMakeLists.txt b/examples/flappy_bird/CMakeLists.txt deleted file mode 100644 index 5a15e09..0000000 --- a/examples/flappy_bird/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -file(GLOB_RECURSE flappy_bird_src "*.cpp") -file(GLOB_RECURSE flappy_bird_lib "lib/*.hpp" "lib/*.h") -file(GLOB_RECURSE flappy_bird_assets "assets/*") - -add_executable(flappy_bird ${flappy_bird_src} ${flappy_bird_lib}) -target_link_libraries(flappy_bird paradiso_core) - -add_custom_command(TARGET flappy_bird POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory - ${CMAKE_CURRENT_SOURCE_DIR}/assets/ $/assets) - \ No newline at end of file diff --git a/examples/flappy_bird/assets/background-day.png b/examples/flappy_bird/assets/background-day.png deleted file mode 100644 index afcb5ec..0000000 Binary files a/examples/flappy_bird/assets/background-day.png and /dev/null differ diff --git a/examples/flappy_bird/assets/base.png b/examples/flappy_bird/assets/base.png deleted file mode 100644 index c374f2b..0000000 Binary files a/examples/flappy_bird/assets/base.png and /dev/null differ diff --git a/examples/flappy_bird/flappy_bird.cpp b/examples/flappy_bird/flappy_bird.cpp deleted file mode 100644 index 357bb5d..0000000 --- a/examples/flappy_bird/flappy_bird.cpp +++ /dev/null @@ -1,310 +0,0 @@ -/** - * paradiso - Paradigmen der Softwareentwicklung - * - * (c) Copyright 2023 Hartmut Seichter - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "lib/image_loader.hpp" - -const int frame_rate = 60; - -struct Background { - paradiso::Sprite backgroundLeft; - paradiso::Sprite backgroundRight; - paradiso::Sprite grassLeft; - paradiso::Sprite grassRight; - - paradiso::Sprite* scrolling[2] = {&backgroundLeft, &backgroundRight}; - - Background() { - auto backgroundImage = - image_loader::load(std::string("background-day.png")); - backgroundLeft = paradiso::Sprite{ - .bitmap = backgroundImage, - .pivot = paradiso::Vector2::make(0.0f, 0.0f), - .scale = paradiso::Vector2::make(1.01f, 1.0f)}; - backgroundRight = paradiso::Sprite{ - .bitmap = backgroundImage, - .pivot = paradiso::Vector2::make(2.0f, 0.0f), - .scale = paradiso::Vector2::make(1.01f, 1.0f)}; - - auto grassImage = image_loader::load(std::string("base.png")); - grassLeft = paradiso::Sprite{ - .bitmap = grassImage, - .pivot = paradiso::Vector2::make(0.0f, -1.0f), - .scale = paradiso::Vector2::make(1.0f, 0.33333f)}; - grassRight = paradiso::Sprite{ - .bitmap = grassImage, - .pivot = paradiso::Vector2::make(2.0f, -1.0f), - .scale = paradiso::Vector2::make(1.0f, 0.33333f)}; - } - - void draw(const paradiso::Shader& shader) { - for (auto sprite : scrolling) { - if (sprite->pivot.x() <= -2.0f) { - sprite->pivot.x() += 4.0f; - } - sprite->pivot.x() -= 0.001f; - shader.set_uniform("pivot", sprite->pivot); - shader.set_uniform("scale", sprite->scale); - shader.set_uniform("rotation", sprite->rotation); - renderer.draw(*sprite, shader); - } - } - - paradiso::Renderer renderer{}; -}; - -struct Grass { - paradiso::Sprite grassLeft; - paradiso::Sprite grassRight; - - paradiso::Sprite* scrolling[2] = {&grassLeft, &grassRight}; - - Grass() { - auto grassImage = image_loader::load(std::string("base.png")); - grassLeft = paradiso::Sprite{ - .bitmap = grassImage, - .pivot = paradiso::Vector2::make(0.0f, -0.9f), - .scale = paradiso::Vector2::make(1.0f, 0.33333f)}; - grassRight = paradiso::Sprite{ - .bitmap = grassImage, - .pivot = paradiso::Vector2::make(2.0f, -0.9f), - .scale = paradiso::Vector2::make(1.0f, 0.33333f)}; - } - - void draw(const paradiso::Shader& shader) { - for (auto sprite : scrolling) { - if (sprite->pivot.x() <= -2.0f) { - sprite->pivot.x() += 4.0f; - } - sprite->pivot.x() -= 0.035f; - shader.set_uniform("pivot", sprite->pivot); - shader.set_uniform("scale", sprite->scale); - shader.set_uniform("rotation", sprite->rotation); - renderer.draw(*sprite, shader); - } - } - - paradiso::Renderer renderer{}; -}; - -struct FlappyBird { - - paradiso::Renderer renderer1{}; - paradiso::Renderer renderer2{}; - paradiso::Renderer renderer3{}; - - std::array birds; - unsigned int flap = 0; - unsigned int flapSpeed = 15; // How many ticks per flap - unsigned int flapCounter = 0; // How many ticks since last flap - - float velocity = 0.0f; - const float max_velocity = 0.05f; - - const float gravity = -0.004f; - const float move_up_velocity = 0.0055f; - - bool move_up = false; - bool paused = true; - - const float max_pos = 0.95f; - const float min_pos = -0.5f; - - float pos = 0.0f; - - float rotation = 0.0f; - - FlappyBird() { - float scaleh = 0.07f; - float scalew = scaleh * 1.416666666666667f; - - birds = { - paradiso::Sprite{ - .bitmap = - image_loader::load(std::string("yellowbird-downflap.png")), - .pivot = paradiso::Vector2::make(0.0f, 0.0f), - .scale = paradiso::Vector2::make(scalew, scaleh)}, - paradiso::Sprite{ - .bitmap = - image_loader::load(std::string("yellowbird-midflap.png")), - .pivot = paradiso::Vector2::make(0.0f, 0.0f), - .scale = paradiso::Vector2::make(scalew, scaleh)}, - paradiso::Sprite{ - .bitmap = - image_loader::load(std::string("yellowbird-upflap.png")), - .pivot = paradiso::Vector2::make(0.0f, 0.0f), - .scale = paradiso::Vector2::make(scalew, scaleh)}}; - } - - void draw(const paradiso::Shader& shader) { - // Update flap state - if (flapCounter < flapSpeed) { - flapCounter++; - } else { - flapCounter = 0; - flap = (flap + 1) % birds.size(); - } - - auto bird = birds[flap]; - bird.pivot.y() = pos; - bird.rotation = rotation; - shader.set_uniform("pivot", bird.pivot); - shader.set_uniform("scale", bird.scale); - shader.set_uniform("rotation", bird.rotation); - - switch (flap) { - case 0: - renderer1.draw(bird, shader); - break; - case 1: - renderer2.draw(bird, shader); - break; - case 2: - renderer3.draw(bird, shader); - break; - } - } - - void update() { - // Stop game - if (paused) - return; - - // Apply gravity - velocity += gravity; - - if (move_up) - velocity += move_up_velocity - gravity; - - // Cap velocity - if (velocity > max_velocity) - velocity = max_velocity; - if (velocity < -max_velocity) - velocity = -max_velocity; - - // Cap position - pos += velocity; - if (pos < min_pos) { - pos = min_pos; - velocity = 0.0f; - } - if (pos > max_pos) { - pos = max_pos; - velocity = 0.0f; - } - - // Update rotation - rotation = velocity * 15.0f; - } - - // keyboard handler - void on_keyboard(const paradiso::Window::KeyboardInputStack& input) { - if (input.size()) { - paused = false; - bool pressed_up = input.top().key == ' ' || input.top().key == 'W'; - - if (input.top().action == 1 && pressed_up) { - move_up = true; - } else if (input.top().action == 0 && pressed_up) { - move_up = false; - } - } - } -}; - -auto main() -> int { - - // Ausgabefenster ... sieht aus als wäre es auf dem Stack - auto window = paradiso::Window(); - - auto size = paradiso::Size{.width = 500, .height = 700}; - - /* - window.set_resizecallback([](auto& w) -> void { - w.set_size(paradiso::Size{.width = 405, .height = 720}); - }); - -*/ - window - .set_size(size) // ... Grösse - .set_position(paradiso::Point{.x = 100, .y = 100}) // ... Position - .set_title("PardiSO.FlappyBird") // ... 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 = size}); - - // nothing beats a classic look - ctx.set_clearcolor(paradiso::RGBA::from_rgb(0x00, 0x00, 0x00)); - - // Load - auto background = Background{}; - auto grass = Grass{}; - - auto flappyBird = FlappyBird{}; - - // timer - - // das update führt den hier mitgegebnen Ausdruck innerhalb der internen - // Updates des Fensters auf. Es wird hier auch explizit ein bool gefordert - // damit das update auch zu jederzeit unterbrochen werden kann - while (window.update([&](paradiso::Window& w) -> bool { - ctx.set_viewport(paradiso::Rectangle{ - .position = paradiso::Point{.x = 0, .y = 0}, .size = size}); - - ctx.clear(); - auto t1 = std::chrono::high_resolution_clock::now(); - - // Keyboard and state change - flappyBird.on_keyboard(w.keyboard_input()); - flappyBird.update(); - - // Draw - background.draw(shader); - grass.draw(shader); - flappyBird.draw(shader); - - // wait for frame rate - auto t2 = std::chrono::high_resolution_clock::now(); - auto duration = - std::chrono::duration_cast(t2 - t1); - auto wait = std::chrono::microseconds(1000000 / frame_rate) - duration; - std::this_thread::sleep_for(wait); - - // Quit - return !(w.keyboard_input().size() && - w.keyboard_input().top().key == 'Q'); - })) { - }; - - return 0; -} diff --git a/examples/flappy_bird/image_loader.cpp b/examples/flappy_bird/image_loader.cpp deleted file mode 100644 index cbde797..0000000 --- a/examples/flappy_bird/image_loader.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include -#include - -#include -#include -#include -#include - -// STB image loading -#define STB_IMAGE_IMPLEMENTATION -#include "lib/stb_image.h" - -#include "lib/image_loader.hpp" - -std::unordered_map image_loader::image_cache = - std::unordered_map(); - -paradiso::Bitmap image_loader::load(const std::string& filename) { - if (image_cache.find(filename) == image_cache.end()) { - std::string path = ASSET_PATH + filename; - std::cout << "Loading " << path << std::endl; - auto data = readBMP(path); - image_cache[filename] = data; - } - return image_cache[filename]; -} - -paradiso::Bitmap image_loader::readBMP(std::string& filename) { - // Load with stb_image - stbi_set_flip_vertically_on_load(true); // flip y axis for OpenGL - int width, height, channels; - unsigned char* image = - stbi_load(filename.c_str(), &width, &height, &channels, 4); - int size = width * height; - - if (!image) - throw std::runtime_error("Error loading image"); - - // Convert to Vector of RGBA - std::vector rgba = std::vector(size); - for (int i = 0; i < size; i++) { - // get rgba values - int pos = i * 4; - int r = image[pos + 0]; - int g = image[pos + 1]; - int b = image[pos + 2]; - int a = image[pos + 3]; - - // bug in from_rgba. it expects bgra, not rgba - auto val = paradiso::RGBA::from_rgba(b, g, r, a); - rgba[i] = val; - } - - // 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]; - } - } - - // free image - stbi_image_free(image); - - return paradiso::Bitmap::from_data( - paradiso::Size{static_cast(height), - static_cast(width)}, - rotated); -} diff --git a/examples/flappy_bird/lib/image_loader.hpp b/examples/flappy_bird/lib/image_loader.hpp deleted file mode 100644 index 52e1847..0000000 --- a/examples/flappy_bird/lib/image_loader.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include - -#include -#include -#include - -class image_loader { - public: - /** - * @brief loads an Image from a file - * @param[in] filename path to file - * @return bitmap from file - */ - static paradiso::Bitmap load(const std::string& filename); - - private: - static inline const std::string ASSET_PATH = "assets/"; - - static std::unordered_map image_cache; - - static paradiso::Bitmap readBMP(std::string& filename); -}; \ No newline at end of file diff --git a/examples/pong/pong.cpp b/examples/pong/pong.cpp index 11f89f0..2b979f7 100644 --- a/examples/pong/pong.cpp +++ b/examples/pong/pong.cpp @@ -1,7 +1,7 @@ /** * paradiso - Paradigmen der Softwareentwicklung * - * (c) Copyright 2023 Hartmut Seichter + * (c) Copyright 2023-2024 Hartmut Seichter * */ @@ -16,7 +16,6 @@ #include -#include #include struct PongStage { @@ -86,7 +85,7 @@ struct PongPaddle { velocity_horizontal *= whoopiness; sprite.pivot.x() += velocity_horizontal; - std::clamp(sprite.pivot.x(), -0.5f, 0.5f); + sprite.pivot.x() = std::clamp(sprite.pivot.x(), -0.5f, 0.5f); // update shader uniforms shader.set_uniform("pivot", sprite.pivot); @@ -151,7 +150,7 @@ struct PongBall { void draw(const paradiso::Shader& shader) { - std::clamp(sprite.pivot.x(), -0.5f, 0.5f); + sprite.pivot.x() = std::clamp(sprite.pivot.x(), -0.5f, 0.5f); // update shader uniforms shader.set_uniform("pivot", sprite.pivot); @@ -166,6 +165,9 @@ struct PongBall { paradiso::Renderer renderer{}; constexpr void push(const auto& impulse) noexcept { velocity += impulse; } + + constexpr void whoop(const auto& whoopiness) noexcept { velocity *= whoopiness; } + }; auto main() -> int { @@ -234,6 +236,19 @@ auto main() -> int { ball.sprite.pivot.x() = 0.0f; ball.sprite.pivot.y() = 0.9f; } + // speed adjust + if (w.keyboard_input().top().key == 'N') { + + std::cout << "Speed Up!\n"; + + ball.push(paradiso::Vector2::make(0.f,0.01f)); + + } else if (w.keyboard_input().top().key == 'M') { + + ball.push(paradiso::Vector2::make(0.f,-0.01f)); + + std::cout << "Speed Lower!\n"; + } } ball.interact(stage); @@ -251,4 +266,4 @@ auto main() -> int { }; return 0; -} \ No newline at end of file +} diff --git a/examples/quickwings/CMakeLists.txt b/examples/quickwings/CMakeLists.txt new file mode 100644 index 0000000..0b5ffe2 --- /dev/null +++ b/examples/quickwings/CMakeLists.txt @@ -0,0 +1,20 @@ +set(quickwings_srcs quickwings.cpp) +set(quickwings_assets + assets/background-day.png + assets/base.png + assets/pipe-green.png + assets/yellowbird-downflap.png + assets/yellowbird-midflap.png + assets/yellowbird-upflap.png + ) + +set_source_files_properties(${quickwings_assets} PROPERTIES HEADER_FILE_ONLY TRUE) + +add_executable(quickwings ${quickwings_srcs} ${quickwings_assets}) + +target_link_libraries(quickwings paradiso_core) + +add_custom_command(TARGET quickwings POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_CURRENT_SOURCE_DIR}/assets/ $/assets) + \ No newline at end of file diff --git a/examples/quickwings/assets/background-day.png b/examples/quickwings/assets/background-day.png new file mode 100644 index 0000000..f9ed139 Binary files /dev/null and b/examples/quickwings/assets/background-day.png differ diff --git a/examples/quickwings/assets/base.png b/examples/quickwings/assets/base.png new file mode 100644 index 0000000..26fa391 Binary files /dev/null and b/examples/quickwings/assets/base.png differ diff --git a/examples/quickwings/assets/gameover.png b/examples/quickwings/assets/gameover.png new file mode 100644 index 0000000..b1df7f5 Binary files /dev/null and b/examples/quickwings/assets/gameover.png differ diff --git a/examples/quickwings/assets/message.png b/examples/quickwings/assets/message.png new file mode 100644 index 0000000..9243ab5 Binary files /dev/null and b/examples/quickwings/assets/message.png differ diff --git a/examples/flappy_bird/assets/pipe-green.png b/examples/quickwings/assets/pipe-green.png similarity index 100% rename from examples/flappy_bird/assets/pipe-green.png rename to examples/quickwings/assets/pipe-green.png diff --git a/examples/quickwings/assets/tappybird/Font/kenvector_future.ttf b/examples/quickwings/assets/tappybird/Font/kenvector_future.ttf new file mode 100644 index 0000000..39ebdfa Binary files /dev/null and b/examples/quickwings/assets/tappybird/Font/kenvector_future.ttf differ diff --git a/examples/quickwings/assets/tappybird/Font/kenvector_future_thin.ttf b/examples/quickwings/assets/tappybird/Font/kenvector_future_thin.ttf new file mode 100644 index 0000000..9f4b4fa Binary files /dev/null and b/examples/quickwings/assets/tappybird/Font/kenvector_future_thin.ttf differ diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterA.png b/examples/quickwings/assets/tappybird/PNG/Letters/letterA.png new file mode 100644 index 0000000..eb9a6ab Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Letters/letterA.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterB.png b/examples/quickwings/assets/tappybird/PNG/Letters/letterB.png new file mode 100644 index 0000000..75a6276 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Letters/letterB.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterC.png b/examples/quickwings/assets/tappybird/PNG/Letters/letterC.png new file mode 100644 index 0000000..8ae3c7f Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Letters/letterC.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterD.png b/examples/quickwings/assets/tappybird/PNG/Letters/letterD.png new file mode 100644 index 0000000..99dffaa Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Letters/letterD.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterE.png b/examples/quickwings/assets/tappybird/PNG/Letters/letterE.png new file mode 100644 index 0000000..d9d0ecf Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Letters/letterE.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterF.png b/examples/quickwings/assets/tappybird/PNG/Letters/letterF.png new file mode 100644 index 0000000..d118f25 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Letters/letterF.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterG.png b/examples/quickwings/assets/tappybird/PNG/Letters/letterG.png new file mode 100644 index 0000000..6285343 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Letters/letterG.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterH.png b/examples/quickwings/assets/tappybird/PNG/Letters/letterH.png new file mode 100644 index 0000000..c0969fd Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Letters/letterH.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterI.png b/examples/quickwings/assets/tappybird/PNG/Letters/letterI.png new file mode 100644 index 0000000..9c5e737 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Letters/letterI.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterJ.png b/examples/quickwings/assets/tappybird/PNG/Letters/letterJ.png new file mode 100644 index 0000000..ecb0f6e Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Letters/letterJ.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterK.png b/examples/quickwings/assets/tappybird/PNG/Letters/letterK.png new file mode 100644 index 0000000..5362d89 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Letters/letterK.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterL.png b/examples/quickwings/assets/tappybird/PNG/Letters/letterL.png new file mode 100644 index 0000000..e747d8a Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Letters/letterL.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterM.png b/examples/quickwings/assets/tappybird/PNG/Letters/letterM.png new file mode 100644 index 0000000..e197a99 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Letters/letterM.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterN.png b/examples/quickwings/assets/tappybird/PNG/Letters/letterN.png new file mode 100644 index 0000000..60884b3 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Letters/letterN.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterO.png b/examples/quickwings/assets/tappybird/PNG/Letters/letterO.png new file mode 100644 index 0000000..390b566 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Letters/letterO.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterP.png b/examples/quickwings/assets/tappybird/PNG/Letters/letterP.png new file mode 100644 index 0000000..70883d0 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Letters/letterP.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterQ.png b/examples/quickwings/assets/tappybird/PNG/Letters/letterQ.png new file mode 100644 index 0000000..c8ee726 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Letters/letterQ.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterR.png b/examples/quickwings/assets/tappybird/PNG/Letters/letterR.png new file mode 100644 index 0000000..fcae55c Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Letters/letterR.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterS.png b/examples/quickwings/assets/tappybird/PNG/Letters/letterS.png new file mode 100644 index 0000000..c5b671f Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Letters/letterS.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterT.png b/examples/quickwings/assets/tappybird/PNG/Letters/letterT.png new file mode 100644 index 0000000..5e4a3e7 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Letters/letterT.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterU.png b/examples/quickwings/assets/tappybird/PNG/Letters/letterU.png new file mode 100644 index 0000000..8fb60a9 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Letters/letterU.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterV.png b/examples/quickwings/assets/tappybird/PNG/Letters/letterV.png new file mode 100644 index 0000000..ad94fc7 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Letters/letterV.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterW.png b/examples/quickwings/assets/tappybird/PNG/Letters/letterW.png new file mode 100644 index 0000000..0b3e63e Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Letters/letterW.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterX.png b/examples/quickwings/assets/tappybird/PNG/Letters/letterX.png new file mode 100644 index 0000000..f65c348 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Letters/letterX.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterY.png b/examples/quickwings/assets/tappybird/PNG/Letters/letterY.png new file mode 100644 index 0000000..ba733c2 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Letters/letterY.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterZ.png b/examples/quickwings/assets/tappybird/PNG/Letters/letterZ.png new file mode 100644 index 0000000..d5e88ad Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Letters/letterZ.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Numbers/number0.png b/examples/quickwings/assets/tappybird/PNG/Numbers/number0.png new file mode 100644 index 0000000..a6ad98c Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Numbers/number0.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Numbers/number1.png b/examples/quickwings/assets/tappybird/PNG/Numbers/number1.png new file mode 100644 index 0000000..99b38b8 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Numbers/number1.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Numbers/number2.png b/examples/quickwings/assets/tappybird/PNG/Numbers/number2.png new file mode 100644 index 0000000..90dd749 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Numbers/number2.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Numbers/number3.png b/examples/quickwings/assets/tappybird/PNG/Numbers/number3.png new file mode 100644 index 0000000..1942bc4 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Numbers/number3.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Numbers/number4.png b/examples/quickwings/assets/tappybird/PNG/Numbers/number4.png new file mode 100644 index 0000000..b72f2e3 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Numbers/number4.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Numbers/number5.png b/examples/quickwings/assets/tappybird/PNG/Numbers/number5.png new file mode 100644 index 0000000..0bb43f8 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Numbers/number5.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Numbers/number6.png b/examples/quickwings/assets/tappybird/PNG/Numbers/number6.png new file mode 100644 index 0000000..f488ffb Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Numbers/number6.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Numbers/number7.png b/examples/quickwings/assets/tappybird/PNG/Numbers/number7.png new file mode 100644 index 0000000..7533db1 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Numbers/number7.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Numbers/number8.png b/examples/quickwings/assets/tappybird/PNG/Numbers/number8.png new file mode 100644 index 0000000..71ba693 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Numbers/number8.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Numbers/number9.png b/examples/quickwings/assets/tappybird/PNG/Numbers/number9.png new file mode 100644 index 0000000..18c1d42 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Numbers/number9.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Planes/planeBlue1.png b/examples/quickwings/assets/tappybird/PNG/Planes/planeBlue1.png new file mode 100644 index 0000000..ea52a1d Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Planes/planeBlue1.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Planes/planeBlue2.png b/examples/quickwings/assets/tappybird/PNG/Planes/planeBlue2.png new file mode 100644 index 0000000..566b1f4 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Planes/planeBlue2.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Planes/planeBlue3.png b/examples/quickwings/assets/tappybird/PNG/Planes/planeBlue3.png new file mode 100644 index 0000000..7264222 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Planes/planeBlue3.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Planes/planeGreen1.png b/examples/quickwings/assets/tappybird/PNG/Planes/planeGreen1.png new file mode 100644 index 0000000..ba2949b Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Planes/planeGreen1.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Planes/planeGreen2.png b/examples/quickwings/assets/tappybird/PNG/Planes/planeGreen2.png new file mode 100644 index 0000000..2ae3006 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Planes/planeGreen2.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Planes/planeGreen3.png b/examples/quickwings/assets/tappybird/PNG/Planes/planeGreen3.png new file mode 100644 index 0000000..4b22f29 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Planes/planeGreen3.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Planes/planeRed1.png b/examples/quickwings/assets/tappybird/PNG/Planes/planeRed1.png new file mode 100644 index 0000000..c0d1ddb Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Planes/planeRed1.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Planes/planeRed2.png b/examples/quickwings/assets/tappybird/PNG/Planes/planeRed2.png new file mode 100644 index 0000000..a492b1d Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Planes/planeRed2.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Planes/planeRed3.png b/examples/quickwings/assets/tappybird/PNG/Planes/planeRed3.png new file mode 100644 index 0000000..5ca6c70 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Planes/planeRed3.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Planes/planeYellow1.png b/examples/quickwings/assets/tappybird/PNG/Planes/planeYellow1.png new file mode 100644 index 0000000..906947d Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Planes/planeYellow1.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Planes/planeYellow2.png b/examples/quickwings/assets/tappybird/PNG/Planes/planeYellow2.png new file mode 100644 index 0000000..aedbe37 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Planes/planeYellow2.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/Planes/planeYellow3.png b/examples/quickwings/assets/tappybird/PNG/Planes/planeYellow3.png new file mode 100644 index 0000000..6f2af91 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/Planes/planeYellow3.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/UI/UIbg.png b/examples/quickwings/assets/tappybird/PNG/UI/UIbg.png new file mode 100644 index 0000000..0f238ff Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/UI/UIbg.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/UI/buttonLarge.png b/examples/quickwings/assets/tappybird/PNG/UI/buttonLarge.png new file mode 100644 index 0000000..edda3bc Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/UI/buttonLarge.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/UI/buttonSmall.png b/examples/quickwings/assets/tappybird/PNG/UI/buttonSmall.png new file mode 100644 index 0000000..ff1fbae Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/UI/buttonSmall.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/UI/medalBronze.png b/examples/quickwings/assets/tappybird/PNG/UI/medalBronze.png new file mode 100644 index 0000000..18ee3df Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/UI/medalBronze.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/UI/medalGold.png b/examples/quickwings/assets/tappybird/PNG/UI/medalGold.png new file mode 100644 index 0000000..9a41593 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/UI/medalGold.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/UI/medalSilver.png b/examples/quickwings/assets/tappybird/PNG/UI/medalSilver.png new file mode 100644 index 0000000..dd6bb8e Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/UI/medalSilver.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/UI/tap.png b/examples/quickwings/assets/tappybird/PNG/UI/tap.png new file mode 100644 index 0000000..5c82864 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/UI/tap.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/UI/tapLeft.png b/examples/quickwings/assets/tappybird/PNG/UI/tapLeft.png new file mode 100644 index 0000000..336fd1d Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/UI/tapLeft.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/UI/tapRight.png b/examples/quickwings/assets/tappybird/PNG/UI/tapRight.png new file mode 100644 index 0000000..daec2ca Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/UI/tapRight.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/UI/tapTick.png b/examples/quickwings/assets/tappybird/PNG/UI/tapTick.png new file mode 100644 index 0000000..5ba2731 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/UI/tapTick.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/UI/textGameOver.png b/examples/quickwings/assets/tappybird/PNG/UI/textGameOver.png new file mode 100644 index 0000000..11d730d Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/UI/textGameOver.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/UI/textGetReady.png b/examples/quickwings/assets/tappybird/PNG/UI/textGetReady.png new file mode 100644 index 0000000..ed0d035 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/UI/textGetReady.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/background.png b/examples/quickwings/assets/tappybird/PNG/background.png new file mode 100644 index 0000000..05c6a07 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/background.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/groundDirt.png b/examples/quickwings/assets/tappybird/PNG/groundDirt.png new file mode 100644 index 0000000..4223b3c Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/groundDirt.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/groundGrass.png b/examples/quickwings/assets/tappybird/PNG/groundGrass.png new file mode 100644 index 0000000..fd3655e Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/groundGrass.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/groundIce.png b/examples/quickwings/assets/tappybird/PNG/groundIce.png new file mode 100644 index 0000000..4ae4512 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/groundIce.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/groundRock.png b/examples/quickwings/assets/tappybird/PNG/groundRock.png new file mode 100644 index 0000000..c7fc7f1 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/groundRock.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/groundSnow.png b/examples/quickwings/assets/tappybird/PNG/groundSnow.png new file mode 100644 index 0000000..891e3e0 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/groundSnow.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/puffLarge.png b/examples/quickwings/assets/tappybird/PNG/puffLarge.png new file mode 100644 index 0000000..4023cc7 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/puffLarge.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/puffSmall.png b/examples/quickwings/assets/tappybird/PNG/puffSmall.png new file mode 100644 index 0000000..12dfc4b Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/puffSmall.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/rock.png b/examples/quickwings/assets/tappybird/PNG/rock.png new file mode 100644 index 0000000..1a89ad9 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/rock.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/rockDown.png b/examples/quickwings/assets/tappybird/PNG/rockDown.png new file mode 100644 index 0000000..90edad5 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/rockDown.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/rockGrass.png b/examples/quickwings/assets/tappybird/PNG/rockGrass.png new file mode 100644 index 0000000..2f06686 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/rockGrass.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/rockGrassDown.png b/examples/quickwings/assets/tappybird/PNG/rockGrassDown.png new file mode 100644 index 0000000..d6a18c6 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/rockGrassDown.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/rockIce.png b/examples/quickwings/assets/tappybird/PNG/rockIce.png new file mode 100644 index 0000000..7dc1fca Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/rockIce.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/rockIceDown.png b/examples/quickwings/assets/tappybird/PNG/rockIceDown.png new file mode 100644 index 0000000..1ed4858 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/rockIceDown.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/rockSnow.png b/examples/quickwings/assets/tappybird/PNG/rockSnow.png new file mode 100644 index 0000000..6c20222 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/rockSnow.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/rockSnowDown.png b/examples/quickwings/assets/tappybird/PNG/rockSnowDown.png new file mode 100644 index 0000000..7bac5dd Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/rockSnowDown.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/starBronze.png b/examples/quickwings/assets/tappybird/PNG/starBronze.png new file mode 100644 index 0000000..6ad5c8e Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/starBronze.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/starGold.png b/examples/quickwings/assets/tappybird/PNG/starGold.png new file mode 100644 index 0000000..c866382 Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/starGold.png differ diff --git a/examples/quickwings/assets/tappybird/PNG/starSilver.png b/examples/quickwings/assets/tappybird/PNG/starSilver.png new file mode 100644 index 0000000..3ad059c Binary files /dev/null and b/examples/quickwings/assets/tappybird/PNG/starSilver.png differ diff --git a/examples/quickwings/assets/tappybird/Spritesheet/planes.png b/examples/quickwings/assets/tappybird/Spritesheet/planes.png new file mode 100644 index 0000000..cd94487 Binary files /dev/null and b/examples/quickwings/assets/tappybird/Spritesheet/planes.png differ diff --git a/examples/quickwings/assets/tappybird/Spritesheet/planes.xml b/examples/quickwings/assets/tappybird/Spritesheet/planes.xml new file mode 100644 index 0000000..82733ab --- /dev/null +++ b/examples/quickwings/assets/tappybird/Spritesheet/planes.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/quickwings/assets/tappybird/Spritesheet/sheet.png b/examples/quickwings/assets/tappybird/Spritesheet/sheet.png new file mode 100644 index 0000000..2584c66 Binary files /dev/null and b/examples/quickwings/assets/tappybird/Spritesheet/sheet.png differ diff --git a/examples/quickwings/assets/tappybird/Spritesheet/sheet.xml b/examples/quickwings/assets/tappybird/Spritesheet/sheet.xml new file mode 100644 index 0000000..129f283 --- /dev/null +++ b/examples/quickwings/assets/tappybird/Spritesheet/sheet.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/quickwings/assets/tappybird/Vector/vector.svg b/examples/quickwings/assets/tappybird/Vector/vector.svg new file mode 100644 index 0000000..92800b3 --- /dev/null +++ b/examples/quickwings/assets/tappybird/Vector/vector.svg @@ -0,0 +1,510 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/quickwings/assets/tappybird/Vector/vector.swf b/examples/quickwings/assets/tappybird/Vector/vector.swf new file mode 100644 index 0000000..4956561 Binary files /dev/null and b/examples/quickwings/assets/tappybird/Vector/vector.swf differ diff --git a/examples/quickwings/assets/tappybird/license.txt b/examples/quickwings/assets/tappybird/license.txt new file mode 100644 index 0000000..b1a5ebe --- /dev/null +++ b/examples/quickwings/assets/tappybird/license.txt @@ -0,0 +1,14 @@ + +############################################################################### + + Tappy Plane by Kenney Vleugels (www.kenney.nl) + + ------------------------------ + + License (CC0) + http://creativecommons.org/publicdomain/zero/1.0/ + + You may use these graphics in personal and commercial projects. + Credit (Kenney or www.kenney.nl) would be nice but is not mandatory. + +############################################################################### \ No newline at end of file diff --git a/examples/quickwings/assets/tappybird/preview.png b/examples/quickwings/assets/tappybird/preview.png new file mode 100644 index 0000000..21772c0 Binary files /dev/null and b/examples/quickwings/assets/tappybird/preview.png differ diff --git a/examples/quickwings/assets/tappybird/sample.png b/examples/quickwings/assets/tappybird/sample.png new file mode 100644 index 0000000..efccaf4 Binary files /dev/null and b/examples/quickwings/assets/tappybird/sample.png differ diff --git a/examples/flappy_bird/assets/yellowbird-downflap.png b/examples/quickwings/assets/yellowbird-downflap.png similarity index 100% rename from examples/flappy_bird/assets/yellowbird-downflap.png rename to examples/quickwings/assets/yellowbird-downflap.png diff --git a/examples/flappy_bird/assets/yellowbird-midflap.png b/examples/quickwings/assets/yellowbird-midflap.png similarity index 100% rename from examples/flappy_bird/assets/yellowbird-midflap.png rename to examples/quickwings/assets/yellowbird-midflap.png diff --git a/examples/flappy_bird/assets/yellowbird-upflap.png b/examples/quickwings/assets/yellowbird-upflap.png similarity index 100% rename from examples/flappy_bird/assets/yellowbird-upflap.png rename to examples/quickwings/assets/yellowbird-upflap.png diff --git a/examples/quickwings/quickwings.cpp b/examples/quickwings/quickwings.cpp new file mode 100644 index 0000000..9df112b --- /dev/null +++ b/examples/quickwings/quickwings.cpp @@ -0,0 +1,529 @@ +/** + * paradiso - Paradigmen der Softwareentwicklung + * + * (c) Copyright 2023-2024 Hartmut Seichter, Robin Rottstädt, brxxh (Hannes Brothuhn) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +const int frame_rate = 60; +bool game_over = false; +float risky_pos_x; +float risky_pos_max_x; +float risky_pos_bottom_y; +float risky_pos_top_y; +float risky_pos_bottom_max_y; +float risky_pos_top_max_y; + +struct Background { + paradiso::Sprite backgroundLeft; + paradiso::Sprite backgroundRight; + paradiso::Sprite grassLeft; + paradiso::Sprite grassRight; + + paradiso::Sprite* scrolling[2] = {&backgroundLeft, &backgroundRight}; + + paradiso::Renderer renderer{}; + + Background() { + auto backgroundImage = + paradiso::BitmapIO::get().load("background-day.png"); + backgroundLeft = paradiso::Sprite{ + .bitmap = backgroundImage, + .pivot = {paradiso::Vector2::make(0.0f, 0.16f)}, + .scale = {paradiso::Vector2::make(1.01f, 1.3f)}}; + backgroundRight = paradiso::Sprite{ + .bitmap = backgroundImage, + .pivot = {paradiso::Vector2::make(2.018f, 0.16f)}, + .scale = {paradiso::Vector2::make(1.01f, 1.3f)}}; + + auto grassImage = paradiso::BitmapIO::get().load("base.png"); + grassLeft = paradiso::Sprite{ + .bitmap = grassImage, + .pivot = {paradiso::Vector2::make(0.0f, -1.0f)}, + .scale = {paradiso::Vector2::make(1.0f, 0.33333f)}}; + grassRight = paradiso::Sprite{ + .bitmap = grassImage, + .pivot = {paradiso::Vector2::make(2.0f, -1.0f)}, + .scale = {paradiso::Vector2::make(1.0f, 0.33333f)}}; + } + + void draw(const paradiso::Shader& shader) { + for (auto sprite : scrolling) { + if (game_over == false) { + if (sprite->pivot.x() <= -2.0f) { + sprite->pivot.x() += 4.0f; + } + sprite->pivot.x() -= 0.002f; + } + shader.set_uniform("pivot", sprite->pivot); + shader.set_uniform("scale", sprite->scale); + shader.set_uniform("rotation", sprite->rotation); + renderer.draw(*sprite, shader); + } + } +}; + +struct Pipe { + paradiso::Sprite pipe_top; + paradiso::Sprite pipe_bottom; + + paradiso::Renderer renderer1{}; + paradiso::Renderer renderer2{}; + + bool paused = false; + + int pipe_spawn_rand_int = rand() % 80 + 15; + float pipe_spawn_rand = float(pipe_spawn_rand_int) / 100; + + bool pos_reset = false; + + Pipe() { + auto pipe_image = paradiso::BitmapIO::get().load("pipe-green.png"); + + pipe_top = paradiso::Sprite{ + .bitmap = pipe_image, + .pivot = {paradiso::Vector2::make(1.4f, pipe_spawn_rand + 1.0f)}, + .scale = {paradiso::Vector2::make(((500.0f - (500.0f - 52.0f)) / 500.0f) * 2.25f, ((700.0f - (700.0f - 320.0f)) / 700.0f) * 2.25f)}, + .rotation = 3.1415926f}; + pipe_bottom = paradiso::Sprite{ + .bitmap = pipe_image, + .pivot = {paradiso::Vector2::make(1.4f, pipe_spawn_rand - 1.5f)}, + .scale = {paradiso::Vector2::make(((500.0f - (500.0f - 52.0f)) / 500.0f) * 2.25f, ((700.0f - (700.0f - 320.0f)) / 700.0f) * 2.25f)}}; + + paused = true; + + } + + void update() { + + if (game_over == true) { + paused = true; + } + + if (paused == true) { + return; + } + else { + pipe_spawn_rand_int = rand() % 80 + 15; + pipe_spawn_rand = float(pipe_spawn_rand_int) / 100; + + pipe_top.pivot.x() -= 0.02f; + pipe_bottom.pivot.x() -= 0.02f; + + risky_pos_x = pipe_top.pivot.x(); + risky_pos_max_x = pipe_top.pivot.x() + ((500.0f - (500.0f - 52.0f)) / 500.0f) * 2.25f; + + risky_pos_top_y = pipe_top.pivot.y(); + risky_pos_top_max_y = pipe_top.pivot.y() + 10.0f; + + risky_pos_bottom_y = pipe_bottom.pivot.y(); + risky_pos_bottom_max_y = pipe_bottom.pivot.y() - 10.0f; + + if (pipe_top.pivot.x() <= -1.4f || pipe_bottom.pivot.x() <= -1.4f) { + pos_reset = true; + + if (pos_reset == true) { + pipe_top.pivot.y() = pipe_spawn_rand + 1.0f; + pipe_bottom.pivot.y() = pipe_spawn_rand - 1.5; + + pos_reset = false; + } + + pipe_top.pivot.x() = 1.4f; + pipe_bottom.pivot.x() = 1.4f; + } + } + } + + void draw(const paradiso::Shader& shader) { + shader.set_uniform("pivot", pipe_bottom.pivot); + shader.set_uniform("scale", pipe_bottom.scale); + renderer1.draw(pipe_bottom, shader); + + shader.set_uniform("pivot", pipe_top.pivot); + shader.set_uniform("scale", pipe_top.scale); + shader.set_uniform("rotation", pipe_top.rotation); + renderer1.draw(pipe_top, shader); + } +}; + +struct Grass { + paradiso::Sprite grassLeft; + paradiso::Sprite grassRight; + paradiso::Sprite* scrolling[2] = {&grassLeft, &grassRight}; + + paradiso::Renderer renderer1{}; + paradiso::Renderer renderer2{}; + + Grass() { + auto grassImage = paradiso::BitmapIO::get().load("base.png"); + grassLeft = paradiso::Sprite{ + .bitmap = grassImage, + .pivot = {paradiso::Vector2::make(0.0f, -0.9f)}, + .scale = {paradiso::Vector2::make(((500.0f - (500.0f - 504.0f)) / 500.0f) * 2.25f, ((700.0f - (700.0f - 112.0f)) / 700.0f) * 2.25f)}}; + grassRight = paradiso::Sprite{ + .bitmap = grassImage, + .pivot = {paradiso::Vector2::make(1.002f, -0.9f)}, + .scale = {paradiso::Vector2::make(((500.0f - (500.0f - 504.0f)) / 500.0f) * 2.25f, ((700.0f - (700.0f - 112.0f)) / 700.0f) * 2.25f)}}; + } + + void draw(const paradiso::Shader& shader) { + if (game_over == false) { + grassLeft.pivot.x() -= 0.02f; + grassRight.pivot.x() -= 0.02f; + + if (grassRight.pivot.x() <= 0.0f) { + grassLeft.pivot.x() = 1.002f; + } + if (grassRight.pivot.x() <= -1.002f) { + grassRight.pivot.x() = 1.002f; + } + } + + shader.set_uniform("pivot", grassLeft.pivot); + shader.set_uniform("scale", grassLeft.scale); + shader.set_uniform("rotation", grassLeft.rotation); + + shader.set_uniform("pivot", grassRight.pivot); + shader.set_uniform("scale", grassRight.scale); + shader.set_uniform("rotation", grassRight.rotation); + + renderer1.draw(grassLeft, shader); + renderer2.draw(grassRight, shader); + } +}; + + +struct QuickWings { + paradiso::Renderer renderer1{}; + paradiso::Renderer renderer2{}; + paradiso::Renderer renderer3{}; + + std::array birds; + unsigned int flap = 0; + unsigned int flapSpeed = 15; // How many ticks per flap + unsigned int flapCounter = 0; // How many ticks since last flap + + float velocity = 0.0f; + const float max_velocity = 0.02f; + + const float gravity = -0.002f; + const float move_up_velocity = 0.02f; + + bool move_up = false; + bool paused = true; + + const float max_pos = 0.95f; + const float min_pos = -0.5f; + + float pos = 0.34f; + + float rotation = 0.0f; + + int collision_counter = 0; + + QuickWings() { + float scaleh = 0.08f; + float scalew = 0.158f; + + birds = { + paradiso::Sprite{ + .bitmap = + paradiso::BitmapIO::get().load("yellowbird-downflap.png"), + .pivot = {paradiso::Vector2::make(0.0f, 0.0f)}, + .scale = {paradiso::Vector2::make(scalew, scaleh)}}, + paradiso::Sprite{ + .bitmap = + paradiso::BitmapIO::get().load("yellowbird-midflap.png"), + .pivot = {paradiso::Vector2::make(0.0f, 0.0f)}, + .scale = {paradiso::Vector2::make(scalew, scaleh)}}, + paradiso::Sprite{ + .bitmap = + paradiso::BitmapIO::get().load("yellowbird-upflap.png"), + .pivot = {paradiso::Vector2::make(0.0f, 0.0f)}, + .scale = {paradiso::Vector2::make(scalew, scaleh)}}}; + } + + void draw(const paradiso::Shader& shader) { + // Update flap state + if (flapCounter < flapSpeed) { + flapCounter++; + } else { + flapCounter = 0; + flap = (flap + 1) % birds.size(); + } + + auto bird = birds[flap]; + bird.pivot.y() = pos; + bird.rotation = rotation; + shader.set_uniform("pivot", bird.pivot); + shader.set_uniform("scale", bird.scale); + shader.set_uniform("rotation", bird.rotation); + + switch (flap) { + case 0: + renderer1.draw(bird, shader); + break; + case 1: + renderer2.draw(bird, shader); + break; + case 2: + renderer3.draw(bird, shader); + break; + } + } + + void update() { + + if (game_over == true) { + paused = true; + } + + // Stop game + if (paused) { + return; + } + else { + // Apply gravity + velocity += gravity; + + if (move_up) + velocity += move_up_velocity - gravity; + + // Cap velocity + if (velocity > max_velocity) + velocity = max_velocity; + if (velocity < -max_velocity) + velocity = -max_velocity; + + // Cap position + pos += velocity; + if (pos < min_pos) { + pos = min_pos; + velocity = 0.0f; + game_over = true; + } + if (pos > max_pos) { + pos = max_pos; + velocity = 0.0f; + game_over = true; + } + + // Update rotation + rotation = velocity * 10.0f; + } + + float final_risky_pos_top_y = risky_pos_top_y - 1.06f; + float final_risky_pos_bottom_y = risky_pos_bottom_y + 1.06f; + + if (risky_pos_x - 0.3f <= 0.0f && risky_pos_max_x >= 0.0f) { + if (pos >= final_risky_pos_top_y && pos <= risky_pos_top_max_y) { + game_over = true; + } + if (pos <= final_risky_pos_bottom_y && pos >= risky_pos_bottom_max_y) { + if (collision_counter == 0) { + collision_counter++; + } + else { + collision_counter = 2; + } + + if (collision_counter == 2) { + game_over = true; + } + } + } + } + + // keyboard handler + void on_keyboard(const paradiso::Window::KeyboardInputStack& input) { + if (input.size()) { + paused = false; + + if (paused == false) { + bool pressed_up = input.top().key == ' ' || input.top().key == 'W'; + + if (input.top().action == 1 && pressed_up) { + move_up = true; + } else if (input.top().action == 0 && pressed_up) { + move_up = false; + } + } + else { + return; + } + } + } +}; + +struct Message { + paradiso::Sprite messageSprite; + paradiso::Renderer renderer{}; + bool start = false; + float pos = 100.0f; + + Message() { + auto messageImage = paradiso::BitmapIO::get().load("message.png"); + messageSprite = paradiso::Sprite{ + .bitmap = messageImage, + .pivot = {paradiso::Vector2::make(0.0f, 0.0f)}, + .scale = {paradiso::Vector2::make(0.8f, 0.8f)} + }; + }; + + void draw(const paradiso::Shader& shader) { + shader.set_uniform("pivot", messageSprite.pivot); + shader.set_uniform("scale", messageSprite.scale); + renderer.draw(messageSprite, shader); + } + + void update() { + if (start == true) { + messageSprite.pivot.y() = pos; + } + } + + void on_keyboard(const paradiso::Window::KeyboardInputStack& input) { + if (input.size()) { + start = true; + } + } +}; + +struct GameOverMessage { + paradiso::Sprite messageSprite; + paradiso::Renderer renderer{}; + + GameOverMessage() { + auto messageImage = paradiso::BitmapIO::get().load("gameover.png"); + messageSprite = paradiso::Sprite{ + .bitmap = messageImage, + .pivot = {paradiso::Vector2::make(0.0f, 0.4f)}, + .scale = {paradiso::Vector2::make(((500.0f - (500.0f - 192.0f)) / 500.0f) * 2.25f, ((700.0f - (700.0f - 42.0f)) / 700.0f) * 2.25f)} + }; + }; + + void draw(const paradiso::Shader& shader) { + shader.set_uniform("pivot", messageSprite.pivot); + shader.set_uniform("scale", messageSprite.scale); + renderer.draw(messageSprite, shader); + } +}; + +auto main() -> int { + std::srand(std::time(nullptr)); + + // Ausgabefenster ... sieht aus als wäre es auf dem Stack + auto window = paradiso::Window(); + + auto size = paradiso::Size{.width = 500, .height = 700}; + + /* + window.set_resizecallback([](auto& w) -> void { + w.set_size(paradiso::Size{.width = 405, .height = 720}); + }); + +*/ + window + .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_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 = size}); + + // nothing beats a classic look + ctx.set_clearcolor(paradiso::RGBA::from_rgb(0x00, 0x00, 0x00)); + + + // Asset loader bekommt den Pfad + + paradiso::BitmapIO::get().set_path("assets"); + + // Load + auto background = Background{}; + auto grass = Grass{}; + auto quickwingsapp = QuickWings{}; + auto pipe = Pipe{}; + auto message = Message{}; + auto gameover = GameOverMessage{}; + + + // timer + + // das update führt den hier mitgegebnen Ausdruck innerhalb der internen + // Updates des Fensters auf. Es wird hier auch explizit ein bool gefordert + // damit das update auch zu jederzeit unterbrochen werden kann + while (window.update([&](paradiso::Window& w) -> bool { + ctx.set_viewport(paradiso::Rectangle{ + .position = paradiso::Point{.x = 0, .y = 0}, .size = size}); + + ctx.clear(); + auto t1 = std::chrono::high_resolution_clock::now(); + + // Keyboard and state change + update + if (quickwingsapp.paused == false) { + pipe.paused = false; + } + + pipe.update(); + + quickwingsapp.on_keyboard(w.keyboard_input()); + quickwingsapp.update(); + + message.on_keyboard(w.keyboard_input()); + message.update(); + + // Draw + background.draw(shader); + pipe.draw(shader); + grass.draw(shader); + message.draw(shader); + + if (game_over == true) { + gameover.draw(shader); + } + + quickwingsapp.draw(shader); + + // wait for frame rate + auto t2 = std::chrono::high_resolution_clock::now(); + auto duration = + std::chrono::duration_cast(t2 - t1); + auto wait = std::chrono::microseconds(1000000 / frame_rate) - duration; + std::this_thread::sleep_for(wait); + + // Quit + return !(w.keyboard_input().size() && + w.keyboard_input().top().key == 'Q'); + })) { + }; + + return 0; +} diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index d437135..cde0660 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -8,6 +8,7 @@ add_subdirectory(src/vendor/glad) add_subdirectory(src/vendor/glfw-3.3.8) set(paradiso_srcs + src/bitmap_io.cpp src/shader.cpp src/window.cpp src/renderer.cpp @@ -18,6 +19,7 @@ set(paradiso_srcs set(paradiso_incs include/paradiso/aabb.hpp include/paradiso/bitmap.hpp + include/paradiso/bitmap_io.hpp include/paradiso/geometry.hpp include/paradiso/sprite.hpp include/paradiso/shader.hpp @@ -35,6 +37,8 @@ target_include_directories( paradiso_core PUBLIC include + PRIVATE + src/vendor/stb ) target_link_libraries( diff --git a/src/lib/include/paradiso/aabb.hpp b/src/lib/include/paradiso/aabb.hpp index 62267bf..cad123f 100644 --- a/src/lib/include/paradiso/aabb.hpp +++ b/src/lib/include/paradiso/aabb.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2023 Hartmut Seichter + * Copyright 2023-2024 Hartmut Seichter * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -59,4 +59,4 @@ struct AABB final { } // namespace paradiso -#endif \ No newline at end of file +#endif diff --git a/src/lib/include/paradiso/bitmap.hpp b/src/lib/include/paradiso/bitmap.hpp index d75d352..d6971f5 100644 --- a/src/lib/include/paradiso/bitmap.hpp +++ b/src/lib/include/paradiso/bitmap.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2023 Hartmut Seichter + * Copyright 2023-2024 Hartmut Seichter * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -106,4 +106,4 @@ struct Bitmap final { }; } // namespace paradiso -#endif \ No newline at end of file +#endif diff --git a/src/lib/include/paradiso/bitmap_io.hpp b/src/lib/include/paradiso/bitmap_io.hpp new file mode 100644 index 0000000..af0c529 --- /dev/null +++ b/src/lib/include/paradiso/bitmap_io.hpp @@ -0,0 +1,56 @@ +/* + * Copyright 2023-2024 Hartmut Seichter + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +#ifndef PARADISO_BITMAP_IO_HPP +#define PARADISO_BITMAP_IO_HPP + +#include + +#include +#include + +namespace paradiso { + +struct BitmapIO { + + static BitmapIO& get(); + + Bitmap load(std::string_view filename, bool ignore_cache = false) const; + + void set_path(std::string_view path); + + std::string path() const; + + private: + + struct Impl; + std::unique_ptr impl_; + + BitmapIO(); + ~BitmapIO() = default; + BitmapIO(const BitmapIO&) = delete; + BitmapIO(BitmapIO&&) = delete; +}; + +} // namespace paradiso + +#endif diff --git a/src/lib/include/paradiso/context.hpp b/src/lib/include/paradiso/context.hpp index f53495a..31a9ac1 100644 --- a/src/lib/include/paradiso/context.hpp +++ b/src/lib/include/paradiso/context.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2023 Hartmut Seichter + * Copyright 2023-2024 Hartmut Seichter * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/lib/include/paradiso/geometry.hpp b/src/lib/include/paradiso/geometry.hpp index e3a8393..acd018a 100644 --- a/src/lib/include/paradiso/geometry.hpp +++ b/src/lib/include/paradiso/geometry.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2023 Hartmut Seichter + * Copyright 2023-2024 Hartmut Seichter * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -71,4 +71,4 @@ struct Rectangle final { }; } // namespace paradiso -#endif \ No newline at end of file +#endif diff --git a/src/lib/include/paradiso/globals.hpp b/src/lib/include/paradiso/globals.hpp index 2927821..440bc7d 100644 --- a/src/lib/include/paradiso/globals.hpp +++ b/src/lib/include/paradiso/globals.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2023 Hartmut Seichter + * Copyright 2023-2024 Hartmut Seichter * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -37,7 +37,8 @@ #include #include +#include -#endif \ No newline at end of file +#endif diff --git a/src/lib/include/paradiso/matrix.hpp b/src/lib/include/paradiso/matrix.hpp index f5c87e0..c359a87 100644 --- a/src/lib/include/paradiso/matrix.hpp +++ b/src/lib/include/paradiso/matrix.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2023 Hartmut Seichter + * Copyright 2023-2024 Hartmut Seichter * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -32,7 +32,7 @@ namespace paradiso { template struct Matrix : MatrixBase> { - Scalar data[R * C]{}; + Scalar data[R * C]{}; static constexpr std::size_t rows{R}; static constexpr std::size_t cols{C}; diff --git a/src/lib/include/paradiso/matrixbase.hpp b/src/lib/include/paradiso/matrixbase.hpp index 5e77268..b20a8d4 100644 --- a/src/lib/include/paradiso/matrixbase.hpp +++ b/src/lib/include/paradiso/matrixbase.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2023 Hartmut Seichter + * Copyright 2023-2024 Hartmut Seichter * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,8 +25,6 @@ #include -#include - namespace paradiso { template struct MatrixBase { @@ -146,4 +144,4 @@ template struct MatrixBase { }; } // namespace paradiso -#endif \ No newline at end of file +#endif diff --git a/src/lib/include/paradiso/renderer.hpp b/src/lib/include/paradiso/renderer.hpp index 2f349de..b52a908 100644 --- a/src/lib/include/paradiso/renderer.hpp +++ b/src/lib/include/paradiso/renderer.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2023 Hartmut Seichter + * Copyright 2023-2024 Hartmut Seichter * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/lib/include/paradiso/rgba.hpp b/src/lib/include/paradiso/rgba.hpp index 0ab6ec4..d7745e2 100644 --- a/src/lib/include/paradiso/rgba.hpp +++ b/src/lib/include/paradiso/rgba.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2023 Hartmut Seichter + * Copyright 2023-2024 Hartmut Seichter * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -90,4 +90,4 @@ struct RGBA final { }; } // namespace paradiso -#endif \ No newline at end of file +#endif diff --git a/src/lib/include/paradiso/shader.hpp b/src/lib/include/paradiso/shader.hpp index 549fe7d..d51f6cf 100644 --- a/src/lib/include/paradiso/shader.hpp +++ b/src/lib/include/paradiso/shader.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2023 Hartmut Seichter + * Copyright 2023-2024 Hartmut Seichter * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -58,7 +58,7 @@ struct Shader final { const Shader& set_uniform_at_location(int location, float v) const; //!< sets a float in a shader - + const Shader& set_uniform_at_location( int location, uint32_t v) const; //!< sets a 32bit unsigned in a shader diff --git a/src/lib/include/paradiso/sprite.hpp b/src/lib/include/paradiso/sprite.hpp index 34a024b..a518e51 100644 --- a/src/lib/include/paradiso/sprite.hpp +++ b/src/lib/include/paradiso/sprite.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2023 Hartmut Seichter + * Copyright 2023-2024 Hartmut Seichter * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -72,4 +72,4 @@ struct Sprite final { }; } // namespace paradiso -#endif \ No newline at end of file +#endif diff --git a/src/lib/include/paradiso/vector.hpp b/src/lib/include/paradiso/vector.hpp index 647f8cf..2012ef5 100644 --- a/src/lib/include/paradiso/vector.hpp +++ b/src/lib/include/paradiso/vector.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2023 Hartmut Seichter + * Copyright 2023-2024 Hartmut Seichter * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -82,4 +82,4 @@ template struct Vector3 : Matrix<3, 1, T> { }; // namespace paradiso -#endif \ No newline at end of file +#endif diff --git a/src/lib/include/paradiso/window.hpp b/src/lib/include/paradiso/window.hpp index 6613b99..91337ac 100644 --- a/src/lib/include/paradiso/window.hpp +++ b/src/lib/include/paradiso/window.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2023 Hartmut Seichter + * Copyright 2023-2024 Hartmut Seichter * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -89,4 +89,4 @@ struct Window final { } // namespace paradiso -#endif \ No newline at end of file +#endif diff --git a/src/lib/src/bitmap_io.cpp b/src/lib/src/bitmap_io.cpp new file mode 100644 index 0000000..3490669 --- /dev/null +++ b/src/lib/src/bitmap_io.cpp @@ -0,0 +1,141 @@ +/* + * Copyright 2023-2024 Hartmut Seichter + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +// based on image_loader by Robin Rottstädt + +#include "paradiso/bitmap_io.hpp" +#include "paradiso/bitmap.hpp" + +#include + +// STB image loading +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" + +#include +#include + +namespace paradiso { + +struct BitmapIO::Impl { + + std::filesystem::path asset_path_ = {}; + + using BitmapCacheType = std::unordered_map; + + BitmapCacheType cache_; + + static Bitmap read(std::string_view filename) { + + // Load with stb_image + stbi_set_flip_vertically_on_load(true); // flip y axis for OpenGL + + int width{}, height{}, channels{}; + + auto stb_free = [](uint8_t* data) { stbi_image_free(data); }; + + if (std::unique_ptr image{ + stbi_load(filename.data(), &width, &height, &channels, 0)}; + image.get()) { + + int size = width * height; + + // Convert to Vector of RGBA + std::vector rgba = + std::vector(size); + for (int i = 0; i < size; i++) { + // get rgba values + int pos = i * 4; + int r = image.get()[pos + 0]; + int g = image.get()[pos + 1]; + int b = image.get()[pos + 2]; + 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; + } + + // 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 Bitmap(); // well, no exception ... + } + + Bitmap load(std::string_view filename) { + if (cache_.find(filename) == cache_.end()) { + + auto asset_filepath = asset_path_ / std::filesystem::path(filename); + + 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; + } + return cache_[filename.data()]; + } +}; + +BitmapIO::BitmapIO() : impl_{std::make_unique()} {} + +BitmapIO& BitmapIO::get() { + static BitmapIO instance; + return instance; +} + +Bitmap BitmapIO::load(std::string_view filename, bool ignore_cache) const { + return impl_->load(filename); +} + +void BitmapIO::set_path(std::string_view path) +{ + impl_->asset_path_ = path; +} + +std::string BitmapIO::path() const +{ + return impl_->asset_path_.generic_string(); +} + + +} // namespace paradiso diff --git a/src/lib/src/context.cpp b/src/lib/src/context.cpp index 031ca07..6ef465c 100644 --- a/src/lib/src/context.cpp +++ b/src/lib/src/context.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2023 Hartmut Seichter + * Copyright 2023-2024 Hartmut Seichter * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -71,7 +71,7 @@ struct Context::impl { Context::Context() : impl_(std::make_unique()) {} -Context::~Context() {} +Context::~Context() = default; Context& Context::set_blend() { return *this; } diff --git a/src/lib/src/renderer.cpp b/src/lib/src/renderer.cpp index 3c5853d..ab03c23 100644 --- a/src/lib/src/renderer.cpp +++ b/src/lib/src/renderer.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2023 Hartmut Seichter + * Copyright 2023-2024 Hartmut Seichter * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,7 +34,7 @@ #include #include -#if defined(_WIN32) +#if defined(_WIN32) #undef max #endif diff --git a/src/lib/src/shader.cpp b/src/lib/src/shader.cpp index 7a6b04e..e3d6b73 100644 --- a/src/lib/src/shader.cpp +++ b/src/lib/src/shader.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2023 Hartmut Seichter + * Copyright 2023-2024 Hartmut Seichter * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/lib/src/shader_sprite.hpp b/src/lib/src/shader_sprite.hpp index fc4c15d..1f546c9 100644 --- a/src/lib/src/shader_sprite.hpp +++ b/src/lib/src/shader_sprite.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2023 Hartmut Seichter + * Copyright 2023-2024 Hartmut Seichter * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -34,7 +34,7 @@ layout (location = 2) in vec2 texture_coords; // pivot der sprite uniform vec2 pivot = vec2( 0.0, 0.0 ); -// scale +// scale uniform vec2 scale = vec2( 1.0, 1.0 ); // rotation uniform float rotation = 0.0; @@ -80,4 +80,4 @@ void main() { })"; } // namespace paradiso -#endif \ No newline at end of file +#endif diff --git a/examples/flappy_bird/lib/stb_image.h b/src/lib/src/vendor/stb/stb_image.h similarity index 100% rename from examples/flappy_bird/lib/stb_image.h rename to src/lib/src/vendor/stb/stb_image.h diff --git a/src/lib/src/window.cpp b/src/lib/src/window.cpp index 4962439..a264dcf 100644 --- a/src/lib/src/window.cpp +++ b/src/lib/src/window.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2023 Hartmut Seichter + * Copyright 2023-2024 Hartmut Seichter * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal