This commit is contained in:
sillysagiri 2023-07-13 09:03:37 +07:00
commit a54568b321
15 changed files with 917 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
build
.cache
test/build
test/.cache

88
CMakeLists.txt Executable file
View File

@ -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)

52
src/core/Core.cpp Executable file
View File

@ -0,0 +1,52 @@
#include <raylib.h>
#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();
}

115
src/core/Graphic.cpp Executable file
View File

@ -0,0 +1,115 @@
#include <imgui.h>
#include <rlImGui.h>
#include <rlgl.h>
#include "core/Panda.hpp"
#include "raylib.h"
#if PLATFORM_ANDROID
#include <imgui_impl_android.h>
#include <imgui_impl_opengl3.h>
#include <android_native_app_glue.h>
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<int>(),
// ini["chunk"]["height"].as<int>(),
// ini["tile"]["width"].as<int>(),
// ini["tile"]["height"].as<int>(),
// };
// }
// panda::TilemapItem panda::LoadTilemap(const char *file, panda::TilemapMetadata metadata, Texture texture)
// {
// return TilemapItem();
// }

52
src/core/Panda.hpp Executable file
View File

@ -0,0 +1,52 @@
#pragma once
#include <memory>
#include <string>
#include <vector>
#include <unordered_map>
#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();
}

8
src/core/Scene.hpp Executable file
View File

@ -0,0 +1,8 @@
#pragma once
class Scene {
public:
Scene() {}
virtual ~Scene() {}
virtual void update() {}
};

173
src/utils/Easing.cpp Executable file
View File

@ -0,0 +1,173 @@
#include "utils/Easing.hpp"
#include <cmath>
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));
}
}

36
src/utils/Easing.hpp Executable file
View File

@ -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);
}

49
src/utils/GridMap.hpp Executable file
View File

@ -0,0 +1,49 @@
#pragma once
#include "utils/RaylibDeprecated.hpp"
#include <cmath>
#include <raylib.h>
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;
};

78
src/utils/Pool.hpp Executable file
View File

@ -0,0 +1,78 @@
#pragma once
#include <list>
#include <vector>
#include <functional>
#include "utils/Random.hpp"
namespace panda
{
// template<typename T>
// 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<T> container;
// std::function<int()> custom;
// };
template<typename T>
class PoolPointer {
private:
std::list<T*> 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); }
};
}

57
src/utils/Random.cpp Executable file
View File

@ -0,0 +1,57 @@
#include "utils/Random.hpp"
#include <chrono>
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;
}

34
src/utils/Random.hpp Executable file
View File

@ -0,0 +1,34 @@
#pragma once
#include <cstdint>
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;
};
}

85
src/utils/RaylibDeprecated.cpp Executable file
View File

@ -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);
}
}
}
}

4
src/utils/RaylibDeprecated.hpp Executable file
View File

@ -0,0 +1,4 @@
#pragma once
#include <raylib.h>
void DrawTextureTiled(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, float scale, Color tint);

81
src/utils/TextureAtlas.cpp Executable file
View File

@ -0,0 +1,81 @@
#include <sstream>
#include <inicpp.h>
#include <raylib.h>
#include "core/Panda.hpp"
namespace
{
struct TextureAtlas
{
Texture2D texture;
std::unordered_map<std::string, panda::TextureAtlasItem> items;
};
}
static std::unordered_map<std::string, TextureAtlas> 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<const char*>());
std::string item;
while (std::getline(ss, item, ';')) {
atlas.items.insert({item, TextureAtlasItem{
ini[item]["x"].as<int>(),
ini[item]["y"].as<int>(),
ini[item]["w"].as<int>(),
ini[item]["h"].as<int>(),
ini[item]["px"].as<float>(),
ini[item]["py"].as<float>(),
}});
}
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);
}