Big refactor, shuffling a lot of files around

This commit is contained in:
2025-11-01 19:51:19 -04:00
parent 99b7d9f49d
commit 62cd94ca78
125 changed files with 4073 additions and 3011 deletions

47
src/util/filesystem_.cpp Normal file
View File

@@ -0,0 +1,47 @@
#include "filesystem_.h"
#include <SDL3/SDL_filesystem.h>
#include <SDL3/SDL_stdinc.h>
#include <filesystem>
namespace anm2ed::util::filesystem
{
std::string path_preferences_get()
{
char* preferencesPath = SDL_GetPrefPath("", "anm2ed");
std::string preferencesPathString = preferencesPath;
SDL_free(preferencesPath);
return preferencesPathString;
}
bool path_is_exist(const std::string& path)
{
std::error_code errorCode;
return std::filesystem::exists(path, errorCode) && ((void)std::filesystem::status(path, errorCode), !errorCode);
}
bool path_is_extension(const std::string& path, const std::string& extension)
{
auto e = std::filesystem::path(path).extension().string();
std::transform(e.begin(), e.end(), e.begin(), ::tolower);
return e == ("." + extension);
}
WorkingDirectory::WorkingDirectory(const std::string& path, bool isFile)
{
previous = std::filesystem::current_path();
if (isFile)
{
std::filesystem::path filePath = path;
std::filesystem::path parentPath = filePath.parent_path();
std::filesystem::current_path(parentPath);
}
else
std::filesystem::current_path(path);
}
WorkingDirectory::~WorkingDirectory()
{
std::filesystem::current_path(previous);
}
}

20
src/util/filesystem_.h Normal file
View File

@@ -0,0 +1,20 @@
#pragma once
#include <filesystem>
#include <string>
namespace anm2ed::util::filesystem
{
std::string path_preferences_get();
bool path_is_exist(const std::string&);
bool path_is_extension(const std::string&, const std::string&);
class WorkingDirectory
{
public:
std::filesystem::path previous;
WorkingDirectory(const std::string&, bool = false);
~WorkingDirectory();
};
}

24
src/util/map_.h Normal file
View File

@@ -0,0 +1,24 @@
#pragma once
#include <map>
namespace anm2ed::util::map
{
template <typename T> int next_id_get(std::map<int, T>& map)
{
int id = 0;
for (auto& [key, value] : map)
{
if (key != id) break;
++id;
}
return id;
}
template <typename T0, typename T1> T1* find(std::map<T0, T1>& map, T0 index)
{
return map.contains(index) ? &map[index] : nullptr;
}
}

81
src/util/math_.cpp Normal file
View File

@@ -0,0 +1,81 @@
#include "math.h"
#include <glm/ext/matrix_transform.hpp>
#include <string>
using namespace glm;
namespace anm2ed::util::math
{
constexpr auto FLOAT_FORMAT_MAX_DECIMALS = 7;
constexpr auto FLOAT_FORMAT_EPSILON = 1e-7f;
constexpr float FLOAT_FORMAT_POW10[] = {1.f, 10.f, 100.f, 1000.f, 10000.f, 100000.f, 1000000.f, 10000000.f};
float round_nearest_multiple(float value, float multiple)
{
return (roundf((value) / (multiple)) * (multiple));
}
int float_decimals_needed(float value)
{
for (int decimalCount = 0; decimalCount <= FLOAT_FORMAT_MAX_DECIMALS; ++decimalCount)
{
auto scale = FLOAT_FORMAT_POW10[decimalCount];
auto rounded = roundf(value * scale) / scale;
if (fabsf(value - rounded) < FLOAT_FORMAT_EPSILON) return decimalCount;
}
return FLOAT_FORMAT_MAX_DECIMALS;
}
const char* float_format_get(float value)
{
static std::string formatString{};
int decimalCount = float_decimals_needed(value);
formatString = (decimalCount == 0) ? "%.0f" : ("%." + std::to_string(decimalCount) + "f");
return formatString.c_str();
}
const char* vec2_format_get(vec2& value)
{
static std::string formatString{};
int decimalCountX = float_decimals_needed(value.x);
int decimalCountY = float_decimals_needed(value.y);
int decimalCount = (decimalCountX > decimalCountY) ? decimalCountX : decimalCountY;
formatString = (decimalCount == 0) ? "%.0f" : ("%." + std::to_string(decimalCount) + "f");
return formatString.c_str();
}
mat4 quad_model_get(vec2 size, vec2 position, vec2 pivot, vec2 scale, float rotation)
{
vec2 scaleAbsolute = glm::abs(scale);
vec2 scaleSign = glm::sign(scale);
vec2 pivotScaled = pivot * scaleAbsolute;
vec2 sizeScaled = size * scaleAbsolute;
mat4 model(1.0f);
model = glm::translate(model, vec3(position - pivotScaled, 0.0f));
model = glm::translate(model, vec3(pivotScaled, 0.0f));
model = glm::scale(model, vec3(scaleSign, 1.0f));
model = glm::rotate(model, glm::radians(rotation), vec3(0, 0, 1));
model = glm::translate(model, vec3(-pivotScaled, 0.0f));
model = glm::scale(model, vec3(sizeScaled, 1.0f));
return model;
}
mat4 quad_model_parent_get(vec2 position, vec2 pivot, vec2 scale, float rotation)
{
vec2 scaleSign = glm::sign(scale);
vec2 scaleAbsolute = glm::abs(scale);
float handedness = (scaleSign.x * scaleSign.y) < 0.0f ? -1.0f : 1.0f;
mat4 local(1.0f);
local = glm::translate(local, vec3(pivot, 0.0f));
local = glm::scale(local, vec3(scaleSign, 1.0f));
local = glm::rotate(local, glm::radians(rotation) * handedness, vec3(0, 0, 1));
local = glm::translate(local, vec3(-pivot, 0.0f));
local = glm::scale(local, vec3(scaleAbsolute, 1.0f));
return glm::translate(mat4(1.0f), vec3(position, 0.0f)) * local;
}
}

