commit a54568b3210d22beb94e7862bf4715a11e804cb9 Author: sillysagiri Date: Thu Jul 13 09:03:37 2023 +0700 v1.0 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8c4071a --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +build +.cache + +test/build +test/.cache \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100755 index 0000000..a940a3b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,88 @@ +cmake_minimum_required(VERSION 3.24) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +set(PROJECT_NAME panda-core) +set(PROJECT_VERSION 1.0) + +project(${PROJECT_NAME} VERSION ${PROJECT_VERSION}) + +############################################################## +set(RAYLIB_DIR "/home/tuanpanda/Panda/04-WORKSPACE/00-PROGRAMMING/_Git Clone/raylib-4.5.0") +set(IMGUI_DIR "/home/tuanpanda/Panda/04-WORKSPACE/00-PROGRAMMING/_Git Clone/imgui-1.89.7") +set(RLIMGUI_DIR "/home/tuanpanda/Panda/04-WORKSPACE/00-PROGRAMMING/_Git Clone/rlImGui") +set(INIFILE_DIR "/home/tuanpanda/Panda/04-WORKSPACE/00-PROGRAMMING/_Git Clone/inifile-cpp") + +### Fallback link +set(RAYLIB_LINK "https://github.com/raysan5/raylib/archive/refs/tags/4.5.0.zip") +set(IMGUI_LINK "https://github.com/ocornut/imgui/archive/refs/tags/v1.89.7.zip") +set(RLIMGUI_LINK "https://github.com/raylib-extras/rlImGui/archive/refs/heads/main.zip") +set(INIFILE_LINK "https://github.com/Rookfighter/inifile-cpp/archive/refs/heads/master.zip") + +############################################################## +if (EXISTS ${RAYLIB_DIR}) + add_subdirectory(${RAYLIB_DIR} raylib) +else() + message(STATUS "Downloading raylib library") + include(FetchContent) + set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) + FetchContent_Declare(raylib URL ${RAYLIB_LINK}) + FetchContent_MakeAvailable(raylib) +endif() + +if (EXISTS ${IMGUI_DIR}) + set(imgui_SOURCE_DIR ${IMGUI_DIR}) +else() + message(STATUS "Downloading imgui library") + include(FetchContent) + FetchContent_Declare(imgui URL ${IMGUI_LINK}) + FetchContent_MakeAvailable(imgui) +endif() + +if (EXISTS ${RLIMGUI_DIR}) + set(rlimgui_SOURCE_DIR ${RLIMGUI_DIR}) +else() + message(STATUS "Downloading rlImGui library") + include(FetchContent) + FetchContent_Declare(rlimgui URL ${RLIMGUI_LINK}) + FetchContent_MakeAvailable(rlimgui) +endif() + +if (EXISTS ${INIFILE_DIR}) + set(inifile-cpp_SOURCE_DIR ${INIFILE_DIR}) +else() + message(STATUS "Downloading inifile-cpp library") + include(FetchContent) + FetchContent_Declare(inifile-cpp URL ${INIFILE_LINK}) + FetchContent_MakeAvailable(inifile-cpp) +endif() + +############################################################## +# yes... im using glob... dont judge me.... + +file(GLOB PROJECT_SOURCES CONFIGURE_DEPENDS + "src/*.cpp" + "src/**/*.cpp" + "${imgui_SOURCE_DIR}/*.cpp" + "${rlimgui_SOURCE_DIR}/*.cpp") + +set(PROJECT_INCLUDE + "src" + ${imgui_SOURCE_DIR} + ${imgui_SOURCE_DIR}/backends + ${rlimgui_SOURCE_DIR} + ${inifile-cpp_SOURCE_DIR}/include) + +set(PROJECT_LIBRARY raylib) + +set(PROJECT_DEFINITION "") + +############################################################## + +add_library(${PROJECT_NAME} STATIC ${PROJECT_SOURCES}) +target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_INCLUDE}) +target_link_libraries(${PROJECT_NAME} PRIVATE ${PROJECT_LIBRARY}) +target_compile_definitions(${PROJECT_NAME} PUBLIC ${PROJECT_DEFINITION}) +target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic) \ No newline at end of file diff --git a/src/core/Core.cpp b/src/core/Core.cpp new file mode 100755 index 0000000..ba96b95 --- /dev/null +++ b/src/core/Core.cpp @@ -0,0 +1,52 @@ +#include + +#include "core/Panda.hpp" + +static Scene* currentScene = nullptr; + +// CORE +void panda::CreateWindow(int w, int h, const char *str) +{ + Random::getInstance().setSeedFromTime(); + + SetConfigFlags( + FLAG_MSAA_4X_HINT | FLAG_WINDOW_RESIZABLE); + + #if PLATFORM_ANDROID + InitWindow(0, 0, str); + #elif PLATFORM_DESKTOP + InitWindow(w, h, str); + SetWindowMinSize(w*0.8f, h*0.8f); + #endif + + // SetTargetFPS(60); + SetExitKey(-1); +} + +void panda::AppUpdate() +{ + if (currentScene != nullptr) + currentScene->update(); +} + +void panda::SetScene(Scene* scene) +{ + if (currentScene != nullptr) + { + delete currentScene; + currentScene = nullptr; + } + + currentScene = scene; +} + +Scene* panda::GetScene() +{ + return currentScene; +} + +// UTILS +panda::Random &panda::GetDefaultRandom() +{ + return Random::getInstance(); +} \ No newline at end of file diff --git a/src/core/Graphic.cpp b/src/core/Graphic.cpp new file mode 100755 index 0000000..a1a9be6 --- /dev/null +++ b/src/core/Graphic.cpp @@ -0,0 +1,115 @@ +#include +#include +#include + +#include "core/Panda.hpp" +#include "raylib.h" + +#if PLATFORM_ANDROID + +#include +#include +#include + +extern "C" struct android_app *GetAndroidApp(void); + +static int32_t handleInputEvent(struct android_app* app, AInputEvent* inputEvent) +{ + return ImGui_ImplAndroid_HandleInputEvent(inputEvent); +} +#endif + +void panda::GuiInit() +{ + #if PLATFORM_ANDROID + GetAndroidApp()->onInputEvent = handleInputEvent; + + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + io.IniFilename = NULL; + + ImGui::StyleColorsDark(); + ImGui_ImplAndroid_Init(GetAndroidApp()->window); + ImGui_ImplOpenGL3_Init("#version 300 es"); + + ImFontConfig font_cfg; + font_cfg.SizePixels = 22.0f; + io.Fonts->AddFontDefault(&font_cfg); + ImGui::GetStyle().ScaleAllSizes(3.0f); + #else + rlImGuiSetup(true); + #endif +} + +void panda::GuiDestroy() +{ + #if PLATFORM_ANDROID + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplAndroid_Shutdown(); + ImGui::DestroyContext(); + #else + rlImGuiShutdown(); + #endif +} + +void panda::GuiBegin() +{ + #if PLATFORM_ANDROID + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplAndroid_NewFrame(); + ImGui::NewFrame(); + #else + rlImGuiBegin(); + #endif +} + +void panda::GuiEnd() +{ + #if PLATFORM_ANDROID + rlDrawRenderBatchActive(); + rlDisableBackfaceCulling(); + + ImGui::Render(); + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + + rlSetTexture(0); + rlEnableBackfaceCulling(); + #else + rlImGuiEnd(); + #endif +} + +void panda::DrawRenderTexture(const RenderTexture &buffer, const float &x, const float &y, const Color &color) +{ + DrawTextureRec( + buffer.texture, + {0.0f, 0.0f, 1.0f*buffer.texture.width, -1.0f*buffer.texture.height}, + {x, y}, color); +} + +///////////////////////////////// + + + + +///////////////////////////////// + +// panda::TilemapMetadata panda::LoadTilemapMetadata(const char *file) +// { +// ini::IniFile ini; +// char* text = LoadFileText(file); +// ini.decode(text); + +// return TilemapMetadata{ +// ini["chunk"]["width"].as(), +// ini["chunk"]["height"].as(), +// ini["tile"]["width"].as(), +// ini["tile"]["height"].as(), +// }; +// } + +// panda::TilemapItem panda::LoadTilemap(const char *file, panda::TilemapMetadata metadata, Texture texture) +// { +// return TilemapItem(); +// } diff --git a/src/core/Panda.hpp b/src/core/Panda.hpp new file mode 100755 index 0000000..16cddfc --- /dev/null +++ b/src/core/Panda.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include +#include +#include +#include + +#include "core/Scene.hpp" +#include "utils/Random.hpp" + +struct Texture; +struct RenderTexture; +struct Color; + +namespace panda +{ + + struct TextureAtlasItem + { + int x; + int y; + int w; + int h; + float px; + float py; + }; + + // Core + void CreateWindow(int w, int h, const char *str); + + void AppUpdate(); + void SetScene(Scene* scene); + Scene* GetScene(); + + // Graphic + void GuiInit(); + void GuiDestroy(); + void GuiBegin(); + void GuiEnd(); + + bool LoadTextureAtlas(const char *image_path, const char *ini_path, std::string AtlasKey); + bool UnloadTextureAtlas(std::string AtlasKey); + void DrawTextureAtlas(std::string AtlasKey, std::string key, int x, int y); + void DrawTextureAtlasPro(std::string AtlasKey, std::string key, int x, int y, Color color, bool flipX = false, bool flipY = false); + void DrawRenderTexture(const RenderTexture &buffer, const float &x, const float &y, const Color &color); + // Tilemap + // TilemapMetadata LoadTilemapMetadata(const char *file); + // TilemapItem LoadTilemap(const char *file, TilemapMetadata metadata, Texture texture); + + // Utils + Random &GetDefaultRandom(); +} diff --git a/src/core/Scene.hpp b/src/core/Scene.hpp new file mode 100755 index 0000000..71a27cf --- /dev/null +++ b/src/core/Scene.hpp @@ -0,0 +1,8 @@ +#pragma once + +class Scene { +public: + Scene() {} + virtual ~Scene() {} + virtual void update() {} +}; diff --git a/src/utils/Easing.cpp b/src/utils/Easing.cpp new file mode 100755 index 0000000..dc246dd --- /dev/null +++ b/src/utils/Easing.cpp @@ -0,0 +1,173 @@ +#include "utils/Easing.hpp" + +#include + +namespace cur = easing; + +#ifndef PI +#define PI 3.1415926545 +#endif + +double cur::inSine(double t) { + return sin(1.5707963 * t); +} + +double cur::outSine(double t) { + return 1 + sin(1.5707963 * (--t)); +} + +double cur::inOutSine(double t) { + return 0.5 * (1 + sin(3.1415926 * (t - 0.5))); +} + +double cur::inQuad(double t) { + return t * t; +} + +double cur::outQuad(double t) { + return t * (2 - t); +} + +double cur::inOutQuad(double t) { + return t < 0.5 ? 2 * t * t : t * (4 - 2 * t) - 1; +} + +double cur::inCubic(double t) { + return t * t * t; +} + +double cur::outCubic(double t) { + return 1 + (--t) * t * t; +} + +double cur::inOutCubic(double t) { + return t < 0.5 ? 4 * t * t * t : 1 + (--t) * (2 * (--t)) * (2 * t); +} + +double cur::inQuart(double t) { + t *= t; + return t * t; +} + +double cur::outQuart(double t) { + t = (--t) * t; + return 1 - t * t; +} + +double cur::inOutQuart(double t) { + if(t < 0.5) { + t *= t; + return 8 * t * t; + } else { + t = (--t) * t; + return 1 - 8 * t * t; + } +} + +double cur::inQuint(double t) { + auto t2 = t * t; + return t * t2 * t2; +} + +double cur::outQuint(double t) { + auto t2 = (--t) * t; + return 1 + t * t2 * t2; +} + +double cur::inOutQuint(double t) { + auto t2 = double { 0.0 }; + if(t < 0.5) { + t2 = t * t; + return 16 * t * t2 * t2; + } else { + t2 = (--t) * t; + return 1 + 16 * t * t2 * t2; + } +} + +double cur::inExpo(double t) { + return (pow(2, 8 * t) - 1) / 255; +} + +double cur::outExpo(double t) { + return 1 - pow(2, -8 * t); +} + +double cur::inOutExpo(double t) { + if(t < 0.5) { + return (pow(2, 16 * t) - 1) / 510; + } else { + return 1 - 0.5 * pow(2, -16 * (t - 0.5)); + } +} + +double cur::inCirc(double t) { + return 1 - sqrt(1 - t); +} + +double cur::outCirc(double t) { + return sqrt(t); +} + +double cur::inOutCirc(double t) { + if(t < 0.5) { + return (1 - sqrt(1 - 2 * t)) * 0.5; + } else { + return (1 + sqrt(2 * t - 1)) * 0.5; + } +} + +double cur::inBack(double t) { + return t * t * (2.70158 * t - 1.70158); +} + +double cur::outBack(double t) { + return 1 + (--t) * t * (2.70158 * t + 1.70158); +} + +double cur::inOutBack(double t) { + if(t < 0.5) { + return t * t * (7 * t - 2.5) * 2; + } else { + return 1 + (--t) * t * 2 * (7 * t + 2.5); + } +} + +double cur::inElastic(double t) { + auto t2 = t * t; + return t2 * t2 * sin(t * PI * 4.5); +} + +double cur::outElastic(double t) { + auto t2 = (t - 1) * (t - 1); + return 1 - t2 * t2 * cos(t * PI * 4.5); +} + +double cur::inOutElastic(double t) { + auto t2 = double { 0.0 }; + if(t < 0.45) { + t2 = t * t; + return 8 * t2 * t2 * sin(t * PI * 9); + } else if(t < 0.55) { + return 0.5 + 0.75 * sin(t * PI * 4); + } else { + t2 = (t - 1) * (t - 1); + return 1 - 8 * t2 * t2 * sin(t * PI * 9); + } +} + +double cur::inBounce(double t) { + return pow(2, 6 * (t - 1)) * abs(sin(t * PI * 3.5)); +} + +double cur::outBounce(double t) { + return 1 - pow(2, -6 * t) * abs(cos(t * PI * 3.5)); +} + +double cur::inOutBounce(double t) { + if(t < 0.5) { + return 8 * pow(2, 8 * (t - 1)) * abs(sin(t * PI * 7)); + } else { + return 1 - 8 * pow(2, -8 * t) * abs(sin(t * PI * 7)); + } +} \ No newline at end of file diff --git a/src/utils/Easing.hpp b/src/utils/Easing.hpp new file mode 100755 index 0000000..d43e824 --- /dev/null +++ b/src/utils/Easing.hpp @@ -0,0 +1,36 @@ +#pragma once + +namespace easing +{ + double inSine(double time); + double outSine(double time); + double inOutSine(double time); + double inQuad(double time); + double outQuad(double time); + double inOutQuad(double time); + double inCubic(double time); + double outCubic(double time); + double inOutCubic(double time); + double inQuart(double time); + double outQuart(double time); + double inOutQuart(double time); + double inQuint(double time); + double outQuint(double time); + double inOutQuint(double time); + double inExpo(double time); + double outExpo(double time); + double inOutExpo(double time); + double inOutExpo(double time); + double inCirc(double time); + double outCirc(double time); + double inOutCirc(double time); + double inBack(double time); + double outBack(double time); + double inOutBack(double time); + double inElastic(double time); + double outElastic(double time); + double inOutElastic(double time); + double inBounce(double time); + double outBounce(double time); + double inOutBounce(double time); +} \ No newline at end of file diff --git a/src/utils/GridMap.hpp b/src/utils/GridMap.hpp new file mode 100755 index 0000000..33fddcb --- /dev/null +++ b/src/utils/GridMap.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include "utils/RaylibDeprecated.hpp" +#include +#include + +class GridMap +{ +public: + GridMap() + { + Image image = GenImageColor(100, 100, WHITE); + ImageDrawLine(&image, image.width*0.5f, 0, image.width*0.5f, image.height, {0, 0, 0, 120}); + ImageDrawLine(&image, 0, image.height*0.5f, 100, image.height*0.5f, {0, 0, 0, 120}); + ImageDrawRectangleLines(&image, {0.0f, 0.0f, image.width - 2.0f, image.height - 2.0f}, 2, {0, 0, 0, 180}); + + texture = LoadTextureFromImage(image); + UnloadImage(image); + } + + ~GridMap() + { + UnloadTexture(texture); + } + + + void Draw(Camera2D camera) + { + Vector2 topLeft = GetScreenToWorld2D({0.0f, 0.0f}, camera); + Vector2 botRight = GetScreenToWorld2D({(float)GetScreenWidth(), (float)GetScreenHeight()}, camera); + + float SWidth = (std::ceil((botRight.x-topLeft.x) / texture.width) + 1) * texture.width; + float SHeight = (std::ceil((botRight.y-topLeft.y) / texture.height) + 1) * texture.height; + + float SX = (std::ceil(topLeft.x / texture.width) - 1) * texture.width; + float SY = (std::ceil(topLeft.y / texture.height) - 1) * texture.height; + + DrawTextureTiled( + texture, + {0.0f, 0.0f, (float)texture.width, (float)texture.height}, + {SX, SY, SWidth, SHeight}, + // {topLeft.x, topLeft.y, botRight.x-topLeft.x, botRight.y-topLeft.y}, + {0.0f, 0.0f}, 0.0f, 1.0f, WHITE + ); + } + +private: + Texture2D texture; +}; \ No newline at end of file diff --git a/src/utils/Pool.hpp b/src/utils/Pool.hpp new file mode 100755 index 0000000..415f6cb --- /dev/null +++ b/src/utils/Pool.hpp @@ -0,0 +1,78 @@ +#pragma once + +#include +#include +#include + +#include "utils/Random.hpp" + +namespace panda +{ + + // template + // class Pool + // { + // public: + // Pool(int size) : container(size) { } + + // T &get() + // { + // if (activeIndex != container.size()) + // { + // activeIndex++; + // return container[activeIndex-1]; + // } + // else + // { + // if (custom) + // { + // return container[custom()]; + // } + // else + // { + // int r = Random::getInstance().UNI() * (container.size()-1); + // return container[r]; + // } + // } + // } + + // void put(int index) + // { + // activeIndex--; + // std::swap(container[activeIndex], container[index]); + // } + + // // int countActive() { return activeIndex; } + // int activeIndex; + // std::vector container; + // std::function custom; + // }; + + template + class PoolPointer { + private: + std::list free; + + public: + PoolPointer() : free() { } + + T* get() { + if (free.empty()) + return new T(); // no objects are free + + // get the last object in the list + auto obj = free.back(); + free.pop_back(); + return obj; + } + + int getFreeSize() + { + return free.size(); + } + + /// Mark the given object for reuse in the future. + inline void put(T* obj) { free.emplace_back(obj); } + }; + +} \ No newline at end of file diff --git a/src/utils/Random.cpp b/src/utils/Random.cpp new file mode 100755 index 0000000..b152782 --- /dev/null +++ b/src/utils/Random.cpp @@ -0,0 +1,57 @@ +#include "utils/Random.hpp" +#include + +panda::Random::Random(uint32_t _w, uint32_t _z) { + m_w = _w; + m_z = _z; +} + +void panda::Random::setSeed(uint32_t w) { + if (w != 0) m_w = w; +} + +void panda::Random::setSeed(uint32_t w, uint32_t z) { + if (w != 0) m_w = w; + if (z != 0) m_z = z; + +} + +void panda::Random::setSeedFromTime() { + m_w = std::chrono::system_clock::now().time_since_epoch().count(); +} + +uint32_t panda::Random::MWC() { + m_z = 36969 * (m_z & 65535) + (m_z >> 16); + m_w = 18000 * (m_w & 65535) + (m_w >> 16); + return (m_z << 16) + m_w; +} + +float panda::Random::UNI() { + return MWC() * inv_uni; +} + +float panda::Random::range(float min, float max) { + return min + (max-min) * UNI(); +} + +float panda::Random::xorshift_uni(uint32_t x) { + return xorshift(x) * inv_uni; +} + +float panda::Random::xorshift64_uni(uint64_t x) { + return xorshift64(x) * inv_uni64; +} + +uint32_t panda::Random::xorshift(uint32_t x) { + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + return x; +} + +uint64_t panda::Random::xorshift64(uint64_t x) { + x ^= x << 13; + x ^= x >> 7; + x ^= x << 17; + return x; +} diff --git a/src/utils/Random.hpp b/src/utils/Random.hpp new file mode 100755 index 0000000..3b65495 --- /dev/null +++ b/src/utils/Random.hpp @@ -0,0 +1,34 @@ +#pragma once +#include + +namespace panda +{ + class Random { + public: + static Random& getInstance() + { + static Random instance; + return instance; + } + + Random(uint32_t _w = 521288629, uint32_t _z = 362436069); + void setSeed(uint32_t w); + void setSeed(uint32_t w, uint32_t z); + void setSeedFromTime(); + + uint32_t MWC(); + float UNI(); + float range(float min, float max); + + float xorshift_uni(uint32_t x); + float xorshift64_uni(uint64_t x); + uint32_t xorshift(uint32_t x); + uint64_t xorshift64(uint64_t x); + + private: + uint32_t m_w; + uint32_t m_z; + float inv_uni = 2.3283064e-10; + float inv_uni64 = 5.4210109e-20; + }; +} \ No newline at end of file diff --git a/src/utils/RaylibDeprecated.cpp b/src/utils/RaylibDeprecated.cpp new file mode 100755 index 0000000..22ac29b --- /dev/null +++ b/src/utils/RaylibDeprecated.cpp @@ -0,0 +1,85 @@ +#include "utils/RaylibDeprecated.hpp" + +// Draw part of a texture (defined by a rectangle) with rotation and scale tiled into dest. +void DrawTextureTiled(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, float scale, Color tint) +{ + if ((texture.id <= 0) || (scale <= 0.0f)) return; // Wanna see a infinite loop?!...just delete this line! + if ((source.width == 0) || (source.height == 0)) return; + + int tileWidth = (int)(source.width*scale), tileHeight = (int)(source.height*scale); + if ((dest.width < tileWidth) && (dest.height < tileHeight)) + { + // Can fit only one tile + DrawTexturePro(texture, {source.x, source.y, ((float)dest.width/tileWidth)*source.width, ((float)dest.height/tileHeight)*source.height}, + {dest.x, dest.y, dest.width, dest.height}, origin, rotation, tint); + } + else if (dest.width <= tileWidth) + { + // Tiled vertically (one column) + int dy = 0; + for (;dy+tileHeight < dest.height; dy += tileHeight) + { + DrawTexturePro(texture, {source.x, source.y, ((float)dest.width/tileWidth)*source.width, source.height}, {dest.x, dest.y + dy, dest.width, (float)tileHeight}, origin, rotation, tint); + } + + // Fit last tile + if (dy < dest.height) + { + DrawTexturePro(texture, {source.x, source.y, ((float)dest.width/tileWidth)*source.width, ((float)(dest.height - dy)/tileHeight)*source.height}, + {dest.x, dest.y + dy, dest.width, dest.height - dy}, origin, rotation, tint); + } + } + else if (dest.height <= tileHeight) + { + // Tiled horizontally (one row) + int dx = 0; + for (;dx+tileWidth < dest.width; dx += tileWidth) + { + DrawTexturePro(texture, {source.x, source.y, source.width, ((float)dest.height/tileHeight)*source.height}, {dest.x + dx, dest.y, (float)tileWidth, dest.height}, origin, rotation, tint); + } + + // Fit last tile + if (dx < dest.width) + { + DrawTexturePro(texture, {source.x, source.y, ((float)(dest.width - dx)/tileWidth)*source.width, ((float)dest.height/tileHeight)*source.height}, + {dest.x + dx, dest.y, dest.width - dx, dest.height}, origin, rotation, tint); + } + } + else + { + // Tiled both horizontally and vertically (rows and columns) + int dx = 0; + for (;dx+tileWidth < dest.width; dx += tileWidth) + { + int dy = 0; + for (;dy+tileHeight < dest.height; dy += tileHeight) + { + DrawTexturePro(texture, source, {dest.x + dx, dest.y + dy, (float)tileWidth, (float)tileHeight}, origin, rotation, tint); + } + + if (dy < dest.height) + { + DrawTexturePro(texture, {source.x, source.y, source.width, ((float)(dest.height - dy)/tileHeight)*source.height}, + {dest.x + dx, dest.y + dy, (float)tileWidth, dest.height - dy}, origin, rotation, tint); + } + } + + // Fit last column of tiles + if (dx < dest.width) + { + int dy = 0; + for (;dy+tileHeight < dest.height; dy += tileHeight) + { + DrawTexturePro(texture, {source.x, source.y, ((float)(dest.width - dx)/tileWidth)*source.width, source.height}, + {dest.x + dx, dest.y + dy, dest.width - dx, (float)tileHeight}, origin, rotation, tint); + } + + // Draw final tile in the bottom right corner + if (dy < dest.height) + { + DrawTexturePro(texture, {source.x, source.y, ((float)(dest.width - dx)/tileWidth)*source.width, ((float)(dest.height - dy)/tileHeight)*source.height}, + {dest.x + dx, dest.y + dy, dest.width - dx, dest.height - dy}, origin, rotation, tint); + } + } + } +} \ No newline at end of file diff --git a/src/utils/RaylibDeprecated.hpp b/src/utils/RaylibDeprecated.hpp new file mode 100755 index 0000000..1368fc4 --- /dev/null +++ b/src/utils/RaylibDeprecated.hpp @@ -0,0 +1,4 @@ +#pragma once +#include + +void DrawTextureTiled(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, float scale, Color tint); \ No newline at end of file diff --git a/src/utils/TextureAtlas.cpp b/src/utils/TextureAtlas.cpp new file mode 100755 index 0000000..b557466 --- /dev/null +++ b/src/utils/TextureAtlas.cpp @@ -0,0 +1,81 @@ +#include +#include +#include + +#include "core/Panda.hpp" + +namespace +{ + struct TextureAtlas + { + Texture2D texture; + std::unordered_map items; + }; +} + +static std::unordered_map TextureAtlasMap; + +bool panda::LoadTextureAtlas(const char *image_path, const char *ini_path, std::string AtlasKey) +{ + + ini::IniFile ini; + TextureAtlas atlas; + + char* text = LoadFileText(ini_path); + ini.decode(text); + + // load texture + atlas.texture = LoadTexture(image_path); + + // loop item + std::stringstream ss(ini["meta"]["list"].as()); + std::string item; + while (std::getline(ss, item, ';')) { + atlas.items.insert({item, TextureAtlasItem{ + ini[item]["x"].as(), + ini[item]["y"].as(), + ini[item]["w"].as(), + ini[item]["h"].as(), + ini[item]["px"].as(), + ini[item]["py"].as(), + }}); + } + + UnloadFileText(text); + + TextureAtlasMap.insert({AtlasKey, atlas}); + return true; +} + +bool panda::UnloadTextureAtlas(std::string AtlasKey) +{ + // looks like its already clear automatically (when close window) + // just incase if it not when changing scene + if (TextureAtlasMap.count(AtlasKey)) + { + TextureAtlas &atlas = TextureAtlasMap.at(AtlasKey); + UnloadTexture(atlas.texture); + TextureAtlasMap.erase(AtlasKey); + } + return true; +} + +void panda::DrawTextureAtlas(std::string AtlasKey, std::string key, int x, int y) +{ + DrawTextureAtlasPro(AtlasKey, key, x, y, WHITE); +} + +void panda::DrawTextureAtlasPro(std::string AtlasKey, std::string key, int x, int y, Color color, bool flipX, bool flipY) +{ + TextureAtlas &atlas = TextureAtlasMap.at(AtlasKey); + TextureAtlasItem &item = atlas.items.at(key); + + float _flipX = (flipX) ? -1.0f : 1.0f; + float _flipY = (flipY) ? -1.0f : 1.0f; + + // todo flip position + DrawTextureRec( + atlas.texture, + {(float)item.x, (float)item.y, item.w*_flipX, item.h*_flipY}, + {x - item.px*item.w, y - item.py*item.h}, color); +}