Added fit, fixed the layer -1 bug finally, refactored here and there

This commit is contained in:
2025-09-09 17:51:17 -04:00
parent 9ad464a74a
commit b2cf67a823
23 changed files with 634 additions and 451 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -51,15 +51,17 @@ using namespace glm;
#define FLOAT_TO_U8(x) (static_cast<u8>((x) * 255.0f))
#define U8_TO_FLOAT(x) ((x) / 255.0f)
#define PERCENT_TO_UNIT(x) (x / 100.0f)
#define UNIT_TO_PERCENT(x) (x * 100.0f)
#define SECOND 1000.0f
#define TICK_DELAY (SECOND / 30.0)
#define UPDATE_DELAY (SECOND / 120.0)
#define ID_NONE -1
#define INDEX_NONE -1
#define VALUE_NONE -1
#define TIME_NONE -1.0f
#define GL_ID_NONE 0
#if defined(_WIN32)
#ifdef _WIN32
#define POPEN _popen
#define PCLOSE _pclose
#define PWRITE_MODE "wb"
@@ -71,7 +73,6 @@ using namespace glm;
#define PREAD_MODE "r"
#endif
static const GLuint GL_TEXTURE_INDICES[] = {0, 1, 2, 2, 3, 0};
static const vec4 COLOR_RED = {1.0f, 0.0f, 0.0f, 1.0f};
static const vec4 COLOR_GREEN = {0.0f, 1.0f, 0.0f, 1.0f};
@@ -104,6 +105,15 @@ static inline std::string string_quote(const std::string& string)
return "\"" + string + "\"";
}
static inline std::string string_to_lowercase(std::string string) {
std::transform
(
string.begin(), string.end(), string.begin(),
[](u8 character){ return std::tolower(character); }
);
return string;
}
#define FLOAT_FORMAT_MAX_DECIMALS 2
#define FLOAT_FORMAT_EPSILON 1e-6f
static constexpr f32 FLOAT_FORMAT_POW10[] = {1.f, 10.f, 100.f};
@@ -144,65 +154,6 @@ static inline const char* vec2_format_get(const vec2& value)
return formatString.c_str();
}
static inline std::string path_canonical_resolve
(
const std::string& inputPath,
const std::string& basePath = std::filesystem::current_path().string()
)
{
auto strings_equal_ignore_case = [](std::string a, std::string b) {
auto to_lower = [](unsigned char c) { return static_cast<char>(std::tolower(c)); };
std::transform(a.begin(), a.end(), a.begin(), to_lower);
std::transform(b.begin(), b.end(), b.begin(), to_lower);
return a == b;
};
std::string sanitized = inputPath;
std::replace(sanitized.begin(), sanitized.end(), '\\', '/');
std::filesystem::path normalizedPath = sanitized;
std::filesystem::path absolutePath = normalizedPath.is_absolute()
? normalizedPath
: (std::filesystem::path(basePath) / normalizedPath);
std::error_code error;
if (std::filesystem::exists(absolutePath, error)) {
std::error_code canonicalError;
std::filesystem::path canonicalPath = std::filesystem::weakly_canonical(absolutePath, canonicalError);
return (canonicalError ? absolutePath : canonicalPath).generic_string();
}
std::filesystem::path resolvedPath = absolutePath.root_path();
std::filesystem::path remainingPath = absolutePath.relative_path();
for (const std::filesystem::path& segment : remainingPath) {
std::filesystem::path candidatePath = resolvedPath / segment;
if (std::filesystem::exists(candidatePath, error)) {
resolvedPath = candidatePath;
continue;
}
bool matched = false;
if (std::filesystem::exists(resolvedPath, error) && std::filesystem::is_directory(resolvedPath, error)) {
for (const auto& directoryEntry : std::filesystem::directory_iterator(resolvedPath, error)) {
if (strings_equal_ignore_case(directoryEntry.path().filename().string(), segment.string())) {
resolvedPath = directoryEntry.path();
matched = true;
break;
}
}
}
if (!matched) return sanitized;
}
if (!std::filesystem::exists(resolvedPath, error))
return sanitized;
std::error_code canonicalError;
std::filesystem::path canonicalPath = std::filesystem::weakly_canonical(resolvedPath, canonicalError);
return (canonicalError ? resolvedPath : canonicalPath).generic_string();
};
static inline std::string working_directory_from_file_set(const std::string& path)
{
std::filesystem::path filePath = path;
@@ -237,7 +188,6 @@ static inline bool path_is_valid(const std::filesystem::path& pathCheck)
std::error_code ec;
if (fs::is_directory(pathCheck, ec)) return false;
if (fs::exists(pathCheck, ec) && !fs::is_regular_file(pathCheck, ec)) return false;
fs::path parentDir = pathCheck.has_parent_path() ? pathCheck.parent_path() : fs::path(".");
if (!fs::is_directory(parentDir, ec)) return false;
@@ -248,7 +198,7 @@ static inline bool path_is_valid(const std::filesystem::path& pathCheck)
testStream.close();
if (!existedBefore && isValid)
fs::remove(pathCheck, ec); // cleanup if we created it
fs::remove(pathCheck, ec);
return isValid;
}
@@ -343,6 +293,39 @@ static inline void map_insert_shift(std::map<int, T>& map, s32 index, const T& v
map[insertIndex] = value;
}
static inline mat4 quad_model_get(vec2 size = {}, vec2 position = {}, vec2 pivot = {}, vec2 scale = vec2(1.0f), f32 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;
}
static inline mat4 quad_model_parent_get(vec2 position = {}, vec2 pivot = {}, vec2 scale = vec2(1.0f), f32 rotation = {})
{
vec2 scaleSign = glm::sign(scale);
vec2 scaleAbsolute = glm::abs(scale);
f32 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;
}
#define DEFINE_ENUM_TO_STRING_FUNCTION(function, array, count) \
static inline std::string function(s32 index) \
{ \

View File

@@ -8,101 +8,103 @@ const u8 TEXTURE_ATLAS[] =
{
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xa0,
0x02, 0x03, 0x00, 0x00, 0x00, 0x8e, 0x1e, 0x81, 0x1f, 0x00, 0x00, 0x00,
0x04, 0x03, 0x00, 0x00, 0x00, 0x01, 0x5e, 0x74, 0xbf, 0x00, 0x00, 0x00,
0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b,
0x12, 0x01, 0xd2, 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x0c, 0x50, 0x4c,
0x54, 0x45, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x60,
0x60, 0x60, 0x58, 0xe6, 0xdc, 0x65, 0x00, 0x00, 0x00, 0x02, 0x74, 0x52,
0x4e, 0x53, 0x00, 0x00, 0x76, 0x93, 0xcd, 0x38, 0x00, 0x00, 0x04, 0x15,
0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xe5, 0xd3, 0xb1, 0x6a, 0x1c, 0x47,
0x1c, 0xc7, 0xf1, 0x2f, 0xb3, 0xc4, 0x2c, 0xe3, 0x63, 0xaf, 0x4b, 0x91,
0x6a, 0x49, 0xb5, 0xcc, 0x1d, 0xf6, 0x81, 0x1b, 0xb1, 0x36, 0x56, 0x1e,
0x21, 0x75, 0xde, 0xc0, 0x79, 0x8a, 0xc1, 0x95, 0x48, 0x61, 0x5c, 0x24,
0xfd, 0x20, 0x1c, 0x98, 0xfc, 0x77, 0xd1, 0x2d, 0x49, 0x63, 0x14, 0x81,
0xb6, 0x34, 0x41, 0xe4, 0x19, 0x5c, 0x8a, 0xb3, 0x09, 0x02, 0x37, 0xe1,
0x72, 0xf8, 0x92, 0x19, 0x5d, 0xb4, 0x91, 0x6e, 0x94, 0x20, 0xab, 0x48,
0xe1, 0x1f, 0x0c, 0x03, 0xf7, 0xe1, 0xfe, 0x33, 0xf3, 0xdf, 0x19, 0xae,
0x8f, 0x76, 0x5c, 0x44, 0x59, 0x28, 0x3a, 0x34, 0x00, 0x22, 0xe8, 0xd6,
0xb4, 0x00, 0x18, 0x0f, 0xda, 0xa1, 0xff, 0x60, 0x86, 0x72, 0xda, 0x96,
0x5a, 0x3c, 0x2c, 0x44, 0x89, 0xd8, 0x00, 0x63, 0x43, 0x89, 0x46, 0xbb,
0x92, 0x00, 0x22, 0x46, 0xc4, 0xc7, 0x52, 0xe6, 0x27, 0x87, 0xc6, 0xb8,
0xf8, 0x43, 0x66, 0x89, 0xb3, 0xb2, 0x68, 0x23, 0x8e, 0x0a, 0x5f, 0x4d,
0x61, 0x07, 0x65, 0x09, 0xa5, 0x06, 0x50, 0xae, 0x2a, 0x21, 0xaf, 0x94,
0x65, 0x77, 0xd1, 0xac, 0x36, 0xd0, 0x51, 0x69, 0x1b, 0x61, 0x52, 0xf4,
0xec, 0xbe, 0x3f, 0x5e, 0x51, 0xb7, 0xe8, 0xb7, 0x62, 0xa9, 0x0c, 0x11,
0x6a, 0x0d, 0xd9, 0x7a, 0xdd, 0x73, 0x3a, 0x41, 0xf3, 0x06, 0xb4, 0xc7,
0x05, 0xd0, 0x1a, 0x46, 0xeb, 0xd5, 0x49, 0xed, 0x74, 0xab, 0x37, 0x07,
0x8f, 0x50, 0x34, 0xf0, 0xe0, 0xc1, 0xbb, 0x99, 0xb1, 0xca, 0x07, 0x88,
0x07, 0x0c, 0xbb, 0x52, 0x1e, 0x38, 0x39, 0xe9, 0x2f, 0x00, 0x11, 0x6a,
0x91, 0x16, 0x07, 0x3c, 0x98, 0x51, 0xf7, 0x59, 0xab, 0xb7, 0x9a, 0x48,
0xcf, 0x6d, 0x53, 0xb7, 0xc3, 0x7c, 0x29, 0x22, 0x14, 0x22, 0xdd, 0x58,
0xe4, 0x0c, 0x86, 0xc4, 0x2d, 0xdf, 0x85, 0xd7, 0x85, 0xd3, 0xdd, 0xa5,
0x32, 0x7a, 0xbd, 0x74, 0x39, 0x94, 0xba, 0x1f, 0xb6, 0x48, 0x26, 0xd2,
0xd7, 0xeb, 0x45, 0x1b, 0xa0, 0xc6, 0xb4, 0x43, 0x99, 0xe3, 0xf7, 0x76,
0xb2, 0x6e, 0x4e, 0x03, 0x84, 0x6f, 0x73, 0x01, 0x0f, 0x7f, 0xfb, 0xf9,
0xed, 0xe4, 0xfd, 0xfc, 0x34, 0x57, 0xb6, 0xac, 0x94, 0x1b, 0xa0, 0xfd,
0x7c, 0xaf, 0x3e, 0x5d, 0x1e, 0x4f, 0xfe, 0x82, 0x59, 0xa5, 0xed, 0x00,
0x3b, 0xd3, 0x9d, 0xe9, 0xc4, 0x10, 0x4a, 0x51, 0x19, 0x06, 0x50, 0xda,
0xd9, 0xba, 0x59, 0xb7, 0x39, 0xda, 0xd5, 0x7e, 0x3c, 0x2c, 0x9e, 0x75,
0x45, 0xaf, 0xe7, 0x6b, 0x97, 0x73, 0xef, 0xa5, 0x76, 0xbb, 0x03, 0xb0,
0x68, 0x50, 0xf3, 0xa5, 0xbd, 0xcb, 0x8f, 0xcf, 0x0a, 0xb7, 0x3c, 0xde,
0x6e, 0x49, 0x3b, 0xdd, 0x19, 0x8b, 0x8c, 0x12, 0x4d, 0xd4, 0x8e, 0x7a,
0x7e, 0xc6, 0x7f, 0x47, 0xd9, 0x30, 0x92, 0xef, 0x23, 0x8c, 0x58, 0x4e,
0x7d, 0x53, 0xb9, 0x30, 0x80, 0x15, 0x18, 0x4f, 0x1c, 0x22, 0x94, 0x10,
0x07, 0x64, 0x2b, 0x62, 0x36, 0x17, 0xba, 0x54, 0xb2, 0x57, 0x42, 0x0e,
0xd3, 0x55, 0x28, 0x11, 0x41, 0xb7, 0xb5, 0x03, 0xd9, 0x23, 0xc2, 0xe1,
0x8c, 0xfc, 0xed, 0xc3, 0x32, 0x74, 0x36, 0x5c, 0xb4, 0x92, 0x85, 0x2d,
0x01, 0xd4, 0xa2, 0xa7, 0xea, 0x8a, 0xaa, 0x2a, 0xba, 0xca, 0xf4, 0xf8,
0x92, 0x4d, 0xa9, 0xbb, 0x8d, 0xc5, 0x3f, 0x7d, 0x6a, 0x44, 0x44, 0x0c,
0x78, 0xd4, 0x41, 0x2c, 0xc5, 0xbd, 0x03, 0x18, 0xc0, 0xfa, 0x52, 0xdb,
0x58, 0x8a, 0xc3, 0x97, 0x30, 0x94, 0xda, 0xf7, 0x46, 0xc8, 0x4b, 0xd4,
0x1e, 0x8b, 0xd7, 0x5c, 0x2c, 0x5e, 0x5b, 0x69, 0x8d, 0x27, 0x07, 0x65,
0xd5, 0xc4, 0x32, 0x6c, 0xd7, 0x8b, 0x33, 0x1e, 0x4a, 0x8c, 0xd7, 0xcf,
0x60, 0x38, 0xa0, 0x17, 0x1b, 0xfe, 0x11, 0xc1, 0xc1, 0xd0, 0x92, 0xf0,
0x8f, 0x4d, 0xa9, 0xc7, 0x16, 0x86, 0x26, 0x22, 0xde, 0xf8, 0x7d, 0xab,
0xab, 0x7d, 0xfb, 0x28, 0xd1, 0xf6, 0x9b, 0xc4, 0x02, 0x28, 0x20, 0x73,
0xc0, 0x08, 0x78, 0x04, 0xea, 0xd7, 0x4e, 0x9d, 0x83, 0x85, 0x79, 0x80,
0x57, 0xc0, 0x12, 0xb2, 0x43, 0xa7, 0xcf, 0xc1, 0x31, 0x69, 0xa1, 0xee,
0x3c, 0x64, 0x0b, 0x0b, 0x0b, 0x67, 0x44, 0xfa, 0x4c, 0xc4, 0xeb, 0x37,
0x90, 0xf9, 0xa9, 0x87, 0xb1, 0x74, 0x28, 0xdd, 0x89, 0x88, 0xd3, 0x22,
0xa2, 0x7b, 0x28, 0x7e, 0xbf, 0xdf, 0xc2, 0x63, 0x39, 0x23, 0x57, 0xbd,
0x39, 0x07, 0x3f, 0x9e, 0xcf, 0x5d, 0xbd, 0x9c, 0xf7, 0xf0, 0x4b, 0xd3,
0x53, 0x66, 0x9d, 0xb6, 0x9c, 0x4e, 0x50, 0x2e, 0x80, 0x91, 0x03, 0x4b,
0xb6, 0x3f, 0x07, 0xfb, 0xea, 0xb5, 0xb2, 0x54, 0x15, 0xca, 0x8e, 0x60,
0x56, 0xca, 0x01, 0x14, 0xfe, 0x08, 0x45, 0x09, 0xe7, 0xc0, 0x78, 0xbd,
0x3e, 0x2b, 0xe5, 0x10, 0x6a, 0x99, 0x91, 0x8f, 0x2c, 0x10, 0x00, 0x46,
0xcc, 0x66, 0x66, 0x7e, 0x08, 0x5a, 0x7a, 0x72, 0x05, 0x10, 0xd6, 0x20,
0x42, 0x75, 0xff, 0x25, 0x28, 0x81, 0x3c, 0x07, 0x54, 0xd8, 0x95, 0x8d,
0x80, 0x39, 0x05, 0x9a, 0x77, 0xa3, 0xc2, 0x0d, 0x10, 0xd6, 0xa0, 0x0e,
0xb0, 0x7b, 0xd2, 0x43, 0x80, 0x70, 0x72, 0xcb, 0x87, 0x45, 0x59, 0x00,
0x76, 0x12, 0x10, 0xa9, 0x45, 0x5b, 0x50, 0xad, 0xe9, 0xd1, 0x1d, 0x03,
0x28, 0x87, 0xf6, 0x57, 0xc1, 0x78, 0xd0, 0x16, 0x2d, 0x36, 0x01, 0x06,
0xb4, 0xf8, 0x01, 0x36, 0x04, 0x4d, 0x8f, 0x16, 0xb1, 0x01, 0xb4, 0x48,
0x17, 0x46, 0x5c, 0x23, 0x13, 0x09, 0xd0, 0x5e, 0x06, 0x40, 0x49, 0x13,
0xe0, 0xe8, 0x9f, 0x40, 0xcc, 0xd8, 0xa3, 0xa5, 0xe9, 0x03, 0x8c, 0x97,
0xc7, 0x67, 0xa1, 0x57, 0xf1, 0x5a, 0xc7, 0xed, 0xca, 0xd1, 0xa5, 0xc5,
0x8d, 0xff, 0x7b, 0xbb, 0x4d, 0x9f, 0x80, 0x1a, 0xf4, 0x11, 0x09, 0x98,
0xc2, 0xb8, 0x87, 0x6c, 0xb5, 0xdb, 0x33, 0x3e, 0x1b, 0x20, 0x95, 0xb8,
0xf8, 0xb5, 0x59, 0x6f, 0xd2, 0x43, 0x8c, 0x72, 0x0c, 0x10, 0x96, 0xd8,
0x82, 0x85, 0x48, 0xf3, 0x61, 0xc0, 0xc7, 0x02, 0x46, 0xd2, 0xa0, 0x44,
0x5c, 0x12, 0xf4, 0x53, 0xe7, 0xd3, 0xa0, 0x5c, 0x95, 0x84, 0x4a, 0x39,
0x7d, 0x03, 0x90, 0x8b, 0xdc, 0x1c, 0x6e, 0xb3, 0x78, 0xfa, 0x1c, 0xe9,
0x93, 0xa7, 0x7b, 0x95, 0xee, 0xee, 0xff, 0xff, 0xcd, 0x6b, 0x91, 0x36,
0x09, 0x85, 0x48, 0x97, 0x84, 0x4c, 0xa4, 0x4f, 0xbe, 0x0f, 0x16, 0x0d,
0x69, 0xa8, 0x5b, 0xd2, 0x50, 0x74, 0x49, 0x88, 0x3f, 0x6d, 0x3d, 0xe7,
0x54, 0x44, 0x48, 0xc6, 0x88, 0xfc, 0x40, 0x22, 0x9f, 0x0a, 0x88, 0x4d,
0xc0, 0xd7, 0x16, 0x94, 0x67, 0x2b, 0x9f, 0xc4, 0x32, 0x26, 0x51, 0xe9,
0x3b, 0x80, 0x3b, 0xcf, 0xb7, 0xe0, 0xab, 0x2f, 0x01, 0x78, 0xb1, 0x05,
0x4f, 0xbe, 0x00, 0xa0, 0xda, 0x82, 0xef, 0x89, 0xd1, 0x5c, 0xc9, 0x9d,
0x6f, 0x37, 0xb3, 0xbd, 0x0a, 0x9b, 0x55, 0xd5, 0x55, 0xf8, 0x8c, 0x4d,
0x5c, 0x02, 0x92, 0xdb, 0x7a, 0xc2, 0x26, 0xd5, 0x6d, 0x61, 0x28, 0xad,
0x6f, 0x0d, 0x0e, 0x50, 0xf6, 0xa6, 0x00, 0xb7, 0x82, 0xad, 0x73, 0x55,
0xb7, 0x85, 0xeb, 0xdb, 0xae, 0xaf, 0xfb, 0x50, 0xca, 0x0e, 0xf3, 0x65,
0x78, 0x4e, 0xfa, 0x32, 0xe0, 0xd2, 0xc7, 0x80, 0x6a, 0x98, 0x92, 0xdb,
0x7a, 0x01, 0x89, 0x8b, 0x95, 0xbc, 0xd4, 0x78, 0xd2, 0xcf, 0x00, 0x93,
0x7e, 0x38, 0xa0, 0x86, 0xa7, 0x96, 0x78, 0x9c, 0xff, 0xfe, 0x9c, 0xff,
0x04, 0xe2, 0xd8, 0x90, 0xc1, 0x18, 0xe1, 0xf4, 0x9b, 0x00, 0x00, 0x00,
0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
0x12, 0x01, 0xd2, 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x0f, 0x50, 0x4c,
0x54, 0x45, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x60, 0x60, 0x60, 0xff,
0xff, 0xff, 0x60, 0x60, 0x60, 0x15, 0x68, 0x14, 0xc2, 0x00, 0x00, 0x00,
0x03, 0x74, 0x52, 0x4e, 0x53, 0x00, 0x00, 0x00, 0xfa, 0x76, 0xc4, 0xde,
0x00, 0x00, 0x04, 0x17, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xed, 0x96,
0x0d, 0x6e, 0xe3, 0x3a, 0x0c, 0x84, 0x07, 0x18, 0x9e, 0xe0, 0xdd, 0xe0,
0xdd, 0x80, 0xc0, 0xf0, 0x00, 0x04, 0xc4, 0xfb, 0x9f, 0x69, 0x61, 0xc9,
0x82, 0xbc, 0x75, 0xda, 0xd8, 0x1b, 0xb4, 0x01, 0x16, 0x3b, 0x40, 0x2b,
0xd1, 0xd1, 0x17, 0xfe, 0x88, 0xb2, 0x82, 0x3f, 0x91, 0x84, 0x87, 0xa2,
0xa3, 0xab, 0x45, 0x5f, 0x75, 0x58, 0x2f, 0xf5, 0x21, 0x29, 0xe5, 0x61,
0xbd, 0xe4, 0x87, 0x2f, 0x54, 0x05, 0x60, 0xfd, 0x39, 0x20, 0x07, 0x3b,
0x39, 0x96, 0x34, 0x49, 0x60, 0x37, 0x17, 0x50, 0x14, 0xc0, 0xdd, 0x95,
0xd4, 0xa7, 0x6b, 0x85, 0x44, 0x75, 0xf9, 0x0a, 0x89, 0x0a, 0xd3, 0x00,
0x28, 0xe1, 0xb0, 0xc0, 0x1c, 0x38, 0xda, 0xf4, 0x1d, 0x90, 0x34, 0x2c,
0x39, 0x9d, 0x3d, 0x7a, 0x5b, 0x0b, 0x56, 0x48, 0x27, 0x80, 0x02, 0x9d,
0xe8, 0x72, 0xfa, 0x58, 0x60, 0xd5, 0xa4, 0xa8, 0xfc, 0x1d, 0x88, 0x6e,
0xc9, 0x8f, 0x40, 0xa0, 0x65, 0x07, 0xaa, 0x45, 0x6d, 0x80, 0x8d, 0xda,
0xa9, 0x65, 0xf7, 0x48, 0xa7, 0x70, 0x00, 0x4c, 0x10, 0x30, 0x88, 0xbe,
0x1e, 0xcd, 0x19, 0x00, 0x34, 0xb3, 0xef, 0x98, 0x30, 0x01, 0x4c, 0x20,
0xb7, 0xf5, 0x99, 0x26, 0x01, 0x52, 0x42, 0xc7, 0x7d, 0x3e, 0x02, 0x4d,
0xd1, 0x1d, 0x98, 0x59, 0x99, 0x81, 0x3d, 0x0c, 0xf9, 0x04, 0xd6, 0xc6,
0xcd, 0x2a, 0x51, 0x8e, 0xae, 0xdc, 0x74, 0x06, 0x66, 0x6b, 0x98, 0xba,
0x72, 0x35, 0x8d, 0x99, 0x01, 0x30, 0xe5, 0xf8, 0xa7, 0xe7, 0xcd, 0x87,
0xc4, 0x0f, 0x89, 0x8e, 0x87, 0x32, 0x29, 0x4f, 0xf6, 0x67, 0x21, 0xaf,
0xe4, 0xd1, 0x34, 0x5a, 0xa0, 0x24, 0xa9, 0xe6, 0xb9, 0x38, 0x6b, 0x96,
0x17, 0x81, 0x8d, 0xda, 0x40, 0x40, 0xf1, 0x45, 0x28, 0xaa, 0x2a, 0x09,
0xf0, 0x4e, 0x03, 0xca, 0x4f, 0x82, 0xb1, 0x51, 0x7e, 0x53, 0x55, 0x93,
0x72, 0x02, 0x26, 0x80, 0xc3, 0xa6, 0x83, 0x58, 0x62, 0x54, 0x35, 0xef,
0x83, 0xa2, 0xf9, 0x0e, 0xac, 0x73, 0xe2, 0xff, 0xd1, 0xff, 0xa7, 0x2f,
0x07, 0xd1, 0x5a, 0x44, 0x4b, 0x46, 0x35, 0x55, 0xf3, 0xf9, 0x8d, 0xf3,
0x9c, 0xc8, 0x29, 0x39, 0x85, 0x29, 0x25, 0xe9, 0x6e, 0x6a, 0x5e, 0x8a,
0x62, 0x0c, 0xc0, 0xe6, 0x39, 0x39, 0x03, 0xe6, 0xcc, 0xed, 0x8f, 0x41,
0x01, 0x33, 0xa4, 0x75, 0x4e, 0x4e, 0x21, 0x81, 0x90, 0xe0, 0x30, 0x29,
0xaa, 0xf6, 0xa4, 0xa5, 0xcd, 0x76, 0xd4, 0xa3, 0xa4, 0x2d, 0x80, 0x96,
0x80, 0x54, 0x55, 0xa3, 0xac, 0x6c, 0xe1, 0x1d, 0xda, 0x80, 0xb3, 0x9a,
0x14, 0x00, 0xa8, 0xaa, 0x7d, 0xe3, 0x82, 0xde, 0xd0, 0x84, 0x52, 0x14,
0x4e, 0x3a, 0xb7, 0x46, 0x32, 0xcd, 0x51, 0xdd, 0xce, 0xd1, 0x1a, 0xcf,
0x9a, 0x4f, 0x1a, 0x76, 0xd5, 0xb0, 0x5e, 0x6d, 0x6f, 0xfa, 0x1a, 0x2f,
0x49, 0x5a, 0xe3, 0x0a, 0x8d, 0x2e, 0xba, 0xd6, 0xd8, 0x55, 0xb9, 0xfa,
0xbd, 0x8f, 0x2b, 0x79, 0x62, 0x88, 0x38, 0xc8, 0x2a, 0x31, 0xf5, 0xf1,
0x25, 0xcc, 0x3e, 0x73, 0xdf, 0x81, 0xf1, 0x51, 0x56, 0xce, 0x10, 0x16,
0x20, 0xa5, 0xed, 0xc1, 0x6d, 0x00, 0x0e, 0x40, 0xc8, 0x00, 0x78, 0x4b,
0x0b, 0x62, 0xb6, 0xc0, 0x7c, 0x71, 0x11, 0x40, 0x1b, 0x9e, 0xa6, 0xd8,
0x94, 0x00, 0x3d, 0x80, 0x46, 0xa7, 0xa3, 0x05, 0xe8, 0xec, 0xee, 0x06,
0xf0, 0x21, 0xa4, 0x50, 0x38, 0x20, 0x77, 0x3a, 0xa9, 0x29, 0x0a, 0x1d,
0x00, 0x40, 0xb5, 0x63, 0x48, 0x6c, 0x6a, 0x78, 0x0c, 0x38, 0xe4, 0xec,
0xd4, 0x0a, 0x69, 0x3a, 0x78, 0x18, 0x92, 0x28, 0xe7, 0xe8, 0x2c, 0xef,
0x00, 0xdd, 0x81, 0xee, 0xe0, 0x9c, 0xb4, 0xc9, 0x21, 0x29, 0xf7, 0x5d,
0x71, 0xcc, 0xfa, 0x91, 0x31, 0x8c, 0x73, 0x59, 0x5d, 0xd2, 0xda, 0xce,
0xb9, 0xa5, 0xf2, 0xf6, 0xb8, 0xc9, 0xb8, 0x01, 0x3e, 0x01, 0x5f, 0x80,
0xd0, 0x75, 0x6e, 0x8d, 0xe5, 0xe1, 0x18, 0x92, 0x35, 0x7f, 0xd4, 0x7c,
0x73, 0x22, 0xdf, 0x00, 0xd1, 0x01, 0xb1, 0x8f, 0x96, 0x2f, 0xb4, 0xf7,
0xab, 0xf2, 0x35, 0x25, 0x86, 0x4c, 0xd8, 0x95, 0xc3, 0x1e, 0x03, 0xb3,
0x05, 0x40, 0x3f, 0x05, 0xab, 0x9a, 0x40, 0x8e, 0x07, 0xbb, 0x6d, 0x21,
0x01, 0x3a, 0x02, 0x02, 0xc0, 0x50, 0x0e, 0x37, 0xb1, 0x7f, 0x68, 0x6d,
0x8c, 0x68, 0x12, 0xa8, 0x4d, 0x39, 0xef, 0x61, 0x87, 0x5a, 0xec, 0x61,
0x39, 0x53, 0x3e, 0x1c, 0x28, 0x46, 0xc4, 0x0a, 0x68, 0x08, 0x98, 0x13,
0x25, 0xba, 0x5a, 0x39, 0x4b, 0x39, 0x1c, 0xa8, 0x46, 0xb6, 0x4c, 0xf0,
0x77, 0xc0, 0x51, 0x2a, 0x95, 0x60, 0x2a, 0xa9, 0x3a, 0x9c, 0x52, 0xe4,
0x28, 0x89, 0x05, 0x20, 0x5f, 0xbf, 0x60, 0x28, 0x4c, 0x80, 0x92, 0xd4,
0xbc, 0xc7, 0xc6, 0xe9, 0x20, 0xbd, 0xed, 0x95, 0xa1, 0xef, 0x03, 0x30,
0x12, 0x06, 0xb1, 0x01, 0x23, 0x53, 0x9f, 0x0e, 0x88, 0x4d, 0x47, 0x00,
0x40, 0x75, 0x75, 0x20, 0x84, 0x51, 0x0c, 0x9b, 0x0e, 0x30, 0x34, 0x80,
0xb5, 0x55, 0x06, 0x03, 0xa5, 0xea, 0x00, 0x24, 0xe5, 0x00, 0x88, 0xa1,
0x95, 0xc3, 0x11, 0x70, 0x56, 0xcc, 0xae, 0xc6, 0x00, 0x1c, 0x43, 0x9c,
0x55, 0xf2, 0x05, 0xf4, 0xc7, 0x7b, 0x87, 0x2b, 0xca, 0x90, 0x68, 0xc2,
0x19, 0x58, 0x39, 0x00, 0x36, 0x01, 0xab, 0xcc, 0xc4, 0x41, 0x9c, 0x3b,
0xed, 0xf8, 0x51, 0xd1, 0xd7, 0xdc, 0xfc, 0x12, 0xb0, 0x20, 0x25, 0x56,
0x5b, 0x53, 0x49, 0xe5, 0xa8, 0xc6, 0x27, 0x00, 0xf7, 0xfd, 0xf0, 0x67,
0xc0, 0x7a, 0xaf, 0x0c, 0x40, 0x7e, 0x0d, 0xa0, 0xb0, 0x03, 0xf2, 0x2f,
0x80, 0x95, 0xb8, 0x22, 0x27, 0x20, 0x5f, 0x40, 0xb7, 0x63, 0x8e, 0x2b,
0x87, 0x71, 0x14, 0x27, 0xa0, 0xfc, 0x0a, 0x58, 0x8d, 0x10, 0x13, 0x88,
0x4f, 0x81, 0xa3, 0x4a, 0xbe, 0x03, 0x91, 0x2b, 0xa4, 0x2a, 0x45, 0xd5,
0xec, 0xa5, 0xf5, 0x42, 0x3e, 0x94, 0x55, 0x91, 0x9f, 0x26, 0xdd, 0x81,
0x8f, 0x65, 0x8d, 0xc4, 0x25, 0xc0, 0x84, 0x59, 0xac, 0x6b, 0x00, 0xc7,
0xc2, 0x4a, 0xcc, 0x6e, 0xb7, 0x31, 0xaf, 0x7a, 0x04, 0x5c, 0xd4, 0x4a,
0xfa, 0xb6, 0xea, 0x83, 0xf2, 0xfc, 0xd5, 0x8f, 0x81, 0x99, 0xc1, 0x53,
0xa0, 0xa9, 0x2b, 0x7e, 0x0e, 0xc0, 0x3f, 0xe0, 0xef, 0x00, 0x28, 0xe9,
0x0e, 0x40, 0x6d, 0xba, 0x01, 0xc8, 0x29, 0xc8, 0x6f, 0x00, 0xa0, 0xc0,
0xeb, 0x00, 0x1d, 0x14, 0xa0, 0xef, 0x00, 0xf4, 0x40, 0xdf, 0x0f, 0xbc,
0x21, 0xe9, 0x97, 0xf7, 0x61, 0xed, 0xf4, 0xf7, 0xf4, 0xd2, 0x22, 0xfe,
0x9d, 0x69, 0x53, 0x57, 0x5e, 0x02, 0x96, 0x8b, 0xc0, 0x25, 0x60, 0xb9,
0x48, 0x5c, 0xb9, 0x1f, 0x96, 0x8b, 0xc0, 0x1d, 0xc0, 0xa4, 0xbc, 0x05,
0xa0, 0x05, 0x2e, 0x03, 0x6b, 0xd1, 0x93, 0x6b, 0xf7, 0xba, 0x24, 0xdd,
0x21, 0xa8, 0x2e, 0xbf, 0xb1, 0x1e, 0x00, 0x2e, 0x13, 0x94, 0xaf, 0xc9,
0x15, 0xc9, 0xef, 0x65, 0x4e, 0x3f, 0xcd, 0xbf, 0x96, 0x4e, 0xc6, 0x73,
0x07, 0xb7, 0x5c, 0xe8, 0x64, 0xde, 0x71, 0x70, 0xb6, 0x5f, 0x07, 0xf4,
0xe4, 0xc1, 0xcb, 0x00, 0xfd, 0xfc, 0xe4, 0xcd, 0x80, 0x9e, 0x3c, 0x7a,
0x27, 0x40, 0xff, 0x4e, 0xe0, 0xfd, 0x49, 0xbf, 0xbf, 0x35, 0xbe, 0xfd,
0x3c, 0xbc, 0xfd, 0x4c, 0x43, 0x27, 0xf3, 0xf6, 0x8b, 0xec, 0x96, 0x0b,
0xdd, 0x7f, 0x19, 0xdf, 0x7f, 0xdd, 0xbf, 0x7e, 0xa1, 0xbc, 0x7e, 0x65,
0xad, 0x4b, 0xf1, 0x85, 0x6b, 0xf7, 0x17, 0x03, 0x7b, 0x85, 0x59, 0xd8,
0xe0, 0xeb, 0xee, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae,
0x42, 0x60, 0x82
};
const u32 TEXTURE_ATLAS_LENGTH = (u32)std::size(TEXTURE_ATLAS);

View File

@@ -305,7 +305,7 @@ bool anm2_serialize(Anm2* self, const std::string& path)
return true;
}
bool anm2_deserialize(Anm2* self, const std::string& path)
bool anm2_deserialize(Anm2* self, const std::string& path, bool isTextures)
{
XMLDocument xmlDocument;
XMLError xmlError;
@@ -330,7 +330,13 @@ bool anm2_deserialize(Anm2* self, const std::string& path)
bool isFirstAnimationDone = false;
std::string defaultAnimation{};
if (!self || path.empty()) return false;
if (!self) return false;
if (path.empty())
{
log_error(ANM2_EMPTY_ERROR);
return false;
}
anm2_new(self);
@@ -338,7 +344,7 @@ bool anm2_deserialize(Anm2* self, const std::string& path)
if (xmlError != XML_SUCCESS)
{
log_error(std::format(ANM2_READ_ERROR, xmlDocument.ErrorStr()));
log_error(std::format(ANM2_PARSE_ERROR, path, xmlDocument.ErrorStr()));
return false;
}
@@ -590,8 +596,17 @@ bool anm2_deserialize(Anm2* self, const std::string& path)
xmlAttribute = xmlAttribute->Next();
}
if (anm2Element == ANM2_ELEMENT_SPRITESHEET)
if (anm2Element == ANM2_ELEMENT_SPRITESHEET && isTextures)
{
// Spritesheet paths from Isaac Rebirth are made with the assumption that the paths are case-insensitive (developed on Windows)
// However when using the resource dumper, the spritesheet paths are all lowercase (on Linux anyways)
// If the check doesn't work, set the spritesheet path to lowercase
// If it doesn't work beyond that then that's on the user :^)
if (!path_exists(spritesheet->path))
spritesheet->path = string_to_lowercase(spritesheet->path);
texture_from_path_init(&spritesheet->texture, spritesheet->path);
}
xmlChild = xmlElement->FirstChildElement();
@@ -617,20 +632,16 @@ bool anm2_deserialize(Anm2* self, const std::string& path)
}
}
// Set default animation ID
for (auto& [id, animation] : self->animations)
if (animation.name == defaultAnimation)
self->defaultAnimationID = id;
// Copy texture data to pixels (used for snapshots)
anm2_spritesheet_texture_pixels_download(self);
if (isTextures) anm2_spritesheet_texture_pixels_download(self);
// Read
log_info(std::format(ANM2_READ_INFO, path));
// Return to old working directory
std::filesystem::current_path(workingPath);
log_info(std::format(ANM2_READ_INFO, path));
return true;
}
@@ -1189,9 +1200,61 @@ void anm2_spritesheet_texture_pixels_download(Anm2* self)
if (texture.id != GL_ID_NONE && !texture.isInvalid)
{
spritesheet.pixels.resize(texture.size.x * texture.size.y * texture.channels);
size_t bufferSize = (size_t)texture.size.x * (size_t)texture.size.y * (size_t)texture.channels;
spritesheet.pixels.resize(bufferSize);
glBindTexture(GL_TEXTURE_2D, texture.id);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, spritesheet.pixels.data());
}
}
}
vec4 anm2_animation_rect_get(Anm2* self, Anm2Reference* reference, bool isRootTransform)
{
f32 minX = std::numeric_limits<f32>::infinity();
f32 minY = std::numeric_limits<f32>::infinity();
f32 maxX = -std::numeric_limits<f32>::infinity();
f32 maxY = -std::numeric_limits<f32>::infinity();
bool any = false;
Anm2Frame frame;
Anm2Frame root;
Anm2Animation* animation = anm2_animation_from_reference(self, reference);
if (!animation) return vec4(-1.0f);
for (f32 t = 0.0f; t <= animation->frameNum; t += 1.0f)
{
for (const auto& [id, _] : animation->layerAnimations)
{
anm2_frame_from_time(self, &frame, {reference->animationID, ANM2_LAYER, id}, t);
if (!frame.isVisible) continue;
if (frame.size.x <= 0 || frame.size.y <= 0) continue;
mat4 rootModel(1.0f);
if (isRootTransform)
{
anm2_frame_from_time(self, &root, {reference->animationID, ANM2_ROOT}, t);
rootModel = quad_model_parent_get(root.position, root.pivot, PERCENT_TO_UNIT(root.scale), root.rotation);
}
mat4 model = quad_model_get(frame.size, frame.position, frame.pivot, PERCENT_TO_UNIT(frame.scale), frame.rotation);
mat4 fullModel = rootModel * model;
vec2 corners[4] = { {0,0}, {1,0}, {1,1}, {0,1} };
for (auto& corner : corners)
{
vec4 world = fullModel * vec4(corner, 0.0f, 1.0f);
minX = std::min(minX, world.x);
minY = std::min(minY, world.y);
maxX = std::max(maxX, world.x);
maxY = std::max(maxY, world.y);
any = true;
}
}
}
if (!any) return vec4(-1.0f);
return {minX, minY, maxX - minX, maxY - minY};
}