44
src/util/math_.h Normal file
View File

@@ -0,0 +1,44 @@
#pragma once
#include <array>
#include <glm/glm/mat4x4.hpp>
namespace anm2ed::util::math
{
template <typename T> constexpr T percent_to_unit(T value)
{
return value / 100.0f;
}
template <typename T> constexpr T unit_to_percent(T value)
{
return value * 100.0f;
}
constexpr float uint8_to_float(int value)
{
return (float)(value / 255.0f);
}
constexpr int float_to_uint8(float value)
{
return (int)(value * 255);
}
constexpr std::array<float, 16> uv_vertices_get(glm::vec2 uvMin, glm::vec2 uvMax)
{
return {0.0f, 0.0f, uvMin.x, uvMin.y, 1.0f, 0.0f, uvMax.x, uvMin.y,
1.0f, 1.0f, uvMax.x, uvMax.y, 0.0f, 1.0f, uvMin.x, uvMax.y};
}
float round_nearest_multiple(float, float);
int float_decimals_needed(float);
const char* float_format_get(float);
const char* vec2_format_get(glm::vec2&);
glm::mat4 quad_model_get(glm::vec2 = {}, glm::vec2 = {}, glm::vec2 = {}, glm::vec2 = glm::vec2(1.0f), float = {});
glm::mat4 quad_model_parent_get(glm::vec2 = {}, glm::vec2 = {}, glm::vec2 = glm::vec2(1.0f), float = {});
}

38
src/util/string_.cpp Normal file
View File

@@ -0,0 +1,38 @@
#include "string_.h"
#include <algorithm>
namespace anm2ed::util::string
{
std::string to_lower(const std::string& string)
{
std::string transformed = string;
std::ranges::transform(transformed, transformed.begin(), [](const unsigned char c) { return std::tolower(c); });
return transformed;
}
std::string backslash_replace(const std::string& string)
{
std::string transformed = string;
for (char& character : transformed)
if (character == '\\') character = '/';
return transformed;
}
std::string backslash_replace_to_lower(const std::string& string)
{
std::string transformed = string;
transformed = backslash_replace(transformed);
return to_lower(transformed);
}
std::string quote(const std::string& string)
{
return "\"" + string + "\"";
}
bool to_bool(const std::string& string)
{
return to_lower(string) == "true";
}
}

11
src/util/string_.h Normal file
View File

@@ -0,0 +1,11 @@
#pragma once
#include <string>
namespace anm2ed::util::string
{
std::string to_lower(const std::string&);
std::string backslash_replace(const std::string&);
std::string backslash_replace_to_lower(const std::string&);
bool to_bool(const std::string&);
}

16
src/util/time_.cpp Normal file
View File

