Big refactor, shuffling a lot of files around
This commit is contained in:
47
src/util/filesystem_.cpp
Normal file
47
src/util/filesystem_.cpp
Normal 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
20
src/util/filesystem_.h
Normal 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
24
src/util/map_.h
Normal 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
81
src/util/math_.cpp
Normal 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
44
src/util/math_.h
Normal 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
38
src/util/string_.cpp
Normal 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
11
src/util/string_.h
Normal 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
16
src/util/time_.cpp
Normal 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
10
src/util/time_.h
Normal 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
11
src/util/unordered_map_.h
Normal 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
63
src/util/vector_.h
Normal 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
38
src/util/xml_.cpp
Normal 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
14
src/util/xml_.h
Normal 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&);
|
||||
}
|
||||
Reference in New Issue
Block a user