View File

@@ -13,7 +13,9 @@
#define ANM2_FRAME_DELAY_MIN 1
#define ANM2_STRING_MAX 0xFF
#define ANM2_EMPTY_ERROR "No path given for anm2"
#define ANM2_READ_ERROR "Failed to read anm2 from file: {}"
#define ANM2_PARSE_ERROR "Failed to parse anm2: {} ({})"
#define ANM2_READ_INFO "Read anm2 from file: {}"
#define ANM2_WRITE_ERROR "Failed to write anm2 to file: {}"
#define ANM2_WRITE_INFO "Wrote anm2 to file: {}"
@@ -272,7 +274,7 @@ void anm2_layer_remove(Anm2* self, s32 id);
void anm2_null_add(Anm2* self);
void anm2_null_remove(Anm2* self, s32 id);
bool anm2_serialize(Anm2* self, const std::string& path);
bool anm2_deserialize(Anm2* self, const std::string& path);
bool anm2_deserialize(Anm2* self, const std::string& path, bool isTextures = true);
void anm2_new(Anm2* self);
void anm2_free(Anm2* self);
void anm2_created_on_set(Anm2* self);
@@ -297,3 +299,4 @@ void anm2_scale(Anm2* self, f32 scale);
void anm2_generate_from_grid(Anm2* self, Anm2Reference* reference, vec2 startPosition, vec2 size, vec2 pivot, s32 columns, s32 count, s32 delay);
void anm2_spritesheet_texture_pixels_upload(Anm2* self);
void anm2_spritesheet_texture_pixels_download(Anm2* self);
vec4 anm2_animation_rect_get(Anm2* anm2, Anm2Reference* reference, bool isRootTransform);