@@ -0,0 +1,16 @@
#include "time_.h"
#include <chrono>
namespace anm2ed::util::time
{
std::string get(const char* format)
{
auto now = std::chrono::system_clock::now();
auto time = std::chrono::system_clock::to_time_t(now);
auto localTime = *std::localtime(&time);
std::ostringstream timeString;
timeString << std::put_time(&localTime, format);
return timeString.str();
}
}

10
src/util/time_.h Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
#include <string>
namespace anm2ed::util::time
{
constexpr auto SECOND_M = 60;
std::string get(const char*);
}

11
src/util/unordered_map_.h Normal file
View File

@@ -0,0 +1,11 @@
#pragma once
#include <unordered_map>
namespace anm2ed::util::unordered_map
{
template <typename T0, typename T1> T1* find(std::unordered_map<T0, T1>& map, T0 index)
{
return map.contains(index) ? &map[index] : nullptr;
}
}

63
src/util/vector_.h Normal file
View File

@@ -0,0 +1,63 @@
#pragma once
#include <algorithm>
#include <ranges>
#include <set>
#include <vector>
namespace anm2ed::util::vector
{
template <typename T> T* find(std::vector<T>& v, int index)
{
return index >= 0 && index < (int)v.size() ? &v[index] : nullptr;
}
template <typename T> std::set<int> move_indices(std::vector<T>& v, std::vector<int>& indices, int index)
{
if (indices.empty()) return {};
std::vector<int> sorted = indices;
std::sort(sorted.begin(), sorted.end());
sorted.erase(std::unique(sorted.begin(), sorted.end()), sorted.end());
// Determine if we are dragging items from below the target (insert before) or above (insert after)
bool insertAfter = !sorted.empty() && sorted.front() <= index;
std::vector<T> moveItems;
moveItems.reserve(sorted.size());
for (int i : sorted)
moveItems.push_back(std::move(v[i]));
for (auto i : sorted | std::views::reverse)
v.erase(v.begin() + i);
int originalSize = (int)v.size() + (int)sorted.size();
int reference = insertAfter ? index + 1 : index;
reference = std::clamp(reference, 0, originalSize);
int removedBeforeReference = 0;
for (int i : sorted)
if (i < reference) ++removedBeforeReference;
int insertPos = reference - removedBeforeReference;
insertPos = std::clamp(insertPos, 0, (int)v.size());
v.insert(v.begin() + insertPos, std::make_move_iterator(moveItems.begin()),
std::make_move_iterator(moveItems.end()));
std::set<int> moveIndices{};
for (int i = 0; i < (int)moveItems.size(); i++)
moveIndices.insert(insertPos + i);
return moveIndices;
}
template <typename T> bool in_bounds(std::vector<T>& v, int& index)
{
return index >= 0 || index <= (int)v.size() - 1;
}
template <typename T> void clamp_in_bounds(std::vector<T>& v, int& index)
{
index = std::clamp(index, 0, (int)v.size() - 1);
}
}

38
src/util/xml_.cpp Normal file
View File

@@ -0,0 +1,38 @@
#include "xml_.h"
#include "math_.h"
using namespace tinyxml2;
namespace anm2ed::util::xml
{
std::string document_to_string(XMLDocument& self)
{
XMLPrinter printer{};
self.Print(&printer);
return std::string(printer.CStr());
}
XMLError query_string_attribute(XMLElement* element, const char* attribute, std::string* out)
{
const char* temp = nullptr;
auto result = element->QueryStringAttribute(attribute, &temp);
if (result == XML_SUCCESS && temp) *out = temp;
return result;
}
XMLError query_path_attribute(XMLElement* element, const char* attribute, std::filesystem::path* out)
{
std::string temp{};
auto result = query_string_attribute(element, attribute, &temp);
if (result == XML_SUCCESS) *out = temp;
return result;
}
void query_color_attribute(XMLElement* element, const char* attribute, float& out)
{
int value{};
element->QueryIntAttribute(attribute, &value);
out = math::uint8_to_float(value);
}
}

14
src/util/xml_.h Normal file
View File

@@ -0,0 +1,14 @@
#pragma once
#include <filesystem>
#include <string>
#include <tinyxml2/tinyxml2.h>
namespace anm2ed::util::xml
{
std::string document_to_string(tinyxml2::XMLDocument&);
tinyxml2::XMLError query_string_attribute(tinyxml2::XMLElement*, const char*, std::string*);
tinyxml2::XMLError query_path_attribute(tinyxml2::XMLElement*, const char*, std::filesystem::path*);
void query_color_attribute(tinyxml2::XMLElement*, const char*, float&);
}