slowly getting back...also, static linking
This commit is contained in:
7
.gitignore
vendored
7
.gitignore
vendored
@@ -4,8 +4,9 @@ release/
|
|||||||
packed/
|
packed/
|
||||||
vcpkg_installed/
|
vcpkg_installed/
|
||||||
out/
|
out/
|
||||||
include/imgui/
|
external/
|
||||||
include/glm/
|
external/
|
||||||
include/tinyxml2
|
external/
|
||||||
|
external/
|
||||||
workshop/resources
|
workshop/resources
|
||||||
.vs/
|
.vs/
|
||||||
|
|||||||
7
.gitmodules
vendored
7
.gitmodules
vendored
@@ -7,6 +7,7 @@
|
|||||||
branch = docking
|
branch = docking
|
||||||
[submodule "external/tinyxml2"]
|
[submodule "external/tinyxml2"]
|
||||||
path = external/tinyxml2
|
path = external/tinyxml2
|
||||||
url = https://github.com/external/tinyxml2
|
url = https://github.com/leethomason/tinyxml2
|
||||||
|
[submodule "external/SDL"]
|
||||||
|
path = external/SDL
|
||||||
|
url = https://github.com/libsdl-org/SDL.git
|
||||||
|
|||||||
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@@ -1,5 +1,8 @@
|
|||||||
{
|
{
|
||||||
"C_Cpp.formatting": "clangFormat",
|
"C_Cpp.formatting": "clangFormat",
|
||||||
"editor.formatOnSave": true,
|
"editor.formatOnSave": true,
|
||||||
"clang-format.style": "file"
|
"clang-format.style": "file",
|
||||||
|
"clangd.arguments": [
|
||||||
|
"--compile-commands-dir=build"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
@@ -1,35 +1,39 @@
|
|||||||
cmake_minimum_required(VERSION 3.15)
|
cmake_minimum_required(VERSION 3.15)
|
||||||
|
project(anm2ed CXX)
|
||||||
|
|
||||||
|
# Optional: auto-pick up vcpkg toolchain on Windows
|
||||||
if(WIN32 AND DEFINED ENV{VCPKG_ROOT} AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
|
if(WIN32 AND DEFINED ENV{VCPKG_ROOT} AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
|
||||||
set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
|
set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
|
||||||
CACHE STRING "Vcpkg toolchain file")
|
CACHE STRING "Vcpkg toolchain file")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
project(anm2ed CXX)
|
|
||||||
|
|
||||||
find_package(SDL3 REQUIRED)
|
|
||||||
find_package(OpenGL REQUIRED)
|
find_package(OpenGL REQUIRED)
|
||||||
|
|
||||||
set(GLAD_SRC
|
# Export compile_commands.json (for clangd, etc.)
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/glad/glad.cpp
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
)
|
if(CMAKE_EXPORT_COMPILE_COMMANDS)
|
||||||
|
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink
|
||||||
|
${CMAKE_BINARY_DIR}/compile_commands.json
|
||||||
|
${CMAKE_SOURCE_DIR}/compile_commands.json
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(GLAD_SRC ${CMAKE_CURRENT_SOURCE_DIR}/include/glad/glad.cpp)
|
||||||
|
|
||||||
set(IMGUI_SRC
|
set(IMGUI_SRC
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/external/imgui/imgui.cpp
|
external/imgui/imgui.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/external/imgui/imgui_draw.cpp
|
external/imgui/imgui_draw.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/external/imgui/imgui_widgets.cpp
|
external/imgui/imgui_widgets.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/external/imgui/imgui_tables.cpp
|
external/imgui/imgui_tables.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/external/imgui/backends/imgui_impl_sdl3.cpp
|
external/imgui/backends/imgui_impl_sdl3.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/external/imgui/backends/imgui_impl_opengl3.cpp
|
external/imgui/backends/imgui_impl_opengl3.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(TINYXML2_SRC
|
set(TINYXML2_SRC external/tinyxml2/tinyxml2.cpp)
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/external/tinyxml2/tinyxml2.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
file(GLOB PROJECT_SRC
|
file(GLOB PROJECT_SRC CONFIGURE_DEPENDS
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp
|
src/*.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/*.h
|
src/*.h
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME}
|
add_executable(${PROJECT_NAME}
|
||||||
@@ -39,39 +43,48 @@ add_executable(${PROJECT_NAME}
|
|||||||
${PROJECT_SRC}
|
${PROJECT_SRC}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(SDL_SHARED OFF CACHE BOOL "" FORCE)
|
||||||
|
set(SDL_STATIC ON CACHE BOOL "" FORCE)
|
||||||
|
add_subdirectory(external/SDL EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
enable_language(RC)
|
enable_language(RC)
|
||||||
target_sources(${PROJECT_NAME} PRIVATE Icon.rc)
|
target_sources(${PROJECT_NAME} PRIVATE Icon.rc)
|
||||||
set_target_properties(${PROJECT_NAME} PROPERTIES WIN32_EXECUTABLE TRUE)
|
set_target_properties(${PROJECT_NAME} PROPERTIES WIN32_EXECUTABLE TRUE)
|
||||||
endif()
|
|
||||||
|
|
||||||
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_23)
|
set_property(TARGET ${PROJECT_NAME} PROPERTY
|
||||||
|
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||||
|
|
||||||
target_include_directories(${PROJECT_NAME} PRIVATE
|
target_compile_options(${PROJECT_NAME} PRIVATE /EHsc)
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/glad
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/external
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/external/imgui
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/external/glm
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/external/tinyxml2
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
|
||||||
)
|
|
||||||
|
|
||||||
if(MSVC)
|
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE /std:c++latest /EHsc)
|
|
||||||
target_link_options(${PROJECT_NAME} PRIVATE /STACK:0xffffff)
|
target_link_options(${PROJECT_NAME} PRIVATE /STACK:0xffffff)
|
||||||
else()
|
else()
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE -O2 -std=c++23 -Wall -Wextra -pedantic -fmax-errors=1)
|
target_compile_options(${PROJECT_NAME} PRIVATE
|
||||||
|
-O2 -Wall -Wextra -pedantic -fmax-errors=1
|
||||||
|
)
|
||||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE -DDEBUG -g)
|
target_compile_definitions(${PROJECT_NAME} PRIVATE DEBUG)
|
||||||
else()
|
target_compile_options(${PROJECT_NAME} PRIVATE -g)
|
||||||
set(CMAKE_BUILD_TYPE "Release")
|
|
||||||
endif()
|
endif()
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE m)
|
target_link_libraries(${PROJECT_NAME} PRIVATE m)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE OpenGL::GL SDL3::SDL3)
|
target_compile_definitions(${PROJECT_NAME} PRIVATE IMGUI_DISABLE_OBSOLETE_FUNCTIONS IMGUI_DEBUG_PARANOID IMGUI_ENABLE_DOCKING)
|
||||||
|
|
||||||
message("System: ${CMAKE_SYSTEM_NAME}")
|
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_23)
|
||||||
message("Project: ${PROJECT_NAME}")
|
|
||||||
message("Build: ${CMAKE_BUILD_TYPE}")
|
target_include_directories(${PROJECT_NAME} PRIVATE
|
||||||
|
external
|
||||||
|
external/imgui
|
||||||
|
external/glm
|
||||||
|
external/tinyxml2
|
||||||
|
include
|
||||||
|
include/glad
|
||||||
|
src
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(${PROJECT_NAME} PRIVATE OpenGL::GL SDL3::SDL3-static)
|
||||||
|
|
||||||
|
message(STATUS "System: ${CMAKE_SYSTEM_NAME}")
|
||||||
|
message(STATUS "Project: ${PROJECT_NAME}")
|
||||||
|
message(STATUS "Build: ${CMAKE_BUILD_TYPE}")
|
||||||
@@ -1 +1 @@
|
|||||||
build/compile_commands.json
|
/home/anon/sda/Personal/Repos/anm2ed/build/compile_commands.json
|
||||||
75
src/COMMON.h
75
src/COMMON.h
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <set>
|
||||||
#define GLAD_GL_IMPLEMENTATION
|
#define GLAD_GL_IMPLEMENTATION
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
#include <glad/glad.h>
|
#include <glad/glad.h>
|
||||||
@@ -10,7 +11,6 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <climits>
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
@@ -241,6 +241,35 @@ template <typename T> static inline void map_insert_shift(std::map<int, T>& map,
|
|||||||
map[insertID] = value;
|
map[insertID] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Map> auto map_keys_to_set(const Map& m) {
|
||||||
|
using Key = typename Map::key_type;
|
||||||
|
std::unordered_set<Key> s;
|
||||||
|
s.reserve(m.size());
|
||||||
|
for (const auto& [key, _] : m) {
|
||||||
|
s.insert(key);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Set> Set set_symmetric_difference(const Set& a, const Set& b) {
|
||||||
|
Set result;
|
||||||
|
result.reserve(a.size() + b.size());
|
||||||
|
|
||||||
|
for (const auto& x : a) {
|
||||||
|
if (!b.contains(x)) {
|
||||||
|
result.insert(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& x : b) {
|
||||||
|
if (!a.contains(x)) {
|
||||||
|
result.insert(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T> static inline T* vector_find(std::vector<T>& v, const T& value) {
|
template <typename T> static inline T* vector_find(std::vector<T>& v, const T& value) {
|
||||||
auto it = std::find(v.begin(), v.end(), value);
|
auto it = std::find(v.begin(), v.end(), value);
|
||||||
return (it != v.end()) ? &(*it) : nullptr;
|
return (it != v.end()) ? &(*it) : nullptr;
|
||||||
@@ -257,11 +286,49 @@ template <typename T> static inline void vector_value_swap(std::vector<T>& v, co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void unordered_set_id_toggle(std::unordered_set<int>& set, int id) {
|
template <typename T> static inline T* vector_get(std::vector<T>& v, size_t index) {
|
||||||
if (auto it = set.find(id); it != set.end())
|
if (index < v.size())
|
||||||
|
return &v[index];
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> static inline void vector_move(std::vector<T>& v, size_t from, size_t to) {
|
||||||
|
if (from >= v.size() || to >= v.size() || from == to)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (from < to) {
|
||||||
|
std::rotate(v.begin() + from, v.begin() + from + 1, v.begin() + to + 1);
|
||||||
|
} else {
|
||||||
|
std::rotate(v.begin() + to, v.begin() + from, v.begin() + from + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void vector_erase_indices(std::vector<T>& v, const std::set<int>& indices) {
|
||||||
|
size_t i = 0;
|
||||||
|
v.erase(std::remove_if(v.begin(), v.end(), [&](const T&) { return indices.count(i++) > 0; }), v.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> static inline void set_key_toggle(std::set<T>& set, T key) {
|
||||||
|
if (auto it = set.find(key); it != set.end())
|
||||||
set.erase(it);
|
set.erase(it);
|
||||||
else
|
else
|
||||||
set.insert(id);
|
set.insert(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> static inline void set_list(std::set<T>& s, const T& key, bool isCtrl, bool isShift, T* lastSelected) {
|
||||||
|
if (isShift && lastSelected) {
|
||||||
|
s.clear();
|
||||||
|
T a = std::min(*lastSelected, key);
|
||||||
|
T b = std::max(*lastSelected, key);
|
||||||
|
for (T i = a; i <= b; i++)
|
||||||
|
s.insert(i);
|
||||||
|
} else if (isCtrl) {
|
||||||
|
set_key_toggle(s, key);
|
||||||
|
*lastSelected = key;
|
||||||
|
} else {
|
||||||
|
s = {key};
|
||||||
|
*lastSelected = key;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline mat4 quad_model_get(vec2 size = {}, vec2 position = {}, vec2 pivot = {}, vec2 scale = vec2(1.0f), float rotation = {}) {
|
static inline mat4 quad_model_get(vec2 size = {}, vec2 position = {}, vec2 pivot = {}, vec2 scale = vec2(1.0f), float rotation = {}) {
|
||||||
|
|||||||
3797
src/RESOURCE.h
3797
src/RESOURCE.h
File diff suppressed because it is too large
Load Diff
96
src/anm2.cpp
96
src/anm2.cpp
@@ -17,7 +17,8 @@ static void _anm2_frame_serialize(Anm2Frame* frame, Anm2Type type, XMLDocument*
|
|||||||
XMLDocument localDocument;
|
XMLDocument localDocument;
|
||||||
XMLDocument* useDocument = document ? document : &localDocument;
|
XMLDocument* useDocument = document ? document : &localDocument;
|
||||||
|
|
||||||
XMLElement* element = useDocument->NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_FRAME]);
|
XMLElement* element = type == ANM2_TRIGGER ? useDocument->NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_TRIGGER])
|
||||||
|
: useDocument->NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_FRAME]);
|
||||||
|
|
||||||
if (type == ANM2_TRIGGER) {
|
if (type == ANM2_TRIGGER) {
|
||||||
element->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_EVENT_ID], frame->eventID); // EventID
|
element->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_EVENT_ID], frame->eventID); // EventID
|
||||||
@@ -118,8 +119,8 @@ static void _anm2_animation_serialize(Anm2Animation* animation, XMLDocument* doc
|
|||||||
// Triggers
|
// Triggers
|
||||||
XMLElement* triggersElement = useDocument->NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_TRIGGERS]);
|
XMLElement* triggersElement = useDocument->NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_TRIGGERS]);
|
||||||
|
|
||||||
for (auto& frame : animation->triggers.frames)
|
for (auto& trigger : animation->triggers.frames)
|
||||||
_anm2_frame_serialize(&frame, ANM2_TRIGGER, useDocument, triggersElement);
|
_anm2_frame_serialize(&trigger, ANM2_TRIGGER, useDocument, triggersElement);
|
||||||
|
|
||||||
element->InsertEndChild(triggersElement);
|
element->InsertEndChild(triggersElement);
|
||||||
|
|
||||||
@@ -220,11 +221,9 @@ bool anm2_serialize(Anm2* self, const std::string& path) {
|
|||||||
|
|
||||||
// Animations
|
// Animations
|
||||||
XMLElement* animationsElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_ANIMATIONS]);
|
XMLElement* animationsElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_ANIMATIONS]);
|
||||||
if (self->defaultAnimationID != ID_NONE)
|
animationsElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_DEFAULT_ANIMATION], self->defaultAnimation.c_str()); // DefaultAnimation
|
||||||
animationsElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_DEFAULT_ANIMATION],
|
|
||||||
self->animations[self->defaultAnimationID].name.c_str()); // DefaultAnimation
|
|
||||||
|
|
||||||
for (auto& [id, animation] : self->animations)
|
for (auto& animation : self->animations)
|
||||||
_anm2_animation_serialize(&animation, &document, animationsElement);
|
_anm2_animation_serialize(&animation, &document, animationsElement);
|
||||||
|
|
||||||
animatedActorElement->InsertEndChild(animationsElement);
|
animatedActorElement->InsertEndChild(animationsElement);
|
||||||
@@ -426,13 +425,9 @@ bool anm2_deserialize(Anm2* self, const std::string& path, bool isTextures) {
|
|||||||
|
|
||||||
anm2_new(self);
|
anm2_new(self);
|
||||||
self->path = path;
|
self->path = path;
|
||||||
std::string defaultAnimation{};
|
|
||||||
int id{};
|
int id{};
|
||||||
|
|
||||||
// Save old working directory and then use anm2's path as directory
|
WorkingDirectory workingDirectory(path);
|
||||||
// (used for loading textures from anm2 correctly which are relative)
|
|
||||||
std::filesystem::path workingPath = std::filesystem::current_path();
|
|
||||||
working_directory_from_file_set(path);
|
|
||||||
|
|
||||||
const XMLElement* root = document.RootElement();
|
const XMLElement* root = document.RootElement();
|
||||||
|
|
||||||
@@ -506,13 +501,13 @@ bool anm2_deserialize(Anm2* self, const std::string& path, bool isTextures) {
|
|||||||
switch (ANM2_ATTRIBUTE_STRING_TO_ENUM(attribute->Name())) {
|
switch (ANM2_ATTRIBUTE_STRING_TO_ENUM(attribute->Name())) {
|
||||||
case ANM2_ATTRIBUTE_NAME:
|
case ANM2_ATTRIBUTE_NAME:
|
||||||
addLayer.name = std::string(attribute->Value());
|
addLayer.name = std::string(attribute->Value());
|
||||||
break; // Name
|
break;
|
||||||
case ANM2_ATTRIBUTE_ID:
|
case ANM2_ATTRIBUTE_ID:
|
||||||
id = std::atoi(attribute->Value());
|
id = std::atoi(attribute->Value());
|
||||||
break; // ID
|
break;
|
||||||
case ANM2_ATTRIBUTE_SPRITESHEET_ID:
|
case ANM2_ATTRIBUTE_SPRITESHEET_ID:
|
||||||
addLayer.spritesheetID = std::atoi(attribute->Value());
|
addLayer.spritesheetID = std::atoi(attribute->Value());
|
||||||
break; // ID
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -575,7 +570,7 @@ bool anm2_deserialize(Anm2* self, const std::string& path, bool isTextures) {
|
|||||||
for (const XMLAttribute* attribute = animations->FirstAttribute(); attribute; attribute = attribute->Next()) {
|
for (const XMLAttribute* attribute = animations->FirstAttribute(); attribute; attribute = attribute->Next()) {
|
||||||
switch (ANM2_ATTRIBUTE_STRING_TO_ENUM(attribute->Name())) {
|
switch (ANM2_ATTRIBUTE_STRING_TO_ENUM(attribute->Name())) {
|
||||||
case ANM2_ATTRIBUTE_DEFAULT_ANIMATION:
|
case ANM2_ATTRIBUTE_DEFAULT_ANIMATION:
|
||||||
defaultAnimation = std::string(attribute->Value());
|
self->defaultAnimation = std::string(attribute->Value());
|
||||||
break; // DefaultAnimation
|
break; // DefaultAnimation
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -585,18 +580,12 @@ bool anm2_deserialize(Anm2* self, const std::string& path, bool isTextures) {
|
|||||||
// Animation
|
// Animation
|
||||||
for (const XMLElement* animation = animations->FirstChildElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_ANIMATION]); animation;
|
for (const XMLElement* animation = animations->FirstChildElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_ANIMATION]); animation;
|
||||||
animation = animation->NextSiblingElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_ANIMATION]))
|
animation = animation->NextSiblingElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_ANIMATION]))
|
||||||
_anm2_animation_deserialize(&self->animations[map_next_id_get(self->animations)], animation);
|
_anm2_animation_deserialize(&self->animations.emplace_back(Anm2Animation()), animation);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& [id, animation] : self->animations)
|
|
||||||
if (animation.name == defaultAnimation)
|
|
||||||
self->defaultAnimationID = id;
|
|
||||||
|
|
||||||
if (isTextures)
|
if (isTextures)
|
||||||
anm2_spritesheet_texture_pixels_download(self);
|
anm2_spritesheet_texture_pixels_download(self);
|
||||||
|
|
||||||
std::filesystem::current_path(workingPath);
|
|
||||||
|
|
||||||
log_info(std::format(ANM2_READ_INFO, path));
|
log_info(std::format(ANM2_READ_INFO, path));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -625,7 +614,7 @@ int anm2_layer_add(Anm2* self) {
|
|||||||
void anm2_layer_remove(Anm2* self, int id) {
|
void anm2_layer_remove(Anm2* self, int id) {
|
||||||
self->layers.erase(id);
|
self->layers.erase(id);
|
||||||
|
|
||||||
for (auto& [_, animation] : self->animations)
|
for (auto& animation : self->animations)
|
||||||
anm2_animation_layer_animation_remove(&animation, id);
|
anm2_animation_layer_animation_remove(&animation, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -641,36 +630,32 @@ void anm2_null_remove(Anm2* self, int id) {
|
|||||||
|
|
||||||
self->nulls.erase(id);
|
self->nulls.erase(id);
|
||||||
|
|
||||||
for (auto& [_, animation] : self->animations)
|
for (auto& animation : self->animations)
|
||||||
anm2_animation_null_animation_remove(&animation, id);
|
anm2_animation_null_animation_remove(&animation, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
int anm2_animation_add(Anm2* self, Anm2Animation* animation, int id) {
|
int anm2_animation_add(Anm2* self, Anm2Animation* animation, int index) {
|
||||||
int addID = map_next_id_get(self->animations);
|
|
||||||
|
|
||||||
Anm2Animation localAnimation;
|
Anm2Animation addAnimation = animation ? *animation : Anm2Animation();
|
||||||
Anm2Animation* addAnimation = animation ? animation : &localAnimation;
|
|
||||||
|
|
||||||
if (!animation)
|
if (!animation)
|
||||||
addAnimation->rootAnimation.frames.push_back(Anm2Frame{});
|
addAnimation.rootAnimation.frames.push_back(Anm2Frame{});
|
||||||
|
|
||||||
if (id != ID_NONE) {
|
int addIndex = index != INDEX_NONE ? index : (int)self->animations.size() - 1;
|
||||||
map_insert_shift(self->animations, id, *addAnimation);
|
|
||||||
return id + 1;
|
|
||||||
} else
|
|
||||||
self->animations[addID] = *addAnimation;
|
|
||||||
|
|
||||||
return addID;
|
self->animations.insert(self->animations.begin() + addIndex, addAnimation);
|
||||||
|
|
||||||
|
return addIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void anm2_animation_remove(Anm2* self, int id) { self->animations.erase(id); }
|
void anm2_animations_remove(Anm2* self, const std::set<int> indices) { vector_erase_indices(self->animations, indices); };
|
||||||
|
|
||||||
void anm2_new(Anm2* self) {
|
void anm2_new(Anm2* self) {
|
||||||
*self = Anm2{};
|
*self = Anm2{};
|
||||||
_anm2_created_on_set(self);
|
_anm2_created_on_set(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
Anm2Animation* anm2_animation_from_reference(Anm2* self, Anm2Reference reference) { return map_find(self->animations, reference.animationID); }
|
Anm2Animation* anm2_animation_from_reference(Anm2* self, Anm2Reference reference) { return vector_get(self->animations, reference.animationIndex); }
|
||||||
|
|
||||||
Anm2Item* anm2_item_from_reference(Anm2* self, Anm2Reference reference) {
|
Anm2Item* anm2_item_from_reference(Anm2* self, Anm2Reference reference) {
|
||||||
if (reference.itemType == ANM2_NONE)
|
if (reference.itemType == ANM2_NONE)
|
||||||
@@ -928,8 +913,8 @@ void anm2_item_frame_set(Anm2* self, Anm2Reference reference, const Anm2FrameCha
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void anm2_animation_merge(Anm2* self, int animationID, const std::vector<int>& mergeIDs, Anm2MergeType type) {
|
void anm2_animation_merge(Anm2* self, int animationIndex, std::set<int> mergeIndices, Anm2MergeType type) {
|
||||||
Anm2Animation newAnimation = self->animations[animationID];
|
Anm2Animation newAnimation = self->animations[animationIndex];
|
||||||
|
|
||||||
auto merge_item = [&](Anm2Item& destinationItem, const Anm2Item& sourceItem) {
|
auto merge_item = [&](Anm2Item& destinationItem, const Anm2Item& sourceItem) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@@ -950,11 +935,11 @@ void anm2_animation_merge(Anm2* self, int animationID, const std::vector<int>& m
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto mergeID : mergeIDs) {
|
for (auto mergeIndices : mergeIndices) {
|
||||||
if (animationID == mergeID)
|
if (animationIndex == mergeIndices)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const Anm2Animation& mergeAnimation = self->animations[mergeID];
|
const Anm2Animation& mergeAnimation = self->animations[mergeIndices];
|
||||||
|
|
||||||
merge_item(newAnimation.rootAnimation, mergeAnimation.rootAnimation);
|
merge_item(newAnimation.rootAnimation, mergeAnimation.rootAnimation);
|
||||||
|
|
||||||
@@ -967,9 +952,9 @@ void anm2_animation_merge(Anm2* self, int animationID, const std::vector<int>& m
|
|||||||
merge_item(newAnimation.triggers, mergeAnimation.triggers);
|
merge_item(newAnimation.triggers, mergeAnimation.triggers);
|
||||||
}
|
}
|
||||||
|
|
||||||
self->animations[animationID] = newAnimation;
|
self->animations[animationIndex] = newAnimation;
|
||||||
|
|
||||||
anm2_animation_length_set(&self->animations[animationID]);
|
anm2_animation_length_set(&self->animations[animationIndex]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void anm2_frame_bake(Anm2* self, Anm2Reference reference, int interval, bool isRoundScale, bool isRoundRotation) {
|
void anm2_frame_bake(Anm2* self, Anm2Reference reference, int interval, bool isRoundScale, bool isRoundRotation) {
|
||||||
@@ -981,7 +966,7 @@ void anm2_frame_bake(Anm2* self, Anm2Reference reference, int interval, bool isR
|
|||||||
if (!frame)
|
if (!frame)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Anm2Reference referenceNext = {reference.animationID, reference.itemType, reference.itemID, reference.frameIndex + 1};
|
Anm2Reference referenceNext = {reference.animationIndex, reference.itemType, reference.itemID, reference.frameIndex + 1};
|
||||||
Anm2Frame* frameNext = anm2_frame_from_reference(self, referenceNext);
|
Anm2Frame* frameNext = anm2_frame_from_reference(self, referenceNext);
|
||||||
if (!frameNext)
|
if (!frameNext)
|
||||||
frameNext = frame;
|
frameNext = frame;
|
||||||
@@ -1028,7 +1013,7 @@ void anm2_scale(Anm2* self, float scale) {
|
|||||||
frame.pivot = vec2((int)(frame.pivot.x * scale), (int)(frame.pivot.y * scale));
|
frame.pivot = vec2((int)(frame.pivot.x * scale), (int)(frame.pivot.y * scale));
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto& [_, animation] : self->animations) {
|
for (auto& animation : self->animations) {
|
||||||
for (auto& frame : animation.rootAnimation.frames)
|
for (auto& frame : animation.rootAnimation.frames)
|
||||||
frame_scale(frame);
|
frame_scale(frame);
|
||||||
|
|
||||||
@@ -1112,7 +1097,7 @@ vec4 anm2_animation_rect_get(Anm2* self, Anm2Reference reference, bool isRootTra
|
|||||||
|
|
||||||
for (float t = 0.0f; t <= animation->frameNum; t += 1.0f) {
|
for (float t = 0.0f; t <= animation->frameNum; t += 1.0f) {
|
||||||
for (const auto& [id, _] : animation->layerAnimations) {
|
for (const auto& [id, _] : animation->layerAnimations) {
|
||||||
anm2_frame_from_time(self, &frame, {reference.animationID, ANM2_LAYER, id}, t);
|
anm2_frame_from_time(self, &frame, {reference.animationIndex, ANM2_LAYER, id}, t);
|
||||||
if (!frame.isVisible)
|
if (!frame.isVisible)
|
||||||
continue;
|
continue;
|
||||||
if (frame.size.x <= 0 || frame.size.y <= 0)
|
if (frame.size.x <= 0 || frame.size.y <= 0)
|
||||||
@@ -1120,7 +1105,7 @@ vec4 anm2_animation_rect_get(Anm2* self, Anm2Reference reference, bool isRootTra
|
|||||||
|
|
||||||
mat4 rootModel(1.0f);
|
mat4 rootModel(1.0f);
|
||||||
if (isRootTransform) {
|
if (isRootTransform) {
|
||||||
anm2_frame_from_time(self, &root, {reference.animationID, ANM2_ROOT}, t);
|
anm2_frame_from_time(self, &root, {reference.animationIndex, ANM2_ROOT}, t);
|
||||||
rootModel = quad_model_parent_get(root.position, root.pivot, PERCENT_TO_UNIT(root.scale), root.rotation);
|
rootModel = quad_model_parent_get(root.position, root.pivot, PERCENT_TO_UNIT(root.scale), root.rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1149,7 +1134,7 @@ void anm2_animation_serialize_to_string(Anm2Animation* animation, std::string* s
|
|||||||
|
|
||||||
void anm2_frame_serialize_to_string(Anm2Frame* frame, Anm2Type type, std::string* string) { _anm2_frame_serialize(frame, type, nullptr, nullptr, string); }
|
void anm2_frame_serialize_to_string(Anm2Frame* frame, Anm2Type type, std::string* string) { _anm2_frame_serialize(frame, type, nullptr, nullptr, string); }
|
||||||
|
|
||||||
bool anm2_animation_deserialize_from_xml(Anm2Animation* animation, const std::string& xml) {
|
bool anm2_animations_deserialize_from_xml(std::vector<Anm2Animation>& animations, const std::string& xml) {
|
||||||
XMLDocument document;
|
XMLDocument document;
|
||||||
|
|
||||||
auto animation_deserialize_error = [&]() {
|
auto animation_deserialize_error = [&]() {
|
||||||
@@ -1160,13 +1145,12 @@ bool anm2_animation_deserialize_from_xml(Anm2Animation* animation, const std::st
|
|||||||
if (document.Parse(xml.c_str()) != XML_SUCCESS)
|
if (document.Parse(xml.c_str()) != XML_SUCCESS)
|
||||||
return animation_deserialize_error();
|
return animation_deserialize_error();
|
||||||
|
|
||||||
const XMLElement* element = document.RootElement();
|
for (const XMLElement* element = document.RootElement(); element; element = element->NextSiblingElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_ANIMATION])) {
|
||||||
if (!element)
|
if (std::string(document.RootElement()->Name()) != std::string(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_ANIMATION]))
|
||||||
return animation_deserialize_error();
|
return animation_deserialize_error();
|
||||||
if (std::string(element->Name()) != std::string(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_ANIMATION]))
|
_anm2_animation_deserialize(&animations.emplace_back(Anm2Animation()), element);
|
||||||
return animation_deserialize_error();
|
}
|
||||||
|
|
||||||
_anm2_animation_deserialize(animation, element);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
17
src/anm2.h
17
src/anm2.h
@@ -23,6 +23,7 @@
|
|||||||
#define ANM2_WRITE_INFO "Wrote anm2 to file: {}"
|
#define ANM2_WRITE_INFO "Wrote anm2 to file: {}"
|
||||||
#define ANM2_CREATED_ON_FORMAT "%d-%B-%Y %I:%M:%S %p"
|
#define ANM2_CREATED_ON_FORMAT "%d-%B-%Y %I:%M:%S %p"
|
||||||
|
|
||||||
|
#define ANM2_ANIMATION_DEFAULT "New Animation"
|
||||||
#define ANM2_EXTENSION "anm2"
|
#define ANM2_EXTENSION "anm2"
|
||||||
#define ANM2_SPRITESHEET_EXTENSION "png"
|
#define ANM2_SPRITESHEET_EXTENSION "png"
|
||||||
|
|
||||||
@@ -185,7 +186,7 @@ struct Anm2Item {
|
|||||||
|
|
||||||
struct Anm2Animation {
|
struct Anm2Animation {
|
||||||
int frameNum = ANM2_FRAME_NUM_MIN;
|
int frameNum = ANM2_FRAME_NUM_MIN;
|
||||||
std::string name = "New Animation";
|
std::string name = ANM2_ANIMATION_DEFAULT;
|
||||||
bool isLoop = true;
|
bool isLoop = true;
|
||||||
Anm2Item rootAnimation;
|
Anm2Item rootAnimation;
|
||||||
std::unordered_map<int, Anm2Item> layerAnimations;
|
std::unordered_map<int, Anm2Item> layerAnimations;
|
||||||
@@ -200,12 +201,12 @@ struct Anm2 {
|
|||||||
std::string path{};
|
std::string path{};
|
||||||
std::string createdBy = "robot";
|
std::string createdBy = "robot";
|
||||||
std::string createdOn{};
|
std::string createdOn{};
|
||||||
|
std::string defaultAnimation = ANM2_ANIMATION_DEFAULT;
|
||||||
std::map<int, Anm2Spritesheet> spritesheets;
|
std::map<int, Anm2Spritesheet> spritesheets;
|
||||||
std::map<int, Anm2Layer> layers;
|
std::map<int, Anm2Layer> layers;
|
||||||
std::map<int, Anm2Null> nulls;
|
std::map<int, Anm2Null> nulls;
|
||||||
std::map<int, Anm2Event> events;
|
std::map<int, Anm2Event> events;
|
||||||
std::map<int, Anm2Animation> animations;
|
std::vector<Anm2Animation> animations;
|
||||||
int defaultAnimationID = ID_NONE;
|
|
||||||
int fps = ANM2_FPS_DEFAULT;
|
int fps = ANM2_FPS_DEFAULT;
|
||||||
int version{};
|
int version{};
|
||||||
|
|
||||||
@@ -213,7 +214,7 @@ struct Anm2 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Anm2Reference {
|
struct Anm2Reference {
|
||||||
int animationID = ID_NONE;
|
int animationIndex = ID_NONE;
|
||||||
Anm2Type itemType = ANM2_NONE;
|
Anm2Type itemType = ANM2_NONE;
|
||||||
int itemID = ID_NONE;
|
int itemID = ID_NONE;
|
||||||
int frameIndex = INDEX_NONE;
|
int frameIndex = INDEX_NONE;
|
||||||
@@ -231,11 +232,11 @@ Anm2Animation* anm2_animation_from_reference(Anm2* self, Anm2Reference reference
|
|||||||
Anm2Frame* anm2_frame_add(Anm2* self, Anm2Frame* frame, Anm2Reference reference);
|
Anm2Frame* anm2_frame_add(Anm2* self, Anm2Frame* frame, Anm2Reference reference);
|
||||||
Anm2Frame* anm2_frame_from_reference(Anm2* self, Anm2Reference reference);
|
Anm2Frame* anm2_frame_from_reference(Anm2* self, Anm2Reference reference);
|
||||||
Anm2Item* anm2_item_from_reference(Anm2* self, Anm2Reference reference);
|
Anm2Item* anm2_item_from_reference(Anm2* self, Anm2Reference reference);
|
||||||
bool anm2_animation_deserialize_from_xml(Anm2Animation* animation, const std::string& xml);
|
bool anm2_animations_deserialize_from_xml(std::vector<Anm2Animation>& animations, const std::string& xml);
|
||||||
bool anm2_deserialize(Anm2* self, const std::string& path, bool isTextures = true);
|
bool anm2_deserialize(Anm2* self, const std::string& path, bool isTextures = true);
|
||||||
bool anm2_frame_deserialize_from_xml(Anm2Frame* frame, const std::string& xml);
|
bool anm2_frame_deserialize_from_xml(Anm2Frame* frame, const std::string& xml);
|
||||||
bool anm2_serialize(Anm2* self, const std::string& path);
|
bool anm2_serialize(Anm2* self, const std::string& path);
|
||||||
int anm2_animation_add(Anm2* self, Anm2Animation* animation = nullptr, int id = ID_NONE);
|
int anm2_animation_add(Anm2* self, Anm2Animation* animation = nullptr, int index = INDEX_NONE);
|
||||||
int anm2_animation_length_get(Anm2Animation* self);
|
int anm2_animation_length_get(Anm2Animation* self);
|
||||||
int anm2_frame_index_from_time(Anm2* self, Anm2Reference reference, float time);
|
int anm2_frame_index_from_time(Anm2* self, Anm2Reference reference, float time);
|
||||||
int anm2_layer_add(Anm2* self);
|
int anm2_layer_add(Anm2* self);
|
||||||
@@ -244,10 +245,10 @@ vec4 anm2_animation_rect_get(Anm2* anm2, Anm2Reference reference, bool isRootTra
|
|||||||
void anm2_animation_layer_animation_add(Anm2Animation* animation, int id);
|
void anm2_animation_layer_animation_add(Anm2Animation* animation, int id);
|
||||||
void anm2_animation_layer_animation_remove(Anm2Animation* animation, int id);
|
void anm2_animation_layer_animation_remove(Anm2Animation* animation, int id);
|
||||||
void anm2_animation_length_set(Anm2Animation* self);
|
void anm2_animation_length_set(Anm2Animation* self);
|
||||||
void anm2_animation_merge(Anm2* self, int animationID, const std::vector<int>& mergeIDs, Anm2MergeType type);
|
void anm2_animation_merge(Anm2* self, int animationID, std::set<int> mergeIndices, Anm2MergeType type);
|
||||||
void anm2_animation_null_animation_add(Anm2Animation* animation, int id);
|
void anm2_animation_null_animation_add(Anm2Animation* animation, int id);
|
||||||
void anm2_animation_null_animation_remove(Anm2Animation* animation, int id);
|
void anm2_animation_null_animation_remove(Anm2Animation* animation, int id);
|
||||||
void anm2_animation_remove(Anm2* self, int id);
|
void anm2_animations_remove(Anm2* self, const std::set<int> indices);
|
||||||
void anm2_animation_serialize_to_string(Anm2Animation* animation, std::string* string);
|
void anm2_animation_serialize_to_string(Anm2Animation* animation, std::string* string);
|
||||||
void anm2_frame_bake(Anm2* self, Anm2Reference reference, int interval, bool isRoundScale, bool isRoundRotation);
|
void anm2_frame_bake(Anm2* self, Anm2Reference reference, int interval, bool isRoundScale, bool isRoundRotation);
|
||||||
void anm2_frame_from_time(Anm2* self, Anm2Frame* frame, Anm2Reference reference, float time);
|
void anm2_frame_from_time(Anm2* self, Anm2Frame* frame, Anm2Reference reference, float time);
|
||||||
|
|||||||
@@ -10,27 +10,27 @@ void clipboard_copy(Clipboard* self) {
|
|||||||
|
|
||||||
switch (self->type) {
|
switch (self->type) {
|
||||||
case CLIPBOARD_FRAME: {
|
case CLIPBOARD_FRAME: {
|
||||||
Anm2Reference* reference = std::get_if<Anm2Reference>(&self->location);
|
if (Anm2Reference* reference = std::get_if<Anm2Reference>(&self->destination)) {
|
||||||
if (!reference)
|
if (Anm2Frame* frame = anm2_frame_from_reference(self->anm2, *reference)) {
|
||||||
break;
|
anm2_frame_serialize_to_string(frame, reference->itemType, &clipboardText);
|
||||||
Anm2Frame* frame = anm2_frame_from_reference(self->anm2, *reference);
|
clipboard_text_set();
|
||||||
if (!frame)
|
}
|
||||||
break;
|
}
|
||||||
anm2_frame_serialize_to_string(frame, reference->itemType, &clipboardText);
|
|
||||||
clipboard_text_set();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CLIPBOARD_ANIMATION: {
|
case CLIPBOARD_ANIMATION: {
|
||||||
int* id = std::get_if<int>(&self->location);
|
if (std::set<int>* set = std::get_if<std::set<int>>(&self->source)) {
|
||||||
if (!id)
|
for (auto& i : *set) {
|
||||||
break;
|
if (Anm2Animation* animation = anm2_animation_from_reference(self->anm2, {i})) {
|
||||||
Anm2Animation* animation = map_find(self->anm2->animations, *id);
|
std::string animationText{};
|
||||||
if (!animation)
|
anm2_animation_serialize_to_string(animation, &animationText);
|
||||||
break;
|
clipboardText += animationText;
|
||||||
anm2_animation_serialize_to_string(animation, &clipboardText);
|
}
|
||||||
clipboard_text_set();
|
}
|
||||||
|
clipboard_text_set();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
} break;
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -41,17 +41,13 @@ void clipboard_cut(Clipboard* self) {
|
|||||||
|
|
||||||
switch (self->type) {
|
switch (self->type) {
|
||||||
case CLIPBOARD_FRAME: {
|
case CLIPBOARD_FRAME: {
|
||||||
Anm2Reference* reference = std::get_if<Anm2Reference>(&self->location);
|
if (Anm2Reference* reference = std::get_if<Anm2Reference>(&self->destination))
|
||||||
if (!reference)
|
anm2_frame_remove(self->anm2, *reference);
|
||||||
break;
|
|
||||||
anm2_frame_remove(self->anm2, *reference);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CLIPBOARD_ANIMATION: {
|
case CLIPBOARD_ANIMATION: {
|
||||||
int* id = std::get_if<int>(&self->location);
|
if (std::set<int>* set = std::get_if<std::set<int>>(&self->source))
|
||||||
if (!id)
|
anm2_animations_remove(self->anm2, *set);
|
||||||
break;
|
|
||||||
anm2_animation_remove(self->anm2, *id);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -69,25 +65,25 @@ bool clipboard_paste(Clipboard* self) {
|
|||||||
|
|
||||||
switch (self->type) {
|
switch (self->type) {
|
||||||
case CLIPBOARD_FRAME: {
|
case CLIPBOARD_FRAME: {
|
||||||
Anm2Reference* reference = std::get_if<Anm2Reference>(&self->location);
|
if (Anm2Reference* reference = std::get_if<Anm2Reference>(&self->destination)) {
|
||||||
if (!reference)
|
Anm2Frame frame;
|
||||||
break;
|
if (!anm2_frame_deserialize_from_xml(&frame, clipboard_string()))
|
||||||
Anm2Frame frame;
|
return false;
|
||||||
if (anm2_frame_deserialize_from_xml(&frame, clipboard_string()))
|
|
||||||
anm2_frame_add(self->anm2, &frame, *reference);
|
anm2_frame_add(self->anm2, &frame, *reference);
|
||||||
else
|
}
|
||||||
return false;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CLIPBOARD_ANIMATION: {
|
case CLIPBOARD_ANIMATION: {
|
||||||
int* id = std::get_if<int>(&self->location);
|
if (int* index = std::get_if<int>(&self->destination)) {
|
||||||
if (!id)
|
std::vector<Anm2Animation> clipboardAnimations;
|
||||||
break;
|
if (!anm2_animations_deserialize_from_xml(clipboardAnimations, clipboard_string()))
|
||||||
Anm2Animation animation;
|
return false;
|
||||||
if (anm2_animation_deserialize_from_xml(&animation, clipboard_string()))
|
|
||||||
anm2_animation_add(self->anm2, &animation, *id);
|
int useIndex = std::clamp(*index + 1, 0, (int)self->anm2->animations.size());
|
||||||
else
|
|
||||||
return false;
|
for (auto& animation : clipboardAnimations)
|
||||||
|
anm2_animation_add(self->anm2, &animation, useIndex++);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -98,5 +94,4 @@ bool clipboard_paste(Clipboard* self) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void clipboard_init(Clipboard* self, Anm2* anm2) { self->anm2 = anm2; }
|
void clipboard_init(Clipboard* self, Anm2* anm2) { self->anm2 = anm2; }
|
||||||
|
|
||||||
bool clipboard_is_value(void) { return SDL_HasClipboardText(); }
|
bool clipboard_is_value(void) { return SDL_HasClipboardText(); }
|
||||||
@@ -1,17 +1,19 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "anm2.h"
|
#include "anm2.h"
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
#define CLIPBOARD_TEXT_SET_WARNING "Unable to set clipboard text! ({})"
|
#define CLIPBOARD_TEXT_SET_WARNING "Unable to set clipboard text! ({})"
|
||||||
|
|
||||||
enum ClipboardType { CLIPBOARD_NONE, CLIPBOARD_FRAME, CLIPBOARD_ANIMATION };
|
enum ClipboardType { CLIPBOARD_NONE, CLIPBOARD_FRAME, CLIPBOARD_ANIMATION };
|
||||||
|
|
||||||
using ClipboardLocation = std::variant<std::monostate, Anm2Reference, int>;
|
using ClipboardValue = std::variant<std::monostate, Anm2Reference, std::set<int>, int>;
|
||||||
|
|
||||||
struct Clipboard {
|
struct Clipboard {
|
||||||
Anm2* anm2 = nullptr;
|
Anm2* anm2 = nullptr;
|
||||||
ClipboardType type;
|
ClipboardType type;
|
||||||
ClipboardLocation location;
|
ClipboardValue source;
|
||||||
|
ClipboardValue destination;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool clipboard_is_value(void);
|
bool clipboard_is_value(void);
|
||||||
|
|||||||
795
src/imgui.cpp
795
src/imgui.cpp
File diff suppressed because it is too large
Load Diff
168
src/imgui.h
168
src/imgui.h
@@ -12,11 +12,9 @@
|
|||||||
#include "snapshots.h"
|
#include "snapshots.h"
|
||||||
#include "tool.h"
|
#include "tool.h"
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
|
#include <SDL3/SDL_mouse.h>
|
||||||
|
|
||||||
#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
|
||||||
#define IMGUI_DEBUG_PARANOID
|
|
||||||
#define IMGUI_IMPL_OPENGL_LOADER_CUSTOM
|
#define IMGUI_IMPL_OPENGL_LOADER_CUSTOM
|
||||||
#define IMGUI_ENABLE_DOCKING
|
|
||||||
#define IM_VEC2_CLASS_EXTRA \
|
#define IM_VEC2_CLASS_EXTRA \
|
||||||
inline bool operator==(const ImVec2& rhs) const { return x == rhs.x && y == rhs.y; } \
|
inline bool operator==(const ImVec2& rhs) const { return x == rhs.x && y == rhs.y; } \
|
||||||
inline bool operator!=(const ImVec2& rhs) const { return !(*this == rhs); } \
|
inline bool operator!=(const ImVec2& rhs) const { return !(*this == rhs); } \
|
||||||
@@ -83,7 +81,6 @@
|
|||||||
#define IMGUI_CHORD_NONE (ImGuiMod_None)
|
#define IMGUI_CHORD_NONE (ImGuiMod_None)
|
||||||
#define IMGUI_FRAME_BORDER 2.0f
|
#define IMGUI_FRAME_BORDER 2.0f
|
||||||
#define IMGUI_LOG_DURATION 3.0f
|
#define IMGUI_LOG_DURATION 3.0f
|
||||||
#define IMGUI_LOG_PADDING 10.0f
|
|
||||||
#define IMGUI_TEXT_HEIGHT_PADDING 4.0f
|
#define IMGUI_TEXT_HEIGHT_PADDING 4.0f
|
||||||
#define IMGUI_PLAYHEAD_LINE_COLOR IM_COL32(UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX)
|
#define IMGUI_PLAYHEAD_LINE_COLOR IM_COL32(UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX)
|
||||||
#define IMGUI_TRIGGERS_EVENT_COLOR IM_COL32(UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, 128)
|
#define IMGUI_TRIGGERS_EVENT_COLOR IM_COL32(UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, 128)
|
||||||
@@ -97,7 +94,7 @@
|
|||||||
#define IMGUI_ACTION_FRAME_CROP "Frame Crop"
|
#define IMGUI_ACTION_FRAME_CROP "Frame Crop"
|
||||||
#define IMGUI_ACTION_FRAME_MOVE "Frame Move"
|
#define IMGUI_ACTION_FRAME_MOVE "Frame Move"
|
||||||
|
|
||||||
#define IMGUI_ACTION_ANIMATION_SWAP "Animation Swap"
|
#define IMGUI_ACTION_ANIMATION_MOVE "Move Animation"
|
||||||
#define IMGUI_ACTION_TRIGGER_MOVE "Trigger At Frame"
|
#define IMGUI_ACTION_TRIGGER_MOVE "Trigger At Frame"
|
||||||
#define IMGUI_ACTION_ITEM_SWAP "Item Swap"
|
#define IMGUI_ACTION_ITEM_SWAP "Item Swap"
|
||||||
#define IMGUI_ACTION_FRAME_DELAY "Frame Delay"
|
#define IMGUI_ACTION_FRAME_DELAY "Frame Delay"
|
||||||
@@ -140,7 +137,11 @@
|
|||||||
#define IMGUI_LOG_ANIMATION_PASTE_ERROR "Failed to parse clipboard text as an animation."
|
#define IMGUI_LOG_ANIMATION_PASTE_ERROR "Failed to parse clipboard text as an animation."
|
||||||
#define IMGUI_LOG_FRAME_PASTE_ERROR "Failed to parse clipboard text as a frame."
|
#define IMGUI_LOG_FRAME_PASTE_ERROR "Failed to parse clipboard text as a frame."
|
||||||
#define IMGUI_LOG_RELOAD_SPRITESHEET "Reloaded spritesheet(s)."
|
#define IMGUI_LOG_RELOAD_SPRITESHEET "Reloaded spritesheet(s)."
|
||||||
|
#define IMGUI_LOG_REMOVE_UNUSED_SPRITESHEETS "Removed unused spritesheet(s)."
|
||||||
|
#define IMGUI_LOG_REMOVE_UNUSED_EVENTS "Removed unused event(s)."
|
||||||
#define IMGUI_LOG_ADD_SPRITESHEET_ERROR "Failed to add spritesheet: {}. Make sure it's a valid PNG file."
|
#define IMGUI_LOG_ADD_SPRITESHEET_ERROR "Failed to add spritesheet: {}. Make sure it's a valid PNG file."
|
||||||
|
#define IMGUI_LOG_ADD_SPRITESHEET "Added spritesheet #{}: {}"
|
||||||
|
#define IMGUI_LOG_REPLACE_SPRITESHEET "Replaced spritesheet #{}: {}"
|
||||||
|
|
||||||
#define IMGUI_NONE "None"
|
#define IMGUI_NONE "None"
|
||||||
#define IMGUI_ANIMATION_DEFAULT_FORMAT "(*) {}"
|
#define IMGUI_ANIMATION_DEFAULT_FORMAT "(*) {}"
|
||||||
@@ -168,6 +169,8 @@
|
|||||||
|
|
||||||
#define IMGUI_TRIGGERS_FONT_SCALE 2.0
|
#define IMGUI_TRIGGERS_FONT_SCALE 2.0
|
||||||
|
|
||||||
|
const ImVec2 IMGUI_TOOL_BUTTON_SIZE = {24, 24};
|
||||||
|
const ImVec2 IMGUI_TOOL_COLOR_SIZE = {24, 24};
|
||||||
const ImVec2 IMGUI_TIMELINE_FRAME_SIZE = {12, 36};
|
const ImVec2 IMGUI_TIMELINE_FRAME_SIZE = {12, 36};
|
||||||
const ImVec2 IMGUI_TIMELINE_FRAME_ATLAS_OFFSET = {ATLAS_SIZE_SMALL.x * 0.25f, (IMGUI_TIMELINE_FRAME_SIZE.y * 0.5f) - (ATLAS_SIZE_SMALL.y * 0.5f)};
|
const ImVec2 IMGUI_TIMELINE_FRAME_ATLAS_OFFSET = {ATLAS_SIZE_SMALL.x * 0.25f, (IMGUI_TIMELINE_FRAME_SIZE.y * 0.5f) - (ATLAS_SIZE_SMALL.y * 0.5f)};
|
||||||
const ImVec2 IMGUI_TIMELINE_ITEM_SELECTABLE_SIZE = {150, 0};
|
const ImVec2 IMGUI_TIMELINE_ITEM_SELECTABLE_SIZE = {150, 0};
|
||||||
@@ -198,6 +201,8 @@ const ImGuiKey IMGUI_INPUT_ZOOM_OUT = ImGuiKey_2;
|
|||||||
const ImGuiKey IMGUI_INPUT_ENTER = ImGuiKey_Enter;
|
const ImGuiKey IMGUI_INPUT_ENTER = ImGuiKey_Enter;
|
||||||
const ImGuiKey IMGUI_INPUT_RENAME = ImGuiKey_F2;
|
const ImGuiKey IMGUI_INPUT_RENAME = ImGuiKey_F2;
|
||||||
const ImGuiKey IMGUI_INPUT_DEFAULT = ImGuiKey_Home;
|
const ImGuiKey IMGUI_INPUT_DEFAULT = ImGuiKey_Home;
|
||||||
|
const ImGuiKeyChord IMGUI_CHORD_SELECT_ALL = ImGuiMod_Ctrl | ImGuiKey_A;
|
||||||
|
const ImGuiKeyChord IMGUI_CHORD_SELECT_NONE = ImGuiKey_Escape;
|
||||||
const ImGuiMouseButton IMGUI_MOUSE_DEFAULT = ImGuiMouseButton_Middle;
|
const ImGuiMouseButton IMGUI_MOUSE_DEFAULT = ImGuiMouseButton_Middle;
|
||||||
|
|
||||||
enum ImguiPopupType { IMGUI_POPUP_NONE, IMGUI_POPUP_BY_ITEM, IMGUI_POPUP_CENTER_WINDOW };
|
enum ImguiPopupType { IMGUI_POPUP_NONE, IMGUI_POPUP_BY_ITEM, IMGUI_POPUP_CENTER_WINDOW };
|
||||||
@@ -228,14 +233,22 @@ struct Imgui {
|
|||||||
Clipboard* clipboard = nullptr;
|
Clipboard* clipboard = nullptr;
|
||||||
SDL_Window* window = nullptr;
|
SDL_Window* window = nullptr;
|
||||||
SDL_GLContext* glContext = nullptr;
|
SDL_GLContext* glContext = nullptr;
|
||||||
|
Anm2 saveAnm2 = Anm2();
|
||||||
|
ImFont* fonts[FONT_COUNT] = {};
|
||||||
|
ImGuiStyle style;
|
||||||
|
std::vector<ImguiLogItem> log{};
|
||||||
std::string pendingPopup{};
|
std::string pendingPopup{};
|
||||||
ImguiPopupType pendingPopupType = IMGUI_POPUP_NONE;
|
ImguiPopupType pendingPopupType = IMGUI_POPUP_NONE;
|
||||||
ImVec2 pendingPopupPosition{};
|
ImVec2 pendingPopupPosition{};
|
||||||
std::vector<ImguiLogItem> log;
|
std::set<int> selectedAnimationIndices{};
|
||||||
ImGuiStyle style;
|
int lastAnimationIndex = ID_NONE;
|
||||||
Anm2 saveAnm2;
|
std::set<int> selectedSpritesheetIDs{};
|
||||||
SDL_SystemCursor cursor;
|
int lastSpritesheetID = ID_NONE;
|
||||||
SDL_SystemCursor pendingCursor;
|
int selectedEventID = ID_NONE;
|
||||||
|
int selectedLayerID = ID_NONE;
|
||||||
|
int selectedNullID = ID_NONE;
|
||||||
|
SDL_SystemCursor cursor = SDL_SYSTEM_CURSOR_DEFAULT;
|
||||||
|
SDL_SystemCursor pendingCursor = SDL_SYSTEM_CURSOR_DEFAULT;
|
||||||
bool isCursorSet = false;
|
bool isCursorSet = false;
|
||||||
bool isContextualActionsEnabled = true;
|
bool isContextualActionsEnabled = true;
|
||||||
bool isQuit = false;
|
bool isQuit = false;
|
||||||
@@ -254,9 +267,12 @@ static void imgui_log_push(Imgui* self, const std::string& text) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void imgui_anm2_new(Imgui* self) {
|
static inline void imgui_anm2_new(Imgui* self) {
|
||||||
*self->reference = Anm2Reference();
|
|
||||||
anm2_free(self->anm2);
|
anm2_free(self->anm2);
|
||||||
anm2_new(self->anm2);
|
anm2_new(self->anm2);
|
||||||
|
|
||||||
|
*self->reference = Anm2Reference();
|
||||||
|
self->selectedAnimationIndices = {};
|
||||||
|
self->selectedSpritesheetIDs = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void imgui_file_open(Imgui* self) { dialog_anm2_open(self->dialog); }
|
static inline void imgui_file_open(Imgui* self) { dialog_anm2_open(self->dialog); }
|
||||||
@@ -576,7 +592,8 @@ enum ImguiItemType {
|
|||||||
IMGUI_ITEM,
|
IMGUI_ITEM,
|
||||||
IMGUI_TEXT,
|
IMGUI_TEXT,
|
||||||
IMGUI_IMAGE,
|
IMGUI_IMAGE,
|
||||||
IMGUI_WINDOW,
|
IMGUI_BEGIN_WINDOW,
|
||||||
|
IMGUI_END_WINDOW,
|
||||||
IMGUI_DOCKSPACE,
|
IMGUI_DOCKSPACE,
|
||||||
IMGUI_BEGIN_CHILD,
|
IMGUI_BEGIN_CHILD,
|
||||||
IMGUI_END_CHILD,
|
IMGUI_END_CHILD,
|
||||||
@@ -611,6 +628,7 @@ static ImGuiKeyChord* imgui_hotkey_chord_registry(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
typedef void (*ImguiFunction)(Imgui*);
|
typedef void (*ImguiFunction)(Imgui*);
|
||||||
|
using IntStringMap = std::map<int, std::string>;
|
||||||
|
|
||||||
#define IMGUI_ITEM_MEMBERS \
|
#define IMGUI_ITEM_MEMBERS \
|
||||||
X(label, std::string, false, {}) \
|
X(label, std::string, false, {}) \
|
||||||
@@ -619,14 +637,16 @@ typedef void (*ImguiFunction)(Imgui*);
|
|||||||
X(popup, std::string, false, {}) \
|
X(popup, std::string, false, {}) \
|
||||||
X(dragDrop, std::string, true, {}) \
|
X(dragDrop, std::string, true, {}) \
|
||||||
X(focusWindow, std::string, true, {}) \
|
X(focusWindow, std::string, true, {}) \
|
||||||
X(items, std::vector<std::string>, false, {}) \
|
X(items, IntStringMap, false, {}) \
|
||||||
X(atlas, AtlasType, false, ATLAS_NONE) \
|
X(atlas, AtlasType, false, ATLAS_NONE) \
|
||||||
X(textureID, int, false, ID_NONE) \
|
X(textureID, int, false, ID_NONE) \
|
||||||
X(chord, ImGuiKeyChord, true, {}) \
|
X(chord, ImGuiKeyChord, true, {}) \
|
||||||
X(hotkey, HotkeyType, true, {}) \
|
X(hotkey, HotkeyType, true, {}) \
|
||||||
X(mnemonicKey, ImGuiKey, false, ImGuiKey_None) \
|
X(mnemonicKey, ImGuiKey, false, ImGuiKey_None) \
|
||||||
X(mnemonicIndex, int, false, INDEX_NONE) \
|
X(mnemonicIndex, int, false, INDEX_NONE) \
|
||||||
|
X(position, vec2, true, {}) \
|
||||||
X(size, vec2, true, {}) \
|
X(size, vec2, true, {}) \
|
||||||
|
X(scale, float, false, 1.0f) \
|
||||||
X(uvMin, vec2, false, vec2()) \
|
X(uvMin, vec2, false, vec2()) \
|
||||||
X(uvMax, vec2, false, vec2(1.0f)) \
|
X(uvMax, vec2, false, vec2(1.0f)) \
|
||||||
X(popupSize, vec2, false, {}) \
|
X(popupSize, vec2, false, {}) \
|
||||||
@@ -638,9 +658,12 @@ typedef void (*ImguiFunction)(Imgui*);
|
|||||||
X(isMnemonicDisabled, bool, false, false) \
|
X(isMnemonicDisabled, bool, false, false) \
|
||||||
X(isEmptyFormat, bool, false, false) \
|
X(isEmptyFormat, bool, false, false) \
|
||||||
X(isUseItemActivated, bool, false, false) \
|
X(isUseItemActivated, bool, false, false) \
|
||||||
X(isSizeToText, bool, false, false) \
|
X(isWidthToText, bool, false, false) \
|
||||||
X(isSizeToRegion, bool, false, false) \
|
X(isWidthToRegion, bool, false, false) \
|
||||||
|
X(isHeightToRegion, bool, false, false) \
|
||||||
X(isHotkeyInLabel, bool, false, false) \
|
X(isHotkeyInLabel, bool, false, false) \
|
||||||
|
X(isAllowHotkeyWhenFocusWindow, bool, false, false) \
|
||||||
|
X(isAtlasStretch, bool, false, false) \
|
||||||
X(isSameLine, bool, false, false) \
|
X(isSameLine, bool, false, false) \
|
||||||
X(isSeparator, bool, false, false) \
|
X(isSeparator, bool, false, false) \
|
||||||
X(id, int, false, 0) \
|
X(id, int, false, 0) \
|
||||||
@@ -651,16 +674,19 @@ typedef void (*ImguiFunction)(Imgui*);
|
|||||||
X(min, int, true, {}) \
|
X(min, int, true, {}) \
|
||||||
X(max, int, true, {}) \
|
X(max, int, true, {}) \
|
||||||
X(value, int, false, {}) \
|
X(value, int, false, {}) \
|
||||||
X(atlasOffset, vec2, false, {}) \
|
X(atlasOffset, vec2, true, {}) \
|
||||||
X(cursorPosition, vec2, true, {}) \
|
X(cursorPosition, vec2, true, {}) \
|
||||||
X(cursorOffset, vec2, false, {}) \
|
X(cursorOffset, vec2, false, {}) \
|
||||||
|
X(textPosition, vec2, true, {}) \
|
||||||
|
X(textOffset, vec2, false, {}) \
|
||||||
X(itemSpacing, vec2, true, {}) \
|
X(itemSpacing, vec2, true, {}) \
|
||||||
X(windowPadding, vec2, true, {}) \
|
X(windowPadding, vec2, true, {}) \
|
||||||
X(framePadding, vec2, true, {}) \
|
X(framePadding, vec2, true, {}) \
|
||||||
X(border, int, true, {}) \
|
X(border, int, true, {}) \
|
||||||
X(flags, int, false, {}) \
|
X(flags, int, false, {}) \
|
||||||
X(windowFlags, int, false, {}) \
|
X(windowFlags, int, false, {}) \
|
||||||
X(rowCount, int, true, {})
|
X(rowCount, int, true, {}) \
|
||||||
|
X(font, ImFont*, true, {})
|
||||||
|
|
||||||
struct ImguiItemOverride {
|
struct ImguiItemOverride {
|
||||||
#define X(name, type, isOptional, ...) std::optional<type> name = {};
|
#define X(name, type, isOptional, ...) std::optional<type> name = {};
|
||||||
@@ -714,6 +740,8 @@ struct ImguiItem {
|
|||||||
IMGUI_ITEM_MEMBERS
|
IMGUI_ITEM_MEMBERS
|
||||||
#undef X
|
#undef X
|
||||||
|
|
||||||
|
out.id += out.idOffset;
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -761,27 +789,27 @@ IMGUI_ITEM(IMGUI_TASKBAR, self.label = "Taskbar", self.size = {0, 32},
|
|||||||
ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoSavedSettings);
|
ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoSavedSettings);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_FILE, self.label = "&File", self.tooltip = "Opens the file menu, for reading/writing anm2 files.", self.popup = "## File Popup",
|
IMGUI_ITEM(IMGUI_FILE, self.label = "&File", self.tooltip = "Opens the file menu, for reading/writing anm2 files.", self.popup = "## File Popup",
|
||||||
self.popupType = IMGUI_POPUP_BY_ITEM, self.isSizeToText = true, self.isSameLine = true);
|
self.popupType = IMGUI_POPUP_BY_ITEM, self.isWidthToText = true, self.isHeightToRegion = true, self.isSameLine = true);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_NEW, self.label = "&New", self.tooltip = "Load a blank .anm2 file to edit.", self.function = imgui_file_new, self.hotkey = HOTKEY_NEW,
|
IMGUI_ITEM(IMGUI_NEW, self.label = "&New", self.tooltip = "Load a blank .anm2 file to edit.", self.function = imgui_file_new, self.hotkey = HOTKEY_NEW,
|
||||||
self.isSizeToText = true, self.isHotkeyInLabel = true);
|
self.isWidthToRegion = true, self.isHotkeyInLabel = true);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_OPEN, self.label = "&Open", self.tooltip = "Open an existing .anm2 file to edit.", self.function = imgui_file_open, self.hotkey = HOTKEY_OPEN,
|
IMGUI_ITEM(IMGUI_OPEN, self.label = "&Open", self.tooltip = "Open an existing .anm2 file to edit.", self.function = imgui_file_open, self.hotkey = HOTKEY_OPEN,
|
||||||
self.isSizeToText = true, self.isHotkeyInLabel = true);
|
self.isWidthToRegion = true, self.isHotkeyInLabel = true);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_SAVE, self.label = "&Save",
|
IMGUI_ITEM(IMGUI_SAVE, self.label = "&Save",
|
||||||
self.tooltip = "Saves the current .anm2 file to its path.\nIf no "
|
self.tooltip = "Saves the current .anm2 file to its path.\nIf no "
|
||||||
"path exists, one can be chosen.",
|
"path exists, one can be chosen.",
|
||||||
self.function = imgui_file_save, self.hotkey = HOTKEY_SAVE, self.isSizeToText = true, self.isHotkeyInLabel = true);
|
self.function = imgui_file_save, self.hotkey = HOTKEY_SAVE, self.isWidthToText = true, self.isHotkeyInLabel = true);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_SAVE_AS, self.label = "S&ave As", self.tooltip = "Saves the current .anm2 file to a chosen path.", self.function = imgui_file_save_as,
|
IMGUI_ITEM(IMGUI_SAVE_AS, self.label = "S&ave As", self.tooltip = "Saves the current .anm2 file to a chosen path.", self.function = imgui_file_save_as,
|
||||||
self.hotkey = HOTKEY_SAVE_AS, self.isSizeToText = true, self.isHotkeyInLabel = true);
|
self.hotkey = HOTKEY_SAVE_AS, self.isWidthToText = true, self.isHotkeyInLabel = true);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_EXPLORE_ANM2_LOCATION, self.label = "E&xplore Anm2 Location", self.tooltip = "Open the system's file explorer in the anm2's path.",
|
IMGUI_ITEM(IMGUI_EXPLORE_ANM2_LOCATION, self.label = "E&xplore Anm2 Location", self.tooltip = "Open the system's file explorer in the anm2's path.",
|
||||||
self.function = imgui_explore, self.isSizeToText = true, self.isSeparator = true);
|
self.function = imgui_explore, self.isWidthToText = true, self.isSeparator = true);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_EXIT, self.label = "&Exit", self.tooltip = "Exits the program.", self.function = imgui_quit, self.hotkey = HOTKEY_EXIT,
|
IMGUI_ITEM(IMGUI_EXIT, self.label = "&Exit", self.tooltip = "Exits the program.", self.function = imgui_quit, self.hotkey = HOTKEY_EXIT,
|
||||||
self.isSizeToText = true, self.isHotkeyInLabel = true);
|
self.isWidthToText = true, self.isHotkeyInLabel = true);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_EXIT_CONFIRMATION, self.label = "Exit Confirmation", self.tooltip = "Unsaved changes will be lost!\nAre you sure you want to exit?");
|
IMGUI_ITEM(IMGUI_EXIT_CONFIRMATION, self.label = "Exit Confirmation", self.tooltip = "Unsaved changes will be lost!\nAre you sure you want to exit?");
|
||||||
|
|
||||||
@@ -790,7 +818,8 @@ IMGUI_ITEM(IMGUI_OPEN_CONFIRMATION, self.label = "Open Confirmation", self.toolt
|
|||||||
IMGUI_ITEM(IMGUI_NO_ANM2_PATH_CONFIRMATION, self.label = "No Anm2 Path", self.tooltip = "You will need to load or make a new .anm2 file first!\n");
|
IMGUI_ITEM(IMGUI_NO_ANM2_PATH_CONFIRMATION, self.label = "No Anm2 Path", self.tooltip = "You will need to load or make a new .anm2 file first!\n");
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_WIZARD, self.label = "&Wizard", self.tooltip = "Opens the wizard menu, for neat functions related to the .anm2.",
|
IMGUI_ITEM(IMGUI_WIZARD, self.label = "&Wizard", self.tooltip = "Opens the wizard menu, for neat functions related to the .anm2.",
|
||||||
self.popup = "## Wizard Popup", self.popupType = IMGUI_POPUP_BY_ITEM, self.isSizeToText = true, self.isSameLine = true);
|
self.popup = "## Wizard Popup", self.popupType = IMGUI_POPUP_BY_ITEM, self.isHeightToRegion = true, self.isWidthToText = true,
|
||||||
|
self.isSameLine = true);
|
||||||
|
|
||||||
#define IMGUI_GENERATE_ANIMATION_FROM_GRID_PADDING 40
|
#define IMGUI_GENERATE_ANIMATION_FROM_GRID_PADDING 40
|
||||||
IMGUI_ITEM(IMGUI_GENERATE_ANIMATION_FROM_GRID, self.label = "&Generate Animation from Grid", self.tooltip = "Generate a new animation from grid values.",
|
IMGUI_ITEM(IMGUI_GENERATE_ANIMATION_FROM_GRID, self.label = "&Generate Animation from Grid", self.tooltip = "Generate a new animation from grid values.",
|
||||||
@@ -875,11 +904,10 @@ IMGUI_ITEM(IMGUI_CHANGE_ALL_FRAME_PROPERTIES_CANCEL, self.label = "Cancel", self
|
|||||||
self.rowCount = IMGUI_CHANGE_ALL_FRAME_PROPERTIES_OPTIONS_ROW_COUNT);
|
self.rowCount = IMGUI_CHANGE_ALL_FRAME_PROPERTIES_OPTIONS_ROW_COUNT);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_SCALE_ANM2, self.label = "S&cale Anm2", self.tooltip = "Scale up all size and position-related frame properties in the anm2.",
|
IMGUI_ITEM(IMGUI_SCALE_ANM2, self.label = "S&cale Anm2", self.tooltip = "Scale up all size and position-related frame properties in the anm2.",
|
||||||
self.popup = "Scale Anm2", self.popupType = IMGUI_POPUP_CENTER_WINDOW, self.popupSize = {260, 75}, self.isSizeToText = true,
|
self.popup = "Scale Anm2", self.popupType = IMGUI_POPUP_CENTER_WINDOW, self.popupSize = {260, 75}, self.isWidthToText = true,
|
||||||
self.isSeparator = true);
|
self.isSeparator = true);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_SCALE_ANM2_OPTIONS_CHILD, self.label = "## Scale Anm2 Options Child",
|
IMGUI_ITEM(IMGUI_SCALE_ANM2_OPTIONS_CHILD, self.label = "## Scale Anm2 Options Child", self.flags = true);
|
||||||
self.size = {IMGUI_SCALE_ANM2.popupSize.x, IMGUI_SCALE_ANM2.popupSize.y - IMGUI_FOOTER_CHILD.size->y}, self.flags = true);
|
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_SCALE_ANM2_VALUE, self.label = "Value",
|
IMGUI_ITEM(IMGUI_SCALE_ANM2_VALUE, self.label = "Value",
|
||||||
self.tooltip = "The size and position-related frame properties in "
|
self.tooltip = "The size and position-related frame properties in "
|
||||||
@@ -894,11 +922,9 @@ IMGUI_ITEM(IMGUI_RENDER_ANIMATION, self.label = "&Render Animation",
|
|||||||
"options can be customized.",
|
"options can be customized.",
|
||||||
self.popup = "Render Animation", self.popupSize = {500, 170}, self.popupType = IMGUI_POPUP_CENTER_WINDOW);
|
self.popup = "Render Animation", self.popupSize = {500, 170}, self.popupType = IMGUI_POPUP_CENTER_WINDOW);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_RENDER_ANIMATION_CHILD, self.label = "## Render Animation Child",
|
IMGUI_ITEM(IMGUI_RENDER_ANIMATION_CHILD, self.label = "## Render Animation Child", self.flags = true);
|
||||||
self.size = {IMGUI_RENDER_ANIMATION.popupSize.x, IMGUI_RENDER_ANIMATION.popupSize.y - IMGUI_FOOTER_CHILD.size->y}, self.flags = true);
|
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_RENDER_ANIMATION_FOOTER_CHILD, self.label = "## Render Animation Footer Child",
|
IMGUI_ITEM(IMGUI_RENDER_ANIMATION_FOOTER_CHILD, self.label = "## Render Animation Footer Child", self.flags = true);
|
||||||
self.size = {IMGUI_RENDER_ANIMATION.popupSize.x, IMGUI_FOOTER_CHILD.size->y}, self.flags = true);
|
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_RENDER_ANIMATION_LOCATION_BROWSE, self.label = "## Location Browse", self.tooltip = "Open file explorer to pick rendered animation location.",
|
IMGUI_ITEM(IMGUI_RENDER_ANIMATION_LOCATION_BROWSE, self.label = "## Location Browse", self.tooltip = "Open file explorer to pick rendered animation location.",
|
||||||
self.atlas = ATLAS_FOLDER, self.isSameLine = true);
|
self.atlas = ATLAS_FOLDER, self.isSameLine = true);
|
||||||
@@ -920,7 +946,11 @@ IMGUI_ITEM(IMGUI_RENDER_ANIMATION_FFMPEG_PATH, self.label = "FFmpeg Path",
|
|||||||
IMGUI_ITEM(IMGUI_RENDER_ANIMATION_OUTPUT, self.label = "Output",
|
IMGUI_ITEM(IMGUI_RENDER_ANIMATION_OUTPUT, self.label = "Output",
|
||||||
self.tooltip = "Select the rendered animation output.\nIt can either be "
|
self.tooltip = "Select the rendered animation output.\nIt can either be "
|
||||||
"one animated image or a sequence of frames.",
|
"one animated image or a sequence of frames.",
|
||||||
self.items = {std::begin(RENDER_TYPE_STRINGS), std::end(RENDER_TYPE_STRINGS)}, self.value = RENDER_PNG);
|
self.items = {{RENDER_PNG, RENDER_TYPE_STRINGS[RENDER_PNG]},
|
||||||
|
{RENDER_GIF, RENDER_TYPE_STRINGS[RENDER_GIF]},
|
||||||
|
{RENDER_WEBM, RENDER_TYPE_STRINGS[RENDER_WEBM]},
|
||||||
|
{RENDER_MP4, RENDER_TYPE_STRINGS[RENDER_MP4]}},
|
||||||
|
self.value = RENDER_PNG);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_RENDER_ANIMATION_FORMAT, self.label = "Format",
|
IMGUI_ITEM(IMGUI_RENDER_ANIMATION_FORMAT, self.label = "Format",
|
||||||
self.tooltip = "(PNG images only).\nSet the format of each output frame; i.e., "
|
self.tooltip = "(PNG images only).\nSet the format of each output frame; i.e., "
|
||||||
@@ -950,28 +980,29 @@ IMGUI_ITEM(IMGUI_RENDERING_ANIMATION_INFO, self.label = "Recording frames. Once
|
|||||||
IMGUI_ITEM(IMGUI_RENDERING_ANIMATION_CANCEL, self.label = "Cancel", self.tooltip = "Cancel rendering the animation.", self.rowCount = 1);
|
IMGUI_ITEM(IMGUI_RENDERING_ANIMATION_CANCEL, self.label = "Cancel", self.tooltip = "Cancel rendering the animation.", self.rowCount = 1);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_PLAYBACK, self.label = "&Playback", self.tooltip = "Opens the playback menu, for configuring playback settings.",
|
IMGUI_ITEM(IMGUI_PLAYBACK, self.label = "&Playback", self.tooltip = "Opens the playback menu, for configuring playback settings.",
|
||||||
self.popup = "## Playback Popup", self.popupType = IMGUI_POPUP_BY_ITEM, self.isSizeToText = true, self.isSameLine = true);
|
self.popup = "## Playback Popup", self.popupType = IMGUI_POPUP_BY_ITEM, self.isWidthToText = true, self.isHeightToRegion = true,
|
||||||
|
self.isSameLine = true);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_ALWAYS_LOOP, self.label = "&Always Loop",
|
IMGUI_ITEM(IMGUI_ALWAYS_LOOP, self.label = "&Always Loop",
|
||||||
self.tooltip = "Sets the animation playback to always loop, "
|
self.tooltip = "Sets the animation playback to always loop, "
|
||||||
"regardless of the animation's loop setting.",
|
"regardless of the animation's loop setting.",
|
||||||
self.isSizeToText = true);
|
self.isWidthToText = true);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_CLAMP_PLAYHEAD, self.label = "&Clamp Playhead",
|
IMGUI_ITEM(IMGUI_CLAMP_PLAYHEAD, self.label = "&Clamp Playhead",
|
||||||
self.tooltip = "The playhead (draggable icon on timeline) won't be "
|
self.tooltip = "The playhead (draggable icon on timeline) won't be "
|
||||||
"able to exceed the animation length.",
|
"able to exceed the animation length.",
|
||||||
self.isSizeToText = true);
|
self.isWidthToText = true);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_SETTINGS, self.label = "&Settings", self.tooltip = "Opens the setting menu, for configuring general program settings.",
|
IMGUI_ITEM(IMGUI_SETTINGS, self.label = "&Settings", self.tooltip = "Opens the setting menu, for configuring general program settings.",
|
||||||
self.popup = "## Settings Popup", self.popupType = IMGUI_POPUP_BY_ITEM, self.isSizeToText = true);
|
self.popup = "## Settings Popup", self.popupType = IMGUI_POPUP_BY_ITEM, self.isWidthToText = true, self.isHeightToRegion = true);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_VSYNC, self.label = "&Vsync",
|
IMGUI_ITEM(IMGUI_VSYNC, self.label = "&Vsync",
|
||||||
self.tooltip = "Toggle vertical sync; synchronizes program "
|
self.tooltip = "Toggle vertical sync; synchronizes program "
|
||||||
"framerate with your monitor's refresh rate.",
|
"framerate with your monitor's refresh rate.",
|
||||||
self.isSizeToText = true, self.isSeparator = true);
|
self.isWidthToText = true, self.isSeparator = true);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_HOTKEYS, self.label = "&Hotkeys", self.tooltip = "Change the program's hotkeys.", self.popup = "Hotkeys", self.popupSize = {500, 405},
|
IMGUI_ITEM(IMGUI_HOTKEYS, self.label = "&Hotkeys", self.tooltip = "Change the program's hotkeys.", self.popup = "Hotkeys", self.popupSize = {500, 405},
|
||||||
self.isSizeToText = true, self.isSeparator = true);
|
self.isWidthToText = true, self.isSeparator = true);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_HOTKEYS_CHILD, self.label = "## Hotkeys Child", self.size = {IMGUI_HOTKEYS.popupSize.x, IMGUI_HOTKEYS.popupSize.y - 35}, self.flags = true);
|
IMGUI_ITEM(IMGUI_HOTKEYS_CHILD, self.label = "## Hotkeys Child", self.size = {IMGUI_HOTKEYS.popupSize.x, IMGUI_HOTKEYS.popupSize.y - 35}, self.flags = true);
|
||||||
|
|
||||||
@@ -984,12 +1015,18 @@ IMGUI_ITEM(IMGUI_HOTKEYS_OPTIONS_CHILD, self.label = "## Merge Options Child", s
|
|||||||
IMGUI_ITEM(IMGUI_HOTKEYS_CONFIRM, self.label = "Confirm", self.tooltip = "Use these hotkeys.", self.rowCount = 1);
|
IMGUI_ITEM(IMGUI_HOTKEYS_CONFIRM, self.label = "Confirm", self.tooltip = "Use these hotkeys.", self.rowCount = 1);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_DEFAULT_SETTINGS, self.label = "&Reset to Default Settings", self.tooltip = "Reset the program's settings to their default state.",
|
IMGUI_ITEM(IMGUI_DEFAULT_SETTINGS, self.label = "&Reset to Default Settings", self.tooltip = "Reset the program's settings to their default state.",
|
||||||
self.isSizeToText = true);
|
self.isWidthToText = true);
|
||||||
|
|
||||||
|
IMGUI_ITEM(IMGUI_ANM2S, self.label = "## Anm2s", self.size = {0, 32},
|
||||||
|
self.flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar |
|
||||||
|
ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoSavedSettings);
|
||||||
|
|
||||||
|
IMGUI_ITEM(IMGUI_ANM2, self.label = "## Anm2");
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_LAYERS, self.label = "Layers", self.flags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
|
IMGUI_ITEM(IMGUI_LAYERS, self.label = "Layers", self.flags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
|
||||||
IMGUI_ITEM(IMGUI_LAYERS_CHILD, self.label = "## Layers Child", self.flags = true);
|
IMGUI_ITEM(IMGUI_LAYERS_CHILD, self.label = "## Layers Child", self.flags = true);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_LAYER, self.label = "## Layer Item", self.dragDrop = "## Layer Drag Drop", self.atlas = ATLAS_LAYER, self.isSizeToRegion = true,
|
IMGUI_ITEM(IMGUI_LAYER, self.label = "## Layer Item", self.dragDrop = "## Layer Drag Drop", self.atlas = ATLAS_LAYER, self.isWidthToRegion = true,
|
||||||
self.idOffset = 3000);
|
self.idOffset = 3000);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_LAYER_SPRITESHEET_ID, self.label = "## Spritesheet ID", self.tooltip = "Change the spritesheet ID this layer uses.",
|
IMGUI_ITEM(IMGUI_LAYER_SPRITESHEET_ID, self.label = "## Spritesheet ID", self.tooltip = "Change the spritesheet ID this layer uses.",
|
||||||
@@ -1024,7 +1061,7 @@ IMGUI_ITEM(IMGUI_ANIMATIONS, self.label = "Animations", self.flags = ImGuiWindow
|
|||||||
IMGUI_ITEM(IMGUI_ANIMATIONS_CHILD, self.label = "## Animations Child", self.flags = true);
|
IMGUI_ITEM(IMGUI_ANIMATIONS_CHILD, self.label = "## Animations Child", self.flags = true);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_ANIMATION, self.label = "## Animation Item", self.dragDrop = "## Animation Drag Drop", self.atlas = ATLAS_ANIMATION,
|
IMGUI_ITEM(IMGUI_ANIMATION, self.label = "## Animation Item", self.dragDrop = "## Animation Drag Drop", self.atlas = ATLAS_ANIMATION,
|
||||||
self.isSizeToRegion = true, self.idOffset = 2000);
|
self.isWidthToRegion = true, self.idOffset = 2000);
|
||||||
|
|
||||||
#define IMGUI_ANIMATIONS_OPTIONS_ROW_COUNT 5
|
#define IMGUI_ANIMATIONS_OPTIONS_ROW_COUNT 5
|
||||||
IMGUI_ITEM(IMGUI_ANIMATION_ADD, self.label = "Add", self.tooltip = "Adds a new animation.", self.snapshotAction = "Add Animation",
|
IMGUI_ITEM(IMGUI_ANIMATION_ADD, self.label = "Add", self.tooltip = "Adds a new animation.", self.snapshotAction = "Add Animation",
|
||||||
@@ -1071,12 +1108,28 @@ IMGUI_ITEM(IMGUI_MERGE_DELETE_ANIMATIONS_AFTER, self.label = "Delete Animations
|
|||||||
IMGUI_ITEM(IMGUI_MERGE_CONFIRM, self.label = "Merge", self.tooltip = "Merge the selected animations with the options set.",
|
IMGUI_ITEM(IMGUI_MERGE_CONFIRM, self.label = "Merge", self.tooltip = "Merge the selected animations with the options set.",
|
||||||
self.snapshotAction = "Merge Animations", self.rowCount = IMGUI_CONFIRM_POPUP_ROW_COUNT, self.isSameLine = true);
|
self.snapshotAction = "Merge Animations", self.rowCount = IMGUI_CONFIRM_POPUP_ROW_COUNT, self.isSameLine = true);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_ANIMATION_REMOVE, self.label = "Remove", self.tooltip = "Remove the selected animation.", self.snapshotAction = "Remove Animation",
|
IMGUI_ITEM(IMGUI_ANIMATION_REMOVE, self.label = "Remove", self.tooltip = "Remove the selected animation(s).", self.snapshotAction = "Remove Animation(s)",
|
||||||
self.rowCount = IMGUI_ANIMATIONS_OPTIONS_ROW_COUNT, self.chord = ImGuiKey_Delete, self.focusWindow = IMGUI_ANIMATIONS.label, self.isSameLine = true);
|
self.rowCount = IMGUI_ANIMATIONS_OPTIONS_ROW_COUNT, self.chord = ImGuiKey_Delete, self.focusWindow = IMGUI_ANIMATIONS.label, self.isSameLine = true);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_ANIMATION_DEFAULT, self.label = "Default", self.tooltip = "Set the selected animation as the default one.",
|
IMGUI_ITEM(IMGUI_ANIMATION_DEFAULT, self.label = "Default", self.tooltip = "Set the referenced animation as the default one.",
|
||||||
self.snapshotAction = "Default Animation", self.rowCount = IMGUI_ANIMATIONS_OPTIONS_ROW_COUNT, self.isSameLine = true);
|
self.snapshotAction = "Default Animation", self.rowCount = IMGUI_ANIMATIONS_OPTIONS_ROW_COUNT, self.isSameLine = true);
|
||||||
|
|
||||||
|
static inline void imgui_animations_select_all(Imgui* self) {
|
||||||
|
for (int i = 0; i < (int)self->anm2->animations.size(); i++)
|
||||||
|
self->selectedAnimationIndices.insert(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
IMGUI_ITEM(IMGUI_ANIMATION_SELECT_ALL, self.label = "## Select None", self.hotkey = HOTKEY_SELECT_ALL, self.focusWindow = IMGUI_ANIMATIONS.label,
|
||||||
|
self.function = imgui_animations_select_all, self.isAllowHotkeyWhenFocusWindow = true);
|
||||||
|
|
||||||
|
static inline void imgui_animations_select_none(Imgui* self) {
|
||||||
|
self->selectedAnimationIndices.clear();
|
||||||
|
*self->reference = Anm2Reference();
|
||||||
|
}
|
||||||
|
|
||||||
|
IMGUI_ITEM(IMGUI_ANIMATION_SELECT_NONE, self.label = "## Select None", self.hotkey = HOTKEY_SELECT_NONE, self.focusWindow = IMGUI_ANIMATIONS.label,
|
||||||
|
self.function = imgui_animations_select_none, self.isAllowHotkeyWhenFocusWindow = true);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_EVENTS, self.label = "Events", self.flags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
|
IMGUI_ITEM(IMGUI_EVENTS, self.label = "Events", self.flags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_EVENTS_CHILD, self.label = "## Events Child", self.flags = true);
|
IMGUI_ITEM(IMGUI_EVENTS_CHILD, self.label = "## Events Child", self.flags = true);
|
||||||
@@ -1100,8 +1153,7 @@ IMGUI_ITEM(IMGUI_SPRITESHEET_CHILD, self.label = "## Spritesheet Child", self.fl
|
|||||||
IMGUI_ITEM(IMGUI_SPRITESHEET, self.label = "## Spritesheet", self.dragDrop = "## Spritesheet Drag Drop");
|
IMGUI_ITEM(IMGUI_SPRITESHEET, self.label = "## Spritesheet", self.dragDrop = "## Spritesheet Drag Drop");
|
||||||
IMGUI_ITEM(IMGUI_SPRITESHEET_TEXT, self.label = "## Spritesheet Text", self.atlas = ATLAS_SPRITESHEET, self.itemSpacing = vec2(8, 0));
|
IMGUI_ITEM(IMGUI_SPRITESHEET_TEXT, self.label = "## Spritesheet Text", self.atlas = ATLAS_SPRITESHEET, self.itemSpacing = vec2(8, 0));
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_SPRITESHEETS_FOOTER_CHILD, self.label = "## Spritesheets Footer Child", self.size = {0, IMGUI_FOOTER_CHILD.size->y * 1.66f},
|
IMGUI_ITEM(IMGUI_SPRITESHEETS_FOOTER_CHILD, self.label = "## Spritesheets Footer Child", self.flags = true);
|
||||||
self.flags = true);
|
|
||||||
|
|
||||||
#define IMGUI_SPRITESHEETS_OPTIONS_FIRST_ROW_COUNT 4
|
#define IMGUI_SPRITESHEETS_OPTIONS_FIRST_ROW_COUNT 4
|
||||||
#define IMGUI_SPRITESHEETS_OPTIONS_SECOND_ROW_COUNT 3
|
#define IMGUI_SPRITESHEETS_OPTIONS_SECOND_ROW_COUNT 3
|
||||||
@@ -1117,12 +1169,12 @@ IMGUI_ITEM(IMGUI_SPRITESHEETS_REPLACE, self.label = "Replace", self.tooltip = "R
|
|||||||
IMGUI_ITEM(IMGUI_SPRITESHEETS_REMOVE_UNUSED, self.label = "Remove Unused",
|
IMGUI_ITEM(IMGUI_SPRITESHEETS_REMOVE_UNUSED, self.label = "Remove Unused",
|
||||||
self.tooltip = "Remove all unused spritesheets in the anm2 (i.e., "
|
self.tooltip = "Remove all unused spritesheets in the anm2 (i.e., "
|
||||||
"the spritesheet isn't used in any layer animations).",
|
"the spritesheet isn't used in any layer animations).",
|
||||||
self.rowCount = IMGUI_SPRITESHEETS_OPTIONS_FIRST_ROW_COUNT);
|
self.snapshotAction = "Remove Unused Spritesheets", self.rowCount = IMGUI_SPRITESHEETS_OPTIONS_FIRST_ROW_COUNT);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_SPRITESHEETS_SELECT_ALL, self.label = "Select All", self.tooltip = "Select all spritesheets.", self.chord = ImGuiMod_Ctrl + ImGuiKey_A,
|
IMGUI_ITEM(IMGUI_SPRITESHEETS_SELECT_ALL, self.label = "Select All", self.tooltip = "Select all spritesheets.", self.hotkey = HOTKEY_SELECT_ALL,
|
||||||
self.focusWindow = IMGUI_SPRITESHEETS.label, self.rowCount = IMGUI_SPRITESHEETS_OPTIONS_SECOND_ROW_COUNT, self.isSameLine = true);
|
self.focusWindow = IMGUI_SPRITESHEETS.label, self.rowCount = IMGUI_SPRITESHEETS_OPTIONS_SECOND_ROW_COUNT, self.isSameLine = true);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_SPRITESHEETS_SELECT_NONE, self.label = "Select None", self.tooltip = "Unselect all spritesheets.", self.chord = ImGuiKey_Escape,
|
IMGUI_ITEM(IMGUI_SPRITESHEETS_SELECT_NONE, self.label = "Select None", self.tooltip = "Unselect all spritesheets.", self.hotkey = HOTKEY_SELECT_NONE,
|
||||||
self.focusWindow = IMGUI_SPRITESHEETS.label, self.rowCount = IMGUI_SPRITESHEETS_OPTIONS_SECOND_ROW_COUNT, self.isSameLine = true);
|
self.focusWindow = IMGUI_SPRITESHEETS.label, self.rowCount = IMGUI_SPRITESHEETS_OPTIONS_SECOND_ROW_COUNT, self.isSameLine = true);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_SPRITESHEET_SAVE, self.label = "Save", self.tooltip = "Save the selected spritesheets to their original locations.",
|
IMGUI_ITEM(IMGUI_SPRITESHEET_SAVE, self.label = "Save", self.tooltip = "Save the selected spritesheets to their original locations.",
|
||||||
@@ -1274,7 +1326,7 @@ IMGUI_ITEM(IMGUI_TOOLS, self.label = "Tools");
|
|||||||
IMGUI_ITEM(IMGUI_TOOL_PAN, self.label = "## Pan",
|
IMGUI_ITEM(IMGUI_TOOL_PAN, self.label = "## Pan",
|
||||||
self.tooltip = "Use the pan tool.\nWill shift the view as the cursor is dragged.\nYou "
|
self.tooltip = "Use the pan tool.\nWill shift the view as the cursor is dragged.\nYou "
|
||||||
"can also use the middle mouse button to pan at any time.",
|
"can also use the middle mouse button to pan at any time.",
|
||||||
self.function = imgui_tool_pan_set, self.hotkey = HOTKEY_PAN, self.atlas = ATLAS_PAN);
|
self.function = imgui_tool_pan_set, self.hotkey = HOTKEY_PAN, self.atlas = ATLAS_PAN, self.isAtlasStretch = true);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_TOOL_MOVE, self.label = "## Move",
|
IMGUI_ITEM(IMGUI_TOOL_MOVE, self.label = "## Move",
|
||||||
self.tooltip = "Use the move tool.\nAnimation Preview: Will move the position "
|
self.tooltip = "Use the move tool.\nAnimation Preview: Will move the position "
|
||||||
@@ -1374,12 +1426,12 @@ IMGUI_ITEM(IMGUI_TIMELINE_ITEM_PROPERTIES_TYPE_CHILD, self.label = "## Item Prop
|
|||||||
IMGUI_ITEM(IMGUI_TIMELINE_ITEM_PROPERTIES_LAYER, self.label = "Layer",
|
IMGUI_ITEM(IMGUI_TIMELINE_ITEM_PROPERTIES_LAYER, self.label = "Layer",
|
||||||
self.tooltip = "The item will be a layer item.\nA layer item is a "
|
self.tooltip = "The item will be a layer item.\nA layer item is a "
|
||||||
"primary graphical item, using a spritesheet.",
|
"primary graphical item, using a spritesheet.",
|
||||||
self.isSizeToText = true, self.value = ANM2_LAYER, self.isSameLine = true);
|
self.isWidthToText = true, self.value = ANM2_LAYER, self.isSameLine = true);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_TIMELINE_ITEM_PROPERTIES_NULL, self.label = "Null",
|
IMGUI_ITEM(IMGUI_TIMELINE_ITEM_PROPERTIES_NULL, self.label = "Null",
|
||||||
self.tooltip = "The item will be a null item.\nA null item is an "
|
self.tooltip = "The item will be a null item.\nA null item is an "
|
||||||
"invisible item, often accessed by a game engine.",
|
"invisible item, often accessed by a game engine.",
|
||||||
self.isSizeToText = true, self.value = ANM2_NULL);
|
self.isWidthToText = true, self.value = ANM2_NULL);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_TIMELINE_ITEM_PROPERTIES_ITEMS_CHILD, self.label = "## Item Properties Items", self.size = {IMGUI_POPUP_ITEM_PROPERTIES_SIZE.x, 250},
|
IMGUI_ITEM(IMGUI_TIMELINE_ITEM_PROPERTIES_ITEMS_CHILD, self.label = "## Item Properties Items", self.size = {IMGUI_POPUP_ITEM_PROPERTIES_SIZE.x, 250},
|
||||||
self.flags = true);
|
self.flags = true);
|
||||||
@@ -1598,16 +1650,16 @@ IMGUI_ITEM(IMGUI_CONTEXT_MENU, self.label = "## Context Menu");
|
|||||||
IMGUI_ITEM(IMGUI_CUT, self.label = "Cut",
|
IMGUI_ITEM(IMGUI_CUT, self.label = "Cut",
|
||||||
self.tooltip = "Cuts the currently selected contextual element; "
|
self.tooltip = "Cuts the currently selected contextual element; "
|
||||||
"removing it and putting it to the clipboard.",
|
"removing it and putting it to the clipboard.",
|
||||||
self.snapshotAction = "Cut", self.function = imgui_cut, self.hotkey = HOTKEY_CUT, self.isSizeToText = true);
|
self.snapshotAction = "Cut", self.function = imgui_cut, self.hotkey = HOTKEY_CUT, self.isWidthToText = true);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_COPY, self.label = "Copy", self.tooltip = "Copies the currently selected contextual element to the clipboard.", self.snapshotAction = "Copy",
|
IMGUI_ITEM(IMGUI_COPY, self.label = "Copy", self.tooltip = "Copies the currently selected contextual element to the clipboard.", self.function = imgui_copy,
|
||||||
self.function = imgui_copy, self.hotkey = HOTKEY_COPY, self.isSizeToText = true);
|
self.hotkey = HOTKEY_COPY, self.isWidthToText = true);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_PASTE, self.label = "Paste", self.tooltip = "Pastes the currently selection contextual element from the clipboard.",
|
IMGUI_ITEM(IMGUI_PASTE, self.label = "Paste", self.tooltip = "Pastes the currently selection contextual element from the clipboard.",
|
||||||
self.snapshotAction = "Paste", self.function = imgui_paste, self.hotkey = HOTKEY_PASTE, self.isSizeToText = true);
|
self.snapshotAction = "Paste", self.function = imgui_paste, self.hotkey = HOTKEY_PASTE, self.isWidthToText = true);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_CHANGE_INPUT_TEXT, self.label = "## Input Text", self.tooltip = "Rename the selected item.", self.snapshotAction = "Rename Item",
|
IMGUI_ITEM(IMGUI_CHANGE_INPUT_TEXT, self.label = "## Input Text", self.tooltip = "Rename the selected item.", self.snapshotAction = "Rename",
|
||||||
self.flags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue, self.max = UCHAR_MAX);
|
self.flags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue, self.max = 0xFFFF);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_CHANGE_INPUT_INT, self.label = "## Input Int", self.tooltip = "Change the selected item's value.", self.snapshotAction = "Change Value",
|
IMGUI_ITEM(IMGUI_CHANGE_INPUT_INT, self.label = "## Input Int", self.tooltip = "Change the selected item's value.", self.snapshotAction = "Change Value",
|
||||||
self.step = 0);
|
self.step = 0);
|
||||||
|
|||||||
@@ -87,8 +87,8 @@ void preview_draw(Preview* self) {
|
|||||||
if (self->settings->previewIsAxes)
|
if (self->settings->previewIsAxes)
|
||||||
canvas_axes_draw(&self->canvas, shaderAxis, transform, self->settings->previewAxesColor);
|
canvas_axes_draw(&self->canvas, shaderAxis, transform, self->settings->previewAxesColor);
|
||||||
|
|
||||||
auto animation_draw = [&](int animationID) {
|
auto animation_draw = [&](int animationIndex) {
|
||||||
Anm2Animation* animation = map_find(self->anm2->animations, animationID);
|
Anm2Animation* animation = anm2_animation_from_reference(self->anm2, {animationIndex});
|
||||||
if (!animation)
|
if (!animation)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ void preview_draw(Preview* self) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
Anm2Frame frame;
|
Anm2Frame frame;
|
||||||
anm2_frame_from_time(self->anm2, &frame, Anm2Reference{animationID, ANM2_LAYER, id}, time);
|
anm2_frame_from_time(self->anm2, &frame, Anm2Reference{animationIndex, ANM2_LAYER, id}, time);
|
||||||
if (!frame.isVisible)
|
if (!frame.isVisible)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -151,7 +151,7 @@ void preview_draw(Preview* self) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
Anm2Frame frame;
|
Anm2Frame frame;
|
||||||
anm2_frame_from_time(self->anm2, &frame, Anm2Reference{animationID, ANM2_NULL, id}, time);
|
anm2_frame_from_time(self->anm2, &frame, Anm2Reference{animationIndex, ANM2_NULL, id}, time);
|
||||||
if (!frame.isVisible)
|
if (!frame.isVisible)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -180,7 +180,7 @@ void preview_draw(Preview* self) {
|
|||||||
|
|
||||||
auto base_draw = [&](float time, vec3 colorOffset = {}, float alphaOffset = {}, bool isOnionskin = {}) {
|
auto base_draw = [&](float time, vec3 colorOffset = {}, float alphaOffset = {}, bool isOnionskin = {}) {
|
||||||
Anm2Frame root;
|
Anm2Frame root;
|
||||||
anm2_frame_from_time(self->anm2, &root, Anm2Reference{animationID, ANM2_ROOT}, time);
|
anm2_frame_from_time(self->anm2, &root, Anm2Reference{animationIndex, ANM2_ROOT}, time);
|
||||||
|
|
||||||
mat4 rootModel =
|
mat4 rootModel =
|
||||||
self->settings->previewIsRootTransform ? quad_model_parent_get(root.position, {}, PERCENT_TO_UNIT(root.scale), root.rotation) : mat4(1.0f);
|
self->settings->previewIsRootTransform ? quad_model_parent_get(root.position, {}, PERCENT_TO_UNIT(root.scale), root.rotation) : mat4(1.0f);
|
||||||
@@ -218,7 +218,7 @@ void preview_draw(Preview* self) {
|
|||||||
onionskins_draw();
|
onionskins_draw();
|
||||||
};
|
};
|
||||||
|
|
||||||
animation_draw(self->reference->animationID);
|
animation_draw(self->reference->animationIndex);
|
||||||
animation_draw(self->animationOverlayID);
|
animation_draw(self->animationOverlayID);
|
||||||
|
|
||||||
canvas_unbind();
|
canvas_unbind();
|
||||||
|
|||||||
15
src/render.h
15
src/render.h
@@ -2,25 +2,16 @@
|
|||||||
|
|
||||||
#include "COMMON.h"
|
#include "COMMON.h"
|
||||||
|
|
||||||
enum RenderType
|
enum RenderType { RENDER_PNG, RENDER_GIF, RENDER_WEBM, RENDER_MP4, RENDER_COUNT };
|
||||||
{
|
|
||||||
RENDER_PNG,
|
|
||||||
RENDER_GIF,
|
|
||||||
RENDER_WEBM,
|
|
||||||
RENDER_MP4,
|
|
||||||
RENDER_COUNT
|
|
||||||
};
|
|
||||||
|
|
||||||
const inline std::string RENDER_TYPE_STRINGS[] =
|
const inline std::string RENDER_TYPE_STRINGS[] = {
|
||||||
{
|
|
||||||
"PNG Images",
|
"PNG Images",
|
||||||
"GIF image",
|
"GIF image",
|
||||||
"WebM video",
|
"WebM video",
|
||||||
"MP4 video",
|
"MP4 video",
|
||||||
};
|
};
|
||||||
|
|
||||||
const inline std::string RENDER_EXTENSIONS[RENDER_COUNT] =
|
const inline std::string RENDER_EXTENSIONS[RENDER_COUNT] = {
|
||||||
{
|
|
||||||
".png",
|
".png",
|
||||||
".gif",
|
".gif",
|
||||||
".webm",
|
".webm",
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
#include "resources.h"
|
#include "resources.h"
|
||||||
|
#include "RESOURCE.h"
|
||||||
|
|
||||||
void resources_init(Resources* self) {
|
void resources_init(Resources* self) {
|
||||||
texture_from_path_init(&self->atlas, ATLAS_PATH);
|
texture_from_memory_init(&self->atlas, TEXTURE_ATLAS_SIZE, TEXTURE_ATLAS, TEXTURE_ATLAS_LENGTH);
|
||||||
|
|
||||||
for (int i = 0; i < SHADER_COUNT; i++)
|
for (int i = 0; i < SHADER_COUNT; i++)
|
||||||
shader_init(&self->shaders[i], SHADER_DATA[i].vertex, SHADER_DATA[i].fragment);
|
shader_init(&self->shaders[i], SHADER_DATA[i].vertex, SHADER_DATA[i].fragment);
|
||||||
|
|||||||
@@ -61,6 +61,8 @@
|
|||||||
X(HOTKEY_COPY, hotkeyCopy, TYPE_STRING, "Ctrl+C") \
|
X(HOTKEY_COPY, hotkeyCopy, TYPE_STRING, "Ctrl+C") \
|
||||||
X(HOTKEY_CUT, hotkeyCut, TYPE_STRING, "Ctrl+X") \
|
X(HOTKEY_CUT, hotkeyCut, TYPE_STRING, "Ctrl+X") \
|
||||||
X(HOTKEY_PASTE, hotkeyPaste, TYPE_STRING, "Ctrl+V") \
|
X(HOTKEY_PASTE, hotkeyPaste, TYPE_STRING, "Ctrl+V") \
|
||||||
|
X(HOTKEY_SELECT_ALL, hotkeySelectAll, TYPE_STRING, "Ctrl+A") \
|
||||||
|
X(HOTKEY_SELECT_NONE, hotkeySelectNone, TYPE_STRING, "Ctrl+Shift+A") \
|
||||||
\
|
\
|
||||||
X(PLAYBACK_IS_LOOP, playbackIsLoop, TYPE_BOOL, true) \
|
X(PLAYBACK_IS_LOOP, playbackIsLoop, TYPE_BOOL, true) \
|
||||||
X(PLAYBACK_IS_CLAMP_PLAYHEAD, playbackIsClampPlayhead, TYPE_BOOL, true) \
|
X(PLAYBACK_IS_CLAMP_PLAYHEAD, playbackIsClampPlayhead, TYPE_BOOL, true) \
|
||||||
@@ -211,7 +213,9 @@ constexpr int SETTINGS_COUNT = (int)std::size(SETTINGS_ENTRIES);
|
|||||||
X(REDO, "Redo") \
|
X(REDO, "Redo") \
|
||||||
X(COPY, "Copy") \
|
X(COPY, "Copy") \
|
||||||
X(CUT, "Cut") \
|
X(CUT, "Cut") \
|
||||||
X(PASTE, "Paste")
|
X(PASTE, "Paste") \
|
||||||
|
X(SELECT_ALL, "Select All") \
|
||||||
|
X(SELECT_NONE, "Select None")
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
#define X(name, str) HOTKEY_##name,
|
#define X(name, str) HOTKEY_##name,
|
||||||
@@ -257,7 +261,9 @@ const inline HotkeyMember SETTINGS_HOTKEY_MEMBERS[HOTKEY_COUNT] = {nullptr,
|
|||||||
&Settings::hotkeyRedo,
|
&Settings::hotkeyRedo,
|
||||||
&Settings::hotkeyCopy,
|
&Settings::hotkeyCopy,
|
||||||
&Settings::hotkeyCut,
|
&Settings::hotkeyCut,
|
||||||
&Settings::hotkeyPaste};
|
&Settings::hotkeyPaste,
|
||||||
|
&Settings::hotkeySelectAll,
|
||||||
|
&Settings::hotkeySelectNone};
|
||||||
|
|
||||||
const inline std::string SETTINGS_IMGUI_DEFAULT = R"(
|
const inline std::string SETTINGS_IMGUI_DEFAULT = R"(
|
||||||
# Dear ImGui
|
# Dear ImGui
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ struct SnapshotStack {
|
|||||||
Snapshot snapshots[SNAPSHOT_STACK_MAX];
|
Snapshot snapshots[SNAPSHOT_STACK_MAX];
|
||||||
int top = 0;
|
int top = 0;
|
||||||
|
|
||||||
bool is_empty() const { return top == 0; }
|
bool empty() const { return top == 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Snapshots {
|
struct Snapshots {
|
||||||
|
|||||||
@@ -76,6 +76,22 @@ bool texture_from_rgba_write(const std::string& path, const uint8_t* data, ivec2
|
|||||||
return isSuccess;
|
return isSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool texture_from_memory_init(Texture* self, ivec2 size, const uint8_t* data, size_t length) {
|
||||||
|
*self = Texture{};
|
||||||
|
self->size = size;
|
||||||
|
|
||||||
|
u8* textureData = stbi_load_from_memory(data, length, &self->size.x, &self->size.y, nullptr, TEXTURE_CHANNELS);
|
||||||
|
|
||||||
|
if (!textureData)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
self->isInvalid = false;
|
||||||
|
|
||||||
|
_texture_gl_set(self, textureData);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool texture_from_gl_write(Texture* self, const std::string& path) { return texture_from_rgba_write(path, texture_download(self).data(), self->size); }
|
bool texture_from_gl_write(Texture* self, const std::string& path) { return texture_from_rgba_write(path, texture_download(self).data(), self->size); }
|
||||||
|
|
||||||
void texture_free(Texture* self) {
|
void texture_free(Texture* self) {
|
||||||
|
|||||||
@@ -18,8 +18,9 @@ struct Texture {
|
|||||||
|
|
||||||
bool texture_from_gl_write(Texture* self, const std::string& path);
|
bool texture_from_gl_write(Texture* self, const std::string& path);
|
||||||
bool texture_from_path_init(Texture* self, const std::string& path);
|
bool texture_from_path_init(Texture* self, const std::string& path);
|
||||||
bool texture_from_rgba_init(Texture* self, ivec2 size, const u8* data);
|
bool texture_from_rgba_init(Texture* self, ivec2 size, const uint8_t* data);
|
||||||
bool texture_from_rgba_write(const std::string& path, const u8* data, ivec2 size);
|
bool texture_from_rgba_write(const std::string& path, const uint8_t* data, ivec2 size);
|
||||||
bool texture_pixel_set(Texture* self, ivec2 position, vec4 color);
|
bool texture_pixel_set(Texture* self, ivec2 position, vec4 color);
|
||||||
void texture_free(Texture* self);
|
void texture_free(Texture* self);
|
||||||
std::vector<u8> texture_download(const Texture* self);
|
bool texture_from_memory_init(Texture* self, ivec2 size, const uint8_t* data, size_t length);
|
||||||
|
std::vector<uint8_t> texture_download(const Texture* self);
|
||||||
Reference in New Issue
Block a user