diff --git a/README.de.md b/README.de.md index de42551..1b90222 100644 --- a/README.de.md +++ b/README.de.md @@ -25,4 +25,5 @@ ParadiSO wird mit den notwendigen Komponenten geliefert. Diese sollte jedoch hie ## Zuarbeiten -* [TimePlex](https://code.technotecture.net/Timeplex) \ No newline at end of file +* [Tim Götzelmann](https://code.technotecture.net/Timeplex) +* [Robin Rottstädt](https://code.technotecture.net/robin_rottstaedt) \ No newline at end of file diff --git a/README.md b/README.md index 2117b39..6c3929a 100644 --- a/README.md +++ b/README.md @@ -25,4 +25,5 @@ ParadiSO comes with batteries included. However, it should be mentioned here: ## Contributors -* [TimePlex](https://code.technotecture.net/Timeplex) \ No newline at end of file +* [Tim Götzelmann](https://code.technotecture.net/Timeplex) +* [Robin Rottstädt](https://code.technotecture.net/robin_rottstaedt) \ No newline at end of file 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/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/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/flappy_bird/assets/background-day.png b/examples/quickwings/assets/background-day.png similarity index 100% rename from examples/flappy_bird/assets/background-day.png rename to examples/quickwings/assets/background-day.png diff --git a/examples/flappy_bird/assets/base.png b/examples/quickwings/assets/base.png similarity index 100% rename from examples/flappy_bird/assets/base.png rename to examples/quickwings/assets/base.png 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/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/flappy_bird/flappy_bird.cpp b/examples/quickwings/quickwings.cpp similarity index 90% rename from examples/flappy_bird/flappy_bird.cpp rename to examples/quickwings/quickwings.cpp index 357bb5d..cd25735 100644 --- a/examples/flappy_bird/flappy_bird.cpp +++ b/examples/quickwings/quickwings.cpp @@ -1,11 +1,12 @@ /** * paradiso - Paradigmen der Softwareentwicklung * - * (c) Copyright 2023 Hartmut Seichter + * (c) Copyright 2023 Hartmut Seichter, Robin Rottstädt * */ #include +#include #include #include #include @@ -17,9 +18,10 @@ #include #include #include +#include #include -#include "lib/image_loader.hpp" +// #include "lib/image_loader.hpp" const int frame_rate = 60; @@ -33,7 +35,7 @@ struct Background { Background() { auto backgroundImage = - image_loader::load(std::string("background-day.png")); + paradiso::BitmapIO::get().load("background-day.png"); backgroundLeft = paradiso::Sprite{ .bitmap = backgroundImage, .pivot = paradiso::Vector2::make(0.0f, 0.0f), @@ -43,7 +45,7 @@ struct Background { .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")); + auto grassImage = paradiso::BitmapIO::get().load("base.png"); grassLeft = paradiso::Sprite{ .bitmap = grassImage, .pivot = paradiso::Vector2::make(0.0f, -1.0f), @@ -77,7 +79,7 @@ struct Grass { paradiso::Sprite* scrolling[2] = {&grassLeft, &grassRight}; Grass() { - auto grassImage = image_loader::load(std::string("base.png")); + auto grassImage = paradiso::BitmapIO::get().load(std::string("base.png")); grassLeft = paradiso::Sprite{ .bitmap = grassImage, .pivot = paradiso::Vector2::make(0.0f, -0.9f), @@ -104,7 +106,7 @@ struct Grass { paradiso::Renderer renderer{}; }; -struct FlappyBird { +struct QuickWings { paradiso::Renderer renderer1{}; paradiso::Renderer renderer2{}; @@ -131,24 +133,24 @@ struct FlappyBird { float rotation = 0.0f; - FlappyBird() { + QuickWings() { float scaleh = 0.07f; float scalew = scaleh * 1.416666666666667f; birds = { paradiso::Sprite{ .bitmap = - image_loader::load(std::string("yellowbird-downflap.png")), + paradiso::BitmapIO::get().load("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")), + paradiso::BitmapIO::get().load("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")), + paradiso::BitmapIO::get().load("yellowbird-upflap.png"), .pivot = paradiso::Vector2::make(0.0f, 0.0f), .scale = paradiso::Vector2::make(scalew, scaleh)}}; } @@ -266,11 +268,16 @@ auto main() -> int { // 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 flappyBird = FlappyBird{}; + auto quickwingsapp = QuickWings{}; // timer @@ -285,13 +292,13 @@ auto main() -> int { auto t1 = std::chrono::high_resolution_clock::now(); // Keyboard and state change - flappyBird.on_keyboard(w.keyboard_input()); - flappyBird.update(); + quickwingsapp.on_keyboard(w.keyboard_input()); + quickwingsapp.update(); // Draw background.draw(shader); grass.draw(shader); - flappyBird.draw(shader); + quickwingsapp.draw(shader); // wait for frame rate auto t2 = std::chrono::high_resolution_clock::now(); 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/bitmap_io.hpp b/src/lib/include/paradiso/bitmap_io.hpp new file mode 100644 index 0000000..0ed2cff --- /dev/null +++ b/src/lib/include/paradiso/bitmap_io.hpp @@ -0,0 +1,56 @@ +/* + * Copyright 2023 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 \ No newline at end of file diff --git a/src/lib/src/bitmap_io.cpp b/src/lib/src/bitmap_io.cpp new file mode 100644 index 0000000..0afdb21 --- /dev/null +++ b/src/lib/src/bitmap_io.cpp @@ -0,0 +1,141 @@ +/* + * Copyright 2023 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.c_str()); + + 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_; +} + + +} // namespace paradiso \ No newline at end of file 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