View File

@@ -241,36 +241,3 @@ void canvas_free(Canvas* self)
glDeleteBuffers(1, &self->textureVBO);
glDeleteBuffers(1, &self->textureEBO);
}
mat4 canvas_model_get(vec2 size, vec2 position, vec2 pivot, vec2 scale, f32 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 canvas_parent_model_get(vec2 position, vec2 pivot, vec2 scale, f32 rotation)
{
vec2 scaleSign = glm::sign(scale);
vec2 scaleAbsolute = glm::abs(scale);
f32 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;
}

View File

@@ -77,8 +77,6 @@ void canvas_rect_draw(Canvas* self, const GLuint& shader, const mat4& transform,
void canvas_framebuffer_resize_check(Canvas* self);
void canvas_unbind(void);
void canvas_viewport_set(Canvas* self);
mat4 canvas_model_get(vec2 size = {}, vec2 position = {}, vec2 pivot = {}, vec2 scale = vec2(1.0f), f32 rotation = {});
mat4 canvas_parent_model_get(vec2 position = {}, vec2 pivot = {}, vec2 scale = vec2(1.0f), f32 rotation = {});
void canvas_texture_draw
(

View File

@@ -30,7 +30,7 @@ void editor_draw(Editor* self)
{
Texture& texture = spritesheet->texture;
mat4 spritesheetTransform = transform * canvas_model_get(texture.size);
mat4 spritesheetTransform = transform * quad_model_get(texture.size);
canvas_texture_draw(&self->canvas, shaderTexture, texture.id, spritesheetTransform);
if (self->settings->editorIsBorder)
@@ -40,10 +40,10 @@ void editor_draw(Editor* self)
if (frame)
{
mat4 cropTransform = transform * canvas_model_get(frame->size, frame->crop);
mat4 cropTransform = transform * quad_model_get(frame->size, frame->crop);
canvas_rect_draw(&self->canvas, shaderLine, cropTransform, EDITOR_FRAME_COLOR);
mat4 pivotTransform = transform * canvas_model_get(CANVAS_PIVOT_SIZE, frame->crop + frame->pivot, CANVAS_PIVOT_SIZE * 0.5f);
mat4 pivotTransform = transform * quad_model_get(CANVAS_PIVOT_SIZE, frame->crop + frame->pivot, CANVAS_PIVOT_SIZE * 0.5f);
f32 vertices[] = ATLAS_UV_VERTICES(ATLAS_PIVOT);
canvas_texture_draw(&self->canvas, shaderTexture, self->resources->atlas.id, pivotTransform, vertices, EDITOR_PIVOT_COLOR);
}

View File

@@ -1,10 +1,5 @@
#include "ffmpeg.h"
static std::string ffmpeg_log_path_get(void)
{
return preferences_path_get() + FFMPEG_LOG_PATH;
}
bool
ffmpeg_render
(
@@ -35,13 +30,8 @@ ffmpeg_render
break;
}
// ffmpeg output will be piped into the log
std::string logOutput = " 2>> \"" + ffmpeg_log_path_get() + "\"";
#if _WIN32
command = string_quote(command) + logOutput;
#else
command += logOutput;
command = string_quote(command);
#endif
log_command(command);

View File

@@ -4,8 +4,6 @@
#include "texture.h"
#define FFMPEG_POPEN_ERROR "popen() (for FFmpeg) failed!\n{}"
#define FFMPEG_LOG_BUFFER_SIZE 256
#define FFMPEG_LOG_PATH "ffmpeg.txt"
static constexpr const char* FFMPEG_GIF_FORMAT =
"\"{0}\" -y "

View File

@@ -42,7 +42,7 @@ void generate_preview_draw(GeneratePreview* self)
vec2 uvMax = (crop + size) / vec2(texture.size);
f32 vertices[] = UV_VERTICES(uvMin, uvMax);
mat4 generateTransform = transform * canvas_model_get(size, {}, pivot);
mat4 generateTransform = transform * quad_model_get(size, {}, pivot);
canvas_texture_draw(&self->canvas, shaderTexture, texture.id, generateTransform, vertices, COLOR_OPAQUE, COLOR_OFFSET_NONE);
}
}

View File

@@ -43,7 +43,7 @@ static bool _imgui_window_color_from_position_get(SDL_Window* self, const vec2&
static void _imgui_anm2_open(Imgui* self, const std::string& path)
{
imgui_file_new(self);
imgui_anm2_new(self);
if (anm2_deserialize(self->anm2, path))
{
@@ -74,12 +74,6 @@ static void _imgui_spritesheet_add(Imgui* self, const std::string& path)
std::filesystem::current_path(workingPath);
}
template<typename T>
static void _imgui_clipboard_hovered_item_set(Imgui* self, const T& data)
{
self->clipboard->hoveredItem = ClipboardItem(data);
}
static bool _imgui_is_window_hovered(void)
{
return ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem);
@@ -128,7 +122,7 @@ static ImVec2 _imgui_item_size_get(const ImguiItem& self, ImguiItemType type)
if (self.is_row())
size.x = (ImGui::GetWindowSize().x - (ImGui::GetStyle().ItemSpacing.x * (self.rowCount + 1))) / self.rowCount;
else if (self.isSizeToText)
size.x = (ImGui::CalcTextSize(self.label_get()).x + ImGui::GetStyle().FramePadding.x);
size.x = (ImGui::CalcTextSize(self.label_get().c_str()).x + ImGui::GetStyle().FramePadding.x);
else if (!self.is_size())
size.x = ImGui::CalcItemWidth();
break;
@@ -188,16 +182,6 @@ static void _imgui_item_pre(const ImguiItem& self, ImguiItemType type)
default:
break;
}
/*
if (self.is_hotkey())
{
std::string chordString = imgui_string_from_chord_get(imgui->hotkeys[self.hotkey]);
if (isShortcutInLabel)
label += std::format(IMGUI_LABEL_SHORTCUT_FORMAT, chordString);
tooltip += std::format(IMGUI_TOOLTIP_SHORTCUT_FORMAT, chordString);
}
*/
}
static void _imgui_item_post(const ImguiItem& self, Imgui* imgui, ImguiItemType type, bool& isActivated)
@@ -238,7 +222,7 @@ static void _imgui_item_post(const ImguiItem& self, Imgui* imgui, ImguiItemType
if (!self.isDisabled) isActivated = true;
if (self.is_tooltip() && ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal))
ImGui::SetTooltip(self.tooltip.c_str());
ImGui::SetTooltip(self.tooltip_get().c_str());
if (isActivated)
{
@@ -429,32 +413,32 @@ static bool NAME(const ImguiItem& self, const ImguiItem& checkboxItem, Imgui* im
#define IMGUI_ITEM_DISABLED_GET(VALUE, ITEM, CONDITION) ImguiItem VALUE = ITEM; VALUE.isDisabled = CONDITION;
IMGUI_ITEM_FUNCTION(_imgui_begin, IMGUI_WINDOW, ImGui::Begin(self.label_get(), nullptr, self.flags));
IMGUI_ITEM_FUNCTION(_imgui_begin, IMGUI_WINDOW, ImGui::Begin(self.label_get().c_str(), nullptr, self.flags));
#define IMGUI_BEGIN_OR_RETURN(item, imgui) if (!_imgui_begin(item, imgui)) { _imgui_end(); return; }
static void _imgui_end(void){ImGui::End();}
IMGUI_ITEM_VOID_FUNCTION(_imgui_dockspace, IMGUI_DOCKSPACE, ImGui::DockSpace(ImGui::GetID(self.label_get()), self.size, self.flags));
IMGUI_ITEM_FUNCTION(_imgui_begin_child, IMGUI_CHILD, ImGui::BeginChild(self.label_get(), self.size, self.flags, self.windowFlags));
IMGUI_ITEM_VOID_FUNCTION(_imgui_dockspace, IMGUI_DOCKSPACE, ImGui::DockSpace(ImGui::GetID(self.label_get().c_str()), self.size, self.flags));
IMGUI_ITEM_FUNCTION(_imgui_begin_child, IMGUI_CHILD, ImGui::BeginChild(self.label_get().c_str(), self.size, self.flags, self.windowFlags));
static void _imgui_end_child(void) {ImGui::EndChild(); }
IMGUI_ITEM_VOID_FUNCTION(_imgui_text, IMGUI_TEXT, ImGui::Text(self.label_get()));
IMGUI_ITEM_FUNCTION(_imgui_button, IMGUI_BUTTON, ImGui::Button(self.label_get(), _imgui_item_size_get(self, type)));
IMGUI_ITEM_FUNCTION(_imgui_begin_table, IMGUI_TABLE, ImGui::BeginTable(self.label_get(), self.value, self.flags));
IMGUI_ITEM_VOID_FUNCTION(_imgui_text, IMGUI_TEXT, ImGui::Text(self.label_get().c_str()));
IMGUI_ITEM_FUNCTION(_imgui_button, IMGUI_BUTTON, ImGui::Button(self.label_get().c_str(), _imgui_item_size_get(self, type)));
IMGUI_ITEM_FUNCTION(_imgui_begin_table, IMGUI_TABLE, ImGui::BeginTable(self.label_get().c_str(), self.value, self.flags));
static void _imgui_end_table(void) {ImGui::EndTable(); }
static void _imgui_table_setup_column(const char* text) {ImGui::TableSetupColumn(text); }
static void _imgui_table_headers_row(void) {ImGui::TableHeadersRow(); }
static void _imgui_table_next_row(void) {ImGui::TableNextRow(); }
static void _imgui_table_set_column_index(s32 index) {ImGui::TableSetColumnIndex(index); }
IMGUI_ITEM_FUNCTION(_imgui_selectable, IMGUI_SELECTABLE, ImGui::Selectable(self.label_get(), self.isSelected, self.flags, _imgui_item_size_get(self, type)));
IMGUI_ITEM_VALUE_FUNCTION(_imgui_radio_button, IMGUI_RADIO_BUTTON, s32, ImGui::RadioButton(self.label_get(), &value, self.value));
IMGUI_ITEM_VALUE_FUNCTION(_imgui_color_button, IMGUI_COLOR_BUTTON, vec4, ImGui::ColorButton(self.label_get(), ImVec4(value), self.flags));
IMGUI_ITEM_VALUE_FUNCTION(_imgui_checkbox, IMGUI_CHECKBOX, bool, ImGui::Checkbox(self.label_get(), &value));
IMGUI_ITEM_VALUE_CLAMP_FUNCTION(_imgui_input_int, IMGUI_INPUT_INT, s32, ImGui::InputInt(self.label_get(), &value, self.step, self.stepFast, self.flags));
IMGUI_ITEM_VALUE_CLAMP_FUNCTION(_imgui_input_int2, IMGUI_INPUT_INT, ivec2, ImGui::InputInt2(self.label_get(), value_ptr(value), self.flags));
IMGUI_ITEM_VALUE_CLAMP_FUNCTION(_imgui_input_float, IMGUI_INPUT_FLOAT, f32, ImGui::InputFloat(self.label_get(), &value, self.step, self.stepFast, _imgui_f32_format_get(self, value), self.flags));
IMGUI_ITEM_VALUE_FUNCTION(_imgui_slider_float, IMGUI_SLIDER_FLOAT, f32, ImGui::SliderFloat(self.label_get(), &value, self.min, self.max, _imgui_f32_format_get(self, value), self.flags));
IMGUI_ITEM_VALUE_FUNCTION(_imgui_drag_float, IMGUI_DRAG_FLOAT, f32, ImGui::DragFloat(self.label_get(), &value, self.speed, self.min, self.max, _imgui_f32_format_get(self, value)));
IMGUI_ITEM_VALUE_FUNCTION(_imgui_drag_float2, IMGUI_DRAG_FLOAT, vec2, ImGui::DragFloat2(self.label_get(), value_ptr(value), self.speed, self.min, self.max, _imgui_vec2_format_get(self, value)));
IMGUI_ITEM_VALUE_FUNCTION(_imgui_color_edit3, IMGUI_COLOR_EDIT, vec3, ImGui::ColorEdit3(self.label_get(), value_ptr(value), self.flags));
IMGUI_ITEM_VALUE_FUNCTION(_imgui_color_edit4, IMGUI_COLOR_EDIT, vec4, ImGui::ColorEdit4(self.label_get(), value_ptr(value), self.flags));
IMGUI_ITEM_FUNCTION(_imgui_selectable, IMGUI_SELECTABLE, ImGui::Selectable(self.label_get().c_str(), self.isSelected, self.flags, _imgui_item_size_get(self, type)));
IMGUI_ITEM_VALUE_FUNCTION(_imgui_radio_button, IMGUI_RADIO_BUTTON, s32, ImGui::RadioButton(self.label_get().c_str(), &value, self.value));
IMGUI_ITEM_VALUE_FUNCTION(_imgui_color_button, IMGUI_COLOR_BUTTON, vec4, ImGui::ColorButton(self.label_get().c_str(), ImVec4(value), self.flags));
IMGUI_ITEM_VALUE_FUNCTION(_imgui_checkbox, IMGUI_CHECKBOX, bool, ImGui::Checkbox(self.label_get().c_str(), &value));
IMGUI_ITEM_VALUE_CLAMP_FUNCTION(_imgui_input_int, IMGUI_INPUT_INT, s32, ImGui::InputInt(self.label_get().c_str(), &value, self.step, self.stepFast, self.flags));
IMGUI_ITEM_VALUE_CLAMP_FUNCTION(_imgui_input_int2, IMGUI_INPUT_INT, ivec2, ImGui::InputInt2(self.label_get().c_str(), value_ptr(value), self.flags));
IMGUI_ITEM_VALUE_CLAMP_FUNCTION(_imgui_input_float, IMGUI_INPUT_FLOAT, f32, ImGui::InputFloat(self.label_get().c_str(), &value, self.step, self.stepFast, _imgui_f32_format_get(self, value), self.flags));
IMGUI_ITEM_VALUE_FUNCTION(_imgui_slider_float, IMGUI_SLIDER_FLOAT, f32, ImGui::SliderFloat(self.label_get().c_str(), &value, self.min, self.max, _imgui_f32_format_get(self, value), self.flags));
IMGUI_ITEM_VALUE_FUNCTION(_imgui_drag_float, IMGUI_DRAG_FLOAT, f32, ImGui::DragFloat(self.label_get().c_str(), &value, self.speed, self.min, self.max, _imgui_f32_format_get(self, value)));
IMGUI_ITEM_VALUE_FUNCTION(_imgui_drag_float2, IMGUI_DRAG_FLOAT, vec2, ImGui::DragFloat2(self.label_get().c_str(), value_ptr(value), self.speed, self.min, self.max, _imgui_vec2_format_get(self, value)));
IMGUI_ITEM_VALUE_FUNCTION(_imgui_color_edit3, IMGUI_COLOR_EDIT, vec3, ImGui::ColorEdit3(self.label_get().c_str(), value_ptr(value), self.flags));
IMGUI_ITEM_VALUE_FUNCTION(_imgui_color_edit4, IMGUI_COLOR_EDIT, vec4, ImGui::ColorEdit4(self.label_get().c_str(), value_ptr(value), self.flags));
IMGUI_ITEM_CHECKBOX_FUNCTION(_imgui_checkbox_selectable, _imgui_selectable(self, imgui));
IMGUI_ITEM_CHECKBOX_VALUE_FUNCTION(_imgui_checkbox_checkbox, bool, _imgui_checkbox(self, imgui, value));
IMGUI_ITEM_CHECKBOX_VALUE_FUNCTION(_imgui_checkbox_input_int, s32, _imgui_input_int(self, imgui, value));
@@ -467,7 +451,7 @@ static bool _imgui_input_text(const ImguiItem& self, Imgui* imgui, std::string&
{
value.resize(self.max);
_imgui_item_pre(self, IMGUI_INPUT_TEXT);
bool isActivated = ImGui::InputText(self.label_get(), value.data(), self.max, self.flags);
bool isActivated = ImGui::InputText(self.label_get().c_str(), value.data(), self.max, self.flags);
_imgui_item_post(self, imgui, IMGUI_INPUT_TEXT, isActivated);
return isActivated;
}
@@ -481,7 +465,7 @@ static bool _imgui_combo(ImguiItem self, Imgui* imgui, s32* value)
_imgui_item_pre(self, IMGUI_COMBO);
bool isActivated = ImGui::Combo(self.label_get(), value, cStrings.data(), (s32)self.items.size());
bool isActivated = ImGui::Combo(self.label_get().c_str(), value, cStrings.data(), (s32)self.items.size());
if (_imgui_is_input_default())
{
*value = self.value;
@@ -499,7 +483,7 @@ IMGUI_ITEM_CUSTOM_FUNCTION(_imgui_atlas_button, IMGUI_ATLAS_BUTTON,
if (self.is_size())
{
isActivated = ImGui::Button(self.label_get(), size);
isActivated = ImGui::Button(self.label_get().c_str(), size);
ImVec2 start = ImGui::GetItemRectMin() + self.atlasOffset;
ImVec2 end = start + ImVec2(ATLAS_SIZE(self.atlas));
@@ -507,7 +491,7 @@ IMGUI_ITEM_CUSTOM_FUNCTION(_imgui_atlas_button, IMGUI_ATLAS_BUTTON,
ImGui::GetWindowDrawList()->AddImage(imgui->resources->atlas.id, start, end, ATLAS_UV_ARGS(self.atlas));
}
else
isActivated = ImGui::ImageButton(self.label_get(), imgui->resources->atlas.id, size, ATLAS_UV_ARGS(self.atlas));
isActivated = ImGui::ImageButton(self.label_get().c_str(), imgui->resources->atlas.id, size, ATLAS_UV_ARGS(self.atlas));
});
static bool _imgui_selectable_input_int(const ImguiItem& self, Imgui* imgui, s32& value)
@@ -592,7 +576,7 @@ static bool _imgui_option_popup(ImguiItem self, Imgui* imgui, ImguiPopupState* s
if (state) *state = IMGUI_POPUP_STATE_CLOSED;
if (imgui_begin_popup_modal(self.label_get(), imgui))
if (imgui_begin_popup_modal(self.label_get().c_str(), imgui))
{
if (state) *state = IMGUI_POPUP_STATE_OPEN;
@@ -1007,7 +991,7 @@ static void _imgui_timeline(Imgui* self)
if (ImGui::IsMouseReleased(ImGuiMouseButton_Left))
{
*self->reference = reference;
self->clipboard->location = hoverReference;
if (reference.itemType == ANM2_LAYER && reference.itemID != ID_NONE)
_imgui_spritesheet_editor_set(self, self->anm2->layers[self->reference->itemID].spritesheetID);
}
}
@@ -1060,12 +1044,6 @@ static void _imgui_timeline(Imgui* self)
if (_imgui_atlas_button(frameButton, self)) *self->reference = reference;
if (ImGui::IsItemHovered())
{
Anm2FrameWithReference frameWithReference = {reference, frame};
_imgui_clipboard_hovered_item_set(self, frameWithReference);
}
if (ImGui::IsItemActivated())
{
if (type == ANM2_TRIGGERS || isModCtrl)
@@ -1291,8 +1269,7 @@ static void _imgui_timeline(Imgui* self)
imgui_end_popup(self);
}
if (_imgui_button(IMGUI_FIT_ANIMATION_LENGTH, self))
anm2_animation_length_set(animation);
if (_imgui_button(IMGUI_FIT_ANIMATION_LENGTH, self)) anm2_animation_length_set(animation);
_imgui_input_int(IMGUI_ANIMATION_LENGTH, self, animation->frameNum);
_imgui_input_int(IMGUI_FPS, self, self->anm2->fps);
@@ -1355,7 +1332,7 @@ static void _imgui_taskbar(Imgui* self)
if (imgui_begin_popup(IMGUI_FILE.popup, self))
{
_imgui_selectable(IMGUI_NEW.copy({self->anm2->path.empty()}), self);
_imgui_selectable(IMGUI_NEW, self);
_imgui_selectable(IMGUI_OPEN, self);
_imgui_selectable(IMGUI_SAVE.copy({self->anm2->path.empty()}), self);
_imgui_selectable(IMGUI_SAVE_AS.copy({self->anm2->path.empty()}), self);
@@ -1664,9 +1641,15 @@ static void _imgui_taskbar(Imgui* self)
rendering_end();
}
_imgui_begin_child(IMGUI_RENDERING_ANIMATION_CHILD, self);
f32 progress = self->preview->time / (animation->frameNum - 1);
ImGui::ProgressBar(progress);
_imgui_text(IMGUI_RENDERING_ANIMATION_INFO, self);
_imgui_end_child(); //IMGUI_RENDERING_ANIMATION_CHILD
if (_imgui_button(IMGUI_RENDERING_ANIMATION_CANCEL, self))
self->preview->isRenderCancelled = true;
@@ -1868,13 +1851,6 @@ static void _imgui_animations(Imgui* self)
anm2_reference_item_clear(self->reference);
}
if (ImGui::IsItemHovered())
{
Anm2AnimationWithID animationWithID = {id, animation};
_imgui_clipboard_hovered_item_set(self, animationWithID);
self->clipboard->location = (s32)id;
}
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None))
{
if (ImGui::IsDragDropActive()) ImGui::SetNextItemWidth(_imgui_item_size_get(animationItem, IMGUI_SELECTABLE).x);
@@ -2298,6 +2274,22 @@ static void _imgui_animation_preview(Imgui* self)
_imgui_begin_child(IMGUI_CANVAS_VIEW_CHILD, self);
_imgui_drag_float(IMGUI_CANVAS_ZOOM, self, zoom);
if (_imgui_button(IMGUI_ANIMATION_PREVIEW_CENTER_VIEW.copy({pan == vec2()}), self)) pan = vec2();
if (_imgui_button(IMGUI_ANIMATION_PREVIEW_FIT.copy({self->reference->animationID == ID_NONE}), self))
{
vec4 rect = anm2_animation_rect_get(self->anm2, self->reference, self->settings->previewIsRootTransform);
if (rect != vec4(-1.0f) && (rect.z > 0 && rect.w > 0))
{
f32 scaleX = self->preview->canvas.size.x / rect.z;
f32 scaleY = self->preview->canvas.size.y / rect.w;
f32 fitScale = std::min(scaleX, scaleY);
zoom = UNIT_TO_PERCENT(fitScale);
vec2 rectCenter = { rect.x + rect.z * 0.5f, rect.y + rect.w * 0.5f };
pan = -rectCenter * fitScale;
}
}
ImGui::Text(mousePositionString.c_str());
_imgui_end_child(); //IMGUI_CANVAS_VIEW_CHILD
@@ -2342,7 +2334,7 @@ static void _imgui_animation_preview(Imgui* self)
_imgui_checkbox(IMGUI_CANVAS_TRIGGERS, self, self->settings->previewIsTriggers);
_imgui_checkbox(IMGUI_CANVAS_PIVOTS, self, self->settings->previewIsPivots);
ImGui::SameLine();
_imgui_checkbox(IMGUI_CANVAS_TARGETS, self, self->settings->previewIsTargets);
_imgui_checkbox(IMGUI_CANVAS_ICONS, self, self->settings->previewIsIcons);
ImGui::SameLine();
_imgui_checkbox(IMGUI_CANVAS_BORDER, self, self->settings->previewIsBorder);
_imgui_end_child(); // IMGUI_CANVAS_HELPER_CHILD
@@ -2368,10 +2360,14 @@ static void _imgui_animation_preview(Imgui* self)
}
if (ImGui::IsItemHovered())
{
self->pendingCursor = TOOL_CURSORS[tool];
imgui_keyboard_nav_disable();
}
else
{
_imgui_end(); // IMGUI_ANIMATION_EDITOR
imgui_keyboard_nav_enable();
return;
}
@@ -2392,25 +2388,24 @@ static void _imgui_animation_preview(Imgui* self)
const ImVec2 mouseDelta = ImGui::GetIO().MouseDelta;
const f32 mouseWheel = ImGui::GetIO().MouseWheel;
if (tool == TOOL_MOVE || tool == TOOL_SCALE || tool == TOOL_ROTATE)
if (isMouseClick || isLeft || isRight || isUp || isDown)
imgui_snapshot(self, IMGUI_ACTION_FRAME_TRANSFORM);
if ((tool == TOOL_PAN && isMouseDown) || isMouseMiddleDown)
pan += vec2(mouseDelta.x, mouseDelta.y);
Anm2Frame* frame = nullptr;
if (self->reference->itemType != ANM2_TRIGGERS)
frame = anm2_frame_from_reference(self->anm2, self->reference);
if (frame)
{
f32 step = isMod ? TOOL_STEP_MOD : TOOL_STEP;
if ((tool == TOOL_PAN && isMouseDown) || isMouseMiddleDown)
pan += vec2(mouseDelta.x, mouseDelta.y);
switch (tool)
{
case TOOL_MOVE:
if (!frame) break;
if (isMouseClick || isLeft || isRight || isUp || isDown)
imgui_snapshot(self, IMGUI_ACTION_MOVE);
if (isMouseDown)
frame->position = vec2(mousePos);
else
@@ -2422,6 +2417,11 @@ static void _imgui_animation_preview(Imgui* self)
}
break;
case TOOL_ROTATE:
if (!frame) break;
if (isMouseClick || isLeft || isRight || isUp || isDown)
imgui_snapshot(self, IMGUI_ACTION_ROTATE);
if (isMouseDown)
frame->rotation += mouseDelta.x;
else
@@ -2431,6 +2431,11 @@ static void _imgui_animation_preview(Imgui* self)
}
break;
case TOOL_SCALE:
if (!frame) break;
if (isMouseClick || isLeft || isRight || isUp || isDown)
imgui_snapshot(self, IMGUI_ACTION_SCALE);
if (isMouseDown)
frame->scale += vec2(mouseDelta.x, mouseDelta.y);
else
@@ -2444,7 +2449,6 @@ static void _imgui_animation_preview(Imgui* self)
default:
break;
}
}
if (mouseWheel != 0 || isZoomIn || isZoomOut)
{
@@ -2499,10 +2503,14 @@ static void _imgui_spritesheet_editor(Imgui* self)
ImGui::Image(self->editor->canvas.framebuffer, vec2(size));
if (ImGui::IsItemHovered())
{
self->pendingCursor = TOOL_CURSORS[tool];
imgui_keyboard_nav_disable();
}
else
{
_imgui_end(); // IMGUI_SPRITESHEET_EDITOR
imgui_keyboard_nav_enable();
return;
}
@@ -2510,6 +2518,12 @@ static void _imgui_spritesheet_editor(Imgui* self)
mousePos = vec2(ImGui::GetMousePos() - editorCursorScreenPos - pan) / PERCENT_TO_UNIT(zoom);
const bool isLeft = ImGui::IsKeyPressed(IMGUI_INPUT_LEFT);
const bool isRight = ImGui::IsKeyPressed(IMGUI_INPUT_RIGHT);
const bool isUp = ImGui::IsKeyPressed(IMGUI_INPUT_UP);
const bool isDown = ImGui::IsKeyPressed(IMGUI_INPUT_DOWN);
const bool isShift = ImGui::IsKeyDown(IMGUI_INPUT_SHIFT);
const bool isCtrl = ImGui::IsKeyDown(IMGUI_INPUT_CTRL);
const bool isMouseClick = ImGui::IsMouseClicked(ImGuiMouseButton_Left);
const bool isMouseDown = ImGui::IsMouseDown(ImGuiMouseButton_Left);
const bool isMouseMiddleDown = ImGui::IsMouseDown(ImGuiMouseButton_Middle);
@@ -2518,9 +2532,6 @@ static void _imgui_spritesheet_editor(Imgui* self)
const f32 mouseWheel = ImGui::GetIO().MouseWheel;
const ImVec2 mouseDelta = ImGui::GetIO().MouseDelta;
if ((tool == TOOL_PAN && isMouseDown) || isMouseMiddleDown)
pan += vec2(mouseDelta.x, mouseDelta.y);
Anm2Frame* frame = nullptr;
if (self->reference->itemType == ANM2_LAYER)
frame = anm2_frame_from_reference(self->anm2, self->reference);
@@ -2529,11 +2540,42 @@ static void _imgui_spritesheet_editor(Imgui* self)
Texture* texture = spritesheet ? &spritesheet->texture : nullptr;
vec2 position = mousePos;
f32 step = isShift ? TOOL_STEP_MOD : TOOL_STEP;
if ((tool == TOOL_PAN && isMouseDown) || isMouseMiddleDown)
pan += vec2(mouseDelta.x, mouseDelta.y);
switch (tool)
{
case TOOL_MOVE:
if (!texture || !frame) break;
if (isMouseClick || isLeft || isRight || isUp || isDown)
imgui_snapshot(self, IMGUI_ACTION_MOVE);
if (isMouseDown)
{
if (self->settings->editorIsGridSnap)
{
position.x = roundf(position.x / gridSize.x) * gridSize.x + gridOffset.x - (gridSize.x * 0.5f);
position.y = roundf(position.y / gridSize.y) * gridSize.y + gridOffset.y - (gridSize.y * 0.5f);
}
frame->pivot = position - frame->crop;
}
else
{
if (isLeft) frame->pivot.x -= step;
if (isRight) frame->pivot.x += step;
if (isUp) frame->pivot.y -= step;
if (isDown) frame->pivot.y += step;
}
break;
case TOOL_CROP:
if (!frame || !texture) break;
if (!texture || !frame) break;
if (isMouseClick || isLeft || isRight || isUp || isDown)
imgui_snapshot(self, IMGUI_ACTION_MOVE);
if (self->settings->editorIsGridSnap)
{
@@ -2543,12 +2585,31 @@ static void _imgui_spritesheet_editor(Imgui* self)
if (isMouseClick)
{
imgui_snapshot(self, IMGUI_ACTION_FRAME_CROP);
frame->crop = position;
frame->size = ivec2(0,0);
}
else if (isMouseDown)
frame->size = position - frame->crop;
else
{
if (isCtrl)
{
if (isLeft) frame->crop.x -= step;
if (isRight) frame->crop.x += step;
if (isUp) frame->crop.y -= step;
if (isDown) frame->crop.y += step;
}
else
{
if (isLeft) frame->size.x -= step;
if (isRight) frame->size.x += step;
if (isUp) frame->size.y -= step;
if (isDown) frame->size.y += step;
}
frame->size.x = std::max({}, frame->size.x);
frame->size.y = std::max({}, frame->size.y);
}
break;
case TOOL_DRAW:
case TOOL_ERASE:
@@ -2610,8 +2671,20 @@ static void _imgui_frame_properties(Imgui* self)
_imgui_color_edit3(IMGUI_FRAME_PROPERTIES_COLOR_OFFSET.copy({!frame}), self, !frame ? dummy_value<vec3>() : frame->offsetRGB);
_imgui_checkbox(IMGUI_FRAME_PROPERTIES_VISIBLE.copy({!frame}), self, !frame ? dummy_value<bool>() : frame->isVisible);
_imgui_checkbox(IMGUI_FRAME_PROPERTIES_INTERPOLATED.copy({!frame}), self, !frame ? dummy_value<bool>() : frame->isInterpolated);
_imgui_checkbox(IMGUI_FRAME_PROPERTIES_ROUND.copy({!frame}), self, self->settings->propertiesIsRound);
if (_imgui_button(IMGUI_FRAME_PROPERTIES_FLIP_X.copy({!frame}), self)) frame->scale.x = -frame->scale.x;
if (_imgui_button(IMGUI_FRAME_PROPERTIES_FLIP_Y.copy({!frame}), self)) frame->scale.y = -frame->scale.y;
if (self->settings->propertiesIsRound && frame)
{
frame->position = glm::trunc(frame->position);
frame->pivot = glm::trunc(frame->pivot);
frame->crop = glm::trunc(frame->crop);
frame->scale = glm::trunc(frame->scale);
frame->rotation = glm::trunc(frame->rotation);
frame->tintRGBA = glm::trunc(frame->tintRGBA);
frame->offsetRGB = glm::trunc(frame->offsetRGB);
}
}
else
{
@@ -2744,9 +2817,10 @@ void imgui_init
ImGuiIO& io = ImGui::GetIO();
io.IniFilename = nullptr;
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
io.ConfigWindowsMoveFromTitleBarOnly = true;
imgui_keyboard_nav_enable();
ImGui::LoadIniSettingsFromDisk(settings_path_get().c_str());
for (s32 i = 0; i < HOTKEY_COUNT; i++)
@@ -2779,6 +2853,8 @@ void imgui_update(Imgui* self)
}
}
imgui_contextual_actions_enable(self);
if (self->pendingCursor != self->cursor)
{
SDL_SetCursor(SDL_CreateSystemCursor(self->pendingCursor));

View File

@@ -64,13 +64,17 @@
#define IMGUI_ACTION_FRAME_CROP "Frame Crop"
#define IMGUI_ACTION_FRAME_SWAP "Frame Swap"
#define IMGUI_ACTION_FRAME_TRANSFORM "Frame Transform"
#define IMGUI_ACTION_ANIMATION_SWAP "Animation Swap"
#define IMGUI_ACTION_TRIGGER_MOVE "Trigger AtFrame"
#define IMGUI_ACTION_FRAME_DELAY "Frame Delay"
#define IMGUI_ACTION_MOVE_PLAYHEAD "Move Playhead"
#define IMGUI_ACTION_DRAW "Draw"
#define IMGUI_ACTION_ERASE "Erase"
#define IMGUI_ACTION_MOVE "Move"
#define IMGUI_ACTION_SCALE "Scale"
#define IMGUI_ACTION_ROTATE "Rotate"
#define IMGUI_ACTION_CROP "Crop"
#define IMGUI_ACTION_RELOAD_SPRITESHEET "Reload Spritesheet(s)"
#define IMGUI_ACTION_REPLACE_SPRITESHEET "Replace Spritesheet"
#define IMGUI_ACTION_OPEN_FILE "Open File"
@@ -110,9 +114,10 @@
#define IMGUI_SELECTABLE_INPUT_INT_FORMAT "#{}"
#define IMGUI_TIMELINE_ANIMATION_NONE "Select an animation to show timeline..."
#define IMGUI_HOTKEY_CHANGE "Input new hotkey..."
#define IMGUI_LABEL_SHORTCUT_FORMAT "({})"
#define IMGUI_TOOLTIP_SHORTCUT_FORMAT "\n(Shortcut: {})"
#define IMGUI_LABEL_HOTKEY_FORMAT " ({})"
#define IMGUI_TOOLTIP_HOTKEY_FORMAT "\n(Hotkey: {})"
#define IMGUI_INVISIBLE_FORMAT "## {}"
#define IMGUI_RENDERING_FFMPEG_INFO_THRESHOLD 0.95f
#define IMGUI_TRIGGERS_FONT_SCALE 2.0
@@ -222,7 +227,7 @@ static void imgui_log_push(Imgui* self, const std::string& text)
log_imgui(text);
}
static inline void imgui_file_new(Imgui* self)
static inline void imgui_anm2_new(Imgui* self)
{
anm2_reference_clear(self->reference);
anm2_free(self->anm2);
@@ -245,6 +250,14 @@ static inline void imgui_file_save(Imgui* self)
}
}
static inline void imgui_file_new(Imgui* self)
{
std::string path = self->anm2->path;
imgui_anm2_new(self);
self->anm2->path = path;
imgui_file_save(self);
}
static inline void imgui_file_save_as(Imgui* self)
{
dialog_anm2_save(self->dialog);
@@ -520,10 +533,17 @@ static inline ImGuiKeyChord imgui_chord_from_string_get(const std::string& str)
return chord;
}
static void imgui_contextual_actions_enable(Imgui* self) { self->isContextualActionsEnabled = true; }
static void imgui_contextual_actions_disable(Imgui* self){ self->isContextualActionsEnabled = false; }
static inline void imgui_keyboard_nav_enable(void) { ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; }
static inline void imgui_keyboard_nav_disable(void) { ImGui::GetIO().ConfigFlags &= ~ImGuiConfigFlags_NavEnableKeyboard; }
static inline void imgui_contextual_actions_enable(Imgui* self) { self->isContextualActionsEnabled = true; }
static inline void imgui_contextual_actions_disable(Imgui* self){ self->isContextualActionsEnabled = false; }
static inline bool imgui_is_popup_open(const std::string& label) { return ImGui::IsPopupOpen(label.c_str()); }
static inline bool imgui_is_any_popup_open(void)
{
return ImGui::IsPopupOpen(nullptr, ImGuiPopupFlags_AnyPopupId);
}
static inline void imgui_open_popup(const std::string& label) { ImGui::OpenPopup(label.c_str()); }
static inline void imgui_pending_popup_process(Imgui* self)
{
@@ -656,7 +676,7 @@ struct ImguiItem
bool isSelected = false;
bool isUseItemActivated = false;
bool isSizeToText = false;
bool isShortcutInLabel = false;
bool isHotkeyInLabel = false;
bool isSameLine = false;
bool isSeparator = false;
s32 id = 0;
@@ -673,6 +693,23 @@ struct ImguiItem
s32 windowFlags{};
s32 rowCount = 0;
bool is_border() const { return border != 0; }
bool is_row() const { return rowCount != 0; }
bool is_hotkey() const { return hotkey != HOTKEY_NONE; }
bool is_chord() const { return chord != IMGUI_CHORD_NONE || is_hotkey(); }
bool is_drag_drop() const { return !dragDrop.empty(); }
bool is_focus_window() const { return !focusWindow.empty(); }
bool is_popup() const { return !popup.empty(); }
bool is_function() const { return function; }
bool is_size() const { return size != ImVec2(); }
bool is_popup_size() const { return popupSize != ImVec2(); }
bool is_tooltip() const { return !tooltip.empty(); }
bool is_undoable() const { return !snapshotAction.empty(); }
bool is_mnemonic() const { return mnemonicKey != ImGuiKey_None; }
bool is_range() const { return min != 0 || max != 0; }
const char* drag_drop_get() const { return dragDrop.c_str(); }
const char* text_get() const { return text.c_str(); }
void construct()
{
static s32 idNew = 0;
@@ -728,24 +765,21 @@ struct ImguiItem
return chord;
}
bool is_border() const { return border != 0; }
bool is_row() const { return rowCount != 0; }
bool is_hotkey() const { return hotkey != HOTKEY_NONE; }
bool is_chord() const { return chord != IMGUI_CHORD_NONE || is_hotkey(); }
bool is_drag_drop() const { return !dragDrop.empty(); }
bool is_focus_window() const { return !focusWindow.empty(); }
bool is_popup() const { return !popup.empty(); }
bool is_function() const { return function; }
bool is_size() const { return size != ImVec2(); }
bool is_popup_size() const { return popupSize != ImVec2(); }
bool is_tooltip() const { return !tooltip.empty(); }
bool is_undoable() const { return !snapshotAction.empty(); }
bool is_mnemonic() const { return mnemonicKey != ImGuiKey_None; }
bool is_range() const { return min != 0 || max != 0; }
const char* label_get() const { return label.c_str(); }
const char* drag_drop_get() const { return dragDrop.c_str(); }
const char* tooltip_get() const { return tooltip.c_str(); }
const char* text_get() const { return text.c_str(); }
std::string label_get() const
{
std::string newLabel = label;
if (isHotkeyInLabel)
newLabel += std::format(IMGUI_LABEL_HOTKEY_FORMAT, imgui_string_from_chord_get(chord_get()));
return newLabel;
}
std::string tooltip_get() const
{
std::string newTooltip = tooltip;
if (is_chord())
newTooltip += std::format(IMGUI_TOOLTIP_HOTKEY_FORMAT, imgui_string_from_chord_get(chord_get()));
return newTooltip;
}
};
#define IMGUI_ITEM(NAME, ...) const inline ImguiItem NAME = []{ ImguiItem self; __VA_ARGS__; self.construct(); return self; }()
@@ -797,7 +831,7 @@ IMGUI_ITEM(IMGUI_NEW,
self.function = imgui_file_new,
self.hotkey = HOTKEY_NEW,
self.isSizeToText = true,
self.isShortcutInLabel = true
self.isHotkeyInLabel = true
);
IMGUI_ITEM(IMGUI_OPEN,
@@ -806,7 +840,7 @@ IMGUI_ITEM(IMGUI_OPEN,
self.function = imgui_file_open,
self.hotkey = HOTKEY_OPEN,
self.isSizeToText = true,
self.isShortcutInLabel = true
self.isHotkeyInLabel = true
);
IMGUI_ITEM(IMGUI_SAVE,
@@ -815,7 +849,7 @@ IMGUI_ITEM(IMGUI_SAVE,
self.function = imgui_file_save,
self.hotkey = HOTKEY_SAVE,
self.isSizeToText = true,
self.isShortcutInLabel = true
self.isHotkeyInLabel = true
);
IMGUI_ITEM(IMGUI_SAVE_AS,
@@ -824,7 +858,7 @@ IMGUI_ITEM(IMGUI_SAVE_AS,
self.function = imgui_file_save_as,
self.hotkey = HOTKEY_SAVE_AS,
self.isSizeToText = true,
self.isShortcutInLabel = true
self.isHotkeyInLabel = true
);
IMGUI_ITEM(IMGUI_EXPLORE_ANM2_LOCATION,
@@ -841,7 +875,7 @@ IMGUI_ITEM(IMGUI_EXIT,
self.function = imgui_quit,
self.hotkey = HOTKEY_EXIT,
self.isSizeToText = true,
self.isShortcutInLabel = true
self.isHotkeyInLabel = true
);
IMGUI_ITEM(IMGUI_EXIT_CONFIRMATION,
@@ -1042,7 +1076,7 @@ IMGUI_ITEM(IMGUI_CHANGE_ALL_FRAME_PROPERTIES_CANCEL,
);
IMGUI_ITEM(IMGUI_SCALE_ANM2,
self.label = "&Scale Anm2",
self.label = "S&cale Anm2",
self.tooltip = "Scale up all size and position-related frame properties in the anm2.",
self.popup = "Scale Anm2",
self.popupType = IMGUI_POPUP_CENTER_WINDOW,
@@ -1135,6 +1169,13 @@ IMGUI_ITEM(IMGUI_RENDER_ANIMATION_CONFIRM,
self.rowCount = IMGUI_OPTION_POPUP_ROW_COUNT
);
IMGUI_ITEM(IMGUI_RENDERING_ANIMATION_CHILD,
self.label = "##Rendering Child",
self.size = {400.0f, 65.0f},
self.flags = true
);
IMGUI_ITEM(IMGUI_RENDERING_ANIMATION_INFO, self.label = "Recording frames. Once done, the program may halt\nas FFmpeg renders the animation. Please be patient!");
IMGUI_ITEM(IMGUI_RENDERING_ANIMATION_CANCEL,
self.label = "Cancel",
self.tooltip = "Cancel rendering the animation.",
@@ -1558,10 +1599,10 @@ IMGUI_ITEM(IMGUI_CANVAS_PIVOTS,
self.value = SETTINGS_PREVIEW_IS_PIVOTS_DEFAULT
);
IMGUI_ITEM(IMGUI_CANVAS_TARGETS,
self.label = "Targets",
self.tooltip = "Toggles drawing the targets (the colored root/null icons).",
self.value = SETTINGS_PREVIEW_IS_TARGETS_DEFAULT
IMGUI_ITEM(IMGUI_CANVAS_ICONS,
self.label = "Icons",
self.tooltip = "Toggles drawing the the colored root/null icons.",
self.value = SETTINGS_PREVIEW_IS_ICONS_DEFAULT
);
IMGUI_ITEM(IMGUI_CANVAS_ALT_ICONS,
@@ -1581,12 +1622,22 @@ IMGUI_ITEM(IMGUI_ANIMATION_PREVIEW,
self.flags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse
);
#define IMGUI_ANIMATION_PREVIEW_VIEW_ROW_COUNT 2
IMGUI_ITEM(IMGUI_ANIMATION_PREVIEW_CENTER_VIEW,
self.label = "Center View",
self.tooltip = "Centers the current view on the animation preview.",
self.hotkey = HOTKEY_CENTER_VIEW,
self.focusWindow = IMGUI_ANIMATION_PREVIEW.label,
self.size = {-FLT_MIN, 0}
self.rowCount = IMGUI_ANIMATION_PREVIEW_VIEW_ROW_COUNT,
self.isSameLine = true
);
IMGUI_ITEM(IMGUI_ANIMATION_PREVIEW_FIT,
self.label = "Fit",
self.tooltip = "Adjust the view/pan based on the size of the animation, to fit the canvas' size.",
self.hotkey = HOTKEY_FIT,
self.focusWindow = IMGUI_ANIMATION_PREVIEW.label,
self.rowCount = IMGUI_ANIMATION_PREVIEW_VIEW_ROW_COUNT
);
IMGUI_ITEM(IMGUI_SPRITESHEET_EDITOR,
@@ -1672,12 +1723,12 @@ IMGUI_ITEM(IMGUI_FRAME_PROPERTIES_COLOR_OFFSET,
self.value = 0
);
const ImVec2 IMGUI_FRAME_PROPERTIES_FLIP_BUTTON_SIZE = {75, 0};
#define IMGUI_FRAME_PROPERTIES_FLIP_ROW_COUNT 2
IMGUI_ITEM(IMGUI_FRAME_PROPERTIES_FLIP_X,
self.label = "Flip X",
self.tooltip = "Change the sign of the X scale, to cheat flipping the layer horizontally.\n(Anm2 doesn't support flipping directly.)",
self.snapshotAction = "Frame Flip X",
self.size = IMGUI_FRAME_PROPERTIES_FLIP_BUTTON_SIZE,
self.rowCount = IMGUI_FRAME_PROPERTIES_FLIP_ROW_COUNT,
self.isSameLine = true
);
@@ -1685,7 +1736,7 @@ IMGUI_ITEM(IMGUI_FRAME_PROPERTIES_FLIP_Y,
self.label = "Flip Y",
self.tooltip = "Change the sign of the Y scale, to cheat flipping the layer vertically.\n(Anm2 doesn't support flipping directly.)",
self.snapshotAction = "Frame Flip Y",
self.size = IMGUI_FRAME_PROPERTIES_FLIP_BUTTON_SIZE
self.rowCount = IMGUI_FRAME_PROPERTIES_FLIP_ROW_COUNT
);
IMGUI_ITEM(IMGUI_FRAME_PROPERTIES_VISIBLE,
@@ -1700,9 +1751,16 @@ IMGUI_ITEM(IMGUI_FRAME_PROPERTIES_INTERPOLATED,
self.label = "Interpolation",
self.tooltip = "Toggles the interpolation of the selected frame.",
self.snapshotAction = "Frame Interpolation",
self.isSameLine = true,
self.value = true
);
IMGUI_ITEM(IMGUI_FRAME_PROPERTIES_ROUND,
self.label = "Round",
self.tooltip = "Values will be rounded to the nearest integer.",
self.value = SETTINGS_PROPERTIES_IS_ROUND_DEFAULT
);
IMGUI_ITEM(IMGUI_FRAME_PROPERTIES_EVENT,
self.label = "Event",
self.tooltip = "Change the event the trigger uses.",
@@ -1727,7 +1785,7 @@ IMGUI_ITEM(IMGUI_TOOL_PAN,
IMGUI_ITEM(IMGUI_TOOL_MOVE,
self.label = "## Move",
self.tooltip = "Use the move tool.\nWill move the selected item as the cursor is dragged, or directional keys are pressed.\n(Animation Preview only.)",
self.tooltip = "Use the move tool.\nWhen in animation preview, will move the position of the frame.\nWhen in spritesheet editor, will move the pivot instead.\nUse mouse or directional keys to change the value.",
self.function = imgui_tool_move_set,
self.hotkey = HOTKEY_MOVE,
self.atlas = ATLAS_MOVE
@@ -1751,7 +1809,7 @@ IMGUI_ITEM(IMGUI_TOOL_SCALE,
IMGUI_ITEM(IMGUI_TOOL_CROP,
self.label = "## Crop",
self.tooltip = "Use the crop tool.\nWill produce a crop rectangle based on how the cursor is dragged.\n(Spritesheet Editor only.)",
self.tooltip = "Use the crop tool.\nWill produce a crop rectangle based on how the cursor is dragged.\nAlternatively, you can use the arrow keys and Ctrl/Shift to move the size/position, respectively.\n(Spritesheet Editor only.)",
self.function = imgui_tool_crop_set,
self.hotkey = HOTKEY_CROP,
self.atlas = ATLAS_CROP
@@ -2082,7 +2140,8 @@ IMGUI_ITEM(IMGUI_TIMELINE_REMOVE_ITEM,
self.label = "Remove",
self.tooltip = "Removes the selected item (layer or null) from the animation.",
self.snapshotAction = "Remove Item",
self.focusWindow = IMGUI_TIMELINE.label,
self.chord = ImGuiKey_Delete,
self.focusWindow = IMGUI_TIMELINE_ITEMS_CHILD.label,
self.rowCount = IMGUI_TIMELINE_FOOTER_ITEM_CHILD_ITEM_COUNT
);

View File

@@ -4,7 +4,7 @@ static bool _anm2_rescale(const std::string& file, f32 scale)
{
Anm2 anm2;
if (!anm2_deserialize(&anm2, file)) return false;
if (!anm2_deserialize(&anm2, file, false)) return false;
anm2_scale(&anm2, scale);
return anm2_serialize(&anm2, file);
}
@@ -35,9 +35,19 @@ main(s32 argc, char* argv[])
return EXIT_FAILURE;
}
else if (std::string(argv[1]) == ARGUMENT_TEST && argv[2])
{
if (anm2_deserialize(&state.anm2, std::string(argv[2]), false)) return EXIT_SUCCESS;
return EXIT_FAILURE;
}
else if (std::string(argv[1]) == ARGUMENT_TEST_GL && argv[2])
{
if (!sdl_init(&state, true)) return EXIT_FAILURE;
if (anm2_deserialize(&state.anm2, std::string(argv[2]))) return EXIT_SUCCESS;
return EXIT_FAILURE;
}
else
if (argv[1])
state.argument = argv[1];
if (argv[1]) state.argument = argv[1];
}
init(&state);

View File

@@ -2,6 +2,9 @@
#include <SDL3/SDL_main.h>
#define ARGUMENT_TEST "--test"
#define ARGUMENT_TEST_GL "--test-gl"
#define ARGUMENT_RESCALE "--rescale"
#define ARGUMENT_RESCALE_ARGUMENT_ERROR "--rescale: specify both anm2 and scale arguments"
#define ARGUMENT_RESCALE_ANM2_ERROR "Unable to rescale anm2 {} by value {}. Make sure the file is valid."

View File

@@ -105,7 +105,7 @@ void preview_draw(Preview* self)
auto root_draw = [&](Anm2Frame root, vec3 colorOffset = {}, f32 alphaOffset = {}, bool isOnionskin = {})
{
mat4 model = canvas_model_get(PREVIEW_TARGET_SIZE, root.position, PREVIEW_TARGET_SIZE * 0.5f, PERCENT_TO_UNIT(root.scale), root.rotation);
mat4 model = quad_model_get(PREVIEW_TARGET_SIZE, root.position, PREVIEW_TARGET_SIZE * 0.5f, PERCENT_TO_UNIT(root.scale), root.rotation);
mat4 rootTransform = transform * model;
vec4 color = isOnionskin ? vec4(colorOffset, 1.0f - alphaOffset) : PREVIEW_ROOT_COLOR;
AtlasType atlas = self->settings->previewIsAltIcons ? ATLAS_TARGET_ALT : ATLAS_TARGET;
@@ -122,7 +122,7 @@ void preview_draw(Preview* self)
anm2_frame_from_time(self->anm2, &frame, Anm2Reference{animationID, ANM2_LAYER, id}, time);
if (!frame.isVisible) return;
mat4 model = canvas_model_get(frame.size, frame.position, frame.pivot, PERCENT_TO_UNIT(frame.scale), frame.rotation);
mat4 model = quad_model_get(frame.size, frame.position, frame.pivot, PERCENT_TO_UNIT(frame.scale), frame.rotation);
mat4 layerTransform = transform * (rootModel * model);
vec3 frameColorOffset = frame.offsetRGB + colorOffset;
vec4 frameTint = frame.tintRGBA;
@@ -149,7 +149,7 @@ void preview_draw(Preview* self)
{
vec4 pivotColor = isOnionskin ? vec4(colorOffset, 1.0f - alphaOffset) : PREVIEW_PIVOT_COLOR;
f32 vertices[] = ATLAS_UV_VERTICES(ATLAS_PIVOT);
mat4 pivotModel = canvas_model_get(CANVAS_PIVOT_SIZE, frame.position, CANVAS_PIVOT_SIZE * 0.5f, PERCENT_TO_UNIT(frame.scale), frame.rotation);
mat4 pivotModel = quad_model_get(CANVAS_PIVOT_SIZE, frame.position, CANVAS_PIVOT_SIZE * 0.5f, PERCENT_TO_UNIT(frame.scale), frame.rotation);
mat4 pivotTransform = transform * (rootModel * pivotModel);
canvas_texture_draw(&self->canvas, shaderTexture, self->resources->atlas.id, pivotTransform, vertices, pivotColor);
}
@@ -173,7 +173,7 @@ void preview_draw(Preview* self)
vec2 size = null.isShowRect ? CANVAS_PIVOT_SIZE : PREVIEW_TARGET_SIZE;
AtlasType atlas = null.isShowRect ? ATLAS_SQUARE : self->settings->previewIsAltIcons ? ATLAS_TARGET_ALT : ATLAS_TARGET;
mat4 model = canvas_model_get(size, frame.position, size * 0.5f, PERCENT_TO_UNIT(frame.scale), frame.rotation);
mat4 model = quad_model_get(size, frame.position, size * 0.5f, PERCENT_TO_UNIT(frame.scale), frame.rotation);
mat4 nullTransform = transform * (rootModel * model);
f32 vertices[] = ATLAS_UV_VERTICES(atlas);
@@ -182,7 +182,7 @@ void preview_draw(Preview* self)
if (null.isShowRect)
{
mat4 rectModel = canvas_model_get(PREVIEW_NULL_RECT_SIZE, frame.position, PREVIEW_NULL_RECT_SIZE * 0.5f, PERCENT_TO_UNIT(frame.scale), frame.rotation);
mat4 rectModel = quad_model_get(PREVIEW_NULL_RECT_SIZE, frame.position, PREVIEW_NULL_RECT_SIZE * 0.5f, PERCENT_TO_UNIT(frame.scale), frame.rotation);
mat4 rectTransform = transform * (rootModel * rectModel);
canvas_rect_draw(&self->canvas, shaderLine, rectTransform, color);
}
@@ -194,15 +194,15 @@ void preview_draw(Preview* self)
anm2_frame_from_time(self->anm2, &root, Anm2Reference{animationID, ANM2_ROOT}, time);
mat4 rootModel = self->settings->previewIsRootTransform ?
canvas_parent_model_get(root.position, {}, PERCENT_TO_UNIT(root.scale), root.rotation) : mat4(1.0f);
quad_model_parent_get(root.position, {}, PERCENT_TO_UNIT(root.scale), root.rotation) : mat4(1.0f);
if (self->settings->previewIsTargets && animation->rootAnimation.isVisible && root.isVisible)
if (self->settings->previewIsIcons && animation->rootAnimation.isVisible && root.isVisible)
root_draw(root, colorOffset, alphaOffset, isOnionskin);
for (auto [i, id] : self->anm2->layerMap)
layer_draw(rootModel, id, time, colorOffset, alphaOffset, isOnionskin);
if (self->settings->previewIsTargets)
if (self->settings->previewIsIcons)
for (auto& [id, _] : animation->nullAnimations)
null_draw(rootModel, id, time, colorOffset, alphaOffset, isOnionskin);
};

View File

@@ -42,8 +42,6 @@ struct Preview
f32 time{};
};
void preview_init(Preview* self, Anm2* anm2, Anm2Reference* reference, Resources* resources, Settings* settings);
void preview_draw(Preview* self);
void preview_tick(Preview* self);

View File

@@ -20,12 +20,19 @@
#define SETTINGS_PATH "settings.ini"
#define SETTINGS_TEMPORARY_EXTENSION ".tmp"
#ifdef _WIN32
#define SETTINGS_FFMPEG_PATH_VALUE_DEFAULT "C:\\ffmpeg\\bin\\ffmpeg.exe"
#else
#define SETTINGS_FFMPEG_PATH_VALUE_DEFAULT "/usr/bin/ffmpeg"
#endif
#define SETTINGS_LIST \
/* name, symbol, type, defaultValue */ \
X(windowSize, WINDOW_SIZE, TYPE_IVEC2_WH, {1280, 720}) \
X(isVsync, IS_VSYNC, TYPE_BOOL, true) \
\
X(hotkeyCenterView, HOTKEY_CENTER_VIEW, TYPE_STRING, "Home") \
X(hotkeyFit, HOTKEY_FIT, TYPE_STRING, "F") \
X(hotkeyZoomIn, HOTKEY_ZOOM_IN, TYPE_STRING, "Ctrl++") \
X(hotkeyZoomOut, HOTKEY_ZOOM_OUT, TYPE_STRING, "Ctrl+-") \
X(hotkeyPlayPause, HOTKEY_PLAY_PAUSE, TYPE_STRING, "Space") \
@@ -84,7 +91,7 @@
X(previewIsRootTransform, PREVIEW_IS_ROOT_TRANSFORM, TYPE_BOOL, false) \
X(previewIsTriggers, PREVIEW_IS_TRIGGERS, TYPE_BOOL, true) \
X(previewIsPivots, PREVIEW_IS_PIVOTS, TYPE_BOOL, false) \
X(previewIsTargets, PREVIEW_IS_TARGETS, TYPE_BOOL, true) \
X(previewIsIcons, PREVIEW_IS_ICONS, TYPE_BOOL, true) \
X(previewIsBorder, PREVIEW_IS_BORDER, TYPE_BOOL, false) \
X(previewIsAltIcons, PREVIEW_IS_ALT_ICONS, TYPE_BOOL, false) \
X(previewOverlayTransparency,PREVIEW_OVERLAY_TRANSPARENCY,TYPE_FLOAT, 255.0f) \
@@ -96,6 +103,8 @@
X(previewAxesColor, PREVIEW_AXES_COLOR, TYPE_VEC4, {1.0,1.0,1.0,0.125}) \
X(previewBackgroundColor, PREVIEW_BACKGROUND_COLOR, TYPE_VEC4, {0.113,0.184,0.286,1.0}) \
\
X(propertiesIsRound, PROPERTIES_IS_ROUND, TYPE_BOOL, true) \
\
X(generateStartPosition, GENERATE_START_POSITION, TYPE_IVEC2, {}) \
X(generateSize, GENERATE_SIZE, TYPE_IVEC2, {64,64}) \
X(generatePivot, GENERATE_PIVOT, TYPE_IVEC2, {32,32}) \
@@ -134,7 +143,7 @@
X(renderType, RENDER_TYPE, TYPE_INT, RENDER_PNG) \
X(renderPath, RENDER_PATH, TYPE_STRING, ".") \
X(renderFormat, RENDER_FORMAT, TYPE_STRING, "{}.png") \
X(ffmpegPath, FFMPEG_PATH, TYPE_STRING, "")
X(ffmpegPath, FFMPEG_PATH, TYPE_STRING, SETTINGS_FFMPEG_PATH_VALUE_DEFAULT)
#define X(name, symbol, type, ...) \
const inline DATATYPE_TO_CTYPE(type) SETTINGS_##symbol##_DEFAULT = __VA_ARGS__;
@@ -169,6 +178,7 @@ constexpr s32 SETTINGS_COUNT = (s32)std::size(SETTINGS_ENTRIES);
#define HOTKEY_LIST \
X(NONE, "None") \
X(CENTER_VIEW, "Center View") \
X(FIT, "Fit") \
X(ZOOM_IN, "Zoom In") \
X(ZOOM_OUT, "Zoom Out") \
X(PLAY_PAUSE, "Play/Pause") \
@@ -213,6 +223,7 @@ const inline HotkeyMember SETTINGS_HOTKEY_MEMBERS[HOTKEY_COUNT] =
{
nullptr,
&Settings::hotkeyCenterView,
&Settings::hotkeyFit,
&Settings::hotkeyZoomIn,
&Settings::hotkeyZoomOut,
&Settings::hotkeyPlayPause,
@@ -251,66 +262,72 @@ Collapsed=0
[Window][Tools]
Pos=8,40
Size=39,612
Size=37,460
Collapsed=0
DockId=0x0000000B,0
[Window][Animations]
Pos=1288,301
Size=304,351
Pos=1288,284
Size=304,216
Collapsed=0
DockId=0x0000000A,0
[Window][Events]
Pos=1005,353
Size=281,299
Pos=1007,332
Size=279,168
Collapsed=0
DockId=0x00000008,0
[Window][Spritesheets]
Pos=1288,40
Size=304,259
Size=304,242
Collapsed=0
DockId=0x00000009,0
[Window][Animation Preview]
Pos=49,40
Size=954,612
Pos=47,40
Size=958,460
Collapsed=0
DockId=0x0000000C,0
[Window][Spritesheet Editor]
Pos=49,40
Size=954,612
Pos=47,40
Size=958,460
Collapsed=0
DockId=0x0000000C,1
[Window][Timeline]
Pos=8,654
Size=1584,238
Pos=8,502
Size=1584,390
Collapsed=0
DockId=0x00000004,0
[Window][Frame Properties]
Pos=1005,40
Size=281,311
Pos=1007,40
Size=279,290
Collapsed=0
DockId=0x00000007,0
[Window][Onionskin]
Pos=8,502
Size=1584,390
Collapsed=0
DockId=0x00000004,1
[Docking][Data]
DockSpace ID=0xFC02A410 Window=0x0E46F4F7 Pos=8,40 Size=1584,852 Split=Y
DockNode ID=0x00000003 Parent=0xFC02A410 SizeRef=1902,612 Split=X
DockNode ID=0x00000001 Parent=0x00000003 SizeRef=1278,1016 Split=X Selected=0x024430EF
DockNode ID=0x00000005 Parent=0x00000001 SizeRef=995,654 Split=X Selected=0x024430EF
DockNode ID=0x0000000B Parent=0x00000005 SizeRef=39,654 Selected=0x18A5FDB9
DockNode ID=0x0000000C Parent=0x00000005 SizeRef=954,654 CentralNode=1 Selected=0x024430EF
DockNode ID=0x00000006 Parent=0x00000001 SizeRef=281,654 Split=Y Selected=0x754E368F
DockNode ID=0x00000007 Parent=0x00000006 SizeRef=631,311 Selected=0x754E368F
DockNode ID=0x00000008 Parent=0x00000006 SizeRef=631,299 Selected=0x8A65D963
DockNode ID=0x00000003 Parent=0xFC02A410 SizeRef=1902,568 Split=X
DockNode ID=0x00000001 Parent=0x00000003 SizeRef=1595,1016 Split=X Selected=0x024430EF
DockNode ID=0x00000005 Parent=0x00000001 SizeRef=997,654 Split=X Selected=0x024430EF
DockNode ID=0x0000000B Parent=0x00000005 SizeRef=37,654 Selected=0x18A5FDB9
DockNode ID=0x0000000C Parent=0x00000005 SizeRef=958,654 CentralNode=1 Selected=0x024430EF
DockNode ID=0x00000006 Parent=0x00000001 SizeRef=279,654 Split=Y Selected=0x754E368F
DockNode ID=0x00000007 Parent=0x00000006 SizeRef=631,359 Selected=0x754E368F
DockNode ID=0x00000008 Parent=0x00000006 SizeRef=631,207 Selected=0x8A65D963
DockNode ID=0x00000002 Parent=0x00000003 SizeRef=304,1016 Split=Y Selected=0x4EFD0020
DockNode ID=0x00000009 Parent=0x00000002 SizeRef=634,259 Selected=0x4EFD0020
DockNode ID=0x0000000A Parent=0x00000002 SizeRef=634,351 Selected=0xC1986EE2
DockNode ID=0x00000004 Parent=0xFC02A410 SizeRef=1902,238 Selected=0x4F89F0DC
DockNode ID=0x00000009 Parent=0x00000002 SizeRef=634,299 Selected=0x4EFD0020
DockNode ID=0x0000000A Parent=0x00000002 SizeRef=634,267 Selected=0xC1986EE2
DockNode ID=0x00000004 Parent=0xFC02A410 SizeRef=1902,390 Selected=0x4F89F0DC
)";
void settings_save(Settings* self);

View File

@@ -26,13 +26,13 @@ static void _snapshot_set(Snapshots* self, Snapshot* snapshot)
self->preview->time = snapshot->time;
self->action = snapshot->action;
anm2_spritesheet_texture_pixels_upload(self->anm2);
//anm2_spritesheet_texture_pixels_upload(self->anm2);
}
Snapshot snapshot_get(Snapshots* self)
{
Snapshot snapshot = {*self->anm2, *self->reference, self->preview->time, self->action};
anm2_spritesheet_texture_pixels_download(&snapshot.anm2);
//anm2_spritesheet_texture_pixels_download(&snapshot.anm2);
return snapshot;
}

View File

@@ -22,18 +22,16 @@ static void _draw(State* self)
SDL_GL_SwapWindow(self->window);
}
void init(State* self)
bool sdl_init(State* self, bool isTestMode = false)
{
settings_init(&self->settings);
if (!SDL_Init(SDL_INIT_VIDEO))
{
log_error(std::format(STATE_SDL_INIT_ERROR, SDL_GetError()));
quit(self);
return;
return false;
}
log_info(STATE_SDL_INIT_INFO);
if (!isTestMode) log_info(STATE_SDL_INIT_INFO);
// Todo, when sdl3 mixer is released officially
/*
@@ -61,6 +59,18 @@ void init(State* self)
log_info(STATE_MIX_INIT_INFO);
*/
if (isTestMode)
{
self->window = SDL_CreateWindow
(
WINDOW_TITLE,
WINDOW_TEST_MODE_SIZE.x, WINDOW_TEST_MODE_SIZE.y,
WINDOW_TEST_MODE_FLAGS
);
}
else
{
self->window = SDL_CreateWindow
(
WINDOW_TITLE,
@@ -68,6 +78,7 @@ void init(State* self)
self->settings.windowSize.y,
WINDOW_FLAGS
);
}
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, STATE_GL_VERSION_MAJOR);
@@ -79,17 +90,17 @@ void init(State* self)
{
log_error(std::format(STATE_GL_CONTEXT_INIT_ERROR, SDL_GetError()));
quit(self);
return;
return false;
}
if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress))
{
log_error(std::format(STATE_GLAD_INIT_ERROR));
quit(self);
return;
return false;
}
log_info(std::format(STATE_GL_CONTEXT_INIT_INFO, (const char*)glGetString(GL_VERSION)));
if (!isTestMode) log_info(std::format(STATE_GL_CONTEXT_INIT_INFO, (const char*)glGetString(GL_VERSION)));
window_vsync_set(self->settings.isVsync);
@@ -100,6 +111,15 @@ void init(State* self)
glDisable(GL_DEPTH_TEST);
glDisable(GL_LINE_SMOOTH);
return true;
}
void init(State* self)
{
settings_init(&self->settings);
if (!sdl_init(self)) return;
if (!self->argument.empty())
{
anm2_deserialize(&self->anm2, self->argument);

View File

@@ -51,6 +51,7 @@ struct State
bool isRunning = true;
};
bool sdl_init(State* self, bool isTestMode);
void init(State* state);
void loop(State* state);
void quit(State* state);

View File

@@ -35,6 +35,7 @@ std::vector<u8> texture_download(const Texture* self)
glBindTexture(GL_TEXTURE_2D, self->id);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
return pixels;
@@ -44,15 +45,11 @@ bool texture_from_path_init(Texture* self, const std::string& path)
{
u8* data = stbi_load(path.c_str(), &self->size.x, &self->size.y, &self->channels, TEXTURE_CHANNELS);
if (!data)
{
data = stbi_load(path_canonical_resolve(path).c_str(), &self->size.x, &self->size.y, &self->channels, TEXTURE_CHANNELS);
if (!data)
{
log_error(std::format(TEXTURE_INIT_ERROR, path));
return false;
}
}
self->isInvalid = false;
@@ -96,13 +93,8 @@ bool texture_from_rgba_init(Texture* self, ivec2 size, s32 channels, const u8* d
bool texture_from_rgba_write(const std::string& path, const u8* data, ivec2 size)
{
bool isSuccess = stbi_write_png(path.c_str(), size.x, size.y, TEXTURE_CHANNELS, data, size.x * TEXTURE_CHANNELS);
if (!isSuccess)
{
isSuccess = stbi_write_png(path_canonical_resolve(path).c_str(), size.x, size.y, TEXTURE_CHANNELS, data, size.x * TEXTURE_CHANNELS);
if (!isSuccess) log_info(std::format(TEXTURE_SAVE_ERROR, path));
}
log_info(std::format(TEXTURE_SAVE_INFO, path));
if (!isSuccess) log_error(std::format(TEXTURE_SAVE_ERROR, path));
else log_info(std::format(TEXTURE_SAVE_INFO, path));
return isSuccess;
}

View File

@@ -5,6 +5,9 @@
#define WINDOW_TITLE "Anm2Ed"
#define WINDOW_TITLE_FORMAT "Anm2Ed ({})"
#define WINDOW_FLAGS SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL
#define WINDOW_TEST_MODE_FLAGS WINDOW_FLAGS | SDL_WINDOW_HIDDEN
static const ivec2 WINDOW_TEST_MODE_SIZE = {1, 1};
void window_title_from_path_set(SDL_Window* self, const std::string& path);
bool window_color_from_position_get(SDL_Window* self, vec2 position, vec4* color);