diff --git a/.gitmodules b/.gitmodules index bc6f51b..8b36230 100644 --- a/.gitmodules +++ b/.gitmodules @@ -8,6 +8,3 @@ [submodule "include/tinyxml2"] path = include/tinyxml2 url = https://github.com/leethomason/tinyxml2 -[submodule "include/inih"] - path = include/inih - url = https://github.com/benhoyt/inih diff --git a/CMakeLists.txt b/CMakeLists.txt index 71e15c1..bc01344 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,10 @@ cmake_minimum_required(VERSION 3.15) -# at least some form of vcpkg detect... if(WIN32 AND DEFINED ENV{VCPKG_ROOT} AND NOT DEFINED CMAKE_TOOLCHAIN_FILE) set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" CACHE STRING "Vcpkg toolchain file") endif() -project(anm2ed C CXX) +project(anm2ed CXX) find_package(SDL3 REQUIRED CONFIG REQUIRED COMPONENTS SDL3-shared) find_package(GLEW REQUIRED) @@ -20,28 +19,23 @@ file(GLOB SOURCES "include/imgui/backends/imgui_impl_sdl3.cpp" "include/imgui/backends/imgui_impl_opengl3.cpp" "include/tinyxml2/tinyxml2.cpp" - "include/inih/ini.c" "${PROJECT_SOURCE_DIR}/src/*.cpp" "${PROJECT_SOURCE_DIR}/src/*.h" ) add_executable(${PROJECT_NAME} ${SOURCES}) -target_include_directories(${PROJECT_NAME} PRIVATE include include/imgui include/tinyxml2 include/inih src) +target_include_directories(${PROJECT_NAME} PRIVATE include include/imgui include/tinyxml2 src) if (NOT MSVC) -set(CMAKE_CXX_FLAGS "-g -O2 -std=c++23 -Wall -Wextra -pedantic -Wno-unused-variable -Wno-unused-parameter -Wno-ignored-qualifiers -Wno-parentheses -Wno-missing-field-initializers -Wno-unused-function -Wno-class-memaccess -Wno-delete-incomplete") + set(CMAKE_CXX_FLAGS "-g -O2 -std=c++23 -Wall -Wextra -pedantic -fmax-errors=1") else() -# /std:c++latest is required to make MSVC grant access to all the latest C++ stuff (C++23 is listed as preview even on dev previews of MSVC....) -# /STACK allocation size change is a hack, a proper fix would be to remove all the instances of allocating gigantic objects on the stack :pleading_face: -# /EHsc is probably also a hack, makes compile warnings about std::chrono go away -set(CMAKE_CXX_FLAGS "/std:c++latest /EHsc") -target_link_options(${PROJECT_NAME} PRIVATE "/STACK:0xffffff") + set(CMAKE_CXX_FLAGS "/std:c++latest /EHsc") # /std:c++latest is required to make MSVC grant access to all the latest C++ stuff (C++23 is listed as preview even on dev previews of MSVC....) endif() if(NOT MSVC) -target_link_libraries(${PROJECT_NAME} PRIVATE m) + target_link_libraries(${PROJECT_NAME} PRIVATE m) endif() -target_link_libraries(${PROJECT_NAME} PRIVATE OpenGL::GL GLEW::GLEW SDL3::SDL3) + target_link_libraries(${PROJECT_NAME} PRIVATE OpenGL::GL GLEW::GLEW SDL3::SDL3) message("System: ${CMAKE_SYSTEM_NAME}") message("Project: ${PROJECT_NAME}") diff --git a/settings.ini b/settings.ini deleted file mode 100644 index 866eec4..0000000 --- a/settings.ini +++ /dev/null @@ -1,69 +0,0 @@ -[Settings] -panX=-521.000000 -panY=258.000000 - -# Dear ImGui -[Window][Window] -Pos=0,32 -Size=1918,1030 -Collapsed=0 - -[Window][Debug##Default] -Pos=60,60 -Size=400,400 -Collapsed=0 - -[Window][Animations] -Pos=1197,40 -Size=485,342 -Collapsed=0 -DockId=0x00000005,0 - -[Window][Events] -Pos=1197,384 -Size=485,345 -Collapsed=0 -DockId=0x00000006,0 - -[Window][Spritesheets] -Pos=1684,40 -Size=226,689 -Collapsed=0 -DockId=0x00000002,0 - -[Window][Spritesheet Editor] -Pos=60,60 -Size=32,35 -Collapsed=0 - -[Window][Timeline] -Pos=8,731 -Size=1902,323 -Collapsed=0 -DockId=0x0000000A,0 - -[Window][Frame Properties] -Pos=890,40 -Size=305,689 -Collapsed=0 -DockId=0x00000008,0 - -[Window][Animation Preview] -Pos=8,40 -Size=880,689 -Collapsed=0 -DockId=0x00000007,0 - -[Docking][Data] -DockSpace ID=0xFB691B2E Window=0xFA2EAA04 Pos=8,40 Size=1902,1014 Split=Y Selected=0x024430EF - DockNode ID=0x00000009 Parent=0xFB691B2E SizeRef=1902,689 Split=X - DockNode ID=0x00000001 Parent=0x00000009 SizeRef=1674,1014 Split=X Selected=0x024430EF - DockNode ID=0x00000003 Parent=0x00000001 SizeRef=1187,1014 Split=X Selected=0x024430EF - DockNode ID=0x00000007 Parent=0x00000003 SizeRef=880,1014 CentralNode=1 Selected=0x024430EF - DockNode ID=0x00000008 Parent=0x00000003 SizeRef=305,1014 Selected=0x754E368F - DockNode ID=0x00000004 Parent=0x00000001 SizeRef=485,1014 Split=Y Selected=0x8A65D963 - DockNode ID=0x00000005 Parent=0x00000004 SizeRef=485,504 Selected=0xC1986EE2 - DockNode ID=0x00000006 Parent=0x00000004 SizeRef=485,508 Selected=0x8A65D963 - DockNode ID=0x00000002 Parent=0x00000009 SizeRef=226,1014 Selected=0x4EFD0020 - DockNode ID=0x0000000A Parent=0xFB691B2E SizeRef=1902,323 Selected=0x4F89F0DC - diff --git a/src/COMMON.h b/src/COMMON.h index 10b263e..e48d386 100644 --- a/src/COMMON.h +++ b/src/COMMON.h @@ -2,34 +2,29 @@ #include +#include #include #include #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include +#include +#include +#include +#include +#include +#include #include -#include -#include -#include +#include +#include +#include +#include +#include #include "STRINGS.h" -#ifndef PATH_MAX -#define PATH_MAX 4096 -#endif - typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; @@ -46,14 +41,58 @@ typedef double f64; #define PI (GLM_PI) #define TAU (PI * 2) -using namespace glm; // fuck you +using namespace glm; #define MIN(x, min) (x < min ? min : x) #define MAX(x, max) (x > max ? max : x) #define CLAMP(x, min, max) (MIN(MAX(x, max), min)) +// Converts a string to a bool +static inline bool string_to_bool(const std::string& string) +{ + return string == "true" || string == "1"; +}; + +// Given a file path, sets the working directory to it +static inline void working_directory_from_file_set(const std::string& path) +{ + std::filesystem::path filePath = path; + std::filesystem::path parentPath = filePath.parent_path(); + std::filesystem::current_path(parentPath); +}; + +// Converts an enum to a string value +static inline const char* enum_to_string(const char* array[], s32 count, s32 index) +{ + return (index >= 0 && index < count) ? array[index] : ""; +}; + +// Converts a string to an enum value +static inline s32 string_to_enum(const std::string& string, const char* const* array, s32 n) +{ + for (s32 i = 0; i < n; i++) + if (string == array[i]) + return i; + return -1; +}; + +// Macro to define enum to string functions +#define DEFINE_ENUM_TO_STRING_FUNCTION(function, array, count) \ + static inline std::string function(s32 index) \ + { \ + return enum_to_string(array, count, index); \ + }; + +// Macro to define string to enum functions +#define DEFINE_STRING_TO_ENUM_FUNCTION(function, enumType, stringArray, count) \ + static inline enumType function(const std::string& string) \ + { \ + return static_cast(string_to_enum(string, stringArray, count)); \ + }; + #define COLOR_FLOAT_TO_INT(x) (static_cast((x) * 255.0f)) #define COLOR_INT_TO_FLOAT(x) ((x) / 255.0f) +#define PERCENT_TO_UNIT(x) (x / 100.0f) #define TICK_DELAY 33.3f #define SECOND 1000.0f @@ -82,8 +121,8 @@ static const f32 GL_UV_VERTICES[] = 1, 1, 1.0f, 1.0f, 0, 1, 0.0f, 1.0f }; -#define IMVEC2_VEC2(value) ImVec2(value.x, value.y) -#define VEC2_IMVEC2(value) glm::vec2(value.x, value.y) + + #define IMVEC4_VEC4(value) ImVec4(value.r, value.g, value.b, value.a) static const GLuint GL_TEXTURE_INDICES[] = {0, 1, 2, 2, 3, 0}; @@ -95,19 +134,15 @@ static const vec4 COLOR_OPAQUE = {1.0f, 1.0f, 1.0f, 1.0f}; static const vec4 COLOR_TRANSPARENT = {0.0f, 0.0f, 0.0f, 1.0f}; static const vec3 COLOR_OFFSET_NONE = {0.0f, 0.0f, 0.0f}; -static inline const char* enum_to_string(const char* arr[], s32 count, s32 index) { return (index >= 0 && index < count) ? arr[index] : "undefined"; } -static inline s32 string_to_enum(const char* str, const char* const* arr, s32 n) { for (s32 i=0; i static inline s32 map_next_id_get(const std::map& map) { s32 id = 0; for (const auto& [key, _] : map) if (key != id) break; else ++id; return id; } -/* Swaps elements in a map */ -/* If neither key exists, do nothing */ -/* If one key exists, change its ID */ -/* If both keys exist, swap */ +// Swaps elements in a map +// If neither key exists, do nothing +// If one key exists, change its ID +// If both keys exist, swap template static inline void map_swap(Map& map, const Key& key1, const Key& key2) { @@ -132,14 +167,4 @@ static inline void map_swap(Map& map, const Key& key1, const Key& key2) map[key1] = std::move(it2->second); map.erase(it2); } -}; - -#define DEFINE_ENUM_TO_STRING_FN(fn_name, arr, count) \ - static inline const char* fn_name(s32 index) { \ - return enum_to_string(arr, count, index); \ - } - -#define DEFINE_STRING_TO_ENUM_FN(fn_name, enum_type, str_array, count) \ - static inline enum_type fn_name(const char* str) { \ - return (enum_type)string_to_enum(str, str_array, count); \ - } +}; \ No newline at end of file diff --git a/src/PACKED.h b/src/PACKED.h index 9d9082d..8d2698e 100644 --- a/src/PACKED.h +++ b/src/PACKED.h @@ -2,8 +2,8 @@ #include "COMMON.h" -static const unsigned int TEXTURE_ATLAS_LENGTH = 916; -static const unsigned char TEXTURE_ATLAS[] = +const u32 TEXTURE_ATLAS_LENGTH = 916; +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, 0x68, @@ -84,7 +84,6 @@ static const unsigned char TEXTURE_ATLAS[] = 0xae, 0x42, 0x60, 0x82 }; -#define TEXTURE_COUNT (TEXTURE_TARGET + 1) enum TextureType { TEXTURE_ROOT, @@ -117,17 +116,18 @@ enum TextureType TEXTURE_PICKER, TEXTURE_FRAME, TEXTURE_FRAME_ALT, - TEXTURE_TARGET + TEXTURE_TARGET, + TEXTURE_COUNT }; -static const vec2 ATLAS_SIZE = {96, 104}; -static const vec2 TEXTURE_SIZE = {16, 16}; -static const vec2 TEXTURE_SIZE_SMALL = {8, 8}; -static const vec2 TEXTURE_SIZE_BIG = {32, 32}; -static const vec2 TEXTURE_SIZE_OBLONG = {16, 40}; +const vec2 ATLAS_SIZE = {96, 104}; +const vec2 TEXTURE_SIZE = {16, 16}; +const vec2 TEXTURE_SIZE_SMALL = {8, 8}; +const vec2 TEXTURE_SIZE_BIG = {32, 32}; +const vec2 TEXTURE_SIZE_OBLONG = {16, 40}; #define ATLAS_UV(x,y){(f32)x / ATLAS_SIZE[0], (f32) y / ATLAS_SIZE[1]} -static const vec2 ATLAS_UVS[TEXTURE_COUNT][2] = +const vec2 ATLAS_UVS[TEXTURE_COUNT][2] = { { ATLAS_UV( 0, 0), ATLAS_UV( 16, 16) }, /* 16 x 16 v */ { ATLAS_UV( 16, 0), ATLAS_UV( 32, 16) }, @@ -162,7 +162,7 @@ static const vec2 ATLAS_UVS[TEXTURE_COUNT][2] = { ATLAS_UV( 48, 64), ATLAS_UV( 80, 96) } /* 32 x 32 */ }; -static const vec2 ATLAS_SIZES[TEXTURE_COUNT] = +const vec2 ATLAS_SIZES[TEXTURE_COUNT] = { TEXTURE_SIZE, TEXTURE_SIZE, @@ -197,89 +197,92 @@ static const vec2 ATLAS_SIZES[TEXTURE_COUNT] = TEXTURE_SIZE_BIG }; -#define IMVEC2_ATLAS_UV_GET(type) IMVEC2_VEC2(ATLAS_UVS[type][0]), IMVEC2_VEC2(ATLAS_UVS[type][1]) #define ATLAS_UV_VERTICES(type) UV_VERTICES(ATLAS_UVS[type][0], ATLAS_UVS[type][1]) /* Shaders */ struct ShaderData { - const char* vertex; - const char* fragment; + std::string vertex; + std::string fragment; }; -#define SHADER_COUNT (SHADER_LINE_DOTTED + 1) enum ShaderType { SHADER_LINE, SHADER_TEXTURE, - SHADER_LINE_DOTTED + SHADER_LINE_DOTTED, + SHADER_COUNT }; -static const char SHADER_VERTEX[] = -"#version 330 core\n" \ -"layout (location = 0) in vec2 i_position;\n" \ -"layout (location = 1) in vec2 i_uv;\n" \ -"\n" \ -"out vec2 i_uv_out;\n" \ -"\n" \ -"uniform mat4 u_transform;\n" \ -"\n" \ -"void main()\n" \ -"{\n" \ -" i_uv_out = i_uv;\n" \ -" gl_Position = u_transform * vec4(i_position, 0.0, 1.0);\n" \ -"}\n"; +const std::string SHADER_VERTEX = R"( +#version 330 core +layout (location = 0) in vec2 i_position; +layout (location = 1) in vec2 i_uv; -static const char SHADER_TEXTURE_FRAGMENT[] = -"#version 330 core\n" \ -"in vec2 i_uv_out;\n" \ -"uniform sampler2D u_texture;\n" \ -"uniform vec4 u_tint;\n" \ -"uniform vec3 u_color_offset;\n" \ -"out vec4 o_fragColor;\n" \ -"void main()\n" \ -"{\n" \ -" vec4 texColor = texture(u_texture, i_uv_out);\n" \ -" texColor *= u_tint;\n" \ -" texColor.rgb += u_color_offset;\n" \ -" o_fragColor = texColor;\n" \ -"}\n"; +out vec2 i_uv_out; -static const char SHADER_FRAGMENT[] = -"#version 330 core\n" \ -"out vec4 o_fragColor;\n" \ -"uniform vec4 u_color;\n" \ -"\n" \ -"void main()\n" \ -"{\n" \ -" o_fragColor = u_color;\n" \ -"}\n"; +uniform mat4 u_transform; -static const char SHADER_LINE_DOTTED_FRAGMENT[] = -"#version 330 core\n" \ -"uniform vec4 u_color;\n" \ -"out vec4 o_fragColor;\n" \ -"void main()\n" \ -"{\n" \ -" float patternX = mod(gl_FragCoord.x, 10.0);\n" \ -" float patternY = mod(gl_FragCoord.y, 10.0);\n" \ -" if (patternX < 5.0 || patternY < 5.0)\n" \ -" {\n" \ -" o_fragColor = u_color;\n" \ -" }\n" \ -" else\n" \ -" {\n" \ -" discard;\n" \ -" }\n" \ -"}\n"; +void main() +{ + i_uv_out = i_uv; + gl_Position = u_transform * vec4(i_position, 0.0, 1.0); +} +)"; -static const char SHADER_UNIFORM_COLOR[] = "u_color"; -static const char SHADER_UNIFORM_TRANSFORM[] = "u_transform"; -static const char SHADER_UNIFORM_TINT[] = "u_tint"; -static const char SHADER_UNIFORM_COLOR_OFFSET[] = "u_color_offset"; -static const char SHADER_UNIFORM_TEXTURE[] = "u_texture"; +const std::string SHADER_FRAGMENT = R"( +#version 330 core +out vec4 o_fragColor; +uniform vec4 u_color; -static const ShaderData SHADER_DATA[SHADER_COUNT] = +void main() +{ + o_fragColor = u_color; +} +)"; + +const std::string SHADER_TEXTURE_FRAGMENT = R"( +#version 330 core +in vec2 i_uv_out; +uniform sampler2D u_texture; +uniform vec4 u_tint; +uniform vec3 u_color_offset; +out vec4 o_fragColor; +void main() +{ + vec4 texColor = texture(u_texture, i_uv_out); + texColor *= u_tint; + texColor.rgb += u_color_offset; + o_fragColor = texColor; +} +)"; + +const std::string SHADER_LINE_DOTTED_FRAGMENT = R"( +#version 330 core +uniform vec4 u_color; +out vec4 o_fragColor; +void main() +{ + float patternX = mod(gl_FragCoord.x, 10.0); + float patternY = mod(gl_FragCoord.y, 10.0); + if (patternX < 5.0 || patternY < 5.0) + { + o_fragColor = u_color; + } + else + { + discard; + } +} +)"; + +#define SHADER_UNIFORM_COLOR "u_color" +#define SHADER_UNIFORM_TRANSFORM "u_transform" +#define SHADER_UNIFORM_TINT "u_tint" +#define SHADER_UNIFORM_COLOR_OFFSET "u_color_offset" +#define SHADER_UNIFORM_TEXTURE "u_texture" + +const ShaderData SHADER_DATA[SHADER_COUNT] = { {SHADER_VERTEX, SHADER_FRAGMENT}, {SHADER_VERTEX, SHADER_TEXTURE_FRAGMENT}, diff --git a/src/STRINGS.h b/src/STRINGS.h index 5c42c5f..d6c4f25 100644 --- a/src/STRINGS.h +++ b/src/STRINGS.h @@ -1,37 +1,32 @@ #pragma once -#define STRING_UNDEFINED "undefined" -#define STRING_EMPTY "" - #define STRING_WINDOW_TITLE "Anm2Ed" -#define STRING_WINDOW_TITLE_EDITING "Anm2Ed (%s)" #define STRING_ANM2_CREATED_ON_FORMAT "%d-%B-%Y %I:%M:%S %p" -#define STRING_ERROR_SDL_INIT "[ERROR] Could not initialize SDL (%s)\n" -#define STRING_ERROR_GL_CONTEXT_INIT "[ERROR] Could not initialize OpenGL context (%s)\n" -#define STRING_ERROR_FILE_READ "[ERROR] Could not read from file: %s\n" -#define STRING_ERROR_SHADER_INIT "[ERROR] Could not initialize shader: %i\n%s" -#define STRING_ERROR_TEXTURE_INIT "[ERROR] Could not initialize texture: %s\n" -#define STRING_ERROR_ANM2_READ "[ERROR] Could not read anm2 from file %s: %s\n" -#define STRING_ERROR_ANM2_WRITE "[ERROR] Could not write anm2 to file %s: %s\n" -#define STRING_ERROR_SETTINGS_INIT "[ERROR] Could not load settings file (%s). Should be created on program exit.\n" +#define STRING_ERROR_SDL_INIT "[ERROR] Could not initialize SDL: " +#define STRING_ERROR_GL_CONTEXT_INIT "[ERROR] Could not initialize OpenGL context: " +#define STRING_ERROR_FILE_READ "[ERROR] Could not read from file: " +#define STRING_ERROR_SHADER_INIT "[ERROR] Could not initialize shader: " +#define STRING_ERROR_TEXTURE_INIT "[ERROR] Could not initialize texture: " +#define STRING_ERROR_ANM2_READ "[ERROR] Could not read anm2 from file: " +#define STRING_ERROR_ANM2_WRITE "[ERROR] Could not write anm2 to file: " +#define STRING_ERROR_SETTINGS_INIT "[ERROR] Could not load settings file: " -#define STRING_INFO_INIT "[INFO] Initializing\n" -#define STRING_INFO_QUIT "[INFO] Exited\n" -#define STRING_INFO_SDL_INIT "[INFO] Initialized SDL\n" -#define STRING_INFO_SDL_QUIT "[INFO] Quit SDL\n" -#define STRING_INFO_GLEW_INIT "[INFO] Initialized GLEW\n" -#define STRING_INFO_GL_CONTEXT_INIT "[INFO] Initialized OpenGL context\n" -#define STRING_INFO_FILE_READ "[INFO] Read from file: %s\n" -#define STRING_INFO_SHADER_INIT "[INFO] Initialized shader: %i\n" -#define STRING_INFO_TEXTURE_INIT "[INFO] Initialized texture: %s\n" -#define STRING_INFO_ANM2_WRITE "[INFO] Wrote anm2 to file: %s\n" -#define STRING_INFO_ANM2_READ "[INFO] Read anm2 from file: %s\n" -#define STRING_INFO_OPENGL "[INFO] OpenGL %s\n" +#define STRING_INFO_INIT "[INFO] Initializing" +#define STRING_INFO_QUIT "[INFO] Exited" +#define STRING_INFO_SDL_INIT "[INFO] Initialized SDL" +#define STRING_INFO_SDL_QUIT "[INFO] Quit SDL" +#define STRING_INFO_GLEW_INIT "[INFO] Initialized GLEW" +#define STRING_INFO_GL_CONTEXT_INIT "[INFO] Initialized OpenGL context" +#define STRING_INFO_FILE_READ "[INFO] Read from file: " +#define STRING_INFO_TEXTURE_INIT "[INFO] Initialized texture: " +#define STRING_INFO_ANM2_WRITE "[INFO] Wrote anm2 to file: " +#define STRING_INFO_ANM2_READ "[INFO] Read anm2 from file: " +#define STRING_INFO_OPENGL "OpenGL" -#define STRING_INFO_IMGUI_INIT "[INFO] Initialized Dear Imgui\n" -#define STRING_INFO_IMGUI_FREE "[INFO] Freed Dear Imgui\n" +#define STRING_INFO_IMGUI_INIT "[INFO] Initialized Dear Imgui" +#define STRING_INFO_IMGUI_FREE "[INFO] Freed Dear Imgui" #define STRING_DIALOG_ANM2_READ "Select .anm2 file to read..." #define STRING_DIALOG_ANM2_WRITE "Select .anm2 file to write to..." @@ -48,7 +43,7 @@ #define STRING_ANM2_ROOT "Root" #define STRING_PREVIEW_FRAMES_DIRECTORY "frames/" -#define STRING_PREVIEW_FRAMES_FORMAT "%s/%03d.png" +#define STRING_PREVIEW_FRAMES_FORMAT "{}/{:03}.png" #define STRING_IMGUI_WINDOW "Window" #define STRING_IMGUI_DOCKSPACE "Dockspace" @@ -78,14 +73,14 @@ #define STRING_IMGUI_ANIMATIONS_REMOVE "Remove" #define STRING_IMGUI_ANIMATIONS_DUPLICATE "Duplicate" #define STRING_IMGUI_ANIMATIONS_SET_AS_DEFAULT "Set as Default" -#define STRING_IMGUI_ANIMATIONS_DEFAULT_ANIMATION_FORMAT "(*) %s " +#define STRING_IMGUI_ANIMATIONS_DEFAULT_ANIMATION_FORMAT "(*) {}" #define STRING_IMGUI_ANIMATIONS_DRAG_DROP "Animation Drag/Drop" #define STRING_IMGUI_EVENTS "Events" #define STRING_IMGUI_EVENTS_EVENT_LABEL "##Event" #define STRING_IMGUI_EVENTS_ADD "Add" #define STRING_IMGUI_EVENTS_REMOVE "Remove" -#define STRING_IMGUI_EVENT_FORMAT "#%i %s" +#define STRING_IMGUI_EVENT_FORMAT "#{} {}" #define STRING_IMGUI_EVENTS_DRAG_DROP "Event Drag/Drop" #define STRING_IMGUI_SPRITESHEETS "Spritesheets" @@ -93,7 +88,7 @@ #define STRING_IMGUI_SPRITESHEETS_REMOVE "Remove" #define STRING_IMGUI_SPRITESHEETS_RELOAD "Reload" #define STRING_IMGUI_SPRITESHEETS_REPLACE "Replace" -#define STRING_IMGUI_SPRITESHEET_FORMAT "#%i %s" +#define STRING_IMGUI_SPRITESHEET_FORMAT "#{} {}" #define STRING_IMGUI_SPRITESHEETS_DRAG_DROP "Spritesheet Drag/Drop" #define STRING_IMGUI_FRAME_PROPERTIES "Frame Properties" @@ -136,7 +131,7 @@ #define STRING_IMGUI_ANIMATION_PREVIEW_ROOT_TRANSFORM "Root Transform" #define STRING_IMGUI_ANIMATION_PREVIEW_SHOW_PIVOT "Show Pivot" #define STRING_IMGUI_ANIMATION_PREVIEW_POSITION "##Position" -#define STRING_IMGUI_ANIMATION_PREVIEW_POSITION_FORMAT "Position: {%5.0f, %5.0f}" +#define STRING_IMGUI_POSITION_FORMAT "Position: {{{:5}, {:5}}}" #define STRING_IMGUI_SPRITESHEET_EDITOR "Spritesheet Editor" #define STRING_IMGUI_SPRITESHEET_EDITOR_LABEL "##Animation Preview" @@ -154,7 +149,6 @@ #define STRING_IMGUI_SPRITESHEET_EDITOR_CENTER_VIEW "Center View" #define STRING_IMGUI_SPRITESHEET_EDITOR_BORDER "Border" #define STRING_IMGUI_SPRITESHEET_EDITOR_POSITION "##Position" -#define STRING_IMGUI_SPRITESHEET_EDITOR_POSITION_FORMAT "Position: {%5.0f, %5.0f}" #define STRING_IMGUI_TIMELINE "Timeline" #define STRING_IMGUI_TIMELINE_HEADER "##Header" @@ -162,9 +156,7 @@ #define STRING_IMGUI_TIMELINE_ELEMENT_DOWN "##Down" #define STRING_IMGUI_TIMELINE_ELEMENT_FRAMES "Element Frames" #define STRING_IMGUI_TIMELINE_ROOT "Root" -#define STRING_IMGUI_TIMELINE_ELEMENT_FORMAT "#%i %s" -#define STRING_IMGUI_TIMELINE_SPRITESHEET_FORMAT "#%i" -#define STRING_IMGUI_TIMELINE_SPRITESHEET_UNKNOWN "#?" +#define STRING_IMGUI_TIMELINE_ITEM_FORMAT "#{} {}" #define STRING_IMGUI_TIMELINE_ELEMENT_SPRITESHEET_ID_LABEL "##Timeline Element Spritesheet ID" #define STRING_IMGUI_TIMELINE_ELEMENT_NAME_LABEL "##Timeline Element Name" #define STRING_IMGUI_TIMELINE_TRIGGERS "Triggers" @@ -196,6 +188,7 @@ #define STRING_IMGUI_TIMELINE_ELEMENT_REMOVE "Remove Element" #define STRING_IMGUI_TIMELINE_LOOP "Loop" #define STRING_IMGUI_TIMELINE_FPS "FPS" +#define STRING_IMGUI_TIMELINE_SPRITESHEET_ID_FORMAT "#{}" #define STRING_IMGUI_TIMELINE_CREATED_BY "Author" #define STRING_IMGUI_TIMELINE_CREATED_ON "Created on: %s" #define STRING_IMGUI_TIMELINE_VERSION "Version: %i" diff --git a/src/anm2.cpp b/src/anm2.cpp index f335d7f..8ffe636 100644 --- a/src/anm2.cpp +++ b/src/anm2.cpp @@ -2,25 +2,24 @@ using namespace tinyxml2; -/* Sets the anm2's date to the system's current date */ -void -anm2_created_on_set(Anm2* self) +static void _anm2_created_on_set(Anm2* self); + +// Sets the anm2's date to the system's current date +static void +_anm2_created_on_set(Anm2* self) { - time_t currentTime; - struct tm* local; - char date[ANM2_STRING_MAX]; + auto now = std::chrono::system_clock::now(); + std::time_t time = std::chrono::system_clock::to_time_t(now); + std::tm localTime = *std::localtime(&time); - currentTime = time(NULL); - local = localtime(¤tTime); - - strftime(date, ANM2_STRING_MAX, STRING_ANM2_CREATED_ON_FORMAT, local); - - strncpy(self->createdOn, date, ANM2_STRING_MAX); + std::ostringstream timeString; + timeString << std::put_time(&localTime, STRING_ANM2_CREATED_ON_FORMAT); + self->createdOn = timeString.str(); } -/* Serializes the anm2 struct into XML and exports it to the given path */ +// Serializes the anm2 struct into XML and exports it to the given path bool -anm2_serialize(Anm2* self, const char* path) +anm2_serialize(Anm2* self, const std::string& path) { XMLDocument document; XMLError error; @@ -34,108 +33,111 @@ anm2_serialize(Anm2* self, const char* path) XMLElement* eventsElement; XMLElement* animationsElement; - if (!self || !path) + if (!self || path.empty()) return false; - /* Update creation date on first version */ + // Update creation date on first version if (self->version == 0) - anm2_created_on_set(self); + _anm2_created_on_set(self); - /* Increment anm2's version */ + // Set anm2 path to argument + self->path = path; + + // Update version self->version++; - /* AnimatedActor */ + // AnimatedActor animatedActorElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_ANIMATED_ACTOR]); document.InsertFirstChild(animatedActorElement); - /* Info */ + // Info infoElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_INFO]); - infoElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_CREATED_BY], self->createdBy); /* CreatedBy */ - infoElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_CREATED_ON], self->createdOn); /* CreatedOn */ - infoElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_VERSION], self->version); /* Version; note its incrementation */ - infoElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_FPS], self->fps); /* FPS */ + infoElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_CREATED_BY], self->createdBy.c_str()); // CreatedBy + infoElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_CREATED_ON], self->createdOn.c_str()); // CreatedOn + infoElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_VERSION], self->version); // Version + infoElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_FPS], self->fps); // FPS animatedActorElement->InsertEndChild(infoElement); - /* Content */ + // Content contentElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_CONTENT]); - /* Spritesheets */ + // Spritesheets spritesheetsElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_SPRITESHEETS]); for (auto & [id, spritesheet] : self->spritesheets) { XMLElement* spritesheetElement; - /* Spritesheet */ + // Spritesheet spritesheetElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_SPRITESHEET]); - spritesheetElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_PATH], spritesheet.path); /* Path */ - spritesheetElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ID], id); /* ID */ + spritesheetElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_PATH], spritesheet.path.c_str()); // Path + spritesheetElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ID], id); // ID spritesheetsElement->InsertEndChild(spritesheetElement); } contentElement->InsertEndChild(spritesheetsElement); - /* Layers */ + // Layers layersElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_LAYERS]); for (auto & [id, layer] : self->layers) { XMLElement* layerElement; - /* Layer */ + // Layer layerElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_LAYER]); - layerElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_NAME], layer.name); /* Path */ - layerElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ID], id); /* ID */ - layerElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_SPRITESHEET_ID], layer.spritesheetID); /* SpritesheetId */ + layerElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_NAME], layer.name.c_str()); // Path + layerElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ID], id); // ID + layerElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_SPRITESHEET_ID], layer.spritesheetID); // SpritesheetId layersElement->InsertEndChild(layerElement); } contentElement->InsertEndChild(layersElement); - /* Nulls */ + // Nulls nullsElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_NULLS]); for (auto & [id, null] : self->nulls) { XMLElement* nullElement; - /* Null */ + // Null nullElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_NULL]); - nullElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_NAME], null.name); /* Name */ - nullElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ID], id); /* ID */ + nullElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_NAME], null.name.c_str()); // Name + nullElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ID], id); // ID - /* special case; only serialize if this is true */ + // special case; only serialize if this is true if (null.isShowRect) - nullElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_SHOW_RECT], null.isShowRect); /* ShowRect */ + nullElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_SHOW_RECT], null.isShowRect); // ShowRect nullsElement->InsertEndChild(nullElement); } contentElement->InsertEndChild(nullsElement); - /* Events */ + // Events eventsElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_EVENTS]); for (auto & [id, event] : self->events) { XMLElement* eventElement; - /* Event */ + // Event eventElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_EVENT]); - eventElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_NAME], event.name); /* Name */ - eventElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ID], id); /* ID */ + eventElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_NAME], event.name.c_str()); // Name + eventElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ID], id); // ID eventsElement->InsertEndChild(eventElement); } contentElement->InsertEndChild(eventsElement); animatedActorElement->InsertEndChild(contentElement); - - /* Animations */ + + // Animations animationsElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_ANIMATIONS]); - animationsElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_DEFAULT_ANIMATION], self->defaultAnimation); + animationsElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_DEFAULT_ANIMATION], self->defaultAnimation.c_str()); // DefaultAnimation - for (auto & [id, animation] : self->animations) + for (const auto & [id, animation] : self->animations) { XMLElement* animationElement; XMLElement* rootAnimationElement; @@ -143,86 +145,86 @@ anm2_serialize(Anm2* self, const char* path) XMLElement* nullAnimationsElement; XMLElement* triggersElement; - /* Animation */ + // Animation animationElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_ANIMATION]); - animationElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_NAME], animation.name); /* Name */ - animationElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_FRAME_NUM], animation.frameNum); /* FrameNum */ - animationElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_LOOP], animation.isLoop); /* Loop */ + animationElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_NAME], animation.name.c_str()); // Name + animationElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_FRAME_NUM], animation.frameNum); // FrameNum + animationElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_LOOP], animation.isLoop); // Loop - /* RootAnimation */ + // RootAnimation rootAnimationElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_ROOT_ANIMATION]); - for (auto & frame : animation.rootAnimation.frames) + for (const auto & frame : animation.rootAnimation.frames) { XMLElement* frameElement; - /* Frame */ + // Frame frameElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_FRAME]); - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_X_POSITION], frame.position.x); /* XPosition */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_Y_POSITION], frame.position.y); /* YPosition */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_X_PIVOT], frame.pivot.x); /* XPivot */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_Y_PIVOT], frame.pivot.y); /* YPivot */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_X_SCALE], frame.scale.x); /* XScale */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_Y_SCALE], frame.scale.y); /* XScale */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_DELAY], frame.delay); /* Delay */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_VISIBLE], frame.isVisible); /* Visible */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_RED_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.r)); /* RedTint */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_GREEN_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.g)); /* GreenTint */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_BLUE_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.b)); /* BlueTint */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ALPHA_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.a)); /* AlphaTint */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_RED_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.r)); /* RedOffset */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_GREEN_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.g)); /* GreenOffset */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_BLUE_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.b)); /* BlueOffset */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ROTATION], frame.rotation); /* Rotation */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_INTERPOLATED], frame.isInterpolated); /* Interpolated */ + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_X_POSITION], frame.position.x); // XPosition + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_Y_POSITION], frame.position.y); // YPosition + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_X_PIVOT], frame.pivot.x); // XPivot + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_Y_PIVOT], frame.pivot.y); // YPivot + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_X_SCALE], frame.scale.x); // XScale + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_Y_SCALE], frame.scale.y); // YScale + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_DELAY], frame.delay); // Delay + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_VISIBLE], frame.isVisible); // Visible + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_RED_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.r)); // RedTint + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_GREEN_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.g)); // GreenTint + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_BLUE_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.b)); // BlueTint + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ALPHA_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.a)); // AlphaTint + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_RED_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.r)); // RedOffset + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_GREEN_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.g)); // GreenOffset + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_BLUE_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.b)); // BlueOffset + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ROTATION], frame.rotation); // Rotation + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_INTERPOLATED], frame.isInterpolated); // Interpolated rootAnimationElement->InsertEndChild(frameElement); } animationElement->InsertEndChild(rootAnimationElement); - /* LayerAnimations */ + // LayerAnimations layerAnimationsElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_LAYER_ANIMATIONS]); for (const auto & [layerID, layerAnimation] : animation.layerAnimations) { XMLElement* layerAnimationElement; - /* LayerAnimation */ + // LayerAnimation layerAnimationElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_LAYER_ANIMATION]); - layerAnimationElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_LAYER_ID], layerID); /* LayerID */ - layerAnimationElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_VISIBLE], layerAnimation.isVisible); /* Visible */ + layerAnimationElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_LAYER_ID], layerID); // LayerId + layerAnimationElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_VISIBLE], layerAnimation.isVisible); // Visible for (auto & frame : layerAnimation.frames) { XMLElement* frameElement; - /* Frame */ + // Frame frameElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_FRAME]); - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_X_POSITION], frame.position.x); /* XPosition */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_Y_POSITION], frame.position.y); /* YPosition */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_X_PIVOT], frame.pivot.x); /* XPivot */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_Y_PIVOT], frame.pivot.y); /* YPivot */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_X_CROP], frame.crop.x); /* XCrop */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_Y_CROP], frame.crop.y); /* YCrop */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_WIDTH], frame.size.x); /* Width */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_HEIGHT], frame.size.y); /* Height */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_X_SCALE], frame.scale.x); /* XScale */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_Y_SCALE], frame.scale.y); /* XScale */ + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_X_POSITION], frame.position.x); // XPosition + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_Y_POSITION], frame.position.y); // YPosition + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_X_PIVOT], frame.pivot.x); // XPivot + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_Y_PIVOT], frame.pivot.y); // YPivot + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_X_CROP], frame.crop.x); // XCrop + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_Y_CROP], frame.crop.y); // YCrop + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_WIDTH], frame.size.x); // Width + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_HEIGHT], frame.size.y); // Height + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_X_SCALE], frame.scale.x); // XScale + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_Y_SCALE], frame.scale.y); // YScale frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_DELAY], frame.delay); /* Delay */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_VISIBLE], frame.isVisible); /* Visible */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_RED_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.r)); /* RedTint */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_GREEN_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.g)); /* GreenTint */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_BLUE_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.b)); /* BlueTint */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ALPHA_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.a)); /* AlphaTint */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_RED_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.r)); /* RedOffset */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_GREEN_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.g)); /* GreenOffset */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_BLUE_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.b)); /* BlueOffset */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ROTATION], frame.rotation); /* Rotation */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_INTERPOLATED], frame.isInterpolated); /* Interpolated */ + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_VISIBLE], frame.isVisible); // Visible + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_RED_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.r)); // RedTint + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_GREEN_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.g)); // GreenTint + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_BLUE_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.b)); // BlueTint + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ALPHA_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.a)); // AlphaTint + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_RED_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.r)); // RedOffset + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_GREEN_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.g)); // GreenOffset + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_BLUE_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.b)); // BlueOffset + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ROTATION], frame.rotation); // Rotation + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_INTERPOLATED], frame.isInterpolated); // Interpolated layerAnimationElement->InsertEndChild(frameElement); } @@ -232,42 +234,42 @@ anm2_serialize(Anm2* self, const char* path) animationElement->InsertEndChild(layerAnimationsElement); - /* NullAnimations */ + // NullAnimations nullAnimationsElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_NULL_ANIMATIONS]); for (const auto & [nullID, nullAnimation] : animation.nullAnimations) { XMLElement* nullAnimationElement; - /* NullAnimation */ + // NullAnimation nullAnimationElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_NULL_ANIMATION]); - nullAnimationElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_NULL_ID], nullID); /* NullID */ - nullAnimationElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_VISIBLE], nullAnimation.isVisible); /* Visible */ + nullAnimationElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_NULL_ID], nullID); // NullId + nullAnimationElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_VISIBLE], nullAnimation.isVisible); // Visible - for (auto & frame : nullAnimation.frames) + for (const auto & frame : nullAnimation.frames) { XMLElement* frameElement; - /* Frame */ + // Frame frameElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_FRAME]); - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_X_POSITION], frame.position.x); /* XPosition */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_Y_POSITION], frame.position.y); /* YPosition */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_X_PIVOT], frame.pivot.x); /* XPivot */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_Y_PIVOT], frame.pivot.y); /* YPivot */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_X_SCALE], frame.scale.x); /* XScale */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_Y_SCALE], frame.scale.y); /* XScale */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_DELAY], frame.delay); /* Delay */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_VISIBLE], frame.isVisible); /* Visible */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_RED_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.r)); /* RedTint */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_GREEN_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.g)); /* GreenTint */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_BLUE_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.b)); /* BlueTint */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ALPHA_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.a)); /* AlphaTint */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_RED_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.r)); /* RedOffset */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_GREEN_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.g)); /* GreenOffset */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_BLUE_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.b)); /* BlueOffset */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ROTATION], frame.rotation); /* Rotation */ - frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_INTERPOLATED], frame.isInterpolated); /* Interpolated */ + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_X_POSITION], frame.position.x); // XPosition + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_Y_POSITION], frame.position.y); // YPosition + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_X_PIVOT], frame.pivot.x); // XPivot + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_Y_PIVOT], frame.pivot.y); // YPivot + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_X_SCALE], frame.scale.x); // XScale + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_Y_SCALE], frame.scale.y); // XScale + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_DELAY], frame.delay); // Delay + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_VISIBLE], frame.isVisible); // Visible + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_RED_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.r)); // RedTint + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_GREEN_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.g)); // GreenTint + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_BLUE_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.b)); // BlueTint + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ALPHA_TINT], COLOR_FLOAT_TO_INT(frame.tintRGBA.a)); // AlphaTint + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_RED_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.r)); // RedOffset + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_GREEN_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.g)); // GreenOffset + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_BLUE_OFFSET], COLOR_FLOAT_TO_INT(frame.offsetRGB.b)); // BlueOffset + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_ROTATION], frame.rotation); // Rotation + frameElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_INTERPOLATED], frame.isInterpolated); // Interpolated nullAnimationElement->InsertEndChild(frameElement); } @@ -277,17 +279,17 @@ anm2_serialize(Anm2* self, const char* path) animationElement->InsertEndChild(nullAnimationsElement); - /* Triggers */ + // Triggers triggersElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_TRIGGERS]); - for (auto & frame : animation.triggers.frames) + for (const auto & frame : animation.triggers.frames) { XMLElement* triggerElement; - /* Trigger */ + // Trigger triggerElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_TRIGGER]); - triggerElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_EVENT_ID], frame.eventID); /* EventID */ - triggerElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_AT_FRAME], frame.atFrame); /* AtFrame */ + triggerElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_EVENT_ID], frame.eventID); // EventID + triggerElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_AT_FRAME], frame.atFrame); // AtFrame triggersElement->InsertEndChild(triggerElement); } @@ -298,23 +300,22 @@ anm2_serialize(Anm2* self, const char* path) animatedActorElement->InsertEndChild(animationsElement); - error = document.SaveFile(path); + error = document.SaveFile(path.c_str()); if (error != XML_SUCCESS) { - printf(STRING_ERROR_ANM2_WRITE, path, document.ErrorStr()); + std::cout << STRING_ERROR_ANM2_WRITE << path << std::endl; return false; } - printf(STRING_INFO_ANM2_WRITE, path); - strncpy(self->path, path, PATH_MAX - 1); + std::cout << STRING_INFO_ANM2_WRITE << path << std::endl; return true; } -/* Loads the .anm2 file and deserializes it into the struct equivalent */ +// Loads the .anm2 file and deserializes it into the struct equivalent bool -anm2_deserialize(Anm2* self, Resources* resources, const char* path) +anm2_deserialize(Anm2* self, Resources* resources, const std::string& path) { XMLDocument xmlDocument; XMLError xmlError; @@ -335,69 +336,72 @@ anm2_deserialize(Anm2* self, Resources* resources, const char* path) Anm2Event addEvent; Anm2Spritesheet addSpritesheet; + if (!self || path.empty()) + return false; + *self = Anm2{}; - xmlError = xmlDocument.LoadFile(path); + xmlError = xmlDocument.LoadFile(path.c_str()); if (xmlError != XML_SUCCESS) { - printf(STRING_ERROR_ANM2_READ, path, xmlDocument.ErrorStr()); + std::cout << STRING_ERROR_ANM2_READ << path << xmlDocument.ErrorStr() << std::endl; return false; } + // Free the loaded textures used by resources so new ones for the anm2 can be loaded resources_textures_free(resources); - /* Save old working directory and then use anm2's path as directory */ - /* (useful for loading textures from anm2 correctly) */ + // Save old working directory and then use anm2's path as directory + // (used for loading textures from anm2 correctly which are relative) std::filesystem::path workingPath = std::filesystem::current_path(); - std::filesystem::path filePath = path; - std::filesystem::path parentPath = filePath.parent_path(); - std::filesystem::current_path(parentPath); - strncpy(self->path, path, PATH_MAX - 1); + working_directory_from_file_set(path); - xmlRoot = xmlDocument.FirstChildElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_ANIMATED_ACTOR]); + self->path = path; + + xmlRoot = xmlDocument.FirstChildElement(ANM2_ELEMENT_ENUM_TO_STRING(ANM2_ELEMENT_ANIMATED_ACTOR).c_str()); xmlElement = xmlRoot; + // Iterate through elements while (xmlElement) { const XMLAttribute* xmlAttribute = NULL; const XMLElement* xmlChild = NULL; s32 id = 0; - - /* Elements */ - anm2Element = anm2_element_from_string(xmlElement->Name()); + + anm2Element = ANM2_ELEMENT_STRING_TO_ENUM(xmlElement->Name()); switch (anm2Element) { - case ANM2_ELEMENT_SPRITESHEET: + case ANM2_ELEMENT_SPRITESHEET: // Spritesheet spritesheet = &addSpritesheet; break; - case ANM2_ELEMENT_LAYER: + case ANM2_ELEMENT_LAYER: // Layer layer = &addLayer; break; - case ANM2_ELEMENT_NULL: + case ANM2_ELEMENT_NULL: // Null null = &addNull; break; - case ANM2_ELEMENT_EVENT: + case ANM2_ELEMENT_EVENT: // Event event = &addEvent; break; - case ANM2_ELEMENT_ANIMATION: + case ANM2_ELEMENT_ANIMATION: // Animation id = map_next_id_get(self->animations); self->animations[id] = Anm2Animation{}; animation = &self->animations[id]; break; - case ANM2_ELEMENT_ROOT_ANIMATION: + case ANM2_ELEMENT_ROOT_ANIMATION: // RootAnimation item = &animation->rootAnimation; break; - case ANM2_ELEMENT_LAYER_ANIMATION: - case ANM2_ELEMENT_NULL_ANIMATION: + case ANM2_ELEMENT_LAYER_ANIMATION: // LayerAnimation + case ANM2_ELEMENT_NULL_ANIMATION: // NullAnimation item = &addItem; break; - case ANM2_ELEMENT_TRIGGERS: + case ANM2_ELEMENT_TRIGGERS: // Triggers item = &animation->triggers; break; - case ANM2_ELEMENT_FRAME: - case ANM2_ELEMENT_TRIGGER: + case ANM2_ELEMENT_FRAME: // Frame + case ANM2_ELEMENT_TRIGGER: // Trigger item->frames.push_back(Anm2Frame{}); frame = &item->frames.back(); default: @@ -406,42 +410,42 @@ anm2_deserialize(Anm2* self, Resources* resources, const char* path) /* Attributes */ xmlAttribute = xmlElement->FirstAttribute(); - + while (xmlAttribute) { - anm2Attribute = anm2_attribute_from_string(xmlAttribute->Name()); + anm2Attribute = ANM2_ATTRIBUTE_STRING_TO_ENUM(xmlAttribute->Name()); switch (anm2Attribute) { - case ANM2_ATTRIBUTE_CREATED_BY: - strncpy(self->createdBy, xmlAttribute->Value(), ANM2_STRING_MAX - 1); + case ANM2_ATTRIBUTE_CREATED_BY: // CreatedBy + self->createdBy = xmlAttribute->Value(); break; - case ANM2_ATTRIBUTE_CREATED_ON: - strncpy(self->createdOn, xmlAttribute->Value(), ANM2_STRING_MAX - 1); + case ANM2_ATTRIBUTE_CREATED_ON: // CreatedOn + self->createdOn = xmlAttribute->Value(); break; - case ANM2_ATTRIBUTE_VERSION: + case ANM2_ATTRIBUTE_VERSION: // Version self->version = atoi(xmlAttribute->Value()); break; - case ANM2_ATTRIBUTE_FPS: + case ANM2_ATTRIBUTE_FPS: // FPS self->fps = atoi(xmlAttribute->Value()); break; - case ANM2_ATTRIBUTE_ID: + case ANM2_ATTRIBUTE_ID: // ID id = atoi(xmlAttribute->Value()); switch (anm2Element) { - case ANM2_ELEMENT_SPRITESHEET: + case ANM2_ELEMENT_SPRITESHEET: // Spritesheet self->spritesheets[id] = addSpritesheet; spritesheet = &self->spritesheets[id]; break; - case ANM2_ELEMENT_LAYER: + case ANM2_ELEMENT_LAYER: // Layer self->layers[id] = addLayer; layer = &self->layers[id]; break; - case ANM2_ELEMENT_NULL: + case ANM2_ELEMENT_NULL: // Null self->nulls[id] = addNull; null = &self->nulls[id]; break; - case ANM2_ELEMENT_EVENT: + case ANM2_ELEMENT_EVENT: // Event self->events[id] = addEvent; event = &self->events[id]; break; @@ -449,33 +453,33 @@ anm2_deserialize(Anm2* self, Resources* resources, const char* path) break; } break; - case ANM2_ATTRIBUTE_LAYER_ID: + case ANM2_ATTRIBUTE_LAYER_ID: // LayerId id = atoi(xmlAttribute->Value()); animation->layerAnimations[id] = addItem; item = &animation->layerAnimations[id]; break; - case ANM2_ATTRIBUTE_NULL_ID: + case ANM2_ATTRIBUTE_NULL_ID: // NullId id = atoi(xmlAttribute->Value()); animation->nullAnimations[id] = addItem; item = &animation->nullAnimations[id]; break; - case ANM2_ATTRIBUTE_PATH: - strncpy(spritesheet->path, xmlAttribute->Value(), PATH_MAX - 1); + case ANM2_ATTRIBUTE_PATH: // Path + spritesheet->path = xmlAttribute->Value(); break; - case ANM2_ATTRIBUTE_NAME: + case ANM2_ATTRIBUTE_NAME: // Name switch (anm2Element) { case ANM2_ELEMENT_LAYER: - strncpy(layer->name, xmlAttribute->Value(), ANM2_STRING_MAX - 1); + layer->name = std::string(xmlAttribute->Value()); break; case ANM2_ELEMENT_NULL: - strncpy(null->name, xmlAttribute->Value(), ANM2_STRING_MAX - 1); + null->name = std::string(xmlAttribute->Value()); break; case ANM2_ELEMENT_ANIMATION: - strncpy(animation->name, xmlAttribute->Value(), ANM2_STRING_MAX - 1); + animation->name = std::string(xmlAttribute->Value()); break; case ANM2_ELEMENT_EVENT: - strncpy(event->name, xmlAttribute->Value(), ANM2_STRING_MAX - 1); + event->name = std::string(xmlAttribute->Value()); break; default: break; @@ -488,7 +492,7 @@ anm2_deserialize(Anm2* self, Resources* resources, const char* path) null->isShowRect = string_to_bool(xmlAttribute->Value()); break; case ANM2_ATTRIBUTE_DEFAULT_ANIMATION: - strncpy(self->defaultAnimation, xmlAttribute->Value(), ANM2_STRING_MAX - 1); + self->defaultAnimation = xmlAttribute->Value(); break; case ANM2_ATTRIBUTE_FRAME_NUM: animation->frameNum = atoi(xmlAttribute->Value()); @@ -584,11 +588,10 @@ anm2_deserialize(Anm2* self, Resources* resources, const char* path) xmlAttribute = xmlAttribute->Next(); } - /* Load spritesheet textures */ + // Load this anm2's spritesheet textures if (anm2Element == ANM2_ELEMENT_SPRITESHEET) - anm2_spritesheet_texture_load(self, resources, spritesheet->path , id); + resources_texture_init(resources, spritesheet->path , id); - /* Iterate through children */ xmlChild = xmlElement->FirstChildElement(); if (xmlChild) @@ -597,7 +600,7 @@ anm2_deserialize(Anm2* self, Resources* resources, const char* path) continue; } - /* Iterate through siblings */ + // Iterate through siblings while (xmlElement) { const XMLElement* xmlNext; @@ -610,20 +613,20 @@ anm2_deserialize(Anm2* self, Resources* resources, const char* path) break; } - /* If no siblings, return to parent. If no parent, end parsing */ + // If no siblings, return to parent. If no parent, end parsing xmlElement = xmlElement->Parent() ? xmlElement->Parent()->ToElement() : NULL; } } - printf(STRING_INFO_ANM2_READ, path); - - /* Set working directory back to old */ + std::cout << STRING_INFO_ANM2_READ << path << std::endl; + + // Return to old working directory std::filesystem::current_path(workingPath); return true; } -/* Adds a new layer to the anm2 */ +// Adds a layer to the anm2 void anm2_layer_add(Anm2* self) { @@ -635,17 +638,22 @@ anm2_layer_add(Anm2* self) animation.layerAnimations[id] = Anm2Item{}; } -/* Removes a layer from the anm2 given the index/id */ +// Removes a layer from the anm2 void anm2_layer_remove(Anm2* self, s32 id) { + // Make sure the layer exists + auto it = self->layers.find(id); + if (it == self->layers.end()) + return; + self->layers.erase(id); for (auto & [animationID, animation] : self->animations) animation.layerAnimations.erase(id); } -/* Adds a new null to the anm2 */ +// Adds a null to the anm2 void anm2_null_add(Anm2* self) { @@ -657,36 +665,41 @@ anm2_null_add(Anm2* self) animation.nullAnimations[id] = Anm2Item{}; } -/* Removes a null from the anm2 given the index/id */ +// Removes the specified null from the anm2 void anm2_null_remove(Anm2* self, s32 id) { + // Make sure the null exists + auto it = self->nulls.find(id); + if (it == self->nulls.end()) + return; + self->nulls.erase(id); for (auto & [animationID, animation] : self->animations) animation.nullAnimations.erase(id); } -/* Adds a new animation to the anm2, makes sure to keep the layeranimations/nullsanimation check */ +// Adds an animation to the anm2 s32 anm2_animation_add(Anm2* self) { s32 id = map_next_id_get(self->animations); Anm2Animation animation; - /* match layers */ + // Match layers for (auto & [layerID, layer] : self->layers) { animation.layerAnimations[layerID] = Anm2Item{}; } - /* match nulls */ + // Match nulls for (auto & [nullID, null] : self->nulls) { animation.nullAnimations[nullID] = Anm2Item{}; } - /* add a root frame */ + // Add a root frame animation.rootAnimation.frames.push_back(Anm2Frame{}); self->animations[id] = animation; @@ -694,34 +707,19 @@ anm2_animation_add(Anm2* self) return id; } +// Removes an animation by id from the anm2 void anm2_animation_remove(Anm2* self, s32 id) { self->animations.erase(id); } -/* Makes an entirely new anm2 */ +// Sets the anm2 to default void anm2_new(Anm2* self) { *self = Anm2{}; - anm2_created_on_set(self); -} - -void -anm2_spritesheet_texture_load(Anm2* self, Resources* resources, const char* path, s32 id) -{ - Texture texture; - - if (resources->textures.find(id) != resources->textures.end() && resources->textures[id].id != resources->textures[TEXTURE_ERROR].id) - texture_free(&resources->textures[id]); - - if (texture_from_path_init(&texture, path)) - resources->textures[id] = texture; - else - texture.isInvalid = true; - - resources->textures[id] = texture; + _anm2_created_on_set(self); } Anm2Animation* @@ -733,7 +731,7 @@ anm2_animation_from_reference(Anm2* self, Anm2Reference* reference) return &it->second; } -/* Returns the item from a anm2 reference. */ +// Returns the item from a anm2 reference. Anm2Item* anm2_item_from_reference(Anm2* self, Anm2Reference* reference) { @@ -767,7 +765,7 @@ anm2_item_from_reference(Anm2* self, Anm2Reference* reference) } } -/* Gets the frame from the reference's properties */ +// Gets the frame from the reference's properties Anm2Frame* anm2_frame_from_reference(Anm2* self, Anm2Reference* reference) { @@ -782,14 +780,15 @@ anm2_frame_from_reference(Anm2* self, Anm2Reference* reference) return &item->frames[reference->frameIndex]; } -/* Creates/fetches a frame from a given time. */ -/* Returns true/false if frame will be valid or not. */ +// Creates or fetches a frame from a given time. void anm2_frame_from_time(Anm2* self, Anm2Frame* frame, Anm2Reference reference, f32 time) { Anm2Animation* animation = anm2_animation_from_reference(self, &reference); - /* Out of range */ + if (!animation) + return; + if (time < 0 || time > animation->frameNum) return; @@ -807,8 +806,7 @@ anm2_frame_from_time(Anm2* self, Anm2Frame* frame, Anm2Reference reference, f32 *frame = item->frames[i]; delayNext += frame->delay; - /* If a frame is within the time constraints, it's a time matched frame, break */ - /* Otherwise, the last found frame parsed will be used. */ + // Use the last parsed frame as the given frame. if (time >= delayCurrent && time < delayNext) { if (i + 1 < (s32)item->frames.size()) @@ -821,7 +819,7 @@ anm2_frame_from_time(Anm2* self, Anm2Frame* frame, Anm2Reference reference, f32 delayCurrent += frame->delay; } - /* Interpolate only if there's a frame following */ + // Interpolate, but only if there's a frame following. if (frame->isInterpolated && nextFrame) { f32 interpolationTime = (time - delayCurrent) / (delayNext - delayCurrent); @@ -834,11 +832,10 @@ anm2_frame_from_time(Anm2* self, Anm2Frame* frame, Anm2Reference reference, f32 } } -/* Returns the current length of the animation, from the used frames. */ +// Returns the animation's length, based on the present frames. s32 anm2_animation_length_get(Anm2* self, s32 animationID) { - /* Get valid animation */ auto it = self->animations.find(animationID); if (it == self->animations.end()) return -1; @@ -846,28 +843,29 @@ anm2_animation_length_get(Anm2* self, s32 animationID) Anm2Animation* animation = &it->second; s32 delayHighest = 0; - /* Root frames */ + // Go through all items and see which one has the latest frame; that's the length + // Root for (auto & frame : animation->rootAnimation.frames) delayHighest = std::max(delayHighest, frame.delay); - /* Layer frames */ + // Layer for (auto & [id, item] : animation->layerAnimations) for (auto & frame : item.frames) delayHighest = std::max(delayHighest, frame.delay); - /* Null frames */ + // Null for (auto & [id, item] : animation->nullAnimations) for (auto & frame : item.frames) delayHighest = std::max(delayHighest, frame.delay); - /* Trigger frames (assuming this is from `animation->triggers.frames`) */ + // Triggers for (auto & trigger : animation->triggers.frames) delayHighest = std::max(delayHighest, trigger.atFrame); return delayHighest; } -/* Will try adding a frame to the anm2 given the specified reference */ +// Will try adding a frame to the anm2 given the specified reference Anm2Frame* anm2_frame_add(Anm2* self, Anm2Reference* reference, s32 time) { @@ -884,7 +882,7 @@ anm2_frame_add(Anm2* self, Anm2Reference* reference, s32 time) if (reference->itemType == ANM2_TRIGGERS) { - /* don't add redudant triggers (i.e. at same time) */ + // Don't add redundant triggers for (auto & frameCheck : item->frames) { if (frameCheck.atFrame == time) @@ -898,20 +896,20 @@ anm2_frame_add(Anm2* self, Anm2Reference* reference, s32 time) { s32 frameDelayCount = 0; - /* Add up all delay to see where this new frame might lie */ + // Get the latest frame delay, to see where this frame might lie for (auto & frameCheck : item->frames) frameDelayCount += frameCheck.delay; - /* If adding the smallest frame would be over the length, don't bother */ + // If adding the smallest frame delay would be over the length, don't bother if (frameDelayCount + ANM2_FRAME_DELAY_MIN > animation->frameNum) return NULL; - /* Will insert next to frame if frame exists */ + // Will insert next to frame if frame exists Anm2Frame* checkFrame = anm2_frame_from_reference(self, reference); if (checkFrame) { - /* Will shrink frame delay to fit */ + // Will shrink frame delay to fit if (frameDelayCount + checkFrame->delay > animation->frameNum) frame.delay = animation->frameNum - frameDelayCount; @@ -929,14 +927,14 @@ anm2_frame_add(Anm2* self, Anm2Reference* reference, s32 time) return NULL; } -/* Clears anm2 reference */ +// Clears the anm2 reference, totally void anm2_reference_clear(Anm2Reference* self) { *self = Anm2Reference{}; } -/* Clears anm2 item reference */ +// Clears the anm2 reference's item void anm2_reference_item_clear(Anm2Reference* self) { @@ -944,7 +942,7 @@ anm2_reference_item_clear(Anm2Reference* self) self->itemID = -1; } -/* Clears anm2 reference */ +// Clears the anm2 reference's frame void anm2_reference_frame_clear(Anm2Reference* self) { diff --git a/src/anm2.h b/src/anm2.h index 081ebc6..0b0b880 100644 --- a/src/anm2.h +++ b/src/anm2.h @@ -6,15 +6,12 @@ #define ANM2_SCALE_CONVERT(x) ((f32)x / 100.0f) #define ANM2_TINT_CONVERT(x) ((f32)x / 255.0f) -#define ANM2_STRING_MAX 0xFF -#define ANM2_STRING_FORMATTED_MAX 0xFFF -#define ANM2_PATH_FORMATTED_MAX PATH_MAX + 0xFF -#define ANM2_BUFFER_MAX 0xFFFFF #define ANM2_FPS_MIN 0 #define ANM2_FPS_MAX 120 #define ANM2_FRAME_NUM_MIN 1 #define ANM2_FRAME_NUM_MAX 1000000 #define ANM2_FRAME_DELAY_MIN 1 +#define ANM2_STRING_MAX 0xFF /* Elements */ #define ANM2_ELEMENT_LIST \ @@ -53,7 +50,8 @@ static const char* ANM2_ELEMENT_STRINGS[] = { #undef X }; -DEFINE_STRING_TO_ENUM_FN(anm2_element_from_string, Anm2Element, ANM2_ELEMENT_STRINGS, ANM2_ELEMENT_COUNT) +DEFINE_STRING_TO_ENUM_FUNCTION(ANM2_ELEMENT_STRING_TO_ENUM, Anm2Element, ANM2_ELEMENT_STRINGS, ANM2_ELEMENT_COUNT) +DEFINE_ENUM_TO_STRING_FUNCTION(ANM2_ELEMENT_ENUM_TO_STRING, ANM2_ELEMENT_STRINGS, ANM2_ELEMENT_COUNT) #define ANM2_ATTRIBUTE_LIST \ X(CREATED_BY, "CreatedBy") \ @@ -107,38 +105,39 @@ static const char* ANM2_ATTRIBUTE_STRINGS[] = { #undef X }; -DEFINE_STRING_TO_ENUM_FN(anm2_attribute_from_string, Anm2Attribute, ANM2_ATTRIBUTE_STRINGS, ANM2_ATTRIBUTE_COUNT) +DEFINE_STRING_TO_ENUM_FUNCTION(ANM2_ATTRIBUTE_STRING_TO_ENUM, Anm2Attribute, ANM2_ATTRIBUTE_STRINGS, ANM2_ATTRIBUTE_COUNT) +DEFINE_ENUM_TO_STRING_FUNCTION(ANM2_ATTRIBUTE_ENUM_TO_STRING, ANM2_ATTRIBUTE_STRINGS, ANM2_ATTRIBUTE_COUNT) -#define ANM2_COUNT (ANM2_TRIGGER + 1) enum Anm2Type { ANM2_NONE, ANM2_ROOT, ANM2_LAYER, ANM2_NULL, - ANM2_TRIGGERS + ANM2_TRIGGERS, + ANM2_COUNT }; struct Anm2Spritesheet { - char path[PATH_MAX] = STRING_EMPTY; + std::string path; }; struct Anm2Layer { + std::string name = STRING_ANM2_NEW_LAYER; s32 spritesheetID = -1; - char name[ANM2_STRING_MAX] = STRING_ANM2_NEW_LAYER; }; struct Anm2Null { - char name[ANM2_STRING_MAX] = STRING_ANM2_NEW_NULL; + std::string name = STRING_ANM2_NEW_NULL; bool isShowRect = false; }; struct Anm2Event { - char name[ANM2_STRING_MAX] = STRING_ANM2_NEW_EVENT; + std::string name = STRING_ANM2_NEW_EVENT; }; struct Anm2Frame @@ -167,7 +166,7 @@ struct Anm2Item struct Anm2Animation { s32 frameNum = ANM2_FRAME_NUM_MIN; - char name[ANM2_STRING_MAX] = STRING_ANM2_NEW_ANIMATION; + std::string name = STRING_ANM2_NEW_ANIMATION; bool isLoop = true; Anm2Item rootAnimation; std::map layerAnimations; @@ -177,23 +176,23 @@ struct Anm2Animation struct Anm2 { - char path[PATH_MAX] = STRING_EMPTY; - s32 fps = 30; - s32 version = 0; - char createdBy[ANM2_STRING_MAX] = STRING_ANM2_CREATED_BY_DEFAULT; - char createdOn[ANM2_STRING_MAX] = STRING_EMPTY; - char defaultAnimation[ANM2_STRING_MAX] = STRING_EMPTY; + std::string path; + std::string defaultAnimation; + std::string createdBy = STRING_ANM2_CREATED_BY_DEFAULT; + std::string createdOn; std::map spritesheets; std::map layers; std::map nulls; std::map events; std::map animations; + s32 fps = 30; + s32 version = 0; }; struct Anm2Reference { - Anm2Type itemType = ANM2_NONE; s32 animationID = -1; + Anm2Type itemType = ANM2_NONE; s32 itemID = -1; s32 frameIndex = -1; @@ -204,13 +203,13 @@ void anm2_layer_add(Anm2* self); 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 char* path); -bool anm2_deserialize(Anm2* self, Resources* resources, const char* path); +bool anm2_serialize(Anm2* self, const std::string& path); +bool anm2_deserialize(Anm2* self, Resources* resources, const std::string& path); void anm2_new(Anm2* self); void anm2_created_on_set(Anm2* self); s32 anm2_animation_add(Anm2* self); void anm2_animation_remove(Anm2* self, s32 id); -void anm2_spritesheet_texture_load(Anm2* self, Resources* resources, const char* path, s32 id); +void anm2_spritesheet_texture_load(Anm2* self, Resources* resources, const std::string& path, s32 id); Anm2Animation* anm2_animation_from_reference(Anm2* self, Anm2Reference* reference); Anm2Item* anm2_item_from_reference(Anm2* self, Anm2Reference* reference); Anm2Frame* anm2_frame_from_reference(Anm2* self, Anm2Reference* reference); diff --git a/src/dialog.cpp b/src/dialog.cpp index b8bc956..d39866c 100644 --- a/src/dialog.cpp +++ b/src/dialog.cpp @@ -2,6 +2,7 @@ static void _dialog_callback(void* userdata, const char* const* filelist, s32 filter); +// Callback that runs during the file dialog; will get the path and determine if one has been selected static void _dialog_callback(void* userdata, const char* const* filelist, s32 filter) { @@ -11,13 +12,14 @@ _dialog_callback(void* userdata, const char* const* filelist, s32 filter) if (filelist && filelist[0] && strlen(filelist[0]) > 0) { - strncpy(self->path, filelist[0], PATH_MAX - 1); + self->path = filelist[0]; self->isSelected = true; } else self->isSelected = false; } +// Initializes dialog void dialog_init(Dialog* self, Anm2* anm2, Anm2Reference* reference, Resources* resources, SDL_Window* window) { @@ -27,7 +29,7 @@ dialog_init(Dialog* self, Anm2* anm2, Anm2Reference* reference, Resources* resou self->window = window; } -/* Opens file dialog for user to pick anm2 files */ +// Opens file dialog to open a new anm2 void dialog_anm2_open(Dialog* self) { @@ -35,7 +37,7 @@ dialog_anm2_open(Dialog* self) self->type = DIALOG_ANM2_OPEN; } -/* Opens file dialog for user to save new anm2 files */ +// Opens file dialog to save anm2 void dialog_anm2_save(Dialog* self) { @@ -43,7 +45,7 @@ dialog_anm2_save(Dialog* self) self->type = DIALOG_ANM2_SAVE; } -/* Opens file dialog for user to pick png files for spritesheets */ +// Opens file dialog to open png void dialog_png_open(Dialog* self) { @@ -51,7 +53,7 @@ dialog_png_open(Dialog* self) self->type = DIALOG_PNG_OPEN; } -/* Opens file dialog for user to pick png file to replace selected one */ +// Opens file dialog to replace a given png void dialog_png_replace(Dialog* self) { @@ -59,6 +61,7 @@ dialog_png_replace(Dialog* self) self->type = DIALOG_PNG_REPLACE; } +// Ticks dialog void dialog_tick(Dialog* self) { @@ -82,19 +85,19 @@ dialog_tick(Dialog* self) case DIALOG_PNG_OPEN: id = map_next_id_get(self->resources->textures); self->anm2->spritesheets[id] = Anm2Spritesheet{}; - strncpy(self->anm2->spritesheets[id].path, self->path, PATH_MAX); - anm2_spritesheet_texture_load(self->anm2, self->resources, self->path, id); + self->path = self->anm2->spritesheets[id].path; + resources_texture_init(self->resources, self->path, id); break; case DIALOG_PNG_REPLACE: - strncpy(self->anm2->spritesheets[self->replaceID].path, self->path, PATH_MAX); - anm2_spritesheet_texture_load(self->anm2, self->resources, self->path, self->replaceID); + self->anm2->spritesheets[self->replaceID].path = self->path; + resources_texture_init(self->resources, self->path, self->replaceID); self->replaceID = -1; break; default: break; } - memset(self->path, '\0', PATH_MAX); + self->path.clear(); self->isSelected = false; } } diff --git a/src/dialog.h b/src/dialog.h index 5031557..a531f4c 100644 --- a/src/dialog.h +++ b/src/dialog.h @@ -4,12 +4,12 @@ #include "resources.h" #include "window.h" -static const SDL_DialogFileFilter DIALOG_FILE_FILTER_ANM2[] = +const SDL_DialogFileFilter DIALOG_FILE_FILTER_ANM2[] = { {"Anm2", "anm2;xml"} }; -static const SDL_DialogFileFilter DIALOG_FILE_FILTER_PNG[] = +const SDL_DialogFileFilter DIALOG_FILE_FILTER_PNG[] = { {"png", "png"} }; @@ -20,7 +20,8 @@ enum DialogType DIALOG_ANM2_OPEN, DIALOG_ANM2_SAVE, DIALOG_PNG_OPEN, - DIALOG_PNG_REPLACE + DIALOG_PNG_REPLACE, + DIALOG_FRAME_DIRECTORY_OPEN, }; struct Dialog @@ -29,9 +30,9 @@ struct Dialog Anm2Reference* reference = NULL; Resources* resources = NULL; SDL_Window* window = NULL; + std::string path; s32 replaceID = -1; - enum DialogType type = DIALOG_NONE; - char path[PATH_MAX] = ""; + DialogType type = DIALOG_NONE; bool isSelected = false; }; @@ -40,4 +41,5 @@ void dialog_anm2_open(Dialog* self); void dialog_png_open(Dialog* self); void dialog_png_replace(Dialog* self); void dialog_anm2_save(Dialog* self); +void dialog_frame_directory_open(Dialog* self); void dialog_tick(Dialog* self); \ No newline at end of file diff --git a/src/editor.cpp b/src/editor.cpp index 98efb3f..76fffb7 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -2,6 +2,7 @@ static s32 _editor_grid_set(Editor* self); +// Sets the editor's grid static s32 _editor_grid_set(Editor* self) { @@ -44,6 +45,7 @@ _editor_grid_set(Editor* self) return (s32)vertices.size(); } +// Initializes editor void editor_init(Editor* self, Anm2* anm2, Anm2Reference* reference, Resources* resources, Settings* settings) { @@ -52,7 +54,7 @@ editor_init(Editor* self, Anm2* anm2, Anm2Reference* reference, Resources* resou self->resources = resources; self->settings = settings; - /* Framebuffer + texture */ + // Framebuffer + texture glGenFramebuffers(1, &self->fbo); glBindFramebuffer(GL_FRAMEBUFFER, self->fbo); @@ -72,11 +74,11 @@ editor_init(Editor* self, Anm2* anm2, Anm2Reference* reference, Resources* resou glBindFramebuffer(GL_FRAMEBUFFER, 0); - /* Grid */ + // Grid glGenVertexArrays(1, &self->gridVAO); glGenBuffers(1, &self->gridVBO); - /* Border */ + // Border glGenVertexArrays(1, &self->borderVAO); glGenBuffers(1, &self->borderVBO); @@ -88,7 +90,7 @@ editor_init(Editor* self, Anm2* anm2, Anm2Reference* reference, Resources* resou glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(f32), (void*)0); - /* Viewing texture */ + // Texture glGenVertexArrays(1, &self->textureVAO); glGenBuffers(1, &self->textureVBO); glGenBuffers(1, &self->textureEBO); @@ -101,11 +103,11 @@ editor_init(Editor* self, Anm2* anm2, Anm2Reference* reference, Resources* resou glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self->textureEBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GL_TEXTURE_INDICES), GL_TEXTURE_INDICES, GL_STATIC_DRAW); - /* Position */ + // Position attribute glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(f32), (void*)0); - /* UV */ + // UV position attribute glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(f32), (void*)(2 * sizeof(f32))); @@ -114,18 +116,18 @@ editor_init(Editor* self, Anm2* anm2, Anm2Reference* reference, Resources* resou _editor_grid_set(self); } +// Draws the editor void editor_draw(Editor* self) { GLuint shaderLine = self->resources->shaders[SHADER_LINE]; GLuint shaderLineDotted = self->resources->shaders[SHADER_LINE_DOTTED]; GLuint shaderTexture = self->resources->shaders[SHADER_TEXTURE]; - f32 zoomFactor = self->settings->editorZoom / 100.0f; + f32 zoomFactor = PERCENT_TO_UNIT(self->settings->editorZoom); - /* Convert pan to pixels */ + // Get normalized panning glm::vec2 ndcPan = glm::vec2(-self->settings->editorPanX / (EDITOR_SIZE.x / 2.0f), -self->settings->editorPanY / (EDITOR_SIZE.y / 2.0f)); - /* Transformation matrix */ glm::mat4 editorTransform = glm::translate(glm::mat4(1.0f), glm::vec3(ndcPan, 0.0f)); editorTransform = glm::scale(editorTransform, glm::vec3(zoomFactor, zoomFactor, 1.0f)); @@ -142,12 +144,10 @@ editor_draw(Editor* self) glClear(GL_COLOR_BUFFER_BIT); - s32 spritesheetID = self->reference->itemType == ANM2_LAYER ? - self->anm2->layers[self->reference->itemID].spritesheetID : -1; - - if (spritesheetID > -1) + // Drawing the selected spritesheet + if (self->spritesheetID > -1) { - Texture* texture = &self->resources->textures[spritesheetID]; + Texture* texture = &self->resources->textures[self->spritesheetID]; glm::mat4 spritesheetTransform = editorTransform; glm::vec2 ndcScale = glm::vec2(texture->size.x, texture->size.y) / (EDITOR_SIZE * 0.5f); @@ -176,6 +176,7 @@ editor_draw(Editor* self) glBindVertexArray(0); glUseProgram(0); + // Border around the spritesheet if (self->settings->editorIsBorder) { glUseProgram(shaderLineDotted); @@ -193,10 +194,10 @@ editor_draw(Editor* self) Anm2Frame* frame = (Anm2Frame*)anm2_frame_from_reference(self->anm2, self->reference); - /* Draw the layer frame's crop and pivot */ + // Drawing the frame's crop and pivot if (frame) { - /* Rect */ + // Crop glm::mat4 rectTransform = editorTransform; glm::vec2 rectNDCPos = frame->crop / (EDITOR_SIZE / 2.0f); @@ -217,7 +218,7 @@ editor_draw(Editor* self) glBindVertexArray(0); glUseProgram(0); - /* Pivot */ + // Pivot glm::mat4 pivotTransform = editorTransform; glm::vec2 pivotNDCPos = ((frame->crop + frame->pivot) - (EDITOR_PIVOT_SIZE / 2.0f)) / (EDITOR_SIZE / 2.0f); glm::vec2 pivotNDCScale = EDITOR_PIVOT_SIZE / (EDITOR_SIZE / 2.0f); @@ -252,6 +253,7 @@ editor_draw(Editor* self) } } + // Grid if (self->settings->editorIsGrid) { static ivec2 previousGridSize = {-1, -1}; @@ -292,12 +294,14 @@ editor_draw(Editor* self) glBindFramebuffer(GL_FRAMEBUFFER, 0); } +// Ticks editor void editor_tick(Editor* self) { self->settings->editorZoom = CLAMP(self->settings->editorZoom, EDITOR_ZOOM_MIN, EDITOR_ZOOM_MAX); } +// Frees editor void editor_free(Editor* self) { diff --git a/src/editor.h b/src/editor.h index 9885eeb..a575833 100644 --- a/src/editor.h +++ b/src/editor.h @@ -12,11 +12,11 @@ #define EDITOR_GRID_OFFSET_MIN 0 #define EDITOR_GRID_OFFSET_MAX 100 -static const vec2 EDITOR_SIZE = {5000, 5000}; -static const vec2 EDITOR_PIVOT_SIZE = {4, 4}; -static const vec4 EDITOR_TEXTURE_TINT = COLOR_OPAQUE; -static const vec4 EDITOR_BORDER_TINT = COLOR_OPAQUE; -static const vec4 EDITOR_FRAME_TINT = COLOR_RED; +const vec2 EDITOR_SIZE = {5000, 5000}; +const vec2 EDITOR_PIVOT_SIZE = {4, 4}; +const vec4 EDITOR_TEXTURE_TINT = COLOR_OPAQUE; +const vec4 EDITOR_BORDER_TINT = COLOR_OPAQUE; +const vec4 EDITOR_FRAME_TINT = COLOR_RED; struct Editor { @@ -34,6 +34,7 @@ struct Editor GLuint textureVBO; GLuint borderVAO; GLuint borderVBO; + s32 spritesheetID = -1; }; void editor_init(Editor* self, Anm2* anm2, Anm2Reference* reference, Resources* resources, Settings* settings); diff --git a/src/imgui.cpp b/src/imgui.cpp index f4417b9..88eefea 100644 --- a/src/imgui.cpp +++ b/src/imgui.cpp @@ -1,6 +1,6 @@ #include "imgui.h" -static void _imgui_tooltip(const char* tooltip); +static void _imgui_tooltip(const std::string& tooltip); static void _imgui_timeline_item_frames(Imgui* self, Anm2Reference reference, s32* index); static void _imgui_timeline_item(Imgui* self, Anm2Reference reference, s32* index); static void _imgui_timeline(Imgui* self); @@ -12,28 +12,42 @@ static void _imgui_spritesheet_editor(Imgui* self); static void _imgui_animation_preview(Imgui* self); static void _imgui_taskbar(Imgui* self); static void _imgui_undoable(Imgui* self); +static void _imgui_undo_stack_push(Imgui* self); +static void _imgui_spritesheet_editor_set(Imgui* self, s32 spritesheetID); -/* Makes a tooltip! */ -static void _imgui_tooltip(const char* tooltip) +// Push undo stack using imgui's members +static void _imgui_undo_stack_push(Imgui* self) { - if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal)) - ImGui::SetTooltip("%s", tooltip); + Snapshot snapshot = {*self->anm2, *self->reference, *self->time}; + snapshots_undo_stack_push(self->snapshots, &snapshot); } +// Tooltip for the last hovered widget +static void _imgui_tooltip(const std::string& tooltip) +{ + if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal)) + ImGui::SetTooltip(tooltip.c_str()); +} + +// If the last widget is activated, pushes the undo stack static void _imgui_undoable(Imgui* self) { if (ImGui::IsItemActivated()) - { - Snapshot snapshot = {*self->anm2, *self->reference, *self->time}; - snapshots_undo_stack_push(self->snapshots, &snapshot); - } + _imgui_undo_stack_push(self); } -/* Displays the item's frames */ +// Will push a new spritesheetID to the editor +static void _imgui_spritesheet_editor_set(Imgui* self, s32 spritesheetID) +{ + // Make sure the spritesheet exists! + if (self->anm2->spritesheets.contains(spritesheetID)) + self->editor->spritesheetID = spritesheetID; +} + +// Drawing the frames of an Anm2Item static void _imgui_timeline_item_frames(Imgui* self, Anm2Reference reference, s32* index) { - static s32 draggedFrameIndex = -1; ImVec2 frameStartPos; ImVec2 framePos; ImVec2 frameFinishPos; @@ -73,6 +87,7 @@ _imgui_timeline_item_frames(Imgui* self, Anm2Reference reference, s32* index) ImGui::PushID(*index); + // Draw only if the animation has a length above 0 if (animation->frameNum > 0) { ImVec2 frameListSize = {IMGUI_TIMELINE_FRAME_SIZE.x * animation->frameNum, IMGUI_TIMELINE_ELEMENTS_TIMELINE_SIZE.y}; @@ -83,18 +98,19 @@ _imgui_timeline_item_frames(Imgui* self, Anm2Reference reference, s32* index) ImGui::BeginChild(STRING_IMGUI_TIMELINE_FRAMES, frameListSize, true); - /* will deselect frame if hovering and click; but, if it's later clicked, this won't have any effect */ + // Will deselect frame if hovering and click; but, if it's later clicked, this won't have any effect if (ImGui::IsWindowHovered() && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) anm2_reference_frame_clear(self->reference); - vec2 mousePos = VEC2_IMVEC2(ImGui::GetMousePos()); - vec2 windowPos = VEC2_IMVEC2(ImGui::GetWindowPos()); + vec2 mousePos = IMVEC2_TO_VEC2(ImGui::GetMousePos()); + vec2 windowPos = IMVEC2_TO_VEC2(ImGui::GetWindowPos()); f32 scrollX = ImGui::GetScrollX(); f32 mousePosRelativeX = mousePos.x - windowPos.x - scrollX; frameStartPos = ImGui::GetCursorPos(); + // Draw the frame background for (s32 i = 0; i < animation->frameNum; i++) { ImGui::PushID(i); @@ -115,6 +131,7 @@ _imgui_timeline_item_frames(Imgui* self, Anm2Reference reference, s32* index) ImGui::PopID(); } + // Draw each frame for (auto [i, frame] : std::views::enumerate(item->frames)) { reference.frameIndex = i; @@ -150,6 +167,10 @@ _imgui_timeline_item_frames(Imgui* self, Anm2Reference reference, s32* index) *self->reference = reference; *self->time = frameTime; + + // Set the preview's spritesheet ID + if (self->reference->itemType == ANM2_LAYER) + _imgui_spritesheet_editor_set(self, self->anm2->layers[self->reference->itemID].spritesheetID); } if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) @@ -159,7 +180,7 @@ _imgui_timeline_item_frames(Imgui* self, Anm2Reference reference, s32* index) ImGui::SetDragDropPayload(STRING_IMGUI_TIMELINE_FRAME_DRAG_DROP, &reference, sizeof(Anm2Reference)); ImGui::Button(STRING_IMGUI_TIMELINE_FRAME_LABEL, frameSize); ImGui::SetCursorPos(ImVec2(1.0f, (IMGUI_TIMELINE_FRAME_SIZE.y / 2) - (TEXTURE_SIZE_SMALL.y / 2))); - ImGui::Image(self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[textureType]), IMVEC2_ATLAS_UV_GET(textureType)); + ImGui::Image(self->resources->atlas.id, VEC2_TO_IMVEC2(ATLAS_SIZES[textureType]), IMVEC2_ATLAS_UV_GET(textureType)); ImGui::EndDragDropSource(); } @@ -175,8 +196,7 @@ _imgui_timeline_item_frames(Imgui* self, Anm2Reference reference, s32* index) self->isSwap = true; self->swapReference = reference; - Snapshot snapshot = {*self->anm2, *self->reference, *self->time}; - snapshots_undo_stack_push(self->snapshots, &snapshot); + _imgui_undo_stack_push(self); } } ImGui::EndDragDropTarget(); @@ -188,7 +208,7 @@ _imgui_timeline_item_frames(Imgui* self, Anm2Reference reference, s32* index) ImGui::SetCursorPos(ImVec2(framePos.x + 1.0f, (framePos.y + (IMGUI_TIMELINE_FRAME_SIZE.y / 2)) - TEXTURE_SIZE_SMALL.y / 2)); - ImGui::Image(self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[textureType]), IMVEC2_ATLAS_UV_GET(textureType)); + ImGui::Image(self->resources->atlas.id, VEC2_TO_IMVEC2(ATLAS_SIZES[textureType]), IMVEC2_ATLAS_UV_GET(textureType)); ImGui::PopID(); @@ -210,7 +230,7 @@ _imgui_timeline_item_frames(Imgui* self, Anm2Reference reference, s32* index) ImGui::PopID(); } -/* Displays each item of the timeline of a selected animation */ +// Displays each item of the timeline of a selected animation static void _imgui_timeline_item(Imgui* self, Anm2Reference reference, s32* index) { @@ -220,11 +240,12 @@ _imgui_timeline_item(Imgui* self, Anm2Reference reference, s32* index) TextureType textureType = TEXTURE_ERROR; s32* spritesheetID = NULL; bool* isShowRect = NULL; - char* namePointer = NULL; Anm2Null* null = NULL; Anm2Layer* layer = NULL; - char nameBuffer[ANM2_STRING_MAX] = STRING_EMPTY; - char nameVisible[ANM2_STRING_FORMATTED_MAX] = STRING_EMPTY; + std::string nameVisible; + std::string* namePointer = NULL; + char nameBuffer[ANM2_STRING_MAX]; + memset(nameBuffer, '\0', sizeof(nameBuffer)); bool isChangeable = reference.itemType != ANM2_ROOT && reference.itemType != ANM2_TRIGGERS; bool isSelected = self->reference->itemID == reference.itemID && self->reference->itemType == reference.itemType; @@ -234,38 +255,40 @@ _imgui_timeline_item(Imgui* self, Anm2Reference reference, s32* index) f32 cursorPosY = ImGui::GetCursorPosY(); ImVec4 color; - Anm2Animation* animation = anm2_animation_from_reference(self->anm2, &reference); Anm2Item* item = anm2_item_from_reference(self->anm2, &reference); + if (!item) + return; + switch (reference.itemType) { case ANM2_ROOT: textureType = TEXTURE_ROOT; color = IMGUI_TIMELINE_ROOT_COLOR; - strncpy(nameVisible, STRING_IMGUI_TIMELINE_ROOT, ANM2_STRING_FORMATTED_MAX); + nameVisible = STRING_IMGUI_TIMELINE_ROOT; break; case ANM2_LAYER: textureType = TEXTURE_LAYER; color = IMGUI_TIMELINE_LAYER_COLOR; layer = &self->anm2->layers[reference.itemID]; spritesheetID = &layer->spritesheetID; - namePointer = layer->name; - snprintf(nameBuffer, ANM2_STRING_MAX, "%s", namePointer); - snprintf(nameVisible, ANM2_STRING_FORMATTED_MAX, STRING_IMGUI_TIMELINE_ELEMENT_FORMAT, reference.itemID, namePointer); + namePointer = &layer->name; + strncpy(nameBuffer, (*namePointer).c_str(), ANM2_STRING_MAX - 1); + nameVisible = std::format(STRING_IMGUI_TIMELINE_ITEM_FORMAT, reference.itemID, *namePointer); break; case ANM2_NULL: textureType = TEXTURE_NULL; color = IMGUI_TIMELINE_NULL_COLOR; null = &self->anm2->nulls[reference.itemID]; isShowRect = &null->isShowRect; - namePointer = null->name; - snprintf(nameBuffer, ANM2_STRING_MAX, "%s", namePointer); - snprintf(nameVisible, ANM2_STRING_FORMATTED_MAX, STRING_IMGUI_TIMELINE_ELEMENT_FORMAT, reference.itemID, namePointer); + namePointer = &null->name; + strncpy(nameBuffer, (*namePointer).c_str(), ANM2_STRING_MAX - 1); + nameVisible = std::format(STRING_IMGUI_TIMELINE_ITEM_FORMAT, reference.itemID, *namePointer); break; case ANM2_TRIGGERS: textureType = TEXTURE_TRIGGERS; color = IMGUI_TIMELINE_TRIGGERS_COLOR; - strncpy(nameVisible, STRING_IMGUI_TIMELINE_TRIGGERS, ANM2_STRING_FORMATTED_MAX); + nameVisible = STRING_IMGUI_TIMELINE_TRIGGERS; break; default: break; @@ -274,10 +297,10 @@ _imgui_timeline_item(Imgui* self, Anm2Reference reference, s32* index) ImGui::PushID(*index); ImGui::PushStyleColor(ImGuiCol_ChildBg, color); - ImGui::BeginChild(nameVisible, IMGUI_TIMELINE_ELEMENT_SIZE, true, ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoScrollbar); + ImGui::BeginChild(nameVisible.c_str(), IMGUI_TIMELINE_ELEMENT_SIZE, true, ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoScrollbar); ImGui::PopStyleColor(); - ImGui::Image(self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[textureType]), IMVEC2_ATLAS_UV_GET(textureType)); + ImGui::Image(self->resources->atlas.id, VEC2_TO_IMVEC2(ATLAS_SIZES[textureType]), IMVEC2_ATLAS_UV_GET(textureType)); ImGui::SameLine(); @@ -287,7 +310,7 @@ _imgui_timeline_item(Imgui* self, Anm2Reference reference, s32* index) { if (ImGui::InputText(STRING_IMGUI_TIMELINE_ANIMATION_LABEL, nameBuffer, ANM2_STRING_MAX, ImGuiInputTextFlags_EnterReturnsTrue)) { - strncpy(namePointer, nameBuffer, ANM2_STRING_MAX); + *namePointer = nameBuffer; textEntryItemIndex = -1; } _imgui_undoable(self); @@ -297,7 +320,7 @@ _imgui_timeline_item(Imgui* self, Anm2Reference reference, s32* index) } else { - if (ImGui::Selectable(nameVisible, isSelected)) + if (ImGui::Selectable(nameVisible.c_str(), isSelected)) { *self->reference = reference; anm2_reference_frame_clear(self->reference); @@ -307,6 +330,7 @@ _imgui_timeline_item(Imgui* self, Anm2Reference reference, s32* index) textEntryItemIndex = *index; } + // Drag and drop items (only layers/nulls) if (isChangeable && ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) { *self->reference = reference; @@ -315,9 +339,9 @@ _imgui_timeline_item(Imgui* self, Anm2Reference reference, s32* index) ImGui::PushStyleColor(ImGuiCol_ChildBg, color); ImGui::SetDragDropPayload(STRING_IMGUI_TIMELINE_ITEM_DRAG_DROP, &reference, sizeof(Anm2Frame)); ImGui::PopStyleColor(); - ImGui::Image(self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[textureType]), IMVEC2_ATLAS_UV_GET(textureType)); + ImGui::Image(self->resources->atlas.id, VEC2_TO_IMVEC2(ATLAS_SIZES[textureType]), IMVEC2_ATLAS_UV_GET(textureType)); ImGui::SameLine(); - ImGui::Text(nameVisible); + ImGui::Text(nameVisible.c_str()); ImGui::EndDragDropSource(); } @@ -331,8 +355,7 @@ _imgui_timeline_item(Imgui* self, Anm2Reference reference, s32* index) self->isSwap = true; self->swapReference = reference; - Snapshot snapshot = {*self->anm2, *self->reference, *self->time}; - snapshots_undo_stack_push(self->snapshots, &snapshot); + _imgui_undo_stack_push(self); } } ImGui::EndDragDropTarget(); @@ -358,7 +381,7 @@ _imgui_timeline_item(Imgui* self, Anm2Reference reference, s32* index) ImGui::EndChild(); - /* IsVisible */ + // IsVisible ImVec2 cursorPos; TextureType visibleTextureType = item->isVisible ? TEXTURE_VISIBLE : TEXTURE_INVISIBLE; @@ -367,26 +390,32 @@ _imgui_timeline_item(Imgui* self, Anm2Reference reference, s32* index) cursorPos = ImGui::GetCursorPos(); ImGui::SetCursorPosX(cursorPos.x + ImGui::GetContentRegionAvail().x - IMGUI_ICON_BUTTON_SIZE.x - ImGui::GetStyle().FramePadding.x * 2); - if (ImGui::ImageButton(STRING_IMGUI_TIMELINE_VISIBLE, self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[visibleTextureType]), IMVEC2_ATLAS_UV_GET(visibleTextureType))) + if + ( + ImGui::ImageButton + ( + STRING_IMGUI_TIMELINE_VISIBLE, + self->resources->atlas.id, + VEC2_TO_IMVEC2(ATLAS_SIZES[visibleTextureType]), + IMVEC2_ATLAS_UV_GET(visibleTextureType) + ) + ) item->isVisible = !item->isVisible; _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_VISIBLE); ImGui::SetCursorPos(cursorPos); - /* Spritesheet IDs */ + // Spritesheet IDs if (spritesheetID) { - char spritesheetIDName[ANM2_STRING_FORMATTED_MAX]; + std::string spritesheetIDName; - if (*spritesheetID == -1) - snprintf(spritesheetIDName, ANM2_STRING_FORMATTED_MAX, STRING_IMGUI_TIMELINE_SPRITESHEET_UNKNOWN); - else - snprintf(spritesheetIDName, ANM2_STRING_FORMATTED_MAX, STRING_IMGUI_TIMELINE_SPRITESHEET_FORMAT, *spritesheetID); + spritesheetIDName = std::format(STRING_IMGUI_TIMELINE_SPRITESHEET_ID_FORMAT, *spritesheetID); ImGui::BeginChild(STRING_IMGUI_TIMELINE_ELEMENT_SPRITESHEET_ID_LABEL, IMGUI_TIMELINE_ELEMENT_SPRITESHEET_ID_SIZE); - ImGui::Image(self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[TEXTURE_SPRITESHEET]), IMVEC2_ATLAS_UV_GET(TEXTURE_SPRITESHEET)); + ImGui::Image(self->resources->atlas.id, VEC2_TO_IMVEC2(ATLAS_SIZES[TEXTURE_SPRITESHEET]), IMVEC2_ATLAS_UV_GET(TEXTURE_SPRITESHEET)); ImGui::SameLine(); if (isSpritesheetTextEntry) @@ -400,7 +429,7 @@ _imgui_timeline_item(Imgui* self, Anm2Reference reference, s32* index) } else { - ImGui::Selectable(spritesheetIDName); + ImGui::Selectable(spritesheetIDName.c_str()); if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) textEntrySpritesheetIndex = *index; @@ -410,14 +439,14 @@ _imgui_timeline_item(Imgui* self, Anm2Reference reference, s32* index) ImGui::EndChild(); } - /* ShowRect */ + // ShowRect if (isShowRect) { TextureType rectTextureType = *isShowRect ? TEXTURE_RECT : TEXTURE_RECT_HIDE; ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - ((IMGUI_ICON_BUTTON_SIZE.x - ImGui::GetStyle().FramePadding.x * 2) * 4)); - if (ImGui::ImageButton(STRING_IMGUI_TIMELINE_RECT, self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[rectTextureType]), IMVEC2_ATLAS_UV_GET(rectTextureType))) + if (ImGui::ImageButton(STRING_IMGUI_TIMELINE_RECT, self->resources->atlas.id, VEC2_TO_IMVEC2(ATLAS_SIZES[rectTextureType]), IMVEC2_ATLAS_UV_GET(rectTextureType))) *isShowRect = !*isShowRect; _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_RECT); @@ -432,11 +461,10 @@ _imgui_timeline_item(Imgui* self, Anm2Reference reference, s32* index) ImGui::SetCursorPosY(cursorPosY + IMGUI_TIMELINE_ELEMENT_SIZE.y); } -/* Timeline */ +// Timeline window static void _imgui_timeline(Imgui* self) { - /* -- Timeline -- */ ImGui::Begin(STRING_IMGUI_TIMELINE); Anm2Animation* animation = anm2_animation_from_reference(self->anm2, self->reference); @@ -480,27 +508,31 @@ _imgui_timeline(Imgui* self) itemScrollX = ImGui::GetScrollX(); itemScrollY = ImGui::GetScrollY(); - _imgui_timeline_item_frames(self, Anm2Reference{ANM2_ROOT, animationID, 0, 0}, &index); + // Root + _imgui_timeline_item_frames(self, Anm2Reference{animationID, ANM2_ROOT, 0, 0}, &index); + // Layers (Reversed) for (auto it = animation->layerAnimations.rbegin(); it != animation->layerAnimations.rend(); it++) { s32 id = it->first; - - _imgui_timeline_item_frames(self, Anm2Reference{ANM2_LAYER, animationID, id, 0}, &index); + _imgui_timeline_item_frames(self, Anm2Reference{animationID, ANM2_LAYER, id, 0}, &index); } + // Nulls for (auto & [id, null] : animation->nullAnimations) - _imgui_timeline_item_frames(self, Anm2Reference{ANM2_NULL, animationID, id, 0}, &index); + _imgui_timeline_item_frames(self, Anm2Reference{animationID, ANM2_NULL, id, 0}, &index); - _imgui_timeline_item_frames(self, Anm2Reference{ANM2_TRIGGERS, animationID, 0, 0}, &index); + // Triggers + _imgui_timeline_item_frames(self, Anm2Reference{animationID, ANM2_TRIGGERS, 0, 0}, &index); + // Swap the two selected elements if (self->isSwap) { Anm2Frame* aFrame = anm2_frame_from_reference(self->anm2, self->reference); Anm2Frame* bFrame = anm2_frame_from_reference(self->anm2, &self->swapReference); Anm2Frame oldFrame = *aFrame; - /* With triggers, just swap the event id */ + // With triggers, just swap the event Id if (self->reference->itemType == ANM2_TRIGGERS) { aFrame->eventID = bFrame->eventID; @@ -526,6 +558,7 @@ _imgui_timeline(Imgui* self) ImGui::EndChild(); ImGui::PopStyleColor(); + // Only draw if animation length isn't 0 if (animation->frameNum > 0) { bool isMouseInElementsRegion = false; @@ -554,6 +587,7 @@ _imgui_timeline(Imgui* self) mousePos.x >= itemsRectMin.x && mousePos.x < itemsRectMax.x && mousePos.y >= itemsRectMin.y && mousePos.y < itemsRectMax.y; + // Dragging/undragging the frame picker if ((isMouseInElementsRegion && ImGui::IsMouseDragging(ImGuiMouseButton_Left)) || isPickerDragging) { s32 frameIndex = CLAMP((s32)(mousePosRelative.x / frameSize.x), 0, (f32)(animation->frameNum - 1)); @@ -565,14 +599,15 @@ _imgui_timeline(Imgui* self) if (isPickerDragging && ImGui::IsMouseReleased(ImGuiMouseButton_Left)) isPickerDragging = false; + // Draw the frame indices, based on the animation length for (s32 i = 0; i < animation->frameNum; i++) { ImVec2 imagePos = ImGui::GetCursorScreenPos(); if (i % IMGUI_TIMELINE_FRAME_INDICES_MULTIPLE == 0) { - char frameIndexString[IMGUI_TIMELINE_FRAME_INDICES_STRING_MAX]; - snprintf(frameIndexString, IMGUI_TIMELINE_FRAME_INDICES_STRING_MAX, "%i", i); + std::string frameIndexString; + frameIndexString = std::to_string(i); ImVec2 bgMin = imagePos; ImVec2 bgMax = ImVec2(imagePos.x + IMGUI_TIMELINE_FRAME_SIZE.x, @@ -581,13 +616,13 @@ _imgui_timeline(Imgui* self) ImU32 bgColor = ImGui::GetColorU32(IMGUI_FRAME_INDICES_OVERLAY_COLOR); drawList->AddRectFilled(bgMin, bgMax, bgColor); - ImVec2 textSize = ImGui::CalcTextSize(frameIndexString); + ImVec2 textSize = ImGui::CalcTextSize(frameIndexString.c_str()); ImVec2 textPos; textPos.x = imagePos.x + (IMGUI_TIMELINE_FRAME_SIZE.x - textSize.x) / 2.0f; textPos.y = imagePos.y + (IMGUI_TIMELINE_FRAME_SIZE.y - textSize.y) / 2.0f; - drawList->AddText(textPos, ImGui::GetColorU32(ImGuiCol_Text), frameIndexString); + drawList->AddText(textPos, ImGui::GetColorU32(ImGuiCol_Text), frameIndexString.c_str()); } else { @@ -599,7 +634,7 @@ _imgui_timeline(Imgui* self) drawList->AddRectFilled(bgMin, bgMax, bgColor); } - ImGui::Image(self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[TEXTURE_FRAME]), IMVEC2_ATLAS_UV_GET(TEXTURE_FRAME)); + ImGui::Image(self->resources->atlas.id, VEC2_TO_IMVEC2(ATLAS_SIZES[TEXTURE_FRAME]), IMVEC2_ATLAS_UV_GET(TEXTURE_FRAME)); ImGui::SameLine(); } @@ -648,19 +683,24 @@ _imgui_timeline(Imgui* self) index = 0; - _imgui_timeline_item(self, Anm2Reference{ANM2_ROOT, animationID, 0, 0}, &index); + // Root + _imgui_timeline_item(self, Anm2Reference{animationID, ANM2_ROOT, 0, 0}, &index); + // Layer for (auto it = animation->layerAnimations.rbegin(); it != animation->layerAnimations.rend(); it++) { s32 id = it->first; - _imgui_timeline_item(self, Anm2Reference{ANM2_LAYER, animationID, id, 0}, &index); + _imgui_timeline_item(self, Anm2Reference{animationID, ANM2_LAYER, id, 0}, &index); } + // Null for (auto & [id, null] : animation->nullAnimations) - _imgui_timeline_item(self, Anm2Reference{ANM2_NULL, animationID, id, 0}, &index); + _imgui_timeline_item(self, Anm2Reference{animationID, ANM2_NULL, id, 0}, &index); - _imgui_timeline_item(self, Anm2Reference{ANM2_TRIGGERS, animationID, 0, 0}, &index); + // Triggers + _imgui_timeline_item(self, Anm2Reference{animationID, ANM2_TRIGGERS, 0, 0}, &index); + // Swap the drag/drop elements if (self->isSwap) { Anm2Animation* animation = anm2_animation_from_reference(self->anm2, self->reference); @@ -687,6 +727,7 @@ _imgui_timeline(Imgui* self) ImGui::EndChild(); ImGui::EndChild(); + // Add Element if (ImGui::Button(STRING_IMGUI_TIMELINE_ELEMENT_ADD)) ImGui::OpenPopup(STRING_IMGUI_TIMELINE_ELEMENT_ADD_MENU); _imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_ADD); @@ -706,8 +747,11 @@ _imgui_timeline(Imgui* self) ImGui::SameLine(); + // Remove Element if (ImGui::Button(STRING_IMGUI_TIMELINE_ELEMENT_REMOVE)) { + _imgui_undo_stack_push(self); + switch (self->reference->itemType) { case ANM2_LAYER: @@ -720,14 +764,13 @@ _imgui_timeline(Imgui* self) break; } - *self->reference = Anm2Reference{}; + anm2_reference_item_clear(self->reference); } - _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_REMOVE); ImGui::SameLine(); - /* Buttons */ + // Play/Pause button if (ImGui::Button(buttonText)) { self->preview->isPlaying = !self->preview->isPlaying; @@ -739,6 +782,7 @@ _imgui_timeline(Imgui* self) ImGui::SameLine(); + // Add frame if (ImGui::Button(STRING_IMGUI_TIMELINE_FRAME_ADD)) anm2_frame_add(self->anm2, self->reference, (s32)*self->time); _imgui_undoable(self); @@ -746,24 +790,25 @@ _imgui_timeline(Imgui* self) ImGui::SameLine(); + // Remove Frame if (ImGui::Button(STRING_IMGUI_TIMELINE_FRAME_REMOVE)) { Anm2Frame* frame = anm2_frame_from_reference(self->anm2, self->reference); if (frame) { + _imgui_undo_stack_push(self); Anm2Item* item = anm2_item_from_reference(self->anm2, self->reference); item->frames.erase(item->frames.begin() + index); anm2_reference_frame_clear(self->reference); } } - _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_FRAME_REMOVE); ImGui::SameLine(); - /* Fit Animation Length */ + // Fit Animation Length if (ImGui::Button(STRING_IMGUI_TIMELINE_FIT_ANIMATION_LENGTH)) { s32 length = anm2_animation_length_get(self->anm2, self->reference->animationID); @@ -775,7 +820,7 @@ _imgui_timeline(Imgui* self) ImGui::SameLine(); - /* Animation Length */ + // Animation Length ImGui::SetNextItemWidth(IMGUI_TIMELINE_ANIMATION_LENGTH_WIDTH); ImGui::InputInt(STRING_IMGUI_TIMELINE_ANIMATION_LENGTH, &animation->frameNum); _imgui_undoable(self); @@ -785,7 +830,7 @@ _imgui_timeline(Imgui* self) ImGui::SameLine(); - /* FPS */ + // FPS ImGui::SetNextItemWidth(IMGUI_TIMELINE_FPS_WIDTH); ImGui::SameLine(); ImGui::InputInt(STRING_IMGUI_TIMELINE_FPS, &self->anm2->fps); @@ -796,33 +841,33 @@ _imgui_timeline(Imgui* self) ImGui::SameLine(); - /* Loop */ + // Loop ImGui::Checkbox(STRING_IMGUI_TIMELINE_LOOP, &animation->isLoop); _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_LOOP); ImGui::SameLine(); - /* CreatedBy */ + // CreatedBy ImGui::SetNextItemWidth(IMGUI_TIMELINE_CREATED_BY_WIDTH); ImGui::SameLine(); - ImGui::InputText(STRING_IMGUI_TIMELINE_CREATED_BY, self->anm2->createdBy, ANM2_STRING_MAX); + ImGui::InputText(STRING_IMGUI_TIMELINE_CREATED_BY, &self->anm2->createdBy[0], ANM2_STRING_MAX); _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_CREATED_BY); ImGui::SameLine(); - /* CreatedOn */ - ImGui::Text(STRING_IMGUI_TIMELINE_CREATED_ON, self->anm2->createdOn); + // CreatedOn + ImGui::Text(STRING_IMGUI_TIMELINE_CREATED_ON, self->anm2->createdOn.c_str()); ImGui::SameLine(); - /* Version */ + // Version ImGui::Text(STRING_IMGUI_TIMELINE_VERSION, self->anm2->version); } ImGui::End(); } -/* Taskbar */ +// Taskbar static void _imgui_taskbar(Imgui* self) { @@ -841,6 +886,7 @@ _imgui_taskbar(Imgui* self) ImGui::Begin(STRING_IMGUI_TASKBAR, NULL, taskbarWindowFlags); + // File if (ImGui::Selectable(STRING_IMGUI_TASKBAR_FILE, false, 0, ImGui::CalcTextSize(STRING_IMGUI_TASKBAR_FILE))) ImGui::OpenPopup(STRING_IMGUI_FILE_MENU); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FILE_MENU); @@ -863,10 +909,11 @@ _imgui_taskbar(Imgui* self) if (ImGui::Selectable(STRING_IMGUI_FILE_SAVE)) { - if (!strcmp(self->anm2->path, STRING_EMPTY) == 0) - anm2_serialize(self->anm2, self->anm2->path); - else + // Open dialog if path empty, otherwise save in-place + if (self->anm2->path.empty()) dialog_anm2_save(self->dialog); + else + anm2_serialize(self->anm2, self->anm2->path); } _imgui_tooltip(STRING_IMGUI_TOOLTIP_FILE_SAVE); @@ -879,6 +926,7 @@ _imgui_taskbar(Imgui* self) ImGui::SameLine(); + // Playback if (ImGui::Selectable(STRING_IMGUI_TASKBAR_PLAYBACK, false, 0, ImGui::CalcTextSize(STRING_IMGUI_TASKBAR_PLAYBACK))) ImGui::OpenPopup(STRING_IMGUI_PLAYBACK_MENU); _imgui_tooltip(STRING_IMGUI_TOOLTIP_PLAYBACK_MENU); @@ -895,6 +943,7 @@ _imgui_taskbar(Imgui* self) ImGui::SameLine(); + // Wizard if (ImGui::Selectable(STRING_IMGUI_TASKBAR_WIZARD, false, 0, ImGui::CalcTextSize(STRING_IMGUI_TASKBAR_WIZARD))) ImGui::OpenPopup(STRING_IMGUI_WIZARD_MENU); _imgui_tooltip(STRING_IMGUI_TOOLTIP_WIZARD_MENU); @@ -916,13 +965,14 @@ _imgui_taskbar(Imgui* self) ImGui::EndPopup(); } + // Add a persistent tooltip to indicate recording if (self->preview->isRecording) { ImVec2 mousePos = ImGui::GetMousePos(); ImGui::SetNextWindowPos(ImVec2(mousePos.x + IMGUI_RECORD_TOOLTIP_OFFSET.x, mousePos.y + IMGUI_RECORD_TOOLTIP_OFFSET.y)); ImGui::BeginTooltip(); - ImGui::Image(self->resources->atlas.id, IMVEC2_VEC2(TEXTURE_SIZE), IMVEC2_ATLAS_UV_GET(TEXTURE_ANIMATION)); + ImGui::Image(self->resources->atlas.id, VEC2_TO_IMVEC2(TEXTURE_SIZE), IMVEC2_ATLAS_UV_GET(TEXTURE_ANIMATION)); ImGui::SameLine(); ImGui::Text(STRING_IMGUI_RECORDING); ImGui::EndTooltip(); @@ -931,7 +981,7 @@ _imgui_taskbar(Imgui* self) ImGui::End(); } -/* Tools */ +// Tools static void _imgui_tools(Imgui* self) { @@ -945,8 +995,8 @@ _imgui_tools(Imgui* self) for (s32 i = 0; i < TOOL_COUNT; i++) { - const char* string = NULL; - const char* tooltip = NULL; + const char* toolString; + const char* toolTooltip; TextureType textureType; if (i > 0 && i % buttonsPerRow != 0) @@ -958,38 +1008,38 @@ _imgui_tools(Imgui* self) switch (i) { case TOOL_PAN: - string = STRING_IMGUI_TOOLS_PAN; - tooltip = STRING_IMGUI_TOOLTIP_TOOLS_PAN; + toolString = STRING_IMGUI_TOOLS_PAN; + toolTooltip = STRING_IMGUI_TOOLTIP_TOOLS_PAN; textureType = TEXTURE_PAN; break; case TOOL_MOVE: - string = STRING_IMGUI_TOOLS_MOVE; - tooltip = STRING_IMGUI_TOOLTIP_TOOLS_MOVE; + toolString = STRING_IMGUI_TOOLS_MOVE; + toolTooltip = STRING_IMGUI_TOOLTIP_TOOLS_MOVE; textureType = TEXTURE_MOVE; break; case TOOL_ROTATE: - string = STRING_IMGUI_TOOLS_ROTATE; - tooltip = STRING_IMGUI_TOOLTIP_TOOLS_ROTATE; + toolString = STRING_IMGUI_TOOLS_ROTATE; + toolTooltip = STRING_IMGUI_TOOLTIP_TOOLS_ROTATE; textureType = TEXTURE_ROTATE; break; case TOOL_SCALE: - string = STRING_IMGUI_TOOLS_SCALE; - tooltip = STRING_IMGUI_TOOLTIP_TOOLS_SCALE; + toolString = STRING_IMGUI_TOOLS_SCALE; + toolTooltip = STRING_IMGUI_TOOLTIP_TOOLS_SCALE; textureType = TEXTURE_SCALE; break; case TOOL_CROP: - string = STRING_IMGUI_TOOLS_CROP; - tooltip = STRING_IMGUI_TOOLTIP_TOOLS_CROP; + toolString = STRING_IMGUI_TOOLS_CROP; + toolTooltip = STRING_IMGUI_TOOLTIP_TOOLS_CROP; textureType = TEXTURE_CROP; break; default: break; } - if (ImGui::ImageButton(string, self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[textureType]), IMVEC2_ATLAS_UV_GET(textureType))) + if (ImGui::ImageButton(toolString, self->resources->atlas.id, VEC2_TO_IMVEC2(ATLAS_SIZES[textureType]), IMVEC2_ATLAS_UV_GET(textureType))) self->tool->type = (ToolType)i; - _imgui_tooltip(tooltip); + _imgui_tooltip(toolTooltip); ImGui::PopStyleColor(); } @@ -998,7 +1048,7 @@ _imgui_tools(Imgui* self) } -/* Animations */ +// Animations static void _imgui_animations(Imgui* self) { @@ -1006,27 +1056,27 @@ _imgui_animations(Imgui* self) ImGui::Begin(STRING_IMGUI_ANIMATIONS); - /* Iterate through all animations, can be selected and names can be edited */ + // Iterate through all animations, can be selected and names can be edited for (auto & [id, animation] : self->anm2->animations) { - char name[ANM2_STRING_FORMATTED_MAX]; + std::string name; bool isSelected = self->reference->animationID == id; bool isTextEntry = textEntryAnimationID == id; - /* Distinguish default animation */ - if (strcmp(animation.name, self->anm2->defaultAnimation) == 0) - snprintf(name, ANM2_STRING_FORMATTED_MAX, STRING_IMGUI_ANIMATIONS_DEFAULT_ANIMATION_FORMAT, animation.name); + // Distinguish default animation + if (animation.name == self->anm2->defaultAnimation) + name = std::format(STRING_IMGUI_ANIMATIONS_DEFAULT_ANIMATION_FORMAT, animation.name); else - strncpy(name, animation.name, ANM2_STRING_FORMATTED_MAX - 1); + name = animation.name; ImGui::PushID(id); - ImGui::Image(self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[TEXTURE_ANIMATION]), IMVEC2_ATLAS_UV_GET(TEXTURE_ANIMATION)); + ImGui::Image(self->resources->atlas.id, VEC2_TO_IMVEC2(ATLAS_SIZES[TEXTURE_ANIMATION]), IMVEC2_ATLAS_UV_GET(TEXTURE_ANIMATION)); ImGui::SameLine(); if (isTextEntry) { - if (ImGui::InputText(STRING_IMGUI_ANIMATIONS_ANIMATION_LABEL, animation.name, ANM2_STRING_MAX, ImGuiInputTextFlags_EnterReturnsTrue)) + if (ImGui::InputText(STRING_IMGUI_ANIMATIONS_ANIMATION_LABEL, &animation.name[0], ANM2_STRING_MAX, ImGuiInputTextFlags_EnterReturnsTrue)) textEntryAnimationID = -1; _imgui_undoable(self); @@ -1035,7 +1085,7 @@ _imgui_animations(Imgui* self) } else { - if (ImGui::Selectable(name, isSelected)) + if (ImGui::Selectable(name.c_str(), isSelected)) { self->reference->animationID = id; anm2_reference_item_clear(self->reference); @@ -1049,9 +1099,9 @@ _imgui_animations(Imgui* self) if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) { ImGui::SetDragDropPayload(STRING_IMGUI_ANIMATIONS_DRAG_DROP, &id, sizeof(s32)); - ImGui::Image(self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[TEXTURE_ANIMATION]), IMVEC2_ATLAS_UV_GET(TEXTURE_ANIMATION)); + ImGui::Image(self->resources->atlas.id, VEC2_TO_IMVEC2(ATLAS_SIZES[TEXTURE_ANIMATION]), IMVEC2_ATLAS_UV_GET(TEXTURE_ANIMATION)); ImGui::SameLine(); - ImGui::Text(name); + ImGui::Text(name.c_str()); ImGui::EndDragDropSource(); } @@ -1062,9 +1112,7 @@ _imgui_animations(Imgui* self) s32 sourceID = *(s32*)payload->Data; if (sourceID != id) { - Snapshot snapshot = {*self->anm2, *self->reference, *self->time}; - snapshots_undo_stack_push(self->snapshots, &snapshot); - + _imgui_undo_stack_push(self); map_swap(self->anm2->animations, sourceID, id); } } @@ -1076,15 +1124,16 @@ _imgui_animations(Imgui* self) ImGui::PopID(); } + // Add if (ImGui::Button(STRING_IMGUI_ANIMATIONS_ADD)) { - bool isDefault = (s32)self->anm2->animations.size() == 0; /* first animation is default automatically */ + bool isDefault = (s32)self->anm2->animations.size() == 0; // First animation is default automatically s32 id = anm2_animation_add(self->anm2); self->reference->animationID = id; if (isDefault) - strncpy(self->anm2->defaultAnimation, self->anm2->animations[id].name, ANM2_STRING_MAX); + self->anm2->defaultAnimation = self->anm2->animations[id].name; } _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATIONS_ADD); @@ -1095,7 +1144,7 @@ _imgui_animations(Imgui* self) if (animation) { - /* Remove */ + // Remove if (ImGui::Button(STRING_IMGUI_ANIMATIONS_REMOVE)) { anm2_animation_remove(self->anm2, self->reference->animationID); @@ -1106,7 +1155,7 @@ _imgui_animations(Imgui* self) ImGui::SameLine(); - /* Duplicate */ + // Duplicate if (ImGui::Button(STRING_IMGUI_ANIMATIONS_DUPLICATE)) { s32 id = map_next_id_get(self->anm2->animations); @@ -1118,9 +1167,9 @@ _imgui_animations(Imgui* self) ImGui::SameLine(); - /* Set as default */ + // Set as default if (ImGui::Button(STRING_IMGUI_ANIMATIONS_SET_AS_DEFAULT)) - strncpy(self->anm2->defaultAnimation, animation->name, ANM2_STRING_MAX); + self->anm2->defaultAnimation = animation->name; _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATIONS_SET_AS_DEFAULT); } @@ -1131,7 +1180,7 @@ _imgui_animations(Imgui* self) ImGui::End(); } -/* Events */ +// Events static void _imgui_events(Imgui* self) { @@ -1140,23 +1189,23 @@ _imgui_events(Imgui* self) ImGui::Begin(STRING_IMGUI_EVENTS); - /* Iterate through all events, can be selected and names can be edited */ + // Iterate through all events for (auto & [id, event] : self->anm2->events) { - char eventString[ANM2_STRING_FORMATTED_MAX]; + std::string eventString; bool isSelected = selectedEventID == id; bool isTextEntry = textEntryEventID == id; - snprintf(eventString, ANM2_STRING_FORMATTED_MAX, STRING_IMGUI_EVENT_FORMAT, (s32)id, event.name); + eventString = std::format(STRING_IMGUI_EVENT_FORMAT, id, event.name); ImGui::PushID(id); - ImGui::Image(self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[TEXTURE_EVENT]), IMVEC2_ATLAS_UV_GET(TEXTURE_EVENT)); + ImGui::Image(self->resources->atlas.id, VEC2_TO_IMVEC2(ATLAS_SIZES[TEXTURE_EVENT]), IMVEC2_ATLAS_UV_GET(TEXTURE_EVENT)); ImGui::SameLine(); if (isTextEntry) { - if (ImGui::InputText(STRING_IMGUI_ANIMATIONS_ANIMATION_LABEL, event.name, ANM2_STRING_MAX, ImGuiInputTextFlags_EnterReturnsTrue)) + if (ImGui::InputText(STRING_IMGUI_ANIMATIONS_ANIMATION_LABEL, &event.name[0], ANM2_STRING_MAX, ImGuiInputTextFlags_EnterReturnsTrue)) { selectedEventID = -1; textEntryEventID = -1; @@ -1168,7 +1217,7 @@ _imgui_events(Imgui* self) } else { - if (ImGui::Selectable(eventString, isSelected)) + if (ImGui::Selectable(eventString.c_str(), isSelected)) selectedEventID = id; if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) @@ -1177,9 +1226,9 @@ _imgui_events(Imgui* self) if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) { ImGui::SetDragDropPayload(STRING_IMGUI_EVENTS_DRAG_DROP, &id, sizeof(s32)); - ImGui::Image(self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[TEXTURE_ANIMATION]), IMVEC2_ATLAS_UV_GET(TEXTURE_EVENT)); + ImGui::Image(self->resources->atlas.id, VEC2_TO_IMVEC2(ATLAS_SIZES[TEXTURE_ANIMATION]), IMVEC2_ATLAS_UV_GET(TEXTURE_EVENT)); ImGui::SameLine(); - ImGui::Text(eventString); + ImGui::Text(eventString.c_str()); ImGui::EndDragDropSource(); } @@ -1190,9 +1239,7 @@ _imgui_events(Imgui* self) s32 sourceID = *(s32*)payload->Data; if (sourceID != id) { - Snapshot snapshot = {*self->anm2, *self->reference, *self->time}; - snapshots_undo_stack_push(self->snapshots, &snapshot); - + _imgui_undo_stack_push(self); map_swap(self->anm2->events, sourceID, id); } } @@ -1232,7 +1279,7 @@ _imgui_events(Imgui* self) ImGui::End(); } -/* Spritesheets */ +// Spritesheets static void _imgui_spritesheets(Imgui* self) { @@ -1243,28 +1290,31 @@ _imgui_spritesheets(Imgui* self) for (auto [id, spritesheet] : self->anm2->spritesheets) { ImVec2 spritesheetPreviewSize = IMGUI_SPRITESHEET_PREVIEW_SIZE; - char spritesheetString[ANM2_STRING_FORMATTED_MAX]; bool isSelected = selectedSpritesheetID == id; Texture* texture = &self->resources->textures[id]; - snprintf(spritesheetString, ANM2_PATH_FORMATTED_MAX, STRING_IMGUI_SPRITESHEET_FORMAT, (s32)id, spritesheet.path); - ImGui::BeginChild(spritesheetString, IMGUI_SPRITESHEET_SIZE, true, ImGuiWindowFlags_None); + std::string spritesheetString = std::format(STRING_IMGUI_SPRITESHEET_FORMAT, id, spritesheet.path); + + ImGui::BeginChild(spritesheetString.c_str(), IMGUI_SPRITESHEET_SIZE, true, ImGuiWindowFlags_None); ImGui::PushID(id); - ImGui::Image(self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[TEXTURE_SPRITESHEET]), IMVEC2_ATLAS_UV_GET(TEXTURE_SPRITESHEET)); + ImGui::Image(self->resources->atlas.id, VEC2_TO_IMVEC2(ATLAS_SIZES[TEXTURE_SPRITESHEET]), IMVEC2_ATLAS_UV_GET(TEXTURE_SPRITESHEET)); ImGui::SameLine(); - if (ImGui::Selectable(spritesheetString, isSelected)) + if (ImGui::Selectable(spritesheetString.c_str(), isSelected)) + { selectedSpritesheetID = id; + _imgui_spritesheet_editor_set(self, selectedSpritesheetID); + } _imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEETS_SELECT); if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) { ImGui::SetDragDropPayload(STRING_IMGUI_SPRITESHEETS_DRAG_DROP, &id, sizeof(s32)); - ImGui::Image(self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[TEXTURE_SPRITESHEET]), IMVEC2_ATLAS_UV_GET(TEXTURE_SPRITESHEET)); + ImGui::Image(self->resources->atlas.id, VEC2_TO_IMVEC2(ATLAS_SIZES[TEXTURE_SPRITESHEET]), IMVEC2_ATLAS_UV_GET(TEXTURE_SPRITESHEET)); ImGui::SameLine(); - ImGui::Text(spritesheetString); + ImGui::Text(spritesheetString.c_str()); ImGui::EndDragDropSource(); } @@ -1290,7 +1340,7 @@ _imgui_spritesheets(Imgui* self) spritesheetPreviewSize.y = IMGUI_SPRITESHEET_PREVIEW_SIZE.x / spritesheetAspect; if (texture->isInvalid) - ImGui::Image(self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[TEXTURE_ERROR]), IMVEC2_ATLAS_UV_GET(TEXTURE_ERROR)); + ImGui::Image(self->resources->atlas.id, VEC2_TO_IMVEC2(ATLAS_SIZES[TEXTURE_ERROR]), IMVEC2_ATLAS_UV_GET(TEXTURE_ERROR)); else ImGui::Image(texture->id, spritesheetPreviewSize); @@ -1305,9 +1355,10 @@ _imgui_spritesheets(Imgui* self) ImGui::SameLine(); + // If spritesheet selected... if (selectedSpritesheetID > -1) { - /* Remove */ + // Remove if (ImGui::Button(STRING_IMGUI_SPRITESHEETS_REMOVE)) { texture_free(&self->resources->textures[selectedSpritesheetID]); @@ -1319,15 +1370,21 @@ _imgui_spritesheets(Imgui* self) ImGui::SameLine(); - /* Reload */ + // Reload if (ImGui::Button(STRING_IMGUI_SPRITESHEETS_RELOAD)) { - anm2_spritesheet_texture_load(self->anm2, self->resources, self->anm2->spritesheets[selectedSpritesheetID].path, selectedSpritesheetID); + // Save the working path, set path, to the anm2's path, load spritesheet, return to old path + std::filesystem::path workingPath = std::filesystem::current_path(); + working_directory_from_file_set(self->anm2->path); + + resources_texture_init(self->resources, self->anm2->spritesheets[selectedSpritesheetID].path, selectedSpritesheetID); + + std::filesystem::current_path(workingPath); } _imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEETS_RELOAD); ImGui::SameLine(); - /* Replace */ + // Replace if (ImGui::Button(STRING_IMGUI_SPRITESHEETS_REPLACE)) { self->dialog->replaceID = selectedSpritesheetID; @@ -1342,75 +1399,70 @@ _imgui_spritesheets(Imgui* self) ImGui::End(); } -/* Animation Preview */ +// Animation Preview static void _imgui_animation_preview(Imgui* self) { static bool isPreviewHover = false; static bool isPreviewCenter = false; static vec2 mousePos = {0, 0}; - char mousePositionString[IMGUI_POSITION_STRING_MAX]; - - memset(mousePositionString, '\0', IMGUI_POSITION_STRING_MAX); - - snprintf(mousePositionString, IMGUI_POSITION_STRING_MAX, STRING_IMGUI_ANIMATION_PREVIEW_POSITION_FORMAT, mousePos.x, mousePos.y); ImGui::Begin(STRING_IMGUI_ANIMATION_PREVIEW, NULL, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse); ImVec2 windowSize = ImGui::GetWindowSize(); - /* Grid settings */ + // Grid settings ImGui::BeginChild(STRING_IMGUI_ANIMATION_PREVIEW_GRID_SETTINGS, IMGUI_ANIMATION_PREVIEW_SETTINGS_CHILD_SIZE, true); - /* Grid toggle */ + // Grid toggle ImGui::Checkbox(STRING_IMGUI_ANIMATION_PREVIEW_GRID, &self->settings->previewIsGrid); _imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_GRID); ImGui::SameLine(); - /* Grid Color */ + // Grid Color ImGui::ColorEdit4(STRING_IMGUI_ANIMATION_PREVIEW_GRID_COLOR, (f32*)&self->settings->previewGridColorR, ImGuiColorEditFlags_NoInputs); _imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_GRID_COLOR); - /* Grid Size */ + // Grid Size ImGui::InputInt2(STRING_IMGUI_ANIMATION_PREVIEW_GRID_SIZE, (s32*)&self->settings->previewGridSizeX); self->settings->previewGridSizeX = CLAMP(self->settings->previewGridSizeX, PREVIEW_GRID_MIN, PREVIEW_GRID_MAX); self->settings->previewGridSizeY = CLAMP(self->settings->previewGridSizeY, PREVIEW_GRID_MIN, PREVIEW_GRID_MAX); _imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_GRID_SIZE); - /* Grid Offset */ + // Grid Offset ImGui::InputInt2(STRING_IMGUI_ANIMATION_PREVIEW_GRID_OFFSET, (s32*)&self->settings->previewGridOffsetX); _imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_GRID_OFFSET); - ImGui::EndChild(); ImGui::SameLine(); ImGui::SameLine(); - /* View settings */ + // View settings ImGui::BeginChild(STRING_IMGUI_ANIMATION_PREVIEW_VIEW_SETTINGS, IMGUI_ANIMATION_PREVIEW_SETTINGS_CHILD_SIZE, true); - /* Zoom */ + // Zoom ImGui::DragFloat(STRING_IMGUI_ANIMATION_PREVIEW_ZOOM, &self->settings->previewZoom, 1, PREVIEW_ZOOM_MIN, PREVIEW_ZOOM_MAX, "%.0f"); _imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_ZOOM); - /* Center view */ + // Center view if (ImGui::Button(STRING_IMGUI_ANIMATION_PREVIEW_CENTER_VIEW)) isPreviewCenter = true; _imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_CENTER_VIEW); - /* Mouse position */ - ImGui::Text(mousePositionString); + // Mouse position; note that mousePos is relative to the animation preview and set later + std::string mousePositionString = std::format(STRING_IMGUI_POSITION_FORMAT, (s32)mousePos.x, (s32)mousePos.y); + ImGui::Text(mousePositionString.c_str()); ImGui::EndChild(); ImGui::SameLine(); - /* Background settings */ + // Background settings ImGui::BeginChild(STRING_IMGUI_ANIMATION_PREVIEW_BACKGROUND_SETTINGS, IMGUI_ANIMATION_PREVIEW_SETTINGS_CHILD_SIZE, true); - /* Background color */ + // Background color ImGui::ColorEdit4(STRING_IMGUI_ANIMATION_PREVIEW_BACKGROUND_COLOR, (f32*)&self->settings->previewBackgroundColorR, ImGuiColorEditFlags_NoInputs); _imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_BACKGROUND_COLOR); @@ -1418,56 +1470,57 @@ _imgui_animation_preview(Imgui* self) ImGui::SameLine(); - /* Helper settings */ + // Helper settings ImGui::BeginChild(STRING_IMGUI_ANIMATION_PREVIEW_HELPER_SETTINGS, IMGUI_ANIMATION_PREVIEW_SETTINGS_CHILD_SIZE, true); - /* Axis toggle */ + // Axis toggle ImGui::Checkbox(STRING_IMGUI_ANIMATION_PREVIEW_AXIS, &self->settings->previewIsAxis); _imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_AXIS); ImGui::SameLine(); - /* Axis colors */ + // Axis colors ImGui::ColorEdit4(STRING_IMGUI_ANIMATION_PREVIEW_AXIS_COLOR, (f32*)&self->settings->previewAxisColorR, ImGuiColorEditFlags_NoInputs); _imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_AXIS_COLOR); - /* Root transform */ + // Root transform ImGui::Checkbox(STRING_IMGUI_ANIMATION_PREVIEW_ROOT_TRANSFORM, &self->settings->previewIsRootTransform); _imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_ROOT_TRANSFORM); - /* Show pivot */ + // Show pivot ImGui::Checkbox(STRING_IMGUI_ANIMATION_PREVIEW_SHOW_PIVOT, &self->settings->previewIsShowPivot); _imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_SHOW_PIVOT); ImGui::EndChild(); - /* Animation preview texture */ - vec2 previewPos = VEC2_IMVEC2(ImGui::GetCursorPos()); + // Animation preview texture + vec2 previewPos = IMVEC2_TO_VEC2(ImGui::GetCursorPos()); - ImGui::Image(self->preview->texture, IMVEC2_VEC2(PREVIEW_SIZE)); + ImGui::Image(self->preview->texture, VEC2_TO_IMVEC2(PREVIEW_SIZE)); self->preview->recordSize = vec2(windowSize.x, windowSize.y - IMGUI_ANIMATION_PREVIEW_SETTINGS_CHILD_SIZE.y); - /* Using tools when hovered */ + // Using tools when hovered if (ImGui::IsItemHovered()) { - vec2 windowPos = VEC2_IMVEC2(ImGui::GetWindowPos()); + vec2 windowPos = IMVEC2_TO_VEC2(ImGui::GetWindowPos()); - mousePos = VEC2_IMVEC2(ImGui::GetMousePos()); + // Setting mouse pos relative to preview + mousePos = IMVEC2_TO_VEC2(ImGui::GetMousePos()); mousePos -= (windowPos + previewPos); mousePos -= (PREVIEW_SIZE / 2.0f); mousePos.x += self->settings->previewPanX; mousePos.y += self->settings->previewPanY; - mousePos.x /= (self->settings->previewZoom / 100.0f); - mousePos.y /= (self->settings->previewZoom / 100.0f); + mousePos.x /= PERCENT_TO_UNIT(self->settings->previewZoom); + mousePos.y /= PERCENT_TO_UNIT(self->settings->previewZoom); Anm2Frame* frame = anm2_frame_from_reference(self->anm2, self->reference); if (self->reference->itemType == ANM2_TRIGGERS) frame = NULL; - /* allow use of keybinds for tools */ + // Allow use of keybinds for tools self->tool->isEnabled = true; switch (self->tool->type) @@ -1486,89 +1539,100 @@ _imgui_animation_preview(Imgui* self) if (frame) { + f32 step = input_held(self->input, INPUT_MOD) ? PREVIEW_MOVE_STEP_MOD : PREVIEW_MOVE_STEP; + if ( mouse_press(&self->input->mouse, MOUSE_LEFT) || - key_press(&self->input->keyboard, INPUT_KEYS[INPUT_LEFT]) || - key_press(&self->input->keyboard, INPUT_KEYS[INPUT_RIGHT]) || - key_press(&self->input->keyboard, INPUT_KEYS[INPUT_UP]) || - key_press(&self->input->keyboard, INPUT_KEYS[INPUT_DOWN]) + input_press(self->input, INPUT_LEFT) || + input_press(self->input, INPUT_RIGHT) || + input_press(self->input, INPUT_UP) || + input_press(self->input, INPUT_DOWN) ) - { - Snapshot snapshot = {*self->anm2, *self->reference, *self->time}; - snapshots_undo_stack_push(self->snapshots, &snapshot); - } + _imgui_undo_stack_push(self); if (mouse_held(&self->input->mouse, MOUSE_LEFT)) - frame->position = VEC2_IMVEC2(mousePos); + frame->position = IMVEC2_TO_VEC2(mousePos); - if (key_held(&self->input->keyboard, INPUT_KEYS[INPUT_LEFT])) - frame->position.x -= PREVIEW_MOVE_STEP; + if (input_held(self->input, INPUT_LEFT)) + frame->position.x -= step; - if (key_held(&self->input->keyboard, INPUT_KEYS[INPUT_RIGHT])) - frame->position.x += PREVIEW_MOVE_STEP; + if (input_held(self->input, INPUT_RIGHT)) + frame->position.x += step; - if (key_held(&self->input->keyboard, INPUT_KEYS[INPUT_UP])) - frame->position.y -= PREVIEW_MOVE_STEP; + if (input_held(self->input, INPUT_UP)) + frame->position.y -= step; - if (key_held(&self->input->keyboard, INPUT_KEYS[INPUT_DOWN])) - frame->position.y += PREVIEW_MOVE_STEP; + if (input_held(self->input, INPUT_DOWN)) + frame->position.y += step; } break; case TOOL_ROTATE: SDL_SetCursor(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_CROSSHAIR)); if (frame) { + f32 step = input_held(self->input, INPUT_MOD) ? PREVIEW_ROTATE_STEP_MOD : PREVIEW_ROTATE_STEP; + if ( mouse_press(&self->input->mouse, MOUSE_LEFT) || - key_press(&self->input->keyboard, INPUT_KEYS[INPUT_LEFT]) || - key_press(&self->input->keyboard, INPUT_KEYS[INPUT_RIGHT]) || - key_press(&self->input->keyboard, INPUT_KEYS[INPUT_UP]) || - key_press(&self->input->keyboard, INPUT_KEYS[INPUT_DOWN]) || - key_press(&self->input->keyboard, INPUT_KEYS[INPUT_ROTATE_LEFT]) || - key_press(&self->input->keyboard, INPUT_KEYS[INPUT_ROTATE_RIGHT]) + input_press(self->input, INPUT_LEFT) || + input_press(self->input, INPUT_RIGHT) || + input_press(self->input, INPUT_UP) || + input_press(self->input, INPUT_DOWN) ) - { - Snapshot snapshot = {*self->anm2, *self->reference, *self->time}; - snapshots_undo_stack_push(self->snapshots, &snapshot); - } + _imgui_undo_stack_push(self); if (mouse_held(&self->input->mouse, MOUSE_LEFT)) frame->rotation += (s32)self->input->mouse.delta.x; if ( - key_held(&self->input->keyboard, INPUT_KEYS[INPUT_LEFT]) || - key_held(&self->input->keyboard, INPUT_KEYS[INPUT_UP]) || - key_held(&self->input->keyboard, INPUT_KEYS[INPUT_ROTATE_LEFT]) + input_held(self->input, INPUT_LEFT) || + input_held(self->input, INPUT_UP) ) - frame->rotation -= PREVIEW_ROTATE_STEP; + frame->rotation -= step; if ( - key_held(&self->input->keyboard, INPUT_KEYS[INPUT_RIGHT]) || - key_held(&self->input->keyboard, INPUT_KEYS[INPUT_DOWN]) || - key_held(&self->input->keyboard, INPUT_KEYS[INPUT_ROTATE_RIGHT]) + input_held(self->input, INPUT_RIGHT) || + input_held(self->input, INPUT_DOWN) ) - frame->rotation += PREVIEW_ROTATE_STEP; + frame->rotation += step; } break; case TOOL_SCALE: SDL_SetCursor(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NE_RESIZE)); if (frame) { - if (mouse_press(&self->input->mouse, MOUSE_LEFT)) - { - Snapshot snapshot = {*self->anm2, *self->reference, *self->time}; - snapshots_undo_stack_push(self->snapshots, &snapshot); - } + f32 step = input_held(self->input, INPUT_MOD) ? PREVIEW_SCALE_STEP_MOD : PREVIEW_SCALE_STEP; + + if + ( + mouse_press(&self->input->mouse, MOUSE_LEFT) || + input_press(self->input, INPUT_LEFT) || + input_press(self->input, INPUT_RIGHT) || + input_press(self->input, INPUT_UP) || + input_press(self->input, INPUT_DOWN) + ) + _imgui_undo_stack_push(self); + + if (input_held(self->input, INPUT_LEFT)) + frame->scale.x -= step; + + if (input_held(self->input, INPUT_RIGHT)) + frame->scale.x += step; + + if (input_held(self->input, INPUT_UP)) + frame->scale.y -= step; + + if (input_held(self->input, INPUT_DOWN)) + frame->scale.y += step; if (mouse_held(&self->input->mouse, MOUSE_LEFT)) { frame->scale.x += (s32)self->input->mouse.delta.x; frame->scale.y += (s32)self->input->mouse.delta.y; - } } break; @@ -1581,15 +1645,15 @@ _imgui_animation_preview(Imgui* self) isPreviewHover = true; - /* Used to not be annoying when at lowest zoom */ + // Used to not be annoying when at lowest zoom self->settings->previewZoom = self->settings->previewZoom == EDITOR_ZOOM_MIN ? 0 : self->settings->previewZoom; - /* Zoom in */ - if (self->input->mouse.wheelDeltaY > 0 || key_press(&self->input->keyboard, INPUT_KEYS[INPUT_ZOOM_IN])) + // Zoom in + if (self->input->mouse.wheelDeltaY > 0 || input_release(self->input, INPUT_ZOOM_IN)) self->settings->previewZoom += PREVIEW_ZOOM_STEP; - /* Zoom out */ - if (self->input->mouse.wheelDeltaY < 0 || key_press(&self->input->keyboard, INPUT_KEYS[INPUT_ZOOM_OUT])) + // Zoom out + if (self->input->mouse.wheelDeltaY < 0 || input_release(self->input, INPUT_ZOOM_OUT)) self->settings->previewZoom -= PREVIEW_ZOOM_STEP; self->settings->previewZoom = CLAMP(self->settings->previewZoom, PREVIEW_ZOOM_MIN, PREVIEW_ZOOM_MAX); @@ -1607,7 +1671,7 @@ _imgui_animation_preview(Imgui* self) { ImVec2 previewWindowRectSize = ImGui::GetCurrentWindow()->ClipRect.GetSize(); - /* Based on the preview's crop in its window, adjust the pan */ + // Based on the preview's crop in its window, adjust the pan self->settings->previewPanX = -(previewWindowRectSize.x - PREVIEW_SIZE.x) / 2.0f; self->settings->previewPanY = -((previewWindowRectSize.y - PREVIEW_SIZE.y) / 2.0f) + (IMGUI_ANIMATION_PREVIEW_SETTINGS_SIZE.y / 2.0f); @@ -1617,47 +1681,42 @@ _imgui_animation_preview(Imgui* self) ImGui::End(); } -/* Spritesheet Editor */ +// Spritesheet Editor static void _imgui_spritesheet_editor(Imgui* self) { static bool isEditorHover = false; static bool isEditorCenter = false; static vec2 mousePos = {0, 0}; - char mousePositionString[IMGUI_POSITION_STRING_MAX]; - - memset(mousePositionString, '\0', IMGUI_POSITION_STRING_MAX); - - snprintf(mousePositionString, IMGUI_POSITION_STRING_MAX, STRING_IMGUI_SPRITESHEET_EDITOR_POSITION_FORMAT, mousePos.x, mousePos.y); ImGui::Begin(STRING_IMGUI_SPRITESHEET_EDITOR, NULL, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse); - /* Grid settings */ + // Grid settings ImGui::BeginChild(STRING_IMGUI_SPRITESHEET_EDITOR_GRID_SETTINGS, IMGUI_SPRITESHEET_EDITOR_SETTINGS_CHILD_SIZE, true); - /* Grid toggle */ + // Grid toggle ImGui::Checkbox(STRING_IMGUI_SPRITESHEET_EDITOR_GRID, &self->settings->editorIsGrid); _imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEET_EDITOR_GRID); ImGui::SameLine(); - /* Grid snap */ + // Grid snap ImGui::Checkbox(STRING_IMGUI_SPRITESHEET_EDITOR_GRID_SNAP, &self->settings->editorIsGridSnap); _imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEET_EDITOR_GRID_SNAP); ImGui::SameLine(); - /* Grid Color */ + // Grid color ImGui::ColorEdit4(STRING_IMGUI_SPRITESHEET_EDITOR_GRID_COLOR, (f32*)&self->settings->editorGridColorR, ImGuiColorEditFlags_NoInputs); _imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEET_EDITOR_GRID_COLOR); - /* Grid Size */ + // Grid size ImGui::InputInt2(STRING_IMGUI_SPRITESHEET_EDITOR_GRID_SIZE, (s32*)&self->settings->editorGridSizeX); self->settings->editorGridSizeX = CLAMP(self->settings->editorGridSizeX, PREVIEW_GRID_MIN, PREVIEW_GRID_MAX); self->settings->editorGridSizeY = CLAMP(self->settings->editorGridSizeY, PREVIEW_GRID_MIN, PREVIEW_GRID_MAX); _imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEET_EDITOR_GRID_SIZE); - /* Grid Offset */ + // Grid offset ImGui::InputInt2(STRING_IMGUI_SPRITESHEET_EDITOR_GRID_OFFSET, (s32*)&self->settings->editorGridOffsetX); _imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEET_EDITOR_GRID_OFFSET); @@ -1665,61 +1724,63 @@ _imgui_spritesheet_editor(Imgui* self) ImGui::SameLine(); - /* View settings */ + // View settings ImGui::BeginChild(STRING_IMGUI_SPRITESHEET_EDITOR_VIEW_SETTINGS, IMGUI_SPRITESHEET_EDITOR_SETTINGS_CHILD_SIZE, true); - /* Zoom */ + // Zoom ImGui::DragFloat(STRING_IMGUI_SPRITESHEET_EDITOR_ZOOM, &self->settings->editorZoom, 1, PREVIEW_ZOOM_MIN, PREVIEW_ZOOM_MAX, "%.0f"); _imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEET_EDITOR_ZOOM); - /* Center view */ + // Center view if (ImGui::Button(STRING_IMGUI_SPRITESHEET_EDITOR_CENTER_VIEW)) isEditorCenter = true; _imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEET_EDITOR_CENTER_VIEW); - /* Info position */ - ImGui::Text(mousePositionString); + // Info position + std::string mousePositionString = std::format(STRING_IMGUI_POSITION_FORMAT, (s32)mousePos.x, (s32)mousePos.y); + ImGui::Text(mousePositionString.c_str()); ImGui::EndChild(); ImGui::SameLine(); - /* Background settings */ + // Background settings ImGui::BeginChild(STRING_IMGUI_SPRITESHEET_EDITOR_BACKGROUND_SETTINGS, IMGUI_SPRITESHEET_EDITOR_SETTINGS_CHILD_SIZE, true); - /* Background color */ + // Background color ImGui::ColorEdit4(STRING_IMGUI_SPRITESHEET_EDITOR_BACKGROUND_COLOR, (f32*)&self->settings->editorBackgroundColorR, ImGuiColorEditFlags_NoInputs); _imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEET_EDITOR_BACKGROUND_COLOR); - /* Border */ + // Border ImGui::Checkbox(STRING_IMGUI_SPRITESHEET_EDITOR_BORDER, &self->settings->editorIsBorder); _imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEET_EDITOR_BORDER); ImGui::EndChild(); - vec2 editorPos = VEC2_IMVEC2(ImGui::GetCursorPos()); - ImGui::Image(self->editor->texture, IMVEC2_VEC2(EDITOR_SIZE)); + vec2 editorPos = IMVEC2_TO_VEC2(ImGui::GetCursorPos()); + ImGui::Image(self->editor->texture, VEC2_TO_IMVEC2(EDITOR_SIZE)); - /* Panning + zoom */ + // Panning and zoom if (ImGui::IsItemHovered()) { - vec2 windowPos = VEC2_IMVEC2(ImGui::GetWindowPos()); - mousePos = VEC2_IMVEC2(ImGui::GetMousePos()); + vec2 windowPos = IMVEC2_TO_VEC2(ImGui::GetWindowPos()); + mousePos = IMVEC2_TO_VEC2(ImGui::GetMousePos()); mousePos -= (windowPos + editorPos); mousePos -= (EDITOR_SIZE / 2.0f); mousePos.x += self->settings->editorPanX; mousePos.y += self->settings->editorPanY; - mousePos.x /= (self->settings->editorZoom / 100.0f); - mousePos.y /= (self->settings->editorZoom / 100.0f); + mousePos.x /= PERCENT_TO_UNIT(self->settings->editorZoom); + mousePos.y /= PERCENT_TO_UNIT(self->settings->editorZoom); isEditorHover = true; Anm2Frame* frame = anm2_frame_from_reference(self->anm2, self->reference); - /* allow use of keybinds for tools */ + // Allow use of keybinds for tools self->tool->isEnabled = true; + // Only changing layer frames if (self->reference->itemType != ANM2_LAYER) frame = NULL; @@ -1729,9 +1790,8 @@ _imgui_spritesheet_editor(Imgui* self) if (mouse_press(&self->input->mouse, MOUSE_LEFT)) { - Snapshot snapshot = {*self->anm2, *self->reference, *self->time}; - snapshots_undo_stack_push(self->snapshots, &snapshot); - + _imgui_undo_stack_push(self); + vec2 cropPosition = mousePos + IMGUI_SPRITESHEET_EDITOR_CROP_FORGIVENESS; if (self->settings->editorIsGridSnap) @@ -1768,15 +1828,15 @@ _imgui_spritesheet_editor(Imgui* self) } } - /* Used to not be annoying when at lowest zoom */ + // Used to not be annoying when at lowest zoom self->settings->editorZoom = self->settings->editorZoom == EDITOR_ZOOM_MIN ? 0 : self->settings->editorZoom; - /* Zoom in */ - if (self->input->mouse.wheelDeltaY > 0 || key_press(&self->input->keyboard, INPUT_KEYS[INPUT_ZOOM_IN])) + // Zoom in + if (self->input->mouse.wheelDeltaY > 0 || input_press(self->input, INPUT_ZOOM_IN)) self->settings->editorZoom += PREVIEW_ZOOM_STEP; - /* Zoom out */ - if (self->input->mouse.wheelDeltaY < 0 || key_press(&self->input->keyboard, INPUT_KEYS[INPUT_ZOOM_OUT])) + // Zoom out + if (self->input->mouse.wheelDeltaY < 0 || input_press(self->input, INPUT_ZOOM_OUT)) self->settings->editorZoom -= PREVIEW_ZOOM_STEP; self->settings->editorZoom = CLAMP(self->settings->editorZoom, EDITOR_ZOOM_MIN, EDITOR_ZOOM_MAX); @@ -1801,7 +1861,7 @@ _imgui_spritesheet_editor(Imgui* self) ImGui::End(); } -/* Frame Properties */ +// Frame properties static void _imgui_frame_properties(Imgui* self) { @@ -1839,50 +1899,50 @@ _imgui_frame_properties(Imgui* self) { case ANM2_ROOT: case ANM2_NULL: - /* Position */ + // Position ImGui::DragFloat2(STRING_IMGUI_FRAME_PROPERTIES_POSITION, value_ptr(frame->position), 1, 0, 0, "%.0f"); _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_POSITION); - /* Scale */ + // Scale ImGui::DragFloat2(STRING_IMGUI_FRAME_PROPERTIES_SCALE, value_ptr(frame->scale), 1.0, 0, 0, "%.1f"); _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_SCALE); - /* Rotation */ + // Rotation ImGui::DragFloat(STRING_IMGUI_FRAME_PROPERTIES_ROTATION, &frame->rotation, 1, 0, 0, "%.1f"); _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_ROTATION); - /* Duration */ + // Duration ImGui::InputInt(STRING_IMGUI_FRAME_PROPERTIES_DURATION, &frame->delay); _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_DURATION); frame->delay = CLAMP(frame->delay, ANM2_FRAME_DELAY_MIN, animation->frameNum + 1); - /* Tint */ + // Tint ImGui::ColorEdit4(STRING_IMGUI_FRAME_PROPERTIES_TINT, value_ptr(frame->tintRGBA)); _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_TINT); - /* Color Offset */ + // Color Offset ImGui::ColorEdit3(STRING_IMGUI_FRAME_PROPERTIES_COLOR_OFFSET, value_ptr(frame->offsetRGB)); _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_COLOR_OFFSET); - /* Visible */ + // Visible ImGui::Checkbox(STRING_IMGUI_FRAME_PROPERTIES_VISIBLE, &frame->isVisible); _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_VISIBLE); ImGui::SameLine(); - /* Interpolation */ + // Interpolation ImGui::Checkbox(STRING_IMGUI_FRAME_PROPERTIES_INTERPOLATED, &frame->isInterpolated); _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_INTERPOLATED); - /* Flip X */ + // Flip X if (ImGui::Button(STRING_IMGUI_FRAME_PROPERTIES_FLIP_X)) frame->scale.x = -frame->scale.x; _imgui_undoable(self); @@ -1890,61 +1950,61 @@ _imgui_frame_properties(Imgui* self) ImGui::SameLine(); - /* Flip Y */ + // Flip Y if (ImGui::Button(STRING_IMGUI_FRAME_PROPERTIES_FLIP_Y)) frame->scale.y = -frame->scale.y; _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_FLIP_Y); break; case ANM2_LAYER: - /* Position */ + // Position ImGui::DragFloat2(STRING_IMGUI_FRAME_PROPERTIES_POSITION, value_ptr(frame->position), 1, 0, 0, "%.0f"); _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_POSITION); - /* Crop Position */ + // Crop Position ImGui::DragFloat2(STRING_IMGUI_FRAME_PROPERTIES_CROP_POSITION, value_ptr(frame->crop), 1, 0, 0, "%.0f"); _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_CROP_POSITION); - /* Crop */ + // Crop ImGui::DragFloat2(STRING_IMGUI_FRAME_PROPERTIES_CROP_SIZE, value_ptr(frame->size), 1, 0, 0, "%.0f"); _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_CROP_SIZE); - /* Pivot */ + // Pivot ImGui::DragFloat2(STRING_IMGUI_FRAME_PROPERTIES_PIVOT, value_ptr(frame->pivot), 1, 0, 0, "%.0f"); _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_PIVOT); - /* Scale */ + // Scale ImGui::DragFloat2(STRING_IMGUI_FRAME_PROPERTIES_SCALE, value_ptr(frame->scale), 1.0, 0, 0, "%.1f"); _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_SCALE); - /* Rotation */ + // Rotation ImGui::DragFloat(STRING_IMGUI_FRAME_PROPERTIES_ROTATION, &frame->rotation, 1, 0, 0, "%.1f"); _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_ROTATION); - /* Duration */ + // Duration ImGui::InputInt(STRING_IMGUI_FRAME_PROPERTIES_DURATION, &frame->delay); _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_DURATION); - /* clamp delay */ + // clamp delay frame->delay = CLAMP(frame->delay, ANM2_FRAME_DELAY_MIN, animation->frameNum + 1); - /* Tint */ + // Tint ImGui::ColorEdit4(STRING_IMGUI_FRAME_PROPERTIES_TINT, value_ptr(frame->tintRGBA)); _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_TINT); - /* Color Offset */ + // Color Offset ImGui::ColorEdit3(STRING_IMGUI_FRAME_PROPERTIES_COLOR_OFFSET, value_ptr(frame->offsetRGB)); _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_COLOR_OFFSET); - /* Flip X */ + // Flip X if (ImGui::Button(STRING_IMGUI_FRAME_PROPERTIES_FLIP_X)) frame->scale.x = -frame->scale.x; _imgui_undoable(self); @@ -1952,30 +2012,30 @@ _imgui_frame_properties(Imgui* self) ImGui::SameLine(); - /* Flip Y */ + // Flip Y if (ImGui::Button(STRING_IMGUI_FRAME_PROPERTIES_FLIP_Y)) frame->scale.y = -frame->scale.y; _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_FLIP_Y); - /* Visible */ + // Visible ImGui::Checkbox(STRING_IMGUI_FRAME_PROPERTIES_VISIBLE, &frame->isVisible); _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_VISIBLE); ImGui::SameLine(); - /* Interpolation */ + // Interpolation ImGui::Checkbox(STRING_IMGUI_FRAME_PROPERTIES_INTERPOLATED, &frame->isInterpolated); _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_INTERPOLATED); break; case ANM2_TRIGGERS: - /* Events drop down; pick one! */ + // Events drop down; pick one! for (auto & [id, event] : self->anm2->events) { eventIDs.push_back(id); - eventNames.push_back(event.name); + eventNames.push_back(event.name.c_str()); if (id == frame->eventID) selectedEventIndex = eventIDs.size() - 1; } @@ -1988,7 +2048,7 @@ _imgui_frame_properties(Imgui* self) _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_EVENT); - /* At Frame */ + // At Frame ImGui::InputInt(STRING_IMGUI_FRAME_PROPERTIES_AT_FRAME, &frame->atFrame); _imgui_undoable(self); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_AT_FRAME); @@ -2003,7 +2063,7 @@ _imgui_frame_properties(Imgui* self) ImGui::End(); } - +// Initializes imgui void imgui_init ( @@ -2052,10 +2112,10 @@ imgui_init ImGui::LoadIniSettingsFromDisk(PATH_SETTINGS); - printf(STRING_INFO_IMGUI_INIT); + std::cout << STRING_INFO_IMGUI_INIT << std::endl; } -/* Main dockspace */ +// Main dockspace static void _imgui_dock(Imgui* self) { @@ -2089,6 +2149,7 @@ _imgui_dock(Imgui* self) ImGui::End(); } +// Ticks imgui void imgui_tick(Imgui* self) { @@ -2102,22 +2163,24 @@ imgui_tick(Imgui* self) _imgui_dock(self); } +// Draws imgui void -imgui_draw(Imgui* self) +imgui_draw(void) { ImGui::Render(); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); } +// Frees imgui void -imgui_free(Imgui* self) +imgui_free(void) { ImGui_ImplSDL3_Shutdown(); ImGui_ImplOpenGL3_Shutdown(); - /* Save Ini manually */ + // Save Ini manually ImGui::SaveIniSettingsToDisk(PATH_SETTINGS); ImGui::DestroyContext(); - printf(STRING_INFO_IMGUI_FREE); + std::cout << STRING_INFO_IMGUI_FREE << std::endl; } diff --git a/src/imgui.h b/src/imgui.h index 40f4aea..a14f01a 100644 --- a/src/imgui.h +++ b/src/imgui.h @@ -32,62 +32,63 @@ #define IMGUI_PICKER_LINE_COLOR IM_COL32(255, 255, 255, 255) #define IMGUI_TOOLS_WIDTH_INCREMENT -2 -#define IMGUI_POSITION_STRING_MAX 0xFF +#define VEC2_TO_IMVEC2(value) ImVec2(value.x, value.y) +#define IMVEC2_TO_VEC2(value) glm::vec2(value.x, value.y) +#define IMVEC2_ATLAS_UV_GET(type) VEC2_TO_IMVEC2(ATLAS_UVS[type][0]), VEC2_TO_IMVEC2(ATLAS_UVS[type][1]) -static const vec2 IMGUI_TASKBAR_MARGINS = {8, 4}; -static const vec2 IMGUI_SPRITESHEET_EDITOR_CROP_FORGIVENESS = {1, 1}; +const vec2 IMGUI_TASKBAR_MARGINS = {8, 4}; +const vec2 IMGUI_SPRITESHEET_EDITOR_CROP_FORGIVENESS = {1, 1}; -static const ImVec2 IMGUI_RECORD_TOOLTIP_OFFSET = {16, 16}; -static const ImVec2 IMGUI_ANIMATION_PREVIEW_SETTINGS_SIZE = {1280, 105}; -static const ImVec2 IMGUI_ANIMATION_PREVIEW_SETTINGS_CHILD_SIZE = {200, 85}; -static const ImVec2 IMGUI_ANIMATION_PREVIEW_POSITION = {8, 135}; +const ImVec2 IMGUI_RECORD_TOOLTIP_OFFSET = {16, 16}; +const ImVec2 IMGUI_ANIMATION_PREVIEW_SETTINGS_SIZE = {1280, 105}; +const ImVec2 IMGUI_ANIMATION_PREVIEW_SETTINGS_CHILD_SIZE = {200, 85}; +const ImVec2 IMGUI_ANIMATION_PREVIEW_POSITION = {8, 135}; -static const ImVec2 IMGUI_SPRITESHEET_EDITOR_SETTINGS_CHILD_SIZE = {200, 85}; -static const ImVec2 IMGUI_SPRITESHEET_EDITOR_SETTINGS_SIZE = {1280, 105}; +const ImVec2 IMGUI_SPRITESHEET_EDITOR_SETTINGS_CHILD_SIZE = {200, 85}; +const ImVec2 IMGUI_SPRITESHEET_EDITOR_SETTINGS_SIZE = {1280, 105}; -static const ImVec2 IMGUI_TIMELINE_ELEMENT_LIST_SIZE = {300, 0}; -static const ImVec2 IMGUI_TIMELINE_FRAMES_SIZE = {0, 0}; -static const ImVec2 IMGUI_TIMELINE_ELEMENT_FRAMES_SIZE = {0, 0}; -static const ImVec2 IMGUI_TIMELINE_FRAME_SIZE = {16, 40}; -static const ImVec2 IMGUI_TIMELINE_VIEWER_SIZE = {0, 40}; -static const ImVec2 IMGUI_TIMELINE_ELEMENTS_TIMELINE_SIZE = {0, 40}; -static const ImVec2 IMGUI_TIMELINE_FRAME_INDICES_SIZE = {0, 40}; -static const ImVec2 IMGUI_TIMELINE_ELEMENT_SIZE = {300, 40}; -static const ImVec2 IMGUI_TIMELINE_ELEMENT_NAME_SIZE = {150, 20}; -static const ImVec2 IMGUI_TIMELINE_ELEMENT_SPRITESHEET_ID_SIZE = {60, 20}; +const ImVec2 IMGUI_TIMELINE_ELEMENT_LIST_SIZE = {300, 0}; +const ImVec2 IMGUI_TIMELINE_FRAMES_SIZE = {0, 0}; +const ImVec2 IMGUI_TIMELINE_ELEMENT_FRAMES_SIZE = {0, 0}; +const ImVec2 IMGUI_TIMELINE_FRAME_SIZE = {16, 40}; +const ImVec2 IMGUI_TIMELINE_VIEWER_SIZE = {0, 40}; +const ImVec2 IMGUI_TIMELINE_ELEMENTS_TIMELINE_SIZE = {0, 40}; +const ImVec2 IMGUI_TIMELINE_FRAME_INDICES_SIZE = {0, 40}; +const ImVec2 IMGUI_TIMELINE_ELEMENT_SIZE = {300, 40}; +const ImVec2 IMGUI_TIMELINE_ELEMENT_NAME_SIZE = {150, 20}; +const ImVec2 IMGUI_TIMELINE_ELEMENT_SPRITESHEET_ID_SIZE = {60, 20}; -static const ImVec2 IMGUI_SPRITESHEET_SIZE = {0, 150}; -static const ImVec2 IMGUI_SPRITESHEET_PREVIEW_SIZE = {100, 100}; -static const ImVec2 IMGUI_IMAGE_TARGET_SIZE = {125, 125}; -static const ImVec2 IMGUI_ICON_BUTTON_SIZE = {24, 24}; -static const ImVec2 IMGUI_DUMMY_SIZE = {1, 1}; +const ImVec2 IMGUI_SPRITESHEET_SIZE = {0, 150}; +const ImVec2 IMGUI_SPRITESHEET_PREVIEW_SIZE = {100, 100}; +const ImVec2 IMGUI_IMAGE_TARGET_SIZE = {125, 125}; +const ImVec2 IMGUI_ICON_BUTTON_SIZE = {24, 24}; +const ImVec2 IMGUI_DUMMY_SIZE = {1, 1}; -static const ImVec4 IMGUI_TIMELINE_HEADER_COLOR = {0.04, 0.04, 0.04, 1.0f}; -static const ImVec4 IMGUI_FRAME_BORDER_COLOR = {1.0f, 1.0f, 1.0f, 0.5f}; -static const ImVec4 IMGUI_FRAME_OVERLAY_COLOR = {0.0f, 0.0f, 0.0f, 0.25f}; -static const ImVec4 IMGUI_FRAME_INDICES_OVERLAY_COLOR = {0.113, 0.184, 0.286, 1.0f}; -static const ImVec4 IMGUI_FRAME_INDICES_COLOR = {0.113, 0.184, 0.286, 0.5f}; +const ImVec4 IMGUI_TIMELINE_HEADER_COLOR = {0.04, 0.04, 0.04, 1.0f}; +const ImVec4 IMGUI_FRAME_BORDER_COLOR = {1.0f, 1.0f, 1.0f, 0.5f}; +const ImVec4 IMGUI_FRAME_OVERLAY_COLOR = {0.0f, 0.0f, 0.0f, 0.25f}; +const ImVec4 IMGUI_FRAME_INDICES_OVERLAY_COLOR = {0.113, 0.184, 0.286, 1.0f}; +const ImVec4 IMGUI_FRAME_INDICES_COLOR = {0.113, 0.184, 0.286, 0.5f}; -static const ImVec4 IMGUI_TIMELINE_ROOT_COLOR = {0.010, 0.049, 0.078, 1.0f}; -static const ImVec4 IMGUI_TIMELINE_LAYER_COLOR = {0.098, 0.039, 0.020, 1.0f}; -static const ImVec4 IMGUI_TIMELINE_NULL_COLOR = {0.020, 0.049, 0.000, 1.0f}; -static const ImVec4 IMGUI_TIMELINE_TRIGGERS_COLOR = {0.078, 0.020, 0.029, 1.0f}; +const ImVec4 IMGUI_TIMELINE_ROOT_COLOR = {0.010, 0.049, 0.078, 1.0f}; +const ImVec4 IMGUI_TIMELINE_LAYER_COLOR = {0.098, 0.039, 0.020, 1.0f}; +const ImVec4 IMGUI_TIMELINE_NULL_COLOR = {0.020, 0.049, 0.000, 1.0f}; +const ImVec4 IMGUI_TIMELINE_TRIGGERS_COLOR = {0.078, 0.020, 0.029, 1.0f}; -static const ImVec4 IMGUI_TIMELINE_ROOT_FRAME_COLOR = {0.020, 0.294, 0.569, 0.5}; -static const ImVec4 IMGUI_TIMELINE_LAYER_FRAME_COLOR = {0.529, 0.157, 0.000, 0.5}; -static const ImVec4 IMGUI_TIMELINE_NULL_FRAME_COLOR = {0.137, 0.353, 0.000, 0.5}; -static const ImVec4 IMGUI_TIMELINE_TRIGGERS_FRAME_COLOR = {0.529, 0.118, 0.196, 0.5}; +const ImVec4 IMGUI_TIMELINE_ROOT_FRAME_COLOR = {0.020, 0.294, 0.569, 0.5}; +const ImVec4 IMGUI_TIMELINE_LAYER_FRAME_COLOR = {0.529, 0.157, 0.000, 0.5}; +const ImVec4 IMGUI_TIMELINE_NULL_FRAME_COLOR = {0.137, 0.353, 0.000, 0.5}; +const ImVec4 IMGUI_TIMELINE_TRIGGERS_FRAME_COLOR = {0.529, 0.118, 0.196, 0.5}; -static const ImVec4 IMGUI_TIMELINE_ROOT_HIGHLIGHT_COLOR = {0.314, 0.588, 0.843, 0.75}; -static const ImVec4 IMGUI_TIMELINE_LAYER_HIGHLIGHT_COLOR = {0.882, 0.412, 0.216, 0.75}; -static const ImVec4 IMGUI_TIMELINE_NULL_HIGHLIGHT_COLOR = {0.431, 0.647, 0.294, 0.75}; -static const ImVec4 IMGUI_TIMELINE_TRIGGERS_HIGHLIGHT_COLOR = {0.804, 0.412, 0.490, 0.75}; - -static const ImVec4 IMGUI_TIMELINE_ROOT_ACTIVE_COLOR = {0.471, 0.882, 1.000, 0.75}; -static const ImVec4 IMGUI_TIMELINE_LAYER_ACTIVE_COLOR = {1.000, 0.618, 0.324, 0.75}; -static const ImVec4 IMGUI_TIMELINE_NULL_ACTIVE_COLOR = {0.646, 0.971, 0.441, 0.75}; -static const ImVec4 IMGUI_TIMELINE_TRIGGERS_ACTIVE_COLOR = {1.000, 0.618, 0.735, 0.75}; +const ImVec4 IMGUI_TIMELINE_ROOT_HIGHLIGHT_COLOR = {0.314, 0.588, 0.843, 0.75}; +const ImVec4 IMGUI_TIMELINE_LAYER_HIGHLIGHT_COLOR = {0.882, 0.412, 0.216, 0.75}; +const ImVec4 IMGUI_TIMELINE_NULL_HIGHLIGHT_COLOR = {0.431, 0.647, 0.294, 0.75}; +const ImVec4 IMGUI_TIMELINE_TRIGGERS_HIGHLIGHT_COLOR = {0.804, 0.412, 0.490, 0.75}; +const ImVec4 IMGUI_TIMELINE_ROOT_ACTIVE_COLOR = {0.471, 0.882, 1.000, 0.75}; +const ImVec4 IMGUI_TIMELINE_LAYER_ACTIVE_COLOR = {1.000, 0.618, 0.324, 0.75}; +const ImVec4 IMGUI_TIMELINE_NULL_ACTIVE_COLOR = {0.646, 0.971, 0.441, 0.75}; +const ImVec4 IMGUI_TIMELINE_TRIGGERS_ACTIVE_COLOR = {1.000, 0.618, 0.735, 0.75}; struct Imgui { @@ -128,5 +129,5 @@ imgui_init ); void imgui_tick(Imgui* self); -void imgui_draw(Imgui* self); -void imgui_free(Imgui* self); \ No newline at end of file +void imgui_draw(); +void imgui_free(); \ No newline at end of file diff --git a/src/input.cpp b/src/input.cpp index 598f418..e61a1b9 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -2,81 +2,120 @@ static void _mouse_tick(Mouse* self); +// Ticks mouse static void _mouse_tick(Mouse* self) { s32 state; - memcpy(&self->previous, &self->current, sizeof(bool) * MOUSE_COUNT); - memset(&self->current, '\0', sizeof(bool) * MOUSE_COUNT); + std::memcpy(&self->previous, &self->current, sizeof(self->current)); + std::memset(&self->current, '\0', sizeof(self->current)); state = SDL_GetMouseState(NULL, NULL); - if (state & SDL_BUTTON_LMASK != 0) + if ((state & SDL_BUTTON_LMASK) != 0) { self->current[MOUSE_LEFT] = true; } - if (state & SDL_BUTTON_RMASK != 0) + if ((state & SDL_BUTTON_RMASK) != 0) { self->current[MOUSE_RIGHT] = true; } - SDL_GetMouseState(&self->position.x, &self->position.y); + SDL_GetMouseState(&self->position.x, &self->position.y); self->delta = self->position - self->oldPosition; self->oldPosition = self->position; } +// Ticks keyboard static void _keyboard_tick(Keyboard* self) { const bool* state; - memcpy(&self->previous, &self->current, sizeof(self->previous)); - memset(&self->current, '\0', sizeof(self->current)); + std::memcpy(&self->previous, &self->current, sizeof(self->previous)); + std::memset(&self->current, '\0', sizeof(self->current)); state = SDL_GetKeyboardState(NULL); - memcpy(&self->current, state, KEY_COUNT); + std::memcpy(&self->current, state, KEY_COUNT); } +// Checks to see if the given mouse button has been pressed bool mouse_press(Mouse* self, MouseType type) { return (self->current[type] && !self->previous[type]); } +// Checks to see if the given mouse button is held bool mouse_held(Mouse* self, MouseType type) { return (self->current[type] && self->previous[type]); } +// Checks to see if the given mouse button is released bool mouse_release(Mouse* self, MouseType type) { return (!self->current[type] && self->previous[type]); } +// Checks to see if the given key is pressed bool key_press(Keyboard* self, KeyType type) { return (self->current[type] && !self->previous[type]); } +// Checks to see if the given key is held bool key_held(Keyboard* self, KeyType type) { return (self->current[type] && self->previous[type]); } +// Checks to see if the given key is released bool key_release(Keyboard* self, KeyType type) { return (!self->current[type] && self->previous[type]); } +// Checks to see if the given input is pressed +bool +input_press(Input* self, InputType type) +{ + for (KeyType key : INPUT_KEYS[type]) + if (!key_press(&self->keyboard, (key))) + return false; + return true; +} + +// Checks to see if the given input is held +bool +input_held(Input* self, InputType type) +{ + for (KeyType key : INPUT_KEYS[type]) + if (!key_held(&self->keyboard, (key))) + return false; + return true; +} + +// Checks to see if the given input is held +bool +input_release(Input* self, InputType type) +{ + for (KeyType key : INPUT_KEYS[type]) + if (!key_release(&self->keyboard, (key))) + return false; + return true; +} + +// Ticks input void input_tick(Input* self) { diff --git a/src/input.h b/src/input.h index a9b305e..ef55b90 100644 --- a/src/input.h +++ b/src/input.h @@ -2,272 +2,278 @@ #include "COMMON.h" -#define MOUSE_COUNT (MOUSE_RIGHT + 1) enum MouseType { MOUSE_LEFT, - MOUSE_RIGHT + MOUSE_RIGHT, + MOUSE_COUNT }; -#define KEY_COUNT (255) enum KeyType { - KEY_UNKNOWN = 0, - KEY_UNKNOWN_TWO = 1, - KEY_UNKNOWN_THREE = 2, - KEY_UNKNOWN_FOUR = 3, - KEY_A = 4, - KEY_B = 5, - KEY_C = 6, - KEY_D = 7, - KEY_E = 8, - KEY_F = 9, - KEY_G = 10, - KEY_H = 11, - KEY_I = 12, - KEY_J = 13, - KEY_K = 14, - KEY_L = 15, - KEY_M = 16, - KEY_N = 17, - KEY_O = 18, - KEY_P = 19, - KEY_Q = 20, - KEY_R = 21, - KEY_S = 22, - KEY_T = 23, - KEY_U = 24, - KEY_V = 25, - KEY_W = 26, - KEY_X = 27, - KEY_Y = 28, - KEY_Z = 29, - KEY_1 = 30, - KEY_2 = 31, - KEY_3 = 32, - KEY_4 = 33, - KEY_5 = 34, - KEY_6 = 35, - KEY_7 = 36, - KEY_8 = 37, - KEY_9 = 38, - KEY_0 = 39, - KEY_RETURN = 40, - KEY_ESCAPE = 41, - KEY_BACKSPACE = 42, - KEY_TAB = 43, - KEY_SPACE = 44, - KEY_MINUS = 45, - KEY_EQUALS = 46, - KEY_LEFTBRACKET = 47, - KEY_RIGHTBRACKET = 48, - KEY_BACKSLASH = 49, - KEY_NONUSHASH = 50, - KEY_SEMICOLON = 51, - KEY_APOSTROPHE = 52, - KEY_GRAVE = 53, - KEY_COMMA = 54, - KEY_PERIOD = 55, - KEY_SLASH = 56, - KEY_CAPSLOCK = 57, - KEY_F1 = 58, - KEY_F2 = 59, - KEY_F3 = 60, - KEY_F4 = 61, - KEY_F5 = 62, - KEY_F6 = 63, - KEY_F7 = 64, - KEY_F8 = 65, - KEY_F9 = 66, - KEY_F10 = 67, - KEY_F11 = 68, - KEY_F12 = 69, - KEY_PRINTSCREEN = 70, - KEY_SCROLLLOCK = 71, - KEY_PAUSE = 72, - KEY_INSERT = 73, - KEY_HOME = 74, - KEY_PAGEUP = 75, - KEY_DELETE = 76, - KEY_END = 77, - KEY_PAGEDOWN = 78, - KEY_RIGHT = 79, - KEY_LEFT = 80, - KEY_DOWN = 81, - KEY_UP = 82, - KEY_NUMLOCKCLEAR = 83, - KEY_KP_DIVIDE = 84, - KEY_KP_MULTIPLY = 85, - KEY_KP_MINUS = 86, - KEY_KP_PLUS = 87, - KEY_KP_ENTER = 88, - KEY_KP_1 = 89, - KEY_KP_2 = 90, - KEY_KP_3 = 91, - KEY_KP_4 = 92, - KEY_KP_5 = 93, - KEY_KP_6 = 94, - KEY_KP_7 = 95, - KEY_KP_8 = 96, - KEY_KP_9 = 97, - KEY_KP_0 = 98, - KEY_KP_PERIOD = 99, - KEY_NONUSBACKSLASH = 100, - KEY_APPLICATION = 101, - KEY_POWER = 102, - KEY_KP_EQUALS = 103, - KEY_F13 = 104, - KEY_F14 = 105, - KEY_F15 = 106, - KEY_F16 = 107, - KEY_F17 = 108, - KEY_F18 = 109, - KEY_F19 = 110, - KEY_F20 = 111, - KEY_F21 = 112, - KEY_F22 = 113, - KEY_F23 = 114, - KEY_F24 = 115, - KEY_EXECUTE = 116, - KEY_HELP = 117, - KEY_MENU = 118, - KEY_SELECT = 119, - KEY_STOP = 120, - KEY_AGAIN = 121, - KEY_UNDO = 122, - KEY_CUT = 123, - KEY_COPY = 124, - KEY_PASTE = 125, - KEY_FIND = 126, - KEY_MUTE = 127, - KEY_VOLUMEUP = 128, - KEY_VOLUMEDOWN = 129, - KEY_LOCKINGCAPSLOCK = 130, - KEY_LOCKINGNUMLOCK = 131, - KEY_LOCKINGSCROLLLOCK = 132, - KEY_KP_COMMA = 133, - KEY_KP_EQUALSAS400 = 134, - KEY_INTERNATIONAL1 = 135, - KEY_INTERNATIONAL2 = 136, - KEY_INTERNATIONAL3 = 137, - KEY_INTERNATIONAL4 = 138, - KEY_INTERNATIONAL5 = 139, - KEY_INTERNATIONAL6 = 140, - KEY_INTERNATIONAL7 = 141, - KEY_INTERNATIONAL8 = 142, - KEY_INTERNATIONAL9 = 143, - KEY_LANG1 = 144, - KEY_LANG2 = 145, - KEY_LANG3 = 146, - KEY_LANG4 = 147, - KEY_LANG5 = 148, - KEY_LANG6 = 149, - KEY_LANG7 = 150, - KEY_LANG8 = 151, - KEY_LANG9 = 152, - KEY_ALTERASE = 153, - KEY_SYSREQ = 154, - KEY_CANCEL = 155, - KEY_CLEAR = 156, - KEY_PRIOR = 157, - KEY_RETURN2 = 158, - KEY_SEPARATOR = 159, - KEY_OUT = 160, - KEY_OPER = 161, - KEY_CLEARAGAIN = 162, - KEY_CRSEL = 163, - KEY_EXSEL = 164, - KEY_KP_00 = 176, - KEY_KP_000 = 177, - KEY_THOUSANDSSEPARATOR = 178, - KEY_DECIMALSEPARATOR = 179, - KEY_CURRENCYUNIT = 180, - KEY_CURRENCYSUBUNIT = 181, - KEY_KP_LEFTPAREN = 182, - KEY_KP_RIGHTPAREN = 183, - KEY_KP_LEFTBRACE = 184, - KEY_KP_RIGHTBRACE = 185, - KEY_KP_TAB = 186, - KEY_KP_BACKSPACE = 187, - KEY_KP_A = 188, - KEY_KP_B = 189, - KEY_KP_C = 190, - KEY_KP_D = 191, - KEY_KP_E = 192, - KEY_KP_F = 193, - KEY_KP_XOR = 194, - KEY_KP_POWER = 195, - KEY_KP_PERCENT = 196, - KEY_KP_LESS = 197, - KEY_KP_GREATER = 198, - KEY_KP_AMPERSAND = 199, - KEY_KP_DBLAMPERSAND = 200, - KEY_KP_VERTICALBAR = 201, - KEY_KP_DBLVERTICALBAR = 202, - KEY_KP_COLON = 203, - KEY_KP_HASH = 204, - KEY_KP_SPACE = 205, - KEY_KP_AT = 206, - KEY_KP_EXCLAM = 207, - KEY_KP_MEMSTORE = 208, - KEY_KP_MEMRECALL = 209, - KEY_KP_MEMCLEAR = 210, - KEY_KP_MEMADD = 211, - KEY_KP_MEMSUBTRACT = 212, - KEY_KP_MEMMULTIPLY = 213, - KEY_KP_MEMDIVIDE = 214, - KEY_KP_PLUSMINUS = 215, - KEY_KP_CLEAR = 216, - KEY_KP_CLEARENTRY = 217, - KEY_KP_BINARY = 218, - KEY_KP_OCTAL = 219, - KEY_KP_DECIMAL = 220, - KEY_KP_HEXADECIMAL = 221, - KEY_LCTRL = 224, - KEY_LSHIFT = 225, - KEY_LALT = 226, - KEY_LGUI = 227, - KEY_RCTRL = 228, - KEY_RSHIFT = 229, - KEY_RALT = 230, - KEY_RGUI = 231 + KEY_UNKNOWN = 0, + KEY_UNKNOWN_TWO = 1, + KEY_UNKNOWN_THREE = 2, + KEY_UNKNOWN_FOUR = 3, + KEY_A = 4, + KEY_B = 5, + KEY_C = 6, + KEY_D = 7, + KEY_E = 8, + KEY_F = 9, + KEY_G = 10, + KEY_H = 11, + KEY_I = 12, + KEY_J = 13, + KEY_K = 14, + KEY_L = 15, + KEY_M = 16, + KEY_N = 17, + KEY_O = 18, + KEY_P = 19, + KEY_Q = 20, + KEY_R = 21, + KEY_S = 22, + KEY_T = 23, + KEY_U = 24, + KEY_V = 25, + KEY_W = 26, + KEY_X = 27, + KEY_Y = 28, + KEY_Z = 29, + KEY_1 = 30, + KEY_2 = 31, + KEY_3 = 32, + KEY_4 = 33, + KEY_5 = 34, + KEY_6 = 35, + KEY_7 = 36, + KEY_8 = 37, + KEY_9 = 38, + KEY_0 = 39, + KEY_RETURN = 40, + KEY_ESCAPE = 41, + KEY_BACKSPACE = 42, + KEY_TAB = 43, + KEY_SPACE = 44, + KEY_MINUS = 45, + KEY_EQUALS = 46, + KEY_LEFTBRACKET = 47, + KEY_RIGHTBRACKET = 48, + KEY_BACKSLASH = 49, + KEY_NONUSHASH = 50, + KEY_SEMICOLON = 51, + KEY_APOSTROPHE = 52, + KEY_GRAVE = 53, + KEY_COMMA = 54, + KEY_PERIOD = 55, + KEY_SLASH = 56, + KEY_CAPSLOCK = 57, + KEY_F1 = 58, + KEY_F2 = 59, + KEY_F3 = 60, + KEY_F4 = 61, + KEY_F5 = 62, + KEY_F6 = 63, + KEY_F7 = 64, + KEY_F8 = 65, + KEY_F9 = 66, + KEY_F10 = 67, + KEY_F11 = 68, + KEY_F12 = 69, + KEY_PRINTSCREEN = 70, + KEY_SCROLLLOCK = 71, + KEY_PAUSE = 72, + KEY_INSERT = 73, + KEY_HOME = 74, + KEY_PAGEUP = 75, + KEY_DELETE = 76, + KEY_END = 77, + KEY_PAGEDOWN = 78, + KEY_RIGHT = 79, + KEY_LEFT = 80, + KEY_DOWN = 81, + KEY_UP = 82, + KEY_NUMLOCKCLEAR = 83, + KEY_KP_DIVIDE = 84, + KEY_KP_MULTIPLY = 85, + KEY_KP_MINUS = 86, + KEY_KP_PLUS = 87, + KEY_KP_ENTER = 88, + KEY_KP_1 = 89, + KEY_KP_2 = 90, + KEY_KP_3 = 91, + KEY_KP_4 = 92, + KEY_KP_5 = 93, + KEY_KP_6 = 94, + KEY_KP_7 = 95, + KEY_KP_8 = 96, + KEY_KP_9 = 97, + KEY_KP_0 = 98, + KEY_KP_PERIOD = 99, + KEY_NONUSBACKSLASH = 100, + KEY_APPLICATION = 101, + KEY_POWER = 102, + KEY_KP_EQUALS = 103, + KEY_F13 = 104, + KEY_F14 = 105, + KEY_F15 = 106, + KEY_F16 = 107, + KEY_F17 = 108, + KEY_F18 = 109, + KEY_F19 = 110, + KEY_F20 = 111, + KEY_F21 = 112, + KEY_F22 = 113, + KEY_F23 = 114, + KEY_F24 = 115, + KEY_EXECUTE = 116, + KEY_HELP = 117, + KEY_MENU = 118, + KEY_SELECT = 119, + KEY_STOP = 120, + KEY_AGAIN = 121, + KEY_UNDO = 122, + KEY_CUT = 123, + KEY_COPY = 124, + KEY_PASTE = 125, + KEY_FIND = 126, + KEY_MUTE = 127, + KEY_VOLUMEUP = 128, + KEY_VOLUMEDOWN = 129, + KEY_LOCKINGCAPSLOCK = 130, + KEY_LOCKINGNUMLOCK = 131, + KEY_LOCKINGSCROLLLOCK = 132, + KEY_KP_COMMA = 133, + KEY_KP_EQUALSAS400 = 134, + KEY_INTERNATIONAL1 = 135, + KEY_INTERNATIONAL2 = 136, + KEY_INTERNATIONAL3 = 137, + KEY_INTERNATIONAL4 = 138, + KEY_INTERNATIONAL5 = 139, + KEY_INTERNATIONAL6 = 140, + KEY_INTERNATIONAL7 = 141, + KEY_INTERNATIONAL8 = 142, + KEY_INTERNATIONAL9 = 143, + KEY_LANG1 = 144, + KEY_LANG2 = 145, + KEY_LANG3 = 146, + KEY_LANG4 = 147, + KEY_LANG5 = 148, + KEY_LANG6 = 149, + KEY_LANG7 = 150, + KEY_LANG8 = 151, + KEY_LANG9 = 152, + KEY_ALTERASE = 153, + KEY_SYSREQ = 154, + KEY_CANCEL = 155, + KEY_CLEAR = 156, + KEY_PRIOR = 157, + KEY_RETURN2 = 158, + KEY_SEPARATOR = 159, + KEY_OUT = 160, + KEY_OPER = 161, + KEY_CLEARAGAIN = 162, + KEY_CRSEL = 163, + KEY_EXSEL = 164, + KEY_KP_00 = 176, + KEY_KP_000 = 177, + KEY_THOUSANDSSEPARATOR = 178, + KEY_DECIMALSEPARATOR = 179, + KEY_CURRENCYUNIT = 180, + KEY_CURRENCYSUBUNIT = 181, + KEY_KP_LEFTPAREN = 182, + KEY_KP_RIGHTPAREN = 183, + KEY_KP_LEFTBRACE = 184, + KEY_KP_RIGHTBRACE = 185, + KEY_KP_TAB = 186, + KEY_KP_BACKSPACE = 187, + KEY_KP_A = 188, + KEY_KP_B = 189, + KEY_KP_C = 190, + KEY_KP_D = 191, + KEY_KP_E = 192, + KEY_KP_F = 193, + KEY_KP_XOR = 194, + KEY_KP_POWER = 195, + KEY_KP_PERCENT = 196, + KEY_KP_LESS = 197, + KEY_KP_GREATER = 198, + KEY_KP_AMPERSAND = 199, + KEY_KP_DBLAMPERSAND = 200, + KEY_KP_VERTICALBAR = 201, + KEY_KP_DBLVERTICALBAR = 202, + KEY_KP_COLON = 203, + KEY_KP_HASH = 204, + KEY_KP_SPACE = 205, + KEY_KP_AT = 206, + KEY_KP_EXCLAM = 207, + KEY_KP_MEMSTORE = 208, + KEY_KP_MEMRECALL = 209, + KEY_KP_MEMCLEAR = 210, + KEY_KP_MEMADD = 211, + KEY_KP_MEMSUBTRACT = 212, + KEY_KP_MEMMULTIPLY = 213, + KEY_KP_MEMDIVIDE = 214, + KEY_KP_PLUSMINUS = 215, + KEY_KP_CLEAR = 216, + KEY_KP_CLEARENTRY = 217, + KEY_KP_BINARY = 218, + KEY_KP_OCTAL = 219, + KEY_KP_DECIMAL = 220, + KEY_KP_HEXADECIMAL = 221, + KEY_LCTRL = 224, + KEY_LSHIFT = 225, + KEY_LALT = 226, + KEY_LGUI = 227, + KEY_RCTRL = 228, + KEY_RSHIFT = 229, + KEY_RALT = 230, + KEY_RGUI = 231, + KEY_COUNT = 255 }; -#define INPUT_COUNT (INPUT_REDO + 1) enum InputType { + INPUT_MOD, + INPUT_DELETE, + INPUT_PLAY, INPUT_PAN, INPUT_MOVE, + INPUT_ROTATE, INPUT_SCALE, INPUT_CROP, INPUT_LEFT, INPUT_RIGHT, INPUT_UP, INPUT_DOWN, - INPUT_ROTATE_LEFT, - INPUT_ROTATE_RIGHT, INPUT_ZOOM_IN, INPUT_ZOOM_OUT, INPUT_UNDO, - INPUT_REDO + INPUT_REDO, + INPUT_SAVE, + INPUT_COUNT }; -static const KeyType INPUT_KEYS[INPUT_COUNT] +const std::vector INPUT_KEYS[INPUT_COUNT] = { - KEY_SPACE, - KEY_T, - KEY_S, - KEY_C, - KEY_LEFT, - KEY_RIGHT, - KEY_UP, - KEY_DOWN, - KEY_Q, - KEY_W, - KEY_1, - KEY_2, - KEY_Z, - KEY_Y + { KEY_LSHIFT }, + { KEY_DELETE }, + { KEY_SPACE }, + { KEY_P }, + { KEY_M }, + { KEY_R }, + { KEY_S }, + { KEY_C }, + { KEY_LEFT }, + { KEY_RIGHT }, + { KEY_UP }, + { KEY_DOWN }, + { KEY_1 }, + { KEY_2 }, + { KEY_Z }, + { KEY_Y }, + { KEY_LCTRL } }; struct Keyboard @@ -298,4 +304,7 @@ bool mouse_release(Mouse* self, MouseType type); bool key_press(Keyboard* self, KeyType type); bool key_held(Keyboard* self, KeyType type); bool key_release(Keyboard* self, KeyType type); +bool input_press(Input* self, InputType type); +bool input_held(Input* self, InputType type); +bool input_release(Input* self, InputType type); void input_tick(Input* self); \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index d26f19b..70699bf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,10 +5,10 @@ main(s32 argc, char* argv[]) { State state; - /* If anm2 given on command line, set state argument to that (will be loaded) */ + // If anm2 given on command line, set state argument to that (will be loaded) if (argc > 0 && argv[1]) { - strncpy(state.argument, argv[1], PATH_MAX - 1); + state.argument = argv[1]; state.isArgument = true; } diff --git a/src/preview.cpp b/src/preview.cpp index 75f41fb..49a3cd8 100644 --- a/src/preview.cpp +++ b/src/preview.cpp @@ -3,6 +3,7 @@ static void _preview_axis_set(Preview* self); static s32 _preview_grid_set(Preview* self); +// Sets the preview's axis (lines across x/y) static void _preview_axis_set(Preview* self) { @@ -16,7 +17,7 @@ _preview_axis_set(Preview* self) glBindVertexArray(0); } -/* Sets and returns the grid's vertices */ +// Sets and returns the grid's vertices static s32 _preview_grid_set(Preview* self) { @@ -59,6 +60,7 @@ _preview_grid_set(Preview* self) return (s32)vertices.size(); } +// Initializes preview void preview_init(Preview* self, Anm2* anm2, Anm2Reference* reference, f32* time, Resources* resources, Settings* settings) { @@ -68,7 +70,7 @@ preview_init(Preview* self, Anm2* anm2, Anm2Reference* reference, f32* time, Res self->resources = resources; self->settings = settings; - /* Framebuffer + texture */ + // Framebuffer + texture glGenFramebuffers(1, &self->fbo); glBindFramebuffer(GL_FRAMEBUFFER, self->fbo); @@ -88,15 +90,15 @@ preview_init(Preview* self, Anm2* anm2, Anm2Reference* reference, f32* time, Res glBindFramebuffer(GL_FRAMEBUFFER, 0); - /* Axis */ + // Axis glGenVertexArrays(1, &self->axisVAO); glGenBuffers(1, &self->axisVBO); - /* Grid */ + // Grid glGenVertexArrays(1, &self->gridVAO); glGenBuffers(1, &self->gridVBO); - /* Rect */ + // Rect glGenVertexArrays(1, &self->rectVAO); glGenBuffers(1, &self->rectVBO); @@ -108,7 +110,7 @@ preview_init(Preview* self, Anm2* anm2, Anm2Reference* reference, f32* time, Res glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(f32), (void*)0); - /* Texture */ + // Texture glGenVertexArrays(1, &self->textureVAO); glGenBuffers(1, &self->textureVBO); glGenBuffers(1, &self->textureEBO); @@ -121,11 +123,11 @@ preview_init(Preview* self, Anm2* anm2, Anm2Reference* reference, f32* time, Res glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self->textureEBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GL_TEXTURE_INDICES), GL_TEXTURE_INDICES, GL_STATIC_DRAW); - /* Position */ + // Position attribute glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(f32), (void*)0); - /* UV */ + // UV attribute glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(f32), (void*)(2 * sizeof(f32))); @@ -135,6 +137,7 @@ preview_init(Preview* self, Anm2* anm2, Anm2Reference* reference, f32* time, Res _preview_grid_set(self); } +// Ticks preview void preview_tick(Preview* self) { @@ -142,12 +145,14 @@ preview_tick(Preview* self) Anm2Animation* animation = anm2_animation_from_reference(self->anm2, self->reference); + // If animation is valid, manage playback if (animation) { if (self->isPlaying) { *self->time += (f32)self->anm2->fps / TICK_RATE; + // If looping, return back to 0; if not, stop at length if (*self->time >= (f32)animation->frameNum - 1) { if (self->settings->playbackIsLoop && !self->isRecording) @@ -157,11 +162,13 @@ preview_tick(Preview* self) } } + // Make sure to clamp time within appropriate range if (!self->isPlaying) *self->time = CLAMP(*self->time, 0.0f, (f32)animation->frameNum - 1); } } +// Draws preview void preview_draw(Preview* self) { @@ -171,7 +178,7 @@ preview_draw(Preview* self) static f32 recordFrameTimeNext = 0.0f; static s32 recordFrameIndex = 0; - f32 zoomFactor = self->settings->previewZoom / 100.0f; + f32 zoomFactor = PERCENT_TO_UNIT(self->settings->previewZoom); glm::vec2 ndcPan = glm::vec2(-self->settings->previewPanX / (PREVIEW_SIZE.x / 2.0f), -self->settings->previewPanY / (PREVIEW_SIZE.y / 2.0f)); glm::mat4 previewTransform = glm::translate(glm::mat4(1.0f), glm::vec3(ndcPan, 0.0f)); previewTransform = glm::scale(previewTransform, glm::vec3(zoomFactor, zoomFactor, 1.0f)); @@ -188,7 +195,7 @@ preview_draw(Preview* self) ); glClear(GL_COLOR_BUFFER_BIT); - /* Grid */ + // Grid if (self->settings->previewIsGrid) { static ivec2 previousGridSize = {-1, -1}; @@ -220,7 +227,7 @@ preview_draw(Preview* self) glUseProgram(0); } - /* Axes */ + // Axes if (self->settings->previewIsAxis) { glUseProgram(shaderLine); @@ -249,21 +256,22 @@ preview_draw(Preview* self) } Anm2Animation* animation = anm2_animation_from_reference(self->anm2, self->reference); - - /* Animation */ + s32& animationID = self->reference->animationID; + + // Animation if (animation) { Anm2Frame rootFrame; Anm2Frame frame; - anm2_frame_from_time(self->anm2, &rootFrame, Anm2Reference{ANM2_ROOT, self->reference->animationID, 0, 0}, *self->time); + anm2_frame_from_time(self->anm2, &rootFrame, Anm2Reference{animationID, ANM2_ROOT, 0, 0}, *self->time); - /* Layers */ + // Layers for (auto & [id, layerAnimation] : animation->layerAnimations) { if (!layerAnimation.isVisible || layerAnimation.frames.size() <= 0) continue; - anm2_frame_from_time(self->anm2, &frame, Anm2Reference{ANM2_LAYER, self->reference->animationID, id, 0}, *self->time); + anm2_frame_from_time(self->anm2, &frame, Anm2Reference{animationID, ANM2_LAYER, id, 0}, *self->time); if (!frame.isVisible) continue; @@ -275,8 +283,12 @@ preview_draw(Preview* self) glm::mat4 layerTransform = previewTransform; - glm::vec2 position = self->settings->previewIsRootTransform ? (frame.position + rootFrame.position) : frame.position; - glm::vec2 scale = frame.scale / 100.0f; + glm::vec2 position = self->settings->previewIsRootTransform ? + (frame.position + rootFrame.position) : frame.position; + + glm::vec2 scale = self->settings->previewIsRootTransform ? + PERCENT_TO_UNIT(frame.scale) * PERCENT_TO_UNIT(rootFrame.scale) : PERCENT_TO_UNIT(frame.scale); + glm::vec2 ndcPos = position / (PREVIEW_SIZE / 2.0f); glm::vec2 ndcPivotOffset = (frame.pivot * scale) / (PREVIEW_SIZE / 2.0f); glm::vec2 ndcScale = (frame.size * scale) / (PREVIEW_SIZE / 2.0f); @@ -316,6 +328,7 @@ preview_draw(Preview* self) glUseProgram(0); } + // Root target if (animation->rootAnimation.isVisible && rootFrame.isVisible) { glm::mat4 rootTransform = previewTransform; @@ -350,25 +363,29 @@ preview_draw(Preview* self) glUseProgram(0); } - /* Pivots */ + // Layer pivots if (self->settings->previewIsShowPivot) { - /* Layers (Reversed) */ + // Layers (Reversed) for (auto & [id, layerAnimation] : animation->layerAnimations) { if (!layerAnimation.isVisible || layerAnimation.frames.size() <= 0) continue; - anm2_frame_from_time(self->anm2, &frame, Anm2Reference{ANM2_LAYER, self->reference->animationID, id, 0}, *self->time); + anm2_frame_from_time(self->anm2, &frame, Anm2Reference{animationID, ANM2_LAYER, id, 0}, *self->time); if (!frame.isVisible) continue; glm::mat4 pivotTransform = previewTransform; - glm::vec2 position = self->settings->previewIsRootTransform ? (frame.position + rootFrame.position) : frame.position; + glm::vec2 position = self->settings->previewIsRootTransform + ? (frame.position + rootFrame.position) : frame.position; - glm::vec2 ndcPos = position /(PREVIEW_SIZE / 2.0f); + glm::vec2 scale = self->settings->previewIsRootTransform ? + PERCENT_TO_UNIT(frame.scale) * PERCENT_TO_UNIT(rootFrame.scale) : PERCENT_TO_UNIT(frame.scale); + + glm::vec2 ndcPos = (position - (PREVIEW_PIVOT_SIZE / 2.0f)) / (PREVIEW_SIZE / 2.0f); glm::vec2 ndcScale = PREVIEW_PIVOT_SIZE / (PREVIEW_SIZE / 2.0f); pivotTransform = glm::translate(pivotTransform, glm::vec3(ndcPos, 0.0f)); @@ -400,13 +417,13 @@ preview_draw(Preview* self) } } - /* Nulls */ + // Null target/rect for (auto & [id, nullAnimation] : animation->nullAnimations) { if (!nullAnimation.isVisible || nullAnimation.frames.size() <= 0) continue; - anm2_frame_from_time(self->anm2, &frame, Anm2Reference{ANM2_NULL, id, 0}, *self->time); + anm2_frame_from_time(self->anm2, &frame, Anm2Reference{animationID, ANM2_NULL, id, 0}, *self->time); if (!frame.isVisible) continue; @@ -449,6 +466,7 @@ preview_draw(Preview* self) glBindBuffer(GL_ARRAY_BUFFER, 0); glUseProgram(0); + // Null rect if (null->isShowRect) { glm::mat4 rectTransform = previewTransform; @@ -476,10 +494,12 @@ preview_draw(Preview* self) } } + // Manage recording if (self->isRecording && animation) { if (recordFrameIndex == 0) { + // Create frames directory, if it exists if ( std::filesystem::exists(STRING_PREVIEW_FRAMES_DIRECTORY) && @@ -496,18 +516,16 @@ preview_draw(Preview* self) if (isRecordThisFrame) { size_t frameSize = (self->recordSize.x * self->recordSize.y * 4); - u8* frame = (u8*)malloc(frameSize); - memset(frame, '\0',frameSize); - char path[PATH_MAX]; + u8* frame = (u8*)calloc(frameSize, 1); + std:: string path; + vec2 position = { self->settings->previewPanX - (PREVIEW_SIZE.x / 2.0f) + (self->recordSize.x / 2.0f), self->settings->previewPanY - (PREVIEW_SIZE.y / 2.0f) + (self->recordSize.y / 2.0f) }; - memset(path, '\0', PATH_MAX); - - snprintf(path, PATH_MAX, STRING_PREVIEW_FRAMES_FORMAT, STRING_PREVIEW_FRAMES_DIRECTORY, recordFrameIndex); + path = std::format(STRING_PREVIEW_FRAMES_FORMAT, STRING_PREVIEW_FRAMES_DIRECTORY, recordFrameIndex); glReadBuffer(GL_FRONT); glReadPixels diff --git a/src/preview.h b/src/preview.h index d10ed58..717e37d 100644 --- a/src/preview.h +++ b/src/preview.h @@ -5,8 +5,9 @@ #include "input.h" #include "settings.h" -static const vec2 PREVIEW_SIZE = {5000, 5000}; -static const vec2 PREVIEW_CENTER = {0, 0}; +const vec2 PREVIEW_SIZE = {5000, 5000}; +const vec2 PREVIEW_CENTER = {0, 0}; + #define PREVIEW_ZOOM_MIN 1 #define PREVIEW_ZOOM_MAX 1000 @@ -16,10 +17,13 @@ static const vec2 PREVIEW_CENTER = {0, 0}; #define PREVIEW_GRID_OFFSET_MIN 0 #define PREVIEW_GRID_OFFSET_MAX 100 #define PREVIEW_MOVE_STEP 1 +#define PREVIEW_MOVE_STEP_MOD 10 #define PREVIEW_ROTATE_STEP 1 +#define PREVIEW_ROTATE_STEP_MOD 10 #define PREVIEW_SCALE_STEP 1 +#define PREVIEW_SCALE_STEP_MOD 10 -static const f32 PREVIEW_AXIS_VERTICES[] = +const f32 PREVIEW_AXIS_VERTICES[] = { -1.0f, 0.0f, 1.0f, 0.0f, @@ -27,13 +31,13 @@ static const f32 PREVIEW_AXIS_VERTICES[] = 0.0f, 1.0f }; -static const vec2 PREVIEW_NULL_RECT_SIZE = {100, 100}; -static const vec2 PREVIEW_POINT_SIZE = {2, 2}; -static const vec2 PREVIEW_PIVOT_SIZE = {4, 4}; -static const vec4 PREVIEW_ROOT_TINT = COLOR_GREEN; -static const vec4 PREVIEW_NULL_TINT = COLOR_BLUE; -static const vec4 PREVIEW_PIVOT_TINT = COLOR_RED; -static const vec2 PREVIEW_TARGET_SIZE = {16, 16}; +const vec2 PREVIEW_NULL_RECT_SIZE = {100, 100}; +const vec2 PREVIEW_POINT_SIZE = {2, 2}; +const vec2 PREVIEW_PIVOT_SIZE = {4, 4}; +const vec4 PREVIEW_ROOT_TINT = COLOR_GREEN; +const vec4 PREVIEW_NULL_TINT = COLOR_BLUE; +const vec4 PREVIEW_PIVOT_TINT = COLOR_RED; +const vec2 PREVIEW_TARGET_SIZE = {16, 16}; struct Preview { diff --git a/src/resources.cpp b/src/resources.cpp index 766e4ef..cfb925d 100644 --- a/src/resources.cpp +++ b/src/resources.cpp @@ -1,6 +1,23 @@ #include "resources.h" -/* Loads in resources */ +// Loads a texture, given a path and an id for it to be assigned to +void +resources_texture_init(Resources* resources, const std::string& path, s32 id) +{ + Texture texture; + + if (resources->textures.find(id) != resources->textures.end() && resources->textures[id].id != resources->textures[TEXTURE_ERROR].id) + texture_free(&resources->textures[id]); + + if (texture_from_path_init(&texture, path)) + resources->textures[id] = texture; + else + texture.isInvalid = true; + + resources->textures[id] = texture; +} + +// Loads in resources void resources_init(Resources* self) { @@ -10,7 +27,7 @@ resources_init(Resources* self) shader_init(&self->shaders[i], SHADER_DATA[i].vertex, SHADER_DATA[i].fragment); } -/* Frees resources*/ +// Frees resources void resources_free(Resources* self) { @@ -22,7 +39,7 @@ resources_free(Resources* self) texture_free(&self->atlas); } -/* Frees loaded textures */ +// Frees loaded textures void resources_textures_free(Resources* self) { diff --git a/src/resources.h b/src/resources.h index 363eb2c..79335d9 100644 --- a/src/resources.h +++ b/src/resources.h @@ -12,5 +12,6 @@ struct Resources }; void resources_init(Resources* self); +void resources_texture_init(Resources* resources, const std::string& path, s32 id); void resources_free(Resources* self); void resources_textures_free(Resources* self); diff --git a/src/settings.cpp b/src/settings.cpp index c82eb3c..d171cc4 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1,31 +1,36 @@ #include "settings.h" -static void _settings_setting_load(Settings* self, char* line); -static void _settings_setting_write(Settings* self, SDL_IOStream* io, SettingsItem type); +static void _settings_setting_load(Settings* self, const std::string& line); +static void _settings_setting_write(Settings* self, std::ostream& out, SettingsEntry entry); -/* Load a particular settings from a line */ -static void -_settings_setting_load(Settings* self, char* line) +static void +_settings_setting_load(Settings* self, const std::string& line) { - for (int i = 0; i < SETTINGS_COUNT; i++) + for (s32 i = 0; i < SETTINGS_COUNT; i++) { - if (strncmp(line, SETTINGS_ENTRIES[i].value, strlen(SETTINGS_ENTRIES[i].value)) == 0) + const std::string& key = SETTINGS_ENTRIES[i].key; + size_t keyLength = key.length(); + + // Compare keys + if (line.compare(0, keyLength, key) == 0) { - char* value = line + strlen(SETTINGS_ENTRIES[i].value); + const char* value = line.c_str() + keyLength; void* target = (u8*)self + SETTINGS_ENTRIES[i].offset; + // Based on type, assign value to offset of settings switch (SETTINGS_ENTRIES[i].type) { case SETTINGS_TYPE_INT: + *(s32*)target = std::atoi(value); + break; case SETTINGS_TYPE_BOOL: - *(s32*)target = atoi(value); + *(s32*)target = string_to_bool(std::string(value)); break; case SETTINGS_TYPE_FLOAT: - *(f32*)target = atof(value); + *(f32*)target = std::atof(value); break; case SETTINGS_TYPE_STRING: - strncpy((char*)target, value, SETTINGS_BUFFER_ITEM - 1); - ((char*)target)[SETTINGS_BUFFER_ITEM - 1] = '\0'; + *(std::string*)target = std::string(value); break; default: break; @@ -35,126 +40,100 @@ _settings_setting_load(Settings* self, char* line) } } -/* Writes a particular setting to the current IO */ -static void -_settings_setting_write(Settings* self, SDL_IOStream* io, SettingsItem type) +// Writes a given setting to the stream +static void +_settings_setting_write(Settings* self, std::ostream& out, SettingsEntry entry) { - char valueBuffer[SETTINGS_BUFFER_ITEM]; - SettingsEntry entry = SETTINGS_ENTRIES[type]; - u8* selfPointer = (u8*)self; - - memset(valueBuffer, '\0', sizeof(valueBuffer)); + std::string value; switch (entry.type) { case SETTINGS_TYPE_INT: - snprintf(valueBuffer, SETTINGS_BUFFER_ITEM, entry.format, *(s32*)(selfPointer + entry.offset)); + value = std::format("{}", *(s32*)(selfPointer + entry.offset)); break; case SETTINGS_TYPE_BOOL: - snprintf(valueBuffer, SETTINGS_BUFFER_ITEM, entry.format, *(bool*)(selfPointer + entry.offset)); + value = std::format("{}", *(bool*)(selfPointer + entry.offset)); break; - case SETTINGS_TYPE_FLOAT: - snprintf(valueBuffer, SETTINGS_BUFFER_ITEM, entry.format, *(f32*)(selfPointer + entry.offset)); + case SETTINGS_TYPE_FLOAT: + value = std::format("{:.3f}", *(f32*)(selfPointer + entry.offset)); break; case SETTINGS_TYPE_STRING: - snprintf(valueBuffer, SETTINGS_BUFFER_ITEM, entry.value, entry.format, *(char*)(selfPointer + entry.offset)); + value = *(std::string*)(selfPointer + entry.offset); break; default: break; } - SDL_WriteIO(io, valueBuffer, strlen(valueBuffer)); - SDL_WriteIO(io, "\n", strlen("\n")); + out << entry.key << value << "\n"; } -/* Saves the program's settings to the PATH_SETTINGS file */ -void +// Saves the current settings +// Note: this is just for this program's settings, additional imgui settings handled elsewhere +void settings_save(Settings* self) { - char buffer[SETTINGS_BUFFER]; + std::ifstream input(PATH_SETTINGS); + std::string oldContents; - /* Get the original settings.ini buffer (as previously saved by imgui before this is called) */ - memset(buffer, '\0', SETTINGS_BUFFER); - - SDL_IOStream* io = SDL_IOFromFile(PATH_SETTINGS, "r"); - - if (!io) - { - printf(STRING_ERROR_SETTINGS_INIT, PATH_SETTINGS); - return; - } - - SDL_ReadIO(io, buffer, SETTINGS_BUFFER); - SDL_CloseIO(io); - - io = SDL_IOFromFile(PATH_SETTINGS, "w"); - - if (!io) + if (!input) { - printf(STRING_ERROR_SETTINGS_INIT, PATH_SETTINGS); + std::cout << STRING_ERROR_SETTINGS_INIT << PATH_SETTINGS << std::endl; return; } - /* [Settings] */ - SDL_WriteIO(io, SETTINGS_SECTION, strlen(SETTINGS_SECTION)); - SDL_WriteIO(io, "\n", strlen("\n")); + // We're writing after the imgui stuff + oldContents.assign((std::istreambuf_iterator(input)), std::istreambuf_iterator()); + input.close(); - /* Write down all elements */ + std::ofstream output(PATH_SETTINGS); + if (!output) + { + std::cout << STRING_ERROR_SETTINGS_INIT << PATH_SETTINGS << std::endl; + return; + } + + // [Settings] + output << SETTINGS_SECTION << "\n"; + + // Write each setting for (s32 i = 0; i < SETTINGS_COUNT; i++) - _settings_setting_write(self, io, (SettingsItem)i); + _settings_setting_write(self, output, SETTINGS_ENTRIES[i]); - SDL_WriteIO(io, "\n", strlen("\n")); + // Write the the imgui section + output << "\n" << SETTINGS_SECTION_IMGUI << "\n"; + output << oldContents; - /* specify that the other settings are imgui */ - SDL_WriteIO(io, SETTINGS_SECTION_IMGUI, strlen(SETTINGS_SECTION_IMGUI)); - SDL_WriteIO(io, "\n", strlen("\n")); - - /* Then write original contents */ - SDL_WriteIO(io, buffer, strlen(buffer)); - SDL_CloseIO(io); + output.close(); } -/* Loads the settings from the PATH_SETTINGS file */ -void +// Load settings +void settings_load(Settings* self) { - char buffer[SETTINGS_BUFFER]; - char* line = NULL; - - memset(buffer, '\0', SETTINGS_BUFFER); - - SDL_IOStream* io = SDL_IOFromFile(PATH_SETTINGS, "r"); - - if (!io) - { - printf(STRING_ERROR_SETTINGS_INIT, PATH_SETTINGS); - return; - } - - size_t bytesRead = SDL_ReadIO(io, buffer, SETTINGS_BUFFER); - SDL_CloseIO(io); - - buffer[bytesRead] = '\0'; - - line = strtok(buffer, "\n"); - - /* The settings will be the first section in the file */ - /* Go through its elements, load them to settings, and go on with your day */ - while (line != NULL) + std::ifstream file(PATH_SETTINGS); + if (!file) { - if (strcmp(line, SETTINGS_SECTION) == 0) + std::cerr << STRING_ERROR_SETTINGS_INIT << PATH_SETTINGS << std::endl; + return; + } + + std::string line; + bool inSettingsSection = false; + + // Iterare through settings lines until the imgui section is reached, then end + while (std::getline(file, line)) + { + if (line == SETTINGS_SECTION) { - line = strtok(NULL, "\n"); + inSettingsSection = true; continue; } - - _settings_setting_load(self, line); - /* get out here */ - if (strcmp(line, SETTINGS_SECTION_IMGUI) == 0) - break; + if (line == SETTINGS_SECTION_IMGUI) + break; - line = strtok(NULL, "\n"); + if (inSettingsSection) + _settings_setting_load(self, line); } } \ No newline at end of file diff --git a/src/settings.h b/src/settings.h index 98efc1d..0edc1f7 100644 --- a/src/settings.h +++ b/src/settings.h @@ -17,61 +17,12 @@ enum SettingsValueType struct SettingsEntry { - const char* value; - const char* format; + std::string key; SettingsValueType type; s32 offset; }; -#define SETTINGS_COUNT (SETTINGS_EDITOR_BACKGROUND_COLOR_A + 1) -enum SettingsItem -{ - SETTINGS_WINDOW_W, - SETTINGS_WINDOW_H, - SETTINGS_PLAYBACK_IS_LOOP, - SETTINGS_PREVIEW_IS_AXIS, - SETTINGS_PREVIEW_IS_GRID, - SETTINGS_PREVIEW_IS_ROOT_TRANSFORM, - SETTINGS_PREVIEW_IS_SHOW_PIVOT, - SETTINGS_PREVIEW_PAN_X, - SETTINGS_PREVIEW_PAN_Y, - SETTINGS_PREVIEW_ZOOM, - SETTINGS_PREVIEW_GRID_SIZE_X, - SETTINGS_PREVIEW_GRID_SIZE_Y, - SETTINGS_PREVIEW_GRID_OFFSET_X, - SETTINGS_PREVIEW_GRID_OFFSET_Y, - SETTINGS_PREVIEW_GRID_COLOR_R, - SETTINGS_PREVIEW_GRID_COLOR_G, - SETTINGS_PREVIEW_GRID_COLOR_B, - SETTINGS_PREVIEW_GRID_COLOR_A, - SETTINGS_PREVIEW_AXIS_COLOR_R, - SETTINGS_PREVIEW_AXIS_COLOR_G, - SETTINGS_PREVIEW_AXIS_COLOR_B, - SETTINGS_PREVIEW_AXIS_COLOR_A, - SETTINGS_PREVIEW_BACKGROUND_COLOR_R, - SETTINGS_PREVIEW_BACKGROUND_COLOR_G, - SETTINGS_PREVIEW_BACKGROUND_COLOR_B, - SETTINGS_PREVIEW_BACKGROUND_COLOR_A, - SETTINGS_EDITOR_IS_GRID, - SETTINGS_EDITOR_IS_GRID_SNAP, - SETTINGS_EDITOR_IS_BORDER, - SETTINGS_EDITOR_PAN_X, - SETTINGS_EDITOR_PAN_Y, - SETTINGS_EDITOR_ZOOM, - SETTINGS_EDITOR_GRID_SIZE_X, - SETTINGS_EDITOR_GRID_SIZE_Y, - SETTINGS_EDITOR_GRID_OFFSET_X, - SETTINGS_EDITOR_GRID_OFFSET_Y, - SETTINGS_EDITOR_GRID_COLOR_R, - SETTINGS_EDITOR_GRID_COLOR_G, - SETTINGS_EDITOR_GRID_COLOR_B, - SETTINGS_EDITOR_GRID_COLOR_A, - SETTINGS_EDITOR_BACKGROUND_COLOR_R, - SETTINGS_EDITOR_BACKGROUND_COLOR_G, - SETTINGS_EDITOR_BACKGROUND_COLOR_B, - SETTINGS_EDITOR_BACKGROUND_COLOR_A, -}; - +#define SETTINGS_COUNT 44 struct Settings { s32 windowW = 1920; @@ -120,52 +71,52 @@ struct Settings f32 editorBackgroundColorA = 1.0f; }; -static const SettingsEntry SETTINGS_ENTRIES[SETTINGS_COUNT] = +const SettingsEntry SETTINGS_ENTRIES[SETTINGS_COUNT] = { - {"windowW=", "windowW=%i", SETTINGS_TYPE_INT, offsetof(Settings, windowW)}, - {"windowH=", "windowH=%i", SETTINGS_TYPE_INT, offsetof(Settings, windowH)}, - {"playbackIsLoop=", "playbackIsLoop=%i", SETTINGS_TYPE_BOOL, offsetof(Settings, playbackIsLoop)}, - {"previewIsAxis=", "previewIsAxis=%i", SETTINGS_TYPE_BOOL, offsetof(Settings, previewIsAxis)}, - {"previewIsGrid=", "previewIsGrid=%i", SETTINGS_TYPE_BOOL, offsetof(Settings, previewIsGrid)}, - {"previewIsRootTransform=", "previewIsRootTransform=%i", SETTINGS_TYPE_BOOL, offsetof(Settings, previewIsRootTransform)}, - {"previewIsShowPivot=", "previewIsShowPivot=%i", SETTINGS_TYPE_BOOL, offsetof(Settings, previewIsShowPivot)}, - {"previewPanX=", "previewPanX=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewPanX)}, - {"previewPanY=", "previewPanY=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewPanY)}, - {"previewZoom=", "previewZoom=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewZoom)}, - {"previewGridSizeX=", "previewGridSizeX=%i", SETTINGS_TYPE_INT, offsetof(Settings, previewGridSizeX)}, - {"previewGridSizeY=", "previewGridSizeY=%i", SETTINGS_TYPE_INT, offsetof(Settings, previewGridSizeY)}, - {"previewGridOffsetX=", "previewGridOffsetX=%i", SETTINGS_TYPE_INT, offsetof(Settings, previewGridOffsetX)}, - {"previewGridOffsetY=", "previewGridOffsetY=%i", SETTINGS_TYPE_INT, offsetof(Settings, previewGridOffsetY)}, - {"previewGridColorR=", "previewGridColorR=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewGridColorR)}, - {"previewGridColorG=", "previewGridColorG=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewGridColorG)}, - {"previewGridColorB=", "previewGridColorB=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewGridColorB)}, - {"previewGridColorA=", "previewGridColorA=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewGridColorA)}, - {"previewAxisColorR=", "previewAxisColorR=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewAxisColorR)}, - {"previewAxisColorG=", "previewAxisColorG=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewAxisColorG)}, - {"previewAxisColorB=", "previewAxisColorB=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewAxisColorB)}, - {"previewAxisColorA=", "previewAxisColorA=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewAxisColorA)}, - {"previewBackgroundColorR=", "previewBackgroundColorR=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewBackgroundColorR)}, - {"previewBackgroundColorG=", "previewBackgroundColorG=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewBackgroundColorG)}, - {"previewBackgroundColorB=", "previewBackgroundColorB=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewBackgroundColorB)}, - {"previewBackgroundColorA=", "previewBackgroundColorA=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewBackgroundColorA)}, - {"editorIsGrid=", "editorIsGrid=%i", SETTINGS_TYPE_BOOL, offsetof(Settings, editorIsGrid)}, - {"editorIsGridSnap=", "editorIsGridSnap=%i", SETTINGS_TYPE_BOOL, offsetof(Settings, editorIsGridSnap)}, - {"editorIsBorder=", "editorIsBorder=%i", SETTINGS_TYPE_BOOL, offsetof(Settings, editorIsBorder)}, - {"editorPanX=", "editorPanX=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorPanX)}, - {"editorPanY=", "editorPanY=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorPanY)}, - {"editorZoom=", "editorZoom=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorZoom)}, - {"editorGridSizeX=", "editorGridSizeX=%i", SETTINGS_TYPE_INT, offsetof(Settings, editorGridSizeX)}, - {"editorGridSizeY=", "editorGridSizeY=%i", SETTINGS_TYPE_INT, offsetof(Settings, editorGridSizeY)}, - {"editorGridOffsetX=", "editorGridOffsetX=%i", SETTINGS_TYPE_INT, offsetof(Settings, editorGridOffsetX)}, - {"editorGridOffsetY=", "editorGridOffsetY=%i", SETTINGS_TYPE_INT, offsetof(Settings, editorGridOffsetY)}, - {"editorGridColorR=", "editorGridColorR=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorGridColorR)}, - {"editorGridColorG=", "editorGridColorG=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorGridColorG)}, - {"editorGridColorB=", "editorGridColorB=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorGridColorB)}, - {"editorGridColorA=", "editorGridColorA=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorGridColorA)}, - {"editorBackgroundColorR=", "editorBackgroundColorR=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorBackgroundColorR)}, - {"editorBackgroundColorG=", "editorBackgroundColorG=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorBackgroundColorG)}, - {"editorBackgroundColorB=", "editorBackgroundColorB=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorBackgroundColorB)}, - {"editorBackgroundColorA=", "editorBackgroundColorA=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorBackgroundColorA)} + {"windowW=", SETTINGS_TYPE_INT, offsetof(Settings, windowW)}, + {"windowH=", SETTINGS_TYPE_INT, offsetof(Settings, windowH)}, + {"playbackIsLoop=", SETTINGS_TYPE_BOOL, offsetof(Settings, playbackIsLoop)}, + {"previewIsAxis=", SETTINGS_TYPE_BOOL, offsetof(Settings, previewIsAxis)}, + {"previewIsGrid=", SETTINGS_TYPE_BOOL, offsetof(Settings, previewIsGrid)}, + {"previewIsRootTransform=", SETTINGS_TYPE_BOOL, offsetof(Settings, previewIsRootTransform)}, + {"previewIsShowPivot=", SETTINGS_TYPE_BOOL, offsetof(Settings, previewIsShowPivot)}, + {"previewPanX=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewPanX)}, + {"previewPanY=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewPanY)}, + {"previewZoom=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewZoom)}, + {"previewGridSizeX=", SETTINGS_TYPE_INT, offsetof(Settings, previewGridSizeX)}, + {"previewGridSizeY=", SETTINGS_TYPE_INT, offsetof(Settings, previewGridSizeY)}, + {"previewGridOffsetX=", SETTINGS_TYPE_INT, offsetof(Settings, previewGridOffsetX)}, + {"previewGridOffsetY=", SETTINGS_TYPE_INT, offsetof(Settings, previewGridOffsetY)}, + {"previewGridColorR=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewGridColorR)}, + {"previewGridColorG=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewGridColorG)}, + {"previewGridColorB=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewGridColorB)}, + {"previewGridColorA=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewGridColorA)}, + {"previewAxisColorR=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewAxisColorR)}, + {"previewAxisColorG=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewAxisColorG)}, + {"previewAxisColorB=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewAxisColorB)}, + {"previewAxisColorA=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewAxisColorA)}, + {"previewBackgroundColorR=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewBackgroundColorR)}, + {"previewBackgroundColorG=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewBackgroundColorG)}, + {"previewBackgroundColorB=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewBackgroundColorB)}, + {"previewBackgroundColorA=", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewBackgroundColorA)}, + {"editorIsGrid=", SETTINGS_TYPE_BOOL, offsetof(Settings, editorIsGrid)}, + {"editorIsGridSnap=", SETTINGS_TYPE_BOOL, offsetof(Settings, editorIsGridSnap)}, + {"editorIsBorder=", SETTINGS_TYPE_BOOL, offsetof(Settings, editorIsBorder)}, + {"editorPanX=", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorPanX)}, + {"editorPanY=", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorPanY)}, + {"editorZoom=", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorZoom)}, + {"editorGridSizeX=", SETTINGS_TYPE_INT, offsetof(Settings, editorGridSizeX)}, + {"editorGridSizeY=", SETTINGS_TYPE_INT, offsetof(Settings, editorGridSizeY)}, + {"editorGridOffsetX=", SETTINGS_TYPE_INT, offsetof(Settings, editorGridOffsetX)}, + {"editorGridOffsetY=", SETTINGS_TYPE_INT, offsetof(Settings, editorGridOffsetY)}, + {"editorGridColorR=", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorGridColorR)}, + {"editorGridColorG=", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorGridColorG)}, + {"editorGridColorB=", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorGridColorB)}, + {"editorGridColorA=", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorGridColorA)}, + {"editorBackgroundColorR=", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorBackgroundColorR)}, + {"editorBackgroundColorG=", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorBackgroundColorG)}, + {"editorBackgroundColorB=", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorBackgroundColorB)}, + {"editorBackgroundColorA=", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorBackgroundColorA)} }; void settings_save(Settings* self); diff --git a/src/shader.cpp b/src/shader.cpp index 58cbeab..de7e910 100644 --- a/src/shader.cpp +++ b/src/shader.cpp @@ -1,14 +1,15 @@ #include "shader.h" -static bool _shader_compile(GLuint* self, const char* text); +static bool _shader_compile(GLuint* self, const std::string& text); +// Compiles the shader; returns true/false based on success static bool -_shader_compile(GLuint* self, const char* text) +_shader_compile(GLuint* self, const std::string& text) { - char compileLog[SHADER_BUFFER_MAX]; + std::string compileLog; s32 isCompile; - const GLchar* source = text; + const GLchar* source = text.c_str(); glShaderSource(*self, 1, &source, NULL); @@ -17,16 +18,17 @@ _shader_compile(GLuint* self, const char* text) if (!isCompile) { - glGetShaderInfoLog(*self, SHADER_BUFFER_MAX, NULL, compileLog); - printf(STRING_ERROR_SHADER_INIT, *self, compileLog); + glGetShaderInfoLog(*self, SHADER_INFO_LOG_MAX, NULL, &compileLog[0]); + std::cout << STRING_ERROR_SHADER_INIT << *self << std::endl << compileLog << std::endl; return false; } return true; } +// Initializes a given shader with vertex/fragment bool -shader_init(GLuint* self, const char* vertex, const char* fragment) +shader_init(GLuint* self, const std::string& vertex, const std::string& fragment) { GLuint vertexHandle; GLuint fragmentHandle; @@ -51,11 +53,10 @@ shader_init(GLuint* self, const char* vertex, const char* fragment) glDeleteShader(vertexHandle); glDeleteShader(fragmentHandle); - printf(STRING_INFO_SHADER_INIT, *self); - return true; } +// Frees a given shader void shader_free(GLuint* self) { diff --git a/src/shader.h b/src/shader.h index 3c09b26..314745a 100644 --- a/src/shader.h +++ b/src/shader.h @@ -2,7 +2,7 @@ #include "COMMON.h" -#define SHADER_BUFFER_MAX 2048 +#define SHADER_INFO_LOG_MAX 0xFF -bool shader_init(GLuint* self, const char* vertex, const char* fragment); +bool shader_init(GLuint* self, const std::string& vertex, const std::string& fragment); void shader_free(GLuint* self); \ No newline at end of file diff --git a/src/snapshots.cpp b/src/snapshots.cpp index ad5d197..1307457 100644 --- a/src/snapshots.cpp +++ b/src/snapshots.cpp @@ -1,11 +1,15 @@ #include "snapshots.h" +// Pushes the undo stack void snapshots_undo_stack_push(Snapshots* self, Snapshot* snapshot) { + // If stack over the limit, shift it if (self->undoStack.top >= SNAPSHOT_STACK_MAX) { - memmove(&self->undoStack.snapshots[0], &self->undoStack.snapshots[1], sizeof(Snapshot) * (SNAPSHOT_STACK_MAX - 1)); + for (s32 i = 0; i < SNAPSHOT_STACK_MAX - 1; i++) + self->undoStack.snapshots[i] = self->undoStack.snapshots[i + 1]; + self->undoStack.top = SNAPSHOT_STACK_MAX - 1; } @@ -13,6 +17,7 @@ snapshots_undo_stack_push(Snapshots* self, Snapshot* snapshot) self->redoStack.top = 0; } +// Pops the undo stack bool snapshots_undo_stack_pop(Snapshots* self, Snapshot* snapshot) { @@ -24,18 +29,21 @@ snapshots_undo_stack_pop(Snapshots* self, Snapshot* snapshot) return true; } +// Pushes the redo stack void snapshots_redo_stack_push(Snapshots* self, Snapshot* snapshot) { if (self->redoStack.top >= SNAPSHOT_STACK_MAX) { - memmove(&self->redoStack.snapshots[0], &self->redoStack.snapshots[1], sizeof(Snapshot) * (SNAPSHOT_STACK_MAX - 1)); + for (s32 i = 0; i < SNAPSHOT_STACK_MAX - 1; i++) + self->redoStack.snapshots[i] = self->redoStack.snapshots[i + 1]; self->redoStack.top = SNAPSHOT_STACK_MAX - 1; } self->redoStack.snapshots[self->redoStack.top++] = *snapshot; } +// Pops the redo stack bool snapshots_redo_stack_pop(Snapshots* self, Snapshot* snapshot) { @@ -46,6 +54,7 @@ snapshots_redo_stack_pop(Snapshots* self, Snapshot* snapshot) return true; } +// Initializes snapshots void snapshots_init(Snapshots* self, Anm2* anm2, Anm2Reference* reference, f32* time, Input* input) { @@ -55,11 +64,16 @@ snapshots_init(Snapshots* self, Anm2* anm2, Anm2Reference* reference, f32* time, self->input = input; } +// Ticks snapshots void snapshots_tick(Snapshots* self) { /* Undo */ - if (key_press(&self->input->keyboard, INPUT_KEYS[INPUT_UNDO])) + if (input_press(self->input, INPUT_UNDO)) + self->isUndo = true; + + // isUndo disconnected, if another part of the program wants to set it + if (self->isUndo) { Snapshot snapshot; if (snapshots_undo_stack_pop(self, &snapshot)) @@ -71,10 +85,16 @@ snapshots_tick(Snapshots* self) *self->reference = snapshot.reference; *self->time = snapshot.time; } + + self->isUndo = false; } /* Redo */ - if (key_press(&self->input->keyboard, INPUT_KEYS[INPUT_REDO])) + if (input_press(self->input, INPUT_REDO)) + self->isRedo = true; + + // isRedo disconnected, if another part of the program wants to set it + if (self->isRedo) { Snapshot snapshot; if (snapshots_redo_stack_pop(self, &snapshot)) @@ -86,5 +106,7 @@ snapshots_tick(Snapshots* self) *self->reference = snapshot.reference; *self->time = snapshot.time; } + + self->isRedo = false; } } \ No newline at end of file diff --git a/src/snapshots.h b/src/snapshots.h index 0d3cb4a..c650362 100644 --- a/src/snapshots.h +++ b/src/snapshots.h @@ -9,7 +9,7 @@ struct Snapshot { Anm2 anm2; Anm2Reference reference; - f32 time; + f32 time = 0.0f; }; struct SnapshotStack @@ -26,6 +26,8 @@ struct Snapshots Input* input = NULL; SnapshotStack undoStack; SnapshotStack redoStack; + bool isUndo = false; + bool isRedo = false; }; void snapshots_undo_stack_push(Snapshots* self, Snapshot* snapshot); diff --git a/src/state.cpp b/src/state.cpp index 799cccd..4cac41d 100644 --- a/src/state.cpp +++ b/src/state.cpp @@ -38,6 +38,21 @@ _tick(State* state) snapshots_tick(&state->snapshots); dialog_tick(&state->dialog); imgui_tick(&state->imgui); + + if (input_release(&state->input, INPUT_SAVE)) + { + // Open dialog if path empty, otherwise save in-place + if (state->anm2.path.empty()) + dialog_anm2_save(&state->dialog); + else + anm2_serialize(&state->anm2, state->anm2.path); + } + + if (input_release(&state->input, INPUT_PLAY)) + { + state->preview.isPlaying = !state->preview.isPlaying; + state->preview.isRecording = false; + } } static void @@ -45,7 +60,7 @@ _draw(State* state) { editor_draw(&state->editor); preview_draw(&state->preview); - imgui_draw(&state->imgui); + imgui_draw(); SDL_GL_SwapWindow(state->window); } @@ -55,16 +70,14 @@ init(State* state) { settings_load(&state->settings); - printf(STRING_INFO_INIT); + std::cout << STRING_INFO_INIT << std::endl; if (!SDL_Init(SDL_INIT_VIDEO)) { - printf(STRING_ERROR_SDL_INIT, SDL_GetError()); + std::cout << STRING_ERROR_SDL_INIT << SDL_GetError() << std::endl; quit(state); } - - printf(STRING_INFO_SDL_INIT); - + SDL_CreateWindowAndRenderer ( STRING_WINDOW_TITLE, @@ -81,14 +94,14 @@ init(State* state) state->glContext = SDL_GL_CreateContext(state->window); - printf(STRING_INFO_OPENGL, glGetString(GL_VERSION)); - if (!state->glContext) { - printf(STRING_ERROR_GL_CONTEXT_INIT, SDL_GetError()); + std::cout << STRING_ERROR_GL_CONTEXT_INIT << SDL_GetError() << std::endl; quit(state); } + std::cout << STRING_INFO_SDL_INIT << "(" << STRING_INFO_OPENGL << glGetString(GL_VERSION) << ")" << std::endl; + glewInit(); glEnable(GL_BLEND); @@ -96,7 +109,7 @@ init(State* state) glDisable(GL_DEPTH_TEST); glLineWidth(LINE_WIDTH); - printf(STRING_INFO_GLEW_INIT); + std::cout << STRING_INFO_GLEW_INIT << std::endl; resources_init(&state->resources); dialog_init(&state->dialog, &state->anm2, &state->reference, &state->resources, state->window); @@ -155,7 +168,7 @@ loop(State* state) void quit(State* state) { - imgui_free(&state->imgui); + imgui_free(); settings_save(&state->settings); preview_free(&state->preview); editor_free(&state->editor); @@ -164,6 +177,6 @@ quit(State* state) SDL_GL_DestroyContext(state->glContext); SDL_Quit(); - printf(STRING_INFO_QUIT); + std::cout << STRING_INFO_QUIT << std::endl; } diff --git a/src/state.h b/src/state.h index 3598a13..ec5c656 100644 --- a/src/state.h +++ b/src/state.h @@ -26,7 +26,7 @@ struct State Snapshots snapshots; bool isArgument = false; bool isRunning = true; - char argument[PATH_MAX] = STRING_EMPTY; + std::string argument; u64 lastTick = 0; u64 tick = 0; }; diff --git a/src/texture.cpp b/src/texture.cpp index e2990ea..9789615 100644 --- a/src/texture.cpp +++ b/src/texture.cpp @@ -9,6 +9,7 @@ #define STB_IMAGE_WRITE_IMPLEMENTATION #include +// Generates GL texture and sets parameters void texture_gl_set(Texture* self, void* data) { @@ -26,26 +27,28 @@ texture_gl_set(Texture* self, void* data) glBindTexture(GL_TEXTURE_2D, 0); } +// Initializes texture from path; returns true/false on success bool -texture_from_path_init(Texture* self, const char* path) +texture_from_path_init(Texture* self, const std::string& path) { void* data; - data = stbi_load(path, &self->size.x, &self->size.y, &self->channels, 4); + data = stbi_load(path.c_str(), &self->size.x, &self->size.y, &self->channels, 4); if (!data) { - printf(STRING_ERROR_TEXTURE_INIT, path); + std::cout << STRING_ERROR_TEXTURE_INIT << path << std::endl; return false; } - printf(STRING_INFO_TEXTURE_INIT, path); + std::cout << STRING_INFO_TEXTURE_INIT << path << std::endl; texture_gl_set(self, data); return true; } +// Initializes texture from data; returns true/false on success bool texture_from_data_init(Texture* self, const u8* data, u32 length) { @@ -61,17 +64,17 @@ texture_from_data_init(Texture* self, const u8* data, u32 length) return true; } -/* Writes a *.png to the path from the data/size */ -/* Returns true on success */ +// Writes an image to the path from the data/size bool -texture_from_data_write(const char* path, const u8* data, s32 width, s32 height) +texture_from_data_write(const std::string& path, const u8* data, s32 width, s32 height) { - return (bool)stbi_write_png(path, width, height, 4, data, width * 4); + return (bool)stbi_write_png(path.c_str(), width, height, 4, data, width * 4); } +// Frees texture void texture_free(Texture* self) { glDeleteTextures(1, &self->id); - memset(self, '\0', sizeof(Texture)); + *self = Texture{}; } \ No newline at end of file diff --git a/src/texture.h b/src/texture.h index 58ace06..dc54141 100644 --- a/src/texture.h +++ b/src/texture.h @@ -11,7 +11,7 @@ struct Texture }; void texture_gl_set(Texture* self, void* data); -bool texture_from_path_init(Texture* self, const char* path); +bool texture_from_path_init(Texture* self, const std::string& path); bool texture_from_data_init(Texture* self, const u8* data, u32 length); void texture_free(Texture* self); -bool texture_from_data_write(const char* path, const u8* data, s32 width, s32 height); \ No newline at end of file +bool texture_from_data_write(const std::string& path, const u8* data, s32 width, s32 height); \ No newline at end of file diff --git a/src/tool.cpp b/src/tool.cpp index b0cfa99..a420bbe 100644 --- a/src/tool.cpp +++ b/src/tool.cpp @@ -1,33 +1,31 @@ #include "tool.h" +// Initializes tools void tool_init(Tool* self, Input* input) { self->input = input; } +// Ticks tools void tool_tick(Tool* self) { if (!self->isEnabled) return; - /* Input handling */ - if (key_press(&self->input->keyboard, INPUT_KEYS[INPUT_PAN])) + // Input handling for tools + if (input_release(self->input, INPUT_PAN)) self->type = TOOL_PAN; - if (key_press(&self->input->keyboard, INPUT_KEYS[INPUT_MOVE])) + if (input_release(self->input, INPUT_MOVE)) self->type = TOOL_MOVE; - if (key_press(&self->input->keyboard, INPUT_KEYS[INPUT_SCALE])) + if (input_release(self->input, INPUT_SCALE)) self->type = TOOL_SCALE; - if (key_press(&self->input->keyboard, INPUT_KEYS[INPUT_CROP])) - self->type = TOOL_CROP; - - if - ( - key_press(&self->input->keyboard, INPUT_KEYS[INPUT_ROTATE_LEFT]) || - key_press(&self->input->keyboard, INPUT_KEYS[INPUT_ROTATE_RIGHT]) - ) + if (input_release(self->input, INPUT_ROTATE)) self->type = TOOL_ROTATE; + + if (input_release(self->input, INPUT_CROP)) + self->type = TOOL_CROP; } \ No newline at end of file diff --git a/src/tool.h b/src/tool.h index 4cb673e..67ceaeb 100644 --- a/src/tool.h +++ b/src/tool.h @@ -2,14 +2,14 @@ #include "input.h" -#define TOOL_COUNT (TOOL_CROP + 1) enum ToolType { TOOL_PAN, TOOL_MOVE, TOOL_ROTATE, TOOL_SCALE, - TOOL_CROP + TOOL_CROP, + TOOL_COUNT }; struct Tool diff --git a/src/window.cpp b/src/window.cpp index 86735f3..8fcc9d4 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -2,13 +2,13 @@ /* Sets the window title from the given anm2 */ void -window_title_from_path_set(SDL_Window* self, const char* path) +window_title_from_path_set(SDL_Window* self, const std::string& path) { - if (!strcmp(path, STRING_EMPTY) == 0) + if (path.empty()) { - char windowTitle[WINDOW_TITLE_MAX]; - snprintf(windowTitle, WINDOW_TITLE_MAX, STRING_WINDOW_TITLE_EDITING, path); - SDL_SetWindowTitle(self, windowTitle); + std::string windowTitle = path; + windowTitle = windowTitle + " (" + path + ")"; + SDL_SetWindowTitle(self, windowTitle.c_str()); } else SDL_SetWindowTitle(self, STRING_WINDOW_TITLE); diff --git a/src/window.h b/src/window.h index 4d55a1a..e314ae8 100644 --- a/src/window.h +++ b/src/window.h @@ -2,6 +2,4 @@ #include "COMMON.h" -#define WINDOW_TITLE_MAX 0xFF + PATH_MAX - -void window_title_from_path_set(SDL_Window* self, const char* path); \ No newline at end of file +void window_title_from_path_set(SDL_Window* self, const std::string& path); \ No newline at end of file