Compare commits
20 Commits
9ad464a74a
...
4ce5a225c3
Author | SHA1 | Date | |
---|---|---|---|
|
4ce5a225c3 | ||
6d191f186d | |||
70d4d44c80 | |||
d35958a289 | |||
b65bcd2316 | |||
cc4501d2f1 | |||
bc8cc37042 | |||
c3bb2bcf17 | |||
9afb845a36 | |||
fe32c74967 | |||
c78f2ee17b | |||
0a8fa44ee6 | |||
f7c4bcea52 | |||
45865bd4d1 | |||
c7dc0db9ce | |||
3da8928d13 | |||
f8fb3df8d4 | |||
6deaaea374 | |||
b0e52bd444 | |||
b2cf67a823 |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,4 +1,11 @@
|
||||
build/
|
||||
concept/
|
||||
release/
|
||||
packed/
|
||||
vcpkg_installed/
|
||||
out/
|
||||
include/imgui/
|
||||
include/glm/
|
||||
include/tinyxml2
|
||||
workshop/resources
|
||||
.vs/
|
||||
|
@@ -10,26 +10,34 @@ project(anm2ed CXX)
|
||||
find_package(SDL3 REQUIRED)
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
||||
set(GLAD_SRC ${CMAKE_CURRENT_SOURCE_DIR}/include/glad/glad.cpp)
|
||||
|
||||
file(GLOB SOURCES
|
||||
${GLAD_SRC}
|
||||
include/imgui/imgui.cpp
|
||||
include/imgui/imgui_draw.cpp
|
||||
include/imgui/imgui_widgets.cpp
|
||||
include/imgui/imgui_tables.cpp
|
||||
include/imgui/backends/imgui_impl_sdl3.cpp
|
||||
include/imgui/backends/imgui_impl_opengl3.cpp
|
||||
include/tinyxml2/tinyxml2.cpp
|
||||
src/*.cpp
|
||||
src/*.h
|
||||
set(GLAD_SRC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/glad/glad.cpp
|
||||
)
|
||||
|
||||
if(NOT MSVC)
|
||||
set_source_files_properties(${GLAD_SRC} PROPERTIES COMPILE_FLAGS "-Wno-cast-function-type")
|
||||
endif()
|
||||
set(IMGUI_SRC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/imgui/imgui.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/imgui/imgui_draw.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/imgui/imgui_widgets.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/imgui/imgui_tables.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/imgui/backends/imgui_impl_sdl3.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/imgui/backends/imgui_impl_opengl3.cpp
|
||||
)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
set(TINYXML2_SRC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/tinyxml2/tinyxml2.cpp
|
||||
)
|
||||
|
||||
file(GLOB PROJECT_SRC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/*.h
|
||||
)
|
||||
|
||||
add_executable(${PROJECT_NAME}
|
||||
${GLAD_SRC}
|
||||
${IMGUI_SRC}
|
||||
${TINYXML2_SRC}
|
||||
${PROJECT_SRC}
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
enable_language(RC)
|
||||
@@ -38,7 +46,14 @@ if(WIN32)
|
||||
endif()
|
||||
|
||||
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_23)
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE include include/glad include/imgui include/tinyxml2 src)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/glad
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/imgui
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/tinyxml2
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE /std:c++latest /EHsc)
|
||||
|
@@ -10,6 +10,17 @@
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": ""
|
||||
},
|
||||
{
|
||||
"name": "x64-Release",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Release",
|
||||
"inheritEnvironments": [ "msvc_x64_x64" ],
|
||||
"buildRoot": "${projectDir}\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\install\\${name}",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": ""
|
||||
}
|
||||
]
|
||||
}
|
18
README.md
18
README.md
@@ -6,21 +6,26 @@ A reimplementation of *The Binding of Isaac: Rebirth*'s proprietary animation ed
|
||||
|
||||
## Features
|
||||
- Extended version of the original proprietary Nicalis animation editor
|
||||
- Smooth [Dear ImGui](https://github.com/ocornut/imgui) interface; docking, dragging and dropping, etc.
|
||||
- Smooth [Dear ImGui](https://github.com/ocornut/imgui) interface; docking, dragging and dropping, etc. You might be familiar with it from You might be familiar with it from (Repentogon)
|
||||
- New features
|
||||
- Can output .webm or *.png sequence
|
||||
- Can output .webm, .mp4 or *.png sequence (wih FFmpeg)
|
||||
- Cutting, copying and pasting
|
||||
- Additional wizard options
|
||||
- Robust snapshot (undo/redo) system
|
||||
- Additional hotkeys/shortcuts
|
||||
- Additional hotkeys/shortcuts (rebindable!)
|
||||
- Onionskinning
|
||||
- Settings that will preserve on exit (stored in %APPDATA% on Windows or ~/.local/share on Linux)
|
||||
|
||||
### Note: Difference from Nicalis editor
|
||||
Layers/nulls are handled differently (in their own window) and are not on the timeline! Add a layer/null in the Layers/Nulls window, and then add a LayerAnimation/NullAnimation in the timeline!
|
||||
|
||||
### Note: Rendering Animations
|
||||
You will need FFmpeg installed! Get it from [here](https://ffmpeg.org/download.html), and point to the downloaded ffmpeg executable within the program!
|
||||
|
||||
## Dependencies
|
||||
Download these from your package manager:
|
||||
- SDL3
|
||||
|
||||
Note, to render animations, you'll need to download [FFmpeg](https://ffmpeg.org/download.html) and specify its install path in the program.
|
||||
|
||||
## Build
|
||||
|
||||
### Windows
|
||||
@@ -45,3 +50,6 @@ cd build
|
||||
cmake ..
|
||||
make
|
||||
```
|
||||
|
||||
## Happy animating!
|
||||

|
||||
|
BIN
assets/atlas.png
BIN
assets/atlas.png
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.2 KiB |
66
assets/atlas_data_write.sh
Executable file
66
assets/atlas_data_write.sh
Executable file
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
INPUT="atlas.png"
|
||||
OUTPUT="../src/PACKED.h"
|
||||
TMP="atlas.bytes"
|
||||
|
||||
# Ensure deps
|
||||
command -v optipng >/dev/null 2>&1 || { echo "error: optipng not found in PATH" >&2; exit 1; }
|
||||
command -v xxd >/dev/null 2>&1 || { echo "error: xxd not found in PATH" >&2; exit 1; }
|
||||
|
||||
# 1) Optimize PNG in place
|
||||
optipng -o7 "$INPUT" >/dev/null
|
||||
|
||||
# 2) Extract ONLY the bytes from xxd -i (between '= {' and '};')
|
||||
# Using awk avoids the earlier '{' vs '= {' mismatch bug.
|
||||
xxd -i "$INPUT" \
|
||||
| awk '
|
||||
/= *\{/ {inside=1; next}
|
||||
inside && /};/ {inside=0; exit}
|
||||
inside {print}
|
||||
' > "$TMP"
|
||||
|
||||
# Sanity check: make sure we got something
|
||||
if ! [ -s "$TMP" ]; then
|
||||
echo "error: failed to extract bytes from xxd output" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 3) Replace ONLY the bytes inside TEXTURE_ATLAS[] initializer
|
||||
# - Find the exact declaration line for TEXTURE_ATLAS
|
||||
# - Print that line
|
||||
# - On the following line with just '{', print it, then insert bytes,
|
||||
# then skip everything until the matching '};' and print that once.
|
||||
awk -v tmpfile="$TMP" '
|
||||
BEGIN { state=0 } # 0=normal, 1=after decl waiting for {, 2=skipping old bytes until };
|
||||
|
||||
# Match the TEXTURE_ATLAS declaration line precisely
|
||||
$0 ~ /^[[:space:]]*const[[:space:]]+u8[[:space:]]+TEXTURE_ATLAS\[\][[:space:]]*=/ {
|
||||
print; state=1; next
|
||||
}
|
||||
|
||||
# After the decl, the next line with a lone "{" starts the initializer
|
||||
state==1 && $0 ~ /^[[:space:]]*{[[:space:]]*$/ {
|
||||
print # print the opening brace line
|
||||
while ((getline line < tmpfile) > 0) print line # insert fresh bytes
|
||||
close(tmpfile)
|
||||
state=2 # now skip old initializer content until we hit the closing "};"
|
||||
next
|
||||
}
|
||||
|
||||
# While skipping, suppress lines until the closing "};", which we reprint once
|
||||
state==2 {
|
||||
if ($0 ~ /^[[:space:]]*};[[:space:]]*$/) {
|
||||
print # print the closing brace+semicolon
|
||||
state=0
|
||||
}
|
||||
next
|
||||
}
|
||||
|
||||
# Default: pass through unchanged
|
||||
{ print }
|
||||
' "$OUTPUT" > "$OUTPUT.tmp" && mv "$OUTPUT.tmp" "$OUTPUT"
|
||||
|
||||
rm -f "$TMP"
|
||||
echo "Updated $OUTPUT with optimized bytes from $INPUT."
|
140
src/COMMON.h
140
src/COMMON.h
@@ -51,15 +51,17 @@ using namespace glm;
|
||||
#define FLOAT_TO_U8(x) (static_cast<u8>((x) * 255.0f))
|
||||
#define U8_TO_FLOAT(x) ((x) / 255.0f)
|
||||
#define PERCENT_TO_UNIT(x) (x / 100.0f)
|
||||
#define UNIT_TO_PERCENT(x) (x * 100.0f)
|
||||
#define SECOND 1000.0f
|
||||
#define TICK_DELAY (SECOND / 30.0)
|
||||
#define UPDATE_DELAY (SECOND / 120.0)
|
||||
#define ID_NONE -1
|
||||
#define INDEX_NONE -1
|
||||
#define VALUE_NONE -1
|
||||
#define TIME_NONE -1.0f
|
||||
#define GL_ID_NONE 0
|
||||
|
||||
#if defined(_WIN32)
|
||||
#ifdef _WIN32
|
||||
#define POPEN _popen
|
||||
#define PCLOSE _pclose
|
||||
#define PWRITE_MODE "wb"
|
||||
@@ -71,7 +73,6 @@ using namespace glm;
|
||||
#define PREAD_MODE "r"
|
||||
#endif
|
||||
|
||||
|
||||
static const GLuint GL_TEXTURE_INDICES[] = {0, 1, 2, 2, 3, 0};
|
||||
static const vec4 COLOR_RED = {1.0f, 0.0f, 0.0f, 1.0f};
|
||||
static const vec4 COLOR_GREEN = {0.0f, 1.0f, 0.0f, 1.0f};
|
||||
@@ -104,6 +105,15 @@ static inline std::string string_quote(const std::string& string)
|
||||
return "\"" + string + "\"";
|
||||
}
|
||||
|
||||
static inline std::string string_to_lowercase(std::string string) {
|
||||
std::transform
|
||||
(
|
||||
string.begin(), string.end(), string.begin(),
|
||||
[](u8 character){ return std::tolower(character); }
|
||||
);
|
||||
return string;
|
||||
}
|
||||
|
||||
#define FLOAT_FORMAT_MAX_DECIMALS 2
|
||||
#define FLOAT_FORMAT_EPSILON 1e-6f
|
||||
static constexpr f32 FLOAT_FORMAT_POW10[] = {1.f, 10.f, 100.f};
|
||||
@@ -144,65 +154,6 @@ static inline const char* vec2_format_get(const vec2& value)
|
||||
return formatString.c_str();
|
||||
}
|
||||
|
||||
static inline std::string path_canonical_resolve
|
||||
(
|
||||
const std::string& inputPath,
|
||||
const std::string& basePath = std::filesystem::current_path().string()
|
||||
)
|
||||
{
|
||||
auto strings_equal_ignore_case = [](std::string a, std::string b) {
|
||||
auto to_lower = [](unsigned char c) { return static_cast<char>(std::tolower(c)); };
|
||||
std::transform(a.begin(), a.end(), a.begin(), to_lower);
|
||||
std::transform(b.begin(), b.end(), b.begin(), to_lower);
|
||||
return a == b;
|
||||
};
|
||||
|
||||
std::string sanitized = inputPath;
|
||||
std::replace(sanitized.begin(), sanitized.end(), '\\', '/');
|
||||
|
||||
std::filesystem::path normalizedPath = sanitized;
|
||||
std::filesystem::path absolutePath = normalizedPath.is_absolute()
|
||||
? normalizedPath
|
||||
: (std::filesystem::path(basePath) / normalizedPath);
|
||||
|
||||
std::error_code error;
|
||||
if (std::filesystem::exists(absolutePath, error)) {
|
||||
std::error_code canonicalError;
|
||||
std::filesystem::path canonicalPath = std::filesystem::weakly_canonical(absolutePath, canonicalError);
|
||||
return (canonicalError ? absolutePath : canonicalPath).generic_string();
|
||||
}
|
||||
|
||||
std::filesystem::path resolvedPath = absolutePath.root_path();
|
||||
std::filesystem::path remainingPath = absolutePath.relative_path();
|
||||
|
||||
for (const std::filesystem::path& segment : remainingPath) {
|
||||
std::filesystem::path candidatePath = resolvedPath / segment;
|
||||
if (std::filesystem::exists(candidatePath, error)) {
|
||||
resolvedPath = candidatePath;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool matched = false;
|
||||
if (std::filesystem::exists(resolvedPath, error) && std::filesystem::is_directory(resolvedPath, error)) {
|
||||
for (const auto& directoryEntry : std::filesystem::directory_iterator(resolvedPath, error)) {
|
||||
if (strings_equal_ignore_case(directoryEntry.path().filename().string(), segment.string())) {
|
||||
resolvedPath = directoryEntry.path();
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!matched) return sanitized;
|
||||
}
|
||||
|
||||
if (!std::filesystem::exists(resolvedPath, error))
|
||||
return sanitized;
|
||||
|
||||
std::error_code canonicalError;
|
||||
std::filesystem::path canonicalPath = std::filesystem::weakly_canonical(resolvedPath, canonicalError);
|
||||
return (canonicalError ? resolvedPath : canonicalPath).generic_string();
|
||||
};
|
||||
|
||||
static inline std::string working_directory_from_file_set(const std::string& path)
|
||||
{
|
||||
std::filesystem::path filePath = path;
|
||||
@@ -237,7 +188,6 @@ static inline bool path_is_valid(const std::filesystem::path& pathCheck)
|
||||
std::error_code ec;
|
||||
|
||||
if (fs::is_directory(pathCheck, ec)) return false;
|
||||
if (fs::exists(pathCheck, ec) && !fs::is_regular_file(pathCheck, ec)) return false;
|
||||
|
||||
fs::path parentDir = pathCheck.has_parent_path() ? pathCheck.parent_path() : fs::path(".");
|
||||
if (!fs::is_directory(parentDir, ec)) return false;
|
||||
@@ -248,16 +198,11 @@ static inline bool path_is_valid(const std::filesystem::path& pathCheck)
|
||||
testStream.close();
|
||||
|
||||
if (!existedBefore && isValid)
|
||||
fs::remove(pathCheck, ec); // cleanup if we created it
|
||||
fs::remove(pathCheck, ec);
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
static inline const char* enum_to_string(const char* array[], s32 count, s32 index)
|
||||
{
|
||||
return (index >= 0 && index < count) ? array[index] : "";
|
||||
};
|
||||
|
||||
static inline s32 string_to_enum(const std::string& string, const char* const* array, s32 n)
|
||||
{
|
||||
for (s32 i = 0; i < n; i++)
|
||||
@@ -287,8 +232,10 @@ static inline s32 map_next_id_get(const std::map<s32, T>& map)
|
||||
return id;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline T* map_find(std::map<s32, T>& map, s32 id)
|
||||
|
||||
template <typename Map>
|
||||
static inline auto map_find(Map& map, typename Map::key_type id)
|
||||
-> typename Map::mapped_type*
|
||||
{
|
||||
if (auto it = map.find(id); it != map.end())
|
||||
return &it->second;
|
||||
@@ -343,11 +290,54 @@ static inline void map_insert_shift(std::map<int, T>& map, s32 index, const T& v
|
||||
map[insertIndex] = value;
|
||||
}
|
||||
|
||||
#define DEFINE_ENUM_TO_STRING_FUNCTION(function, array, count) \
|
||||
static inline std::string function(s32 index) \
|
||||
{ \
|
||||
return enum_to_string(array, count, index); \
|
||||
};
|
||||
template <typename T>
|
||||
void vector_value_erase(std::vector<T>& v, const T& value)
|
||||
{
|
||||
v.erase(std::remove(v.begin(), v.end(), value), v.end());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void vector_value_swap(std::vector<T>& v, const T& a, const T& b)
|
||||
{
|
||||
for (auto& element : v)
|
||||
{
|
||||
if (element == a) element = b;
|
||||
else if (element == b) element = a;
|
||||
}
|
||||
}
|
||||
|
||||
static inline mat4 quad_model_get(vec2 size = {}, vec2 position = {}, vec2 pivot = {}, vec2 scale = vec2(1.0f), f32 rotation = {})
|
||||
{
|
||||
vec2 scaleAbsolute = glm::abs(scale);
|
||||
vec2 scaleSign = glm::sign(scale);
|
||||
vec2 pivotScaled = pivot * scaleAbsolute;
|
||||
vec2 sizeScaled = size * scaleAbsolute;
|
||||
|
||||
mat4 model(1.0f);
|
||||
model = glm::translate(model, vec3(position - pivotScaled, 0.0f));
|
||||
model = glm::translate(model, vec3(pivotScaled, 0.0f));
|
||||
model = glm::scale(model, vec3(scaleSign, 1.0f));
|
||||
model = glm::rotate(model, glm::radians(rotation), vec3(0, 0, 1));
|
||||
model = glm::translate(model, vec3(-pivotScaled, 0.0f));
|
||||
model = glm::scale(model, vec3(sizeScaled, 1.0f));
|
||||
return model;
|
||||
}
|
||||
|
||||
static inline mat4 quad_model_parent_get(vec2 position = {}, vec2 pivot = {}, vec2 scale = vec2(1.0f), f32 rotation = {})
|
||||
{
|
||||
vec2 scaleSign = glm::sign(scale);
|
||||
vec2 scaleAbsolute = glm::abs(scale);
|
||||
f32 handedness = (scaleSign.x * scaleSign.y) < 0.0f ? -1.0f : 1.0f;
|
||||
|
||||
mat4 local(1.0f);
|
||||
local = glm::translate(local, vec3(pivot, 0.0f));
|
||||
local = glm::scale(local, vec3(scaleSign, 1.0f));
|
||||
local = glm::rotate(local, glm::radians(rotation) * handedness, vec3(0, 0, 1));
|
||||
local = glm::translate(local, vec3(-pivot, 0.0f));
|
||||
local = glm::scale(local, vec3(scaleAbsolute, 1.0f));
|
||||
|
||||
return glm::translate(mat4(1.0f), vec3(position, 0.0f)) * local;
|
||||
}
|
||||
|
||||
#define DEFINE_STRING_TO_ENUM_FUNCTION(function, enumType, stringArray, count) \
|
||||
static inline enumType function(const std::string& string) \
|
||||
|
201
src/PACKED.h
201
src/PACKED.h
@@ -1,5 +1,3 @@
|
||||
// Includes packed resources (i.e., textures, shaders)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "COMMON.h"
|
||||
@@ -8,101 +6,108 @@ const u8 TEXTURE_ATLAS[] =
|
||||
{
|
||||
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
|
||||
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0xa0,
|
||||
0x02, 0x03, 0x00, 0x00, 0x00, 0x8e, 0x1e, 0x81, 0x1f, 0x00, 0x00, 0x00,
|
||||
0x04, 0x03, 0x00, 0x00, 0x00, 0x01, 0x5e, 0x74, 0xbf, 0x00, 0x00, 0x00,
|
||||
0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b,
|
||||
0x12, 0x01, 0xd2, 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x0c, 0x50, 0x4c,
|
||||
0x54, 0x45, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x60,
|
||||
0x60, 0x60, 0x58, 0xe6, 0xdc, 0x65, 0x00, 0x00, 0x00, 0x02, 0x74, 0x52,
|
||||
0x4e, 0x53, 0x00, 0x00, 0x76, 0x93, 0xcd, 0x38, 0x00, 0x00, 0x04, 0x15,
|
||||
0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xe5, 0xd3, 0xb1, 0x6a, 0x1c, 0x47,
|
||||
0x1c, 0xc7, 0xf1, 0x2f, 0xb3, 0xc4, 0x2c, 0xe3, 0x63, 0xaf, 0x4b, 0x91,
|
||||
0x6a, 0x49, 0xb5, 0xcc, 0x1d, 0xf6, 0x81, 0x1b, 0xb1, 0x36, 0x56, 0x1e,
|
||||
0x21, 0x75, 0xde, 0xc0, 0x79, 0x8a, 0xc1, 0x95, 0x48, 0x61, 0x5c, 0x24,
|
||||
0xfd, 0x20, 0x1c, 0x98, 0xfc, 0x77, 0xd1, 0x2d, 0x49, 0x63, 0x14, 0x81,
|
||||
0xb6, 0x34, 0x41, 0xe4, 0x19, 0x5c, 0x8a, 0xb3, 0x09, 0x02, 0x37, 0xe1,
|
||||
0x72, 0xf8, 0x92, 0x19, 0x5d, 0xb4, 0x91, 0x6e, 0x94, 0x20, 0xab, 0x48,
|
||||
0xe1, 0x1f, 0x0c, 0x03, 0xf7, 0xe1, 0xfe, 0x33, 0xf3, 0xdf, 0x19, 0xae,
|
||||
0x8f, 0x76, 0x5c, 0x44, 0x59, 0x28, 0x3a, 0x34, 0x00, 0x22, 0xe8, 0xd6,
|
||||
0xb4, 0x00, 0x18, 0x0f, 0xda, 0xa1, 0xff, 0x60, 0x86, 0x72, 0xda, 0x96,
|
||||
0x5a, 0x3c, 0x2c, 0x44, 0x89, 0xd8, 0x00, 0x63, 0x43, 0x89, 0x46, 0xbb,
|
||||
0x92, 0x00, 0x22, 0x46, 0xc4, 0xc7, 0x52, 0xe6, 0x27, 0x87, 0xc6, 0xb8,
|
||||
0xf8, 0x43, 0x66, 0x89, 0xb3, 0xb2, 0x68, 0x23, 0x8e, 0x0a, 0x5f, 0x4d,
|
||||
0x61, 0x07, 0x65, 0x09, 0xa5, 0x06, 0x50, 0xae, 0x2a, 0x21, 0xaf, 0x94,
|
||||
0x65, 0x77, 0xd1, 0xac, 0x36, 0xd0, 0x51, 0x69, 0x1b, 0x61, 0x52, 0xf4,
|
||||
0xec, 0xbe, 0x3f, 0x5e, 0x51, 0xb7, 0xe8, 0xb7, 0x62, 0xa9, 0x0c, 0x11,
|
||||
0x6a, 0x0d, 0xd9, 0x7a, 0xdd, 0x73, 0x3a, 0x41, 0xf3, 0x06, 0xb4, 0xc7,
|
||||
0x05, 0xd0, 0x1a, 0x46, 0xeb, 0xd5, 0x49, 0xed, 0x74, 0xab, 0x37, 0x07,
|
||||
0x8f, 0x50, 0x34, 0xf0, 0xe0, 0xc1, 0xbb, 0x99, 0xb1, 0xca, 0x07, 0x88,
|
||||
0x07, 0x0c, 0xbb, 0x52, 0x1e, 0x38, 0x39, 0xe9, 0x2f, 0x00, 0x11, 0x6a,
|
||||
0x91, 0x16, 0x07, 0x3c, 0x98, 0x51, 0xf7, 0x59, 0xab, 0xb7, 0x9a, 0x48,
|
||||
0xcf, 0x6d, 0x53, 0xb7, 0xc3, 0x7c, 0x29, 0x22, 0x14, 0x22, 0xdd, 0x58,
|
||||
0xe4, 0x0c, 0x86, 0xc4, 0x2d, 0xdf, 0x85, 0xd7, 0x85, 0xd3, 0xdd, 0xa5,
|
||||
0x32, 0x7a, 0xbd, 0x74, 0x39, 0x94, 0xba, 0x1f, 0xb6, 0x48, 0x26, 0xd2,
|
||||
0xd7, 0xeb, 0x45, 0x1b, 0xa0, 0xc6, 0xb4, 0x43, 0x99, 0xe3, 0xf7, 0x76,
|
||||
0xb2, 0x6e, 0x4e, 0x03, 0x84, 0x6f, 0x73, 0x01, 0x0f, 0x7f, 0xfb, 0xf9,
|
||||
0xed, 0xe4, 0xfd, 0xfc, 0x34, 0x57, 0xb6, 0xac, 0x94, 0x1b, 0xa0, 0xfd,
|
||||
0x7c, 0xaf, 0x3e, 0x5d, 0x1e, 0x4f, 0xfe, 0x82, 0x59, 0xa5, 0xed, 0x00,
|
||||
0x3b, 0xd3, 0x9d, 0xe9, 0xc4, 0x10, 0x4a, 0x51, 0x19, 0x06, 0x50, 0xda,
|
||||
0xd9, 0xba, 0x59, 0xb7, 0x39, 0xda, 0xd5, 0x7e, 0x3c, 0x2c, 0x9e, 0x75,
|
||||
0x45, 0xaf, 0xe7, 0x6b, 0x97, 0x73, 0xef, 0xa5, 0x76, 0xbb, 0x03, 0xb0,
|
||||
0x68, 0x50, 0xf3, 0xa5, 0xbd, 0xcb, 0x8f, 0xcf, 0x0a, 0xb7, 0x3c, 0xde,
|
||||
0x6e, 0x49, 0x3b, 0xdd, 0x19, 0x8b, 0x8c, 0x12, 0x4d, 0xd4, 0x8e, 0x7a,
|
||||
0x7e, 0xc6, 0x7f, 0x47, 0xd9, 0x30, 0x92, 0xef, 0x23, 0x8c, 0x58, 0x4e,
|
||||
0x7d, 0x53, 0xb9, 0x30, 0x80, 0x15, 0x18, 0x4f, 0x1c, 0x22, 0x94, 0x10,
|
||||
0x07, 0x64, 0x2b, 0x62, 0x36, 0x17, 0xba, 0x54, 0xb2, 0x57, 0x42, 0x0e,
|
||||
0xd3, 0x55, 0x28, 0x11, 0x41, 0xb7, 0xb5, 0x03, 0xd9, 0x23, 0xc2, 0xe1,
|
||||
0x8c, 0xfc, 0xed, 0xc3, 0x32, 0x74, 0x36, 0x5c, 0xb4, 0x92, 0x85, 0x2d,
|
||||
0x01, 0xd4, 0xa2, 0xa7, 0xea, 0x8a, 0xaa, 0x2a, 0xba, 0xca, 0xf4, 0xf8,
|
||||
0x92, 0x4d, 0xa9, 0xbb, 0x8d, 0xc5, 0x3f, 0x7d, 0x6a, 0x44, 0x44, 0x0c,
|
||||
0x78, 0xd4, 0x41, 0x2c, 0xc5, 0xbd, 0x03, 0x18, 0xc0, 0xfa, 0x52, 0xdb,
|
||||
0x58, 0x8a, 0xc3, 0x97, 0x30, 0x94, 0xda, 0xf7, 0x46, 0xc8, 0x4b, 0xd4,
|
||||
0x1e, 0x8b, 0xd7, 0x5c, 0x2c, 0x5e, 0x5b, 0x69, 0x8d, 0x27, 0x07, 0x65,
|
||||
0xd5, 0xc4, 0x32, 0x6c, 0xd7, 0x8b, 0x33, 0x1e, 0x4a, 0x8c, 0xd7, 0xcf,
|
||||
0x60, 0x38, 0xa0, 0x17, 0x1b, 0xfe, 0x11, 0xc1, 0xc1, 0xd0, 0x92, 0xf0,
|
||||
0x8f, 0x4d, 0xa9, 0xc7, 0x16, 0x86, 0x26, 0x22, 0xde, 0xf8, 0x7d, 0xab,
|
||||
0xab, 0x7d, 0xfb, 0x28, 0xd1, 0xf6, 0x9b, 0xc4, 0x02, 0x28, 0x20, 0x73,
|
||||
0xc0, 0x08, 0x78, 0x04, 0xea, 0xd7, 0x4e, 0x9d, 0x83, 0x85, 0x79, 0x80,
|
||||
0x57, 0xc0, 0x12, 0xb2, 0x43, 0xa7, 0xcf, 0xc1, 0x31, 0x69, 0xa1, 0xee,
|
||||
0x3c, 0x64, 0x0b, 0x0b, 0x0b, 0x67, 0x44, 0xfa, 0x4c, 0xc4, 0xeb, 0x37,
|
||||
0x90, 0xf9, 0xa9, 0x87, 0xb1, 0x74, 0x28, 0xdd, 0x89, 0x88, 0xd3, 0x22,
|
||||
0xa2, 0x7b, 0x28, 0x7e, 0xbf, 0xdf, 0xc2, 0x63, 0x39, 0x23, 0x57, 0xbd,
|
||||
0x39, 0x07, 0x3f, 0x9e, 0xcf, 0x5d, 0xbd, 0x9c, 0xf7, 0xf0, 0x4b, 0xd3,
|
||||
0x53, 0x66, 0x9d, 0xb6, 0x9c, 0x4e, 0x50, 0x2e, 0x80, 0x91, 0x03, 0x4b,
|
||||
0xb6, 0x3f, 0x07, 0xfb, 0xea, 0xb5, 0xb2, 0x54, 0x15, 0xca, 0x8e, 0x60,
|
||||
0x56, 0xca, 0x01, 0x14, 0xfe, 0x08, 0x45, 0x09, 0xe7, 0xc0, 0x78, 0xbd,
|
||||
0x3e, 0x2b, 0xe5, 0x10, 0x6a, 0x99, 0x91, 0x8f, 0x2c, 0x10, 0x00, 0x46,
|
||||
0xcc, 0x66, 0x66, 0x7e, 0x08, 0x5a, 0x7a, 0x72, 0x05, 0x10, 0xd6, 0x20,
|
||||
0x42, 0x75, 0xff, 0x25, 0x28, 0x81, 0x3c, 0x07, 0x54, 0xd8, 0x95, 0x8d,
|
||||
0x80, 0x39, 0x05, 0x9a, 0x77, 0xa3, 0xc2, 0x0d, 0x10, 0xd6, 0xa0, 0x0e,
|
||||
0xb0, 0x7b, 0xd2, 0x43, 0x80, 0x70, 0x72, 0xcb, 0x87, 0x45, 0x59, 0x00,
|
||||
0x76, 0x12, 0x10, 0xa9, 0x45, 0x5b, 0x50, 0xad, 0xe9, 0xd1, 0x1d, 0x03,
|
||||
0x28, 0x87, 0xf6, 0x57, 0xc1, 0x78, 0xd0, 0x16, 0x2d, 0x36, 0x01, 0x06,
|
||||
0xb4, 0xf8, 0x01, 0x36, 0x04, 0x4d, 0x8f, 0x16, 0xb1, 0x01, 0xb4, 0x48,
|
||||
0x17, 0x46, 0x5c, 0x23, 0x13, 0x09, 0xd0, 0x5e, 0x06, 0x40, 0x49, 0x13,
|
||||
0xe0, 0xe8, 0x9f, 0x40, 0xcc, 0xd8, 0xa3, 0xa5, 0xe9, 0x03, 0x8c, 0x97,
|
||||
0xc7, 0x67, 0xa1, 0x57, 0xf1, 0x5a, 0xc7, 0xed, 0xca, 0xd1, 0xa5, 0xc5,
|
||||
0x8d, 0xff, 0x7b, 0xbb, 0x4d, 0x9f, 0x80, 0x1a, 0xf4, 0x11, 0x09, 0x98,
|
||||
0xc2, 0xb8, 0x87, 0x6c, 0xb5, 0xdb, 0x33, 0x3e, 0x1b, 0x20, 0x95, 0xb8,
|
||||
0xf8, 0xb5, 0x59, 0x6f, 0xd2, 0x43, 0x8c, 0x72, 0x0c, 0x10, 0x96, 0xd8,
|
||||
0x82, 0x85, 0x48, 0xf3, 0x61, 0xc0, 0xc7, 0x02, 0x46, 0xd2, 0xa0, 0x44,
|
||||
0x5c, 0x12, 0xf4, 0x53, 0xe7, 0xd3, 0xa0, 0x5c, 0x95, 0x84, 0x4a, 0x39,
|
||||
0x7d, 0x03, 0x90, 0x8b, 0xdc, 0x1c, 0x6e, 0xb3, 0x78, 0xfa, 0x1c, 0xe9,
|
||||
0x93, 0xa7, 0x7b, 0x95, 0xee, 0xee, 0xff, 0xff, 0xcd, 0x6b, 0x91, 0x36,
|
||||
0x09, 0x85, 0x48, 0x97, 0x84, 0x4c, 0xa4, 0x4f, 0xbe, 0x0f, 0x16, 0x0d,
|
||||
0x69, 0xa8, 0x5b, 0xd2, 0x50, 0x74, 0x49, 0x88, 0x3f, 0x6d, 0x3d, 0xe7,
|
||||
0x54, 0x44, 0x48, 0xc6, 0x88, 0xfc, 0x40, 0x22, 0x9f, 0x0a, 0x88, 0x4d,
|
||||
0xc0, 0xd7, 0x16, 0x94, 0x67, 0x2b, 0x9f, 0xc4, 0x32, 0x26, 0x51, 0xe9,
|
||||
0x3b, 0x80, 0x3b, 0xcf, 0xb7, 0xe0, 0xab, 0x2f, 0x01, 0x78, 0xb1, 0x05,
|
||||
0x4f, 0xbe, 0x00, 0xa0, 0xda, 0x82, 0xef, 0x89, 0xd1, 0x5c, 0xc9, 0x9d,
|
||||
0x6f, 0x37, 0xb3, 0xbd, 0x0a, 0x9b, 0x55, 0xd5, 0x55, 0xf8, 0x8c, 0x4d,
|
||||
0x5c, 0x02, 0x92, 0xdb, 0x7a, 0xc2, 0x26, 0xd5, 0x6d, 0x61, 0x28, 0xad,
|
||||
0x6f, 0x0d, 0x0e, 0x50, 0xf6, 0xa6, 0x00, 0xb7, 0x82, 0xad, 0x73, 0x55,
|
||||
0xb7, 0x85, 0xeb, 0xdb, 0xae, 0xaf, 0xfb, 0x50, 0xca, 0x0e, 0xf3, 0x65,
|
||||
0x78, 0x4e, 0xfa, 0x32, 0xe0, 0xd2, 0xc7, 0x80, 0x6a, 0x98, 0x92, 0xdb,
|
||||
0x7a, 0x01, 0x89, 0x8b, 0x95, 0xbc, 0xd4, 0x78, 0xd2, 0xcf, 0x00, 0x93,
|
||||
0x7e, 0x38, 0xa0, 0x86, 0xa7, 0x96, 0x78, 0x9c, 0xff, 0xfe, 0x9c, 0xff,
|
||||
0x04, 0xe2, 0xd8, 0x90, 0xc1, 0x18, 0xe1, 0xf4, 0x9b, 0x00, 0x00, 0x00,
|
||||
0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
|
||||
0x12, 0x01, 0xd2, 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x0f, 0x50, 0x4c,
|
||||
0x54, 0x45, 0x00, 0x00, 0x00, 0x76, 0x76, 0x76, 0xff, 0xff, 0xff, 0x60,
|
||||
0x60, 0x60, 0xff, 0xff, 0xff, 0x3e, 0xd5, 0x47, 0x6d, 0x00, 0x00, 0x00,
|
||||
0x03, 0x74, 0x52, 0x4e, 0x53, 0x00, 0x00, 0x00, 0xfa, 0x76, 0xc4, 0xde,
|
||||
0x00, 0x00, 0x04, 0x62, 0x49, 0x44, 0x41, 0x54, 0x58, 0xc3, 0xed, 0x59,
|
||||
0x5b, 0x6e, 0x24, 0x37, 0x0c, 0x2c, 0x80, 0xbc, 0x40, 0xee, 0x90, 0x03,
|
||||
0x10, 0x20, 0x0f, 0xc0, 0x80, 0x75, 0xff, 0x33, 0xe5, 0x83, 0xa2, 0x5a,
|
||||
0x63, 0xcf, 0xae, 0xa7, 0x37, 0xb1, 0x03, 0x6c, 0xac, 0x0f, 0x77, 0x6b,
|
||||
0x5a, 0xd5, 0x7c, 0x15, 0x49, 0xb5, 0x0c, 0xfc, 0xc2, 0x20, 0x9f, 0xff,
|
||||
0xae, 0xd9, 0xd7, 0x28, 0x00, 0xe0, 0xb1, 0x9e, 0x04, 0x40, 0x9a, 0x92,
|
||||
0x76, 0xac, 0x27, 0xf3, 0x78, 0x21, 0xbd, 0x00, 0x01, 0xa0, 0x04, 0x98,
|
||||
0xd0, 0x46, 0x26, 0x00, 0x04, 0x49, 0xe8, 0x9e, 0x36, 0xc0, 0x95, 0x80,
|
||||
0x2e, 0x51, 0x64, 0xdf, 0xee, 0x15, 0xa4, 0x92, 0x83, 0x58, 0x2a, 0x29,
|
||||
0x4b, 0xd8, 0x00, 0x9d, 0x17, 0xf6, 0x02, 0xc9, 0x56, 0x68, 0xe6, 0x6d,
|
||||
0x4b, 0xbf, 0xa2, 0x67, 0x4c, 0x4d, 0x35, 0xec, 0xb5, 0x89, 0x41, 0x24,
|
||||
0x9e, 0x01, 0x94, 0xd0, 0xd4, 0xb6, 0x34, 0x35, 0x7b, 0x81, 0x78, 0x90,
|
||||
0xe5, 0xf6, 0x08, 0x28, 0x40, 0x13, 0xcc, 0x13, 0x50, 0x08, 0x03, 0x20,
|
||||
0xee, 0x51, 0xee, 0x06, 0x48, 0xfb, 0x8e, 0x61, 0x64, 0x02, 0x9a, 0x4a,
|
||||
0x1c, 0x00, 0xe1, 0xf2, 0xb8, 0xb8, 0xbb, 0x1b, 0x80, 0x48, 0xad, 0xb6,
|
||||
0x75, 0x59, 0xcf, 0x04, 0xda, 0x4b, 0x00, 0x12, 0x03, 0x30, 0x77, 0x37,
|
||||
0x33, 0x21, 0x01, 0xd2, 0xae, 0xc0, 0x75, 0xd4, 0x2e, 0x40, 0xb0, 0x00,
|
||||
0x40, 0x44, 0xc4, 0x45, 0xa0, 0x4c, 0x40, 0x99, 0x17, 0x60, 0x02, 0x37,
|
||||
0x5e, 0xd2, 0x15, 0x5f, 0x98, 0x99, 0xd9, 0x13, 0xc0, 0xa2, 0x86, 0xb4,
|
||||
0xdf, 0xed, 0x22, 0x8d, 0x88, 0x00, 0x10, 0x5a, 0xff, 0xe1, 0xc7, 0xe4,
|
||||
0x83, 0xe1, 0x8b, 0xc6, 0xd0, 0x5c, 0xde, 0x48, 0x94, 0x07, 0x72, 0x5f,
|
||||
0xf3, 0xa1, 0xf9, 0xdb, 0xe7, 0x93, 0x17, 0xc1, 0xa6, 0x80, 0x93, 0xa4,
|
||||
0x5f, 0x9c, 0x92, 0xe5, 0x13, 0xbc, 0x71, 0x2f, 0x0a, 0x00, 0x02, 0x08,
|
||||
0x02, 0xac, 0xcd, 0x5a, 0x09, 0xba, 0xb3, 0xec, 0x12, 0x45, 0x77, 0x27,
|
||||
0x81, 0x26, 0x28, 0x40, 0xeb, 0x3c, 0x19, 0x40, 0x3f, 0xb7, 0x2d, 0x4a,
|
||||
0xe8, 0x1e, 0xa4, 0x0d, 0x40, 0x3a, 0x4f, 0x6c, 0xab, 0xd4, 0xcf, 0x01,
|
||||
0x68, 0xb9, 0x47, 0x42, 0xcb, 0x9d, 0x15, 0x39, 0x80, 0xc9, 0x93, 0xa1,
|
||||
0xf9, 0x7e, 0x2e, 0x15, 0x51, 0x15, 0xa6, 0xe5, 0x41, 0x8f, 0x44, 0x42,
|
||||
0xb3, 0x01, 0x4a, 0x68, 0x0e, 0xcd, 0xf7, 0x73, 0x9a, 0x6a, 0xa6, 0x30,
|
||||
0xd2, 0x59, 0xae, 0xd5, 0x00, 0xd9, 0x79, 0x32, 0x34, 0xd7, 0x72, 0x96,
|
||||
0x47, 0x42, 0x52, 0x4d, 0x52, 0x4d, 0x4b, 0x09, 0x8c, 0x4a, 0x57, 0x9e,
|
||||
0xc0, 0xdc, 0x1d, 0x80, 0x66, 0xd0, 0xa1, 0x09, 0x28, 0x48, 0x24, 0x84,
|
||||
0x2c, 0xf7, 0x65, 0x34, 0x09, 0x21, 0x13, 0x4e, 0x53, 0x29, 0xb1, 0x9e,
|
||||
0x97, 0x39, 0x01, 0x48, 0x01, 0x61, 0x00, 0xe9, 0xee, 0xed, 0x56, 0x8d,
|
||||
0x4a, 0x90, 0x10, 0xa7, 0x81, 0x66, 0x6b, 0x6e, 0xe2, 0xb4, 0x0e, 0x6d,
|
||||
0x01, 0x50, 0xba, 0xaf, 0xc0, 0x95, 0x66, 0x20, 0x08, 0x67, 0x39, 0x28,
|
||||
0xc7, 0x3c, 0xfd, 0x19, 0x35, 0x4c, 0x4d, 0xb2, 0xa9, 0x01, 0x53, 0x24,
|
||||
0xd4, 0x24, 0x05, 0x24, 0xf9, 0xc0, 0xbf, 0x83, 0x5c, 0x64, 0xcf, 0xdd,
|
||||
0xcf, 0x8c, 0xb9, 0xe6, 0xbf, 0xca, 0xf7, 0xb9, 0xbe, 0xdc, 0x1f, 0xd6,
|
||||
0x75, 0xa9, 0xa6, 0x49, 0x4d, 0x5e, 0x57, 0x00, 0x40, 0x57, 0xc2, 0x29,
|
||||
0xa1, 0x47, 0xed, 0xc6, 0x94, 0x9d, 0x7d, 0x5d, 0xc5, 0xcd, 0xde, 0xab,
|
||||
0xb6, 0xd8, 0xa9, 0xfd, 0x86, 0x5d, 0x11, 0x01, 0x40, 0xcd, 0xed, 0xf4,
|
||||
0xce, 0x2a, 0xba, 0xec, 0x6a, 0xd7, 0x45, 0x71, 0xcc, 0x4a, 0x00, 0x28,
|
||||
0x0a, 0x80, 0x0c, 0x93, 0x52, 0x6c, 0x96, 0xae, 0xc2, 0xa5, 0x00, 0xa2,
|
||||
0x25, 0x6d, 0x0d, 0x82, 0x06, 0x68, 0x16, 0x10, 0x9a, 0x9a, 0x88, 0x82,
|
||||
0xa6, 0x76, 0xfa, 0xa5, 0x2e, 0x09, 0x87, 0x4a, 0xc5, 0x4a, 0x80, 0x99,
|
||||
0x9a, 0xba, 0x12, 0x91, 0xa4, 0x76, 0x8c, 0xba, 0x09, 0xc5, 0xa9, 0x92,
|
||||
0x06, 0x03, 0xcf, 0x01, 0xd9, 0x12, 0x98, 0x38, 0x55, 0x6a, 0x01, 0x4f,
|
||||
0x55, 0xa2, 0x32, 0xb5, 0x99, 0xd5, 0x2a, 0x69, 0x26, 0xd0, 0x02, 0xde,
|
||||
0x19, 0x2d, 0x4c, 0xb0, 0x7b, 0x76, 0x8e, 0x77, 0x3a, 0x6f, 0xb4, 0xf2,
|
||||
0x0d, 0xe9, 0xc6, 0xad, 0xb9, 0xda, 0xf4, 0x14, 0x9c, 0xbe, 0x67, 0xc6,
|
||||
0x73, 0x4e, 0x29, 0x93, 0xcc, 0x01, 0xe4, 0x05, 0xe0, 0xdb, 0x2d, 0xc2,
|
||||
0xa6, 0xc6, 0x29, 0x61, 0xab, 0x24, 0x91, 0x3f, 0x22, 0x5f, 0xef, 0x08,
|
||||
0x94, 0x4c, 0x6a, 0x02, 0xd4, 0xa4, 0xe6, 0x43, 0xe9, 0xbe, 0x4d, 0xef,
|
||||
0x7f, 0x3a, 0x0e, 0x39, 0xba, 0xb3, 0xf7, 0xb1, 0x8b, 0x2d, 0xfd, 0xd4,
|
||||
0xa2, 0x1e, 0x15, 0x5b, 0xf7, 0xf4, 0x01, 0x58, 0xff, 0xb0, 0xe6, 0x52,
|
||||
0x5c, 0x3d, 0xe2, 0xec, 0x19, 0xd0, 0xea, 0x38, 0x09, 0x6b, 0x3d, 0x94,
|
||||
0x58, 0x8b, 0x62, 0xf7, 0x83, 0x69, 0x03, 0x4c, 0xb0, 0x37, 0x0c, 0x10,
|
||||
0xa6, 0x5a, 0x2f, 0xf4, 0xae, 0x64, 0x50, 0xb0, 0xb0, 0x38, 0x88, 0x7d,
|
||||
0x33, 0xb5, 0x27, 0x3c, 0xb5, 0x2b, 0x9f, 0x04, 0xe9, 0x6d, 0xad, 0xda,
|
||||
0x74, 0x9c, 0x01, 0x24, 0x9c, 0x4e, 0x27, 0x84, 0x4e, 0x76, 0x4a, 0x1b,
|
||||
0xbb, 0x75, 0x69, 0xd7, 0xd9, 0xde, 0xb5, 0xf5, 0x0e, 0x46, 0x89, 0x01,
|
||||
0x28, 0x49, 0x46, 0x02, 0x10, 0xea, 0x08, 0xb0, 0x8c, 0xe5, 0x19, 0x4d,
|
||||
0x9d, 0xbd, 0x59, 0x1b, 0x0c, 0x05, 0xd9, 0xfc, 0x0e, 0xe6, 0x08, 0xd0,
|
||||
0x1d, 0x87, 0x01, 0x00, 0x70, 0x77, 0x77, 0x87, 0x82, 0xac, 0x55, 0x41,
|
||||
0x29, 0x23, 0xe0, 0x08, 0xc0, 0x0e, 0x87, 0x01, 0x02, 0x81, 0x92, 0x5e,
|
||||
0xab, 0xc4, 0xb6, 0x1f, 0x1e, 0x0a, 0xc4, 0xb2, 0xe1, 0x04, 0xa4, 0x7a,
|
||||
0x0d, 0xab, 0x97, 0x26, 0x79, 0xf1, 0x9d, 0xd7, 0x26, 0x76, 0x01, 0xba,
|
||||
0x26, 0x74, 0xe0, 0xcb, 0x05, 0x86, 0x38, 0x13, 0xe4, 0x00, 0x2c, 0x1b,
|
||||
0x00, 0x19, 0x80, 0xb8, 0xd9, 0x63, 0xc9, 0x9c, 0x48, 0x7f, 0x15, 0xdd,
|
||||
0xf1, 0x3e, 0xbd, 0x24, 0x5f, 0x04, 0x0c, 0x68, 0x95, 0xd3, 0xb1, 0xc0,
|
||||
0xba, 0xbe, 0x82, 0xf5, 0x03, 0xc0, 0x2a, 0xa7, 0xcc, 0x8f, 0x00, 0x57,
|
||||
0x5d, 0x99, 0x52, 0xf1, 0x1a, 0x40, 0xb9, 0xdb, 0x74, 0xfe, 0x04, 0x70,
|
||||
0xd4, 0xc6, 0xb2, 0x01, 0x74, 0x33, 0x69, 0x00, 0xd7, 0xde, 0x6f, 0xae,
|
||||
0xdb, 0x06, 0xd9, 0x1f, 0x4d, 0x9d, 0x9b, 0x3f, 0x03, 0x6c, 0x22, 0xd4,
|
||||
0x00, 0xea, 0xc7, 0x80, 0x63, 0x38, 0x73, 0x01, 0xca, 0x2e, 0x95, 0xdc,
|
||||
0x59, 0xee, 0x57, 0x3e, 0x1c, 0x05, 0x79, 0xdc, 0xba, 0x32, 0xf5, 0xb9,
|
||||
0xd1, 0xba, 0xea, 0xed, 0xe9, 0xd6, 0x36, 0xfe, 0x63, 0xc0, 0xaa, 0x83,
|
||||
0x6b, 0xfd, 0x0b, 0x80, 0xfe, 0xd4, 0xc0, 0xec, 0x0a, 0xc4, 0x6d, 0xed,
|
||||
0x10, 0x1e, 0x36, 0x3b, 0xa7, 0x4a, 0xaf, 0x91, 0xf5, 0xb1, 0x0b, 0xdd,
|
||||
0x18, 0xfe, 0x66, 0xd8, 0xfb, 0x57, 0x3f, 0x07, 0x8c, 0x05, 0x1f, 0x02,
|
||||
0x82, 0x13, 0xe2, 0xaf, 0x02, 0xe0, 0x1b, 0xf0, 0x7b, 0x00, 0xd6, 0xde,
|
||||
0xef, 0x65, 0x80, 0xae, 0xae, 0xfd, 0x32, 0x80, 0xa9, 0x7c, 0xd8, 0x7e,
|
||||
0x7c, 0x08, 0xe8, 0xcf, 0xbf, 0x97, 0x01, 0xfd, 0xbd, 0x78, 0x9e, 0x07,
|
||||
0xfc, 0x7b, 0x00, 0x3e, 0x19, 0xff, 0x31, 0xe0, 0xf3, 0x8d, 0xfe, 0xc5,
|
||||
0x38, 0xdc, 0x8f, 0xf4, 0x6d, 0x2e, 0xdd, 0x66, 0xeb, 0xef, 0x99, 0xd3,
|
||||
0x73, 0x36, 0xf6, 0x32, 0x60, 0xce, 0x93, 0x5e, 0x07, 0xac, 0xd3, 0x9f,
|
||||
0x97, 0xfb, 0xc3, 0x9c, 0x6b, 0xdc, 0x00, 0xf4, 0x97, 0xe2, 0x0d, 0x40,
|
||||
0x9f, 0x59, 0xde, 0x01, 0x88, 0xe1, 0x5d, 0x37, 0xfd, 0x29, 0xe0, 0x7b,
|
||||
0x7c, 0x8f, 0xaf, 0x19, 0x77, 0x3f, 0xb6, 0xf6, 0x3f, 0x15, 0x5e, 0x1c,
|
||||
0xca, 0x9b, 0x04, 0x27, 0x70, 0xeb, 0xc0, 0x63, 0x8e, 0x1d, 0x3e, 0x0f,
|
||||
0xb0, 0x56, 0xfe, 0x99, 0x77, 0x00, 0x7f, 0xdc, 0x05, 0xfc, 0xf5, 0xe9,
|
||||
0x12, 0x6e, 0x01, 0x3e, 0xdf, 0xad, 0xb7, 0x23, 0x7d, 0x9f, 0x4b, 0xb7,
|
||||
0xd9, 0x7a, 0x3f, 0x1f, 0xbe, 0xc7, 0xff, 0x75, 0xfc, 0x0d, 0x3b, 0xd4,
|
||||
0xd5, 0x4b, 0x3b, 0xfe, 0xb6, 0x75, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,
|
||||
0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
|
||||
};
|
||||
|
||||
const u32 TEXTURE_ATLAS_LENGTH = (u32)std::size(TEXTURE_ATLAS);
|
||||
@@ -120,8 +125,8 @@ enum AtlasType
|
||||
ATLAS_INVISIBLE,
|
||||
ATLAS_SHOW_RECT,
|
||||
ATLAS_HIDE_RECT,
|
||||
ATLAS_PLACEHOLDER,
|
||||
ATLAS_PLACEHOLDER2,
|
||||
ATLAS_SHOW_UNUSED,
|
||||
ATLAS_HIDE_UNUSED,
|
||||
ATLAS_PAN,
|
||||
ATLAS_MOVE,
|
||||
ATLAS_ROTATE,
|
||||
|
1186
src/anm2.cpp
1186
src/anm2.cpp
File diff suppressed because it is too large
Load Diff
84
src/anm2.h
84
src/anm2.h
@@ -13,7 +13,11 @@
|
||||
#define ANM2_FRAME_DELAY_MIN 1
|
||||
#define ANM2_STRING_MAX 0xFF
|
||||
|
||||
#define ANM2_EMPTY_ERROR "No path given for anm2"
|
||||
#define ANM2_READ_ERROR "Failed to read anm2 from file: {}"
|
||||
#define ANM2_PARSE_ERROR "Failed to parse anm2: {} ({})"
|
||||
#define ANM2_FRAME_PARSE_ERROR "Failed to parse frame: {} ({})"
|
||||
#define ANM2_ANIMATION_PARSE_ERROR "Failed to parse frame: {} ({})"
|
||||
#define ANM2_READ_INFO "Read anm2 from file: {}"
|
||||
#define ANM2_WRITE_ERROR "Failed to write anm2 to file: {}"
|
||||
#define ANM2_WRITE_INFO "Wrote anm2 to file: {}"
|
||||
@@ -61,7 +65,6 @@ const inline char* ANM2_ELEMENT_STRINGS[] =
|
||||
};
|
||||
|
||||
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") \
|
||||
@@ -118,7 +121,6 @@ static const char* ANM2_ATTRIBUTE_STRINGS[] =
|
||||
};
|
||||
|
||||
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)
|
||||
|
||||
enum Anm2Type
|
||||
{
|
||||
@@ -140,7 +142,7 @@ struct Anm2Spritesheet
|
||||
struct Anm2Layer
|
||||
{
|
||||
std::string name = "New Layer";
|
||||
s32 spritesheetID = ID_NONE;
|
||||
s32 spritesheetID{};
|
||||
};
|
||||
|
||||
struct Anm2Null
|
||||
@@ -198,7 +200,8 @@ struct Anm2Animation
|
||||
std::string name = "New Animation";
|
||||
bool isLoop = true;
|
||||
Anm2Item rootAnimation;
|
||||
std::map<s32, Anm2Item> layerAnimations;
|
||||
std::unordered_map<s32, Anm2Item> layerAnimations;
|
||||
std::vector<s32> layerOrder;
|
||||
std::map<s32, Anm2Item> nullAnimations;
|
||||
Anm2Item triggers;
|
||||
};
|
||||
@@ -213,7 +216,6 @@ struct Anm2
|
||||
std::map<s32, Anm2Null> nulls;
|
||||
std::map<s32, Anm2Event> events;
|
||||
std::map<s32, Anm2Animation> animations;
|
||||
std::map<s32, s32> layerMap; // index, id
|
||||
s32 defaultAnimationID = ID_NONE;
|
||||
s32 fps = ANM2_FPS_DEFAULT;
|
||||
s32 version{};
|
||||
@@ -225,27 +227,10 @@ struct Anm2Reference
|
||||
Anm2Type itemType = ANM2_NONE;
|
||||
s32 itemID = ID_NONE;
|
||||
s32 frameIndex = INDEX_NONE;
|
||||
f32 time = VALUE_NONE;
|
||||
auto operator<=>(const Anm2Reference&) const = default;
|
||||
};
|
||||
|
||||
struct Anm2AnimationWithID
|
||||
{
|
||||
s32 id;
|
||||
Anm2Animation animation;
|
||||
};
|
||||
|
||||
struct Anm2EventWithID
|
||||
{
|
||||
s32 id;
|
||||
Anm2Event event;
|
||||
};
|
||||
|
||||
struct Anm2FrameWithReference
|
||||
{
|
||||
Anm2Reference reference;
|
||||
Anm2Frame frame;
|
||||
};
|
||||
|
||||
enum Anm2MergeType
|
||||
{
|
||||
ANM2_MERGE_APPEND_FRAMES,
|
||||
@@ -267,33 +252,42 @@ enum OnionskinDrawOrder
|
||||
ONIONSKIN_ABOVE
|
||||
};
|
||||
|
||||
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 std::string& path);
|
||||
bool anm2_deserialize(Anm2* self, const std::string& path);
|
||||
void anm2_new(Anm2* self);
|
||||
void anm2_free(Anm2* self);
|
||||
void anm2_created_on_set(Anm2* self);
|
||||
s32 anm2_animation_add(Anm2* self);
|
||||
void anm2_animation_remove(Anm2* self, s32 id);
|
||||
Anm2Animation* anm2_animation_from_reference(Anm2* self, Anm2Reference* reference);
|
||||
Anm2Item* anm2_item_from_reference(Anm2* self, Anm2Reference* reference);
|
||||
Anm2Frame* anm2_frame_add(Anm2* self, Anm2Frame* frame, Anm2Reference* reference);
|
||||
Anm2Frame* anm2_frame_from_reference(Anm2* self, Anm2Reference* reference);
|
||||
s32 anm2_frame_index_from_time(Anm2* self, Anm2Reference reference, f32 time);
|
||||
Anm2Frame* anm2_frame_add(Anm2* self, Anm2Frame* frame, Anm2Reference* reference, s32 time = 0.0f);
|
||||
void anm2_frame_erase(Anm2* self, Anm2Reference* reference);
|
||||
void anm2_frame_from_time(Anm2* self, Anm2Frame* frame, Anm2Reference reference, f32 time);
|
||||
void anm2_reference_clear(Anm2Reference* self);
|
||||
void anm2_reference_item_clear(Anm2Reference* self);
|
||||
void anm2_reference_frame_clear(Anm2Reference* self);
|
||||
Anm2Item* anm2_item_from_reference(Anm2* self, Anm2Reference* reference);
|
||||
bool anm2_animation_deserialize_from_xml(Anm2Animation* animation, const std::string& xml);
|
||||
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_serialize(Anm2* self, const std::string& path);
|
||||
s32 anm2_animation_add(Anm2* self, Anm2Animation* animation = nullptr, s32 id = ID_NONE);
|
||||
s32 anm2_animation_length_get(Anm2Animation* self);
|
||||
s32 anm2_frame_index_from_time(Anm2* self, Anm2Reference reference, f32 time);
|
||||
s32 anm2_layer_add(Anm2* self);
|
||||
s32 anm2_null_add(Anm2* self);
|
||||
vec4 anm2_animation_rect_get(Anm2* anm2, Anm2Reference* reference, bool isRootTransform);
|
||||
void anm2_animation_layer_animation_add(Anm2Animation* animation, s32 id);
|
||||
void anm2_animation_layer_animation_remove(Anm2Animation* animation, s32 id);
|
||||
void anm2_animation_length_set(Anm2Animation* self);
|
||||
void anm2_animation_merge(Anm2* self, s32 animationID, const std::vector<s32>& mergeIDs, Anm2MergeType type);
|
||||
void anm2_animation_null_animation_add(Anm2Animation* animation, s32 id);
|
||||
void anm2_animation_null_animation_remove(Anm2Animation* animation, s32 id);
|
||||
void anm2_animation_remove(Anm2* self, s32 id);
|
||||
void anm2_animation_serialize_to_string(Anm2Animation* animation, std::string* string);
|
||||
void anm2_created_on_set(Anm2* self);
|
||||
void anm2_frame_bake(Anm2* self, Anm2Reference* reference, s32 interval, bool isRoundScale, bool isRoundRotation);
|
||||
void anm2_item_frame_set(Anm2* self, Anm2Reference* reference, const Anm2FrameChange& change, Anm2ChangeType type, s32 start, s32 count);
|
||||
void anm2_scale(Anm2* self, f32 scale);
|
||||
void anm2_frame_from_time(Anm2* self, Anm2Frame* frame, Anm2Reference reference, f32 time);
|
||||
void anm2_frame_remove(Anm2* self, Anm2Reference* reference);
|
||||
void anm2_frame_serialize_to_string(Anm2Frame* frame, Anm2Type type, std::string* string);
|
||||
void anm2_free(Anm2* self);
|
||||
void anm2_generate_from_grid(Anm2* self, Anm2Reference* reference, vec2 startPosition, vec2 size, vec2 pivot, s32 columns, s32 count, s32 delay);
|
||||
void anm2_spritesheet_texture_pixels_upload(Anm2* self);
|
||||
void anm2_item_frame_set(Anm2* self, Anm2Reference* reference, const Anm2FrameChange& change, Anm2ChangeType type, s32 start, s32 count);
|
||||
void anm2_layer_remove(Anm2* self, s32 id);
|
||||
void anm2_new(Anm2* self);
|
||||
void anm2_null_remove(Anm2* self, s32 id);
|
||||
void anm2_reference_clear(Anm2Reference* self);
|
||||
void anm2_reference_frame_clear(Anm2Reference* self);
|
||||
void anm2_reference_item_clear(Anm2Reference* self);
|
||||
void anm2_scale(Anm2* self, f32 scale);
|
||||
void anm2_spritesheet_texture_pixels_download(Anm2* self);
|
||||
void anm2_spritesheet_texture_pixels_upload(Anm2* self);
|
@@ -197,6 +197,7 @@ void canvas_rect_draw(Canvas* self, const GLuint& shader, const mat4& transform,
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
|
||||
void canvas_axes_draw(Canvas* self, GLuint& shader, mat4& transform, vec4& color)
|
||||
{
|
||||
vec4 originNDC = transform * vec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
@@ -241,36 +242,3 @@ void canvas_free(Canvas* self)
|
||||
glDeleteBuffers(1, &self->textureVBO);
|
||||
glDeleteBuffers(1, &self->textureEBO);
|
||||
}
|
||||
|
||||
mat4 canvas_model_get(vec2 size, vec2 position, vec2 pivot, vec2 scale, f32 rotation)
|
||||
{
|
||||
vec2 scaleAbsolute = glm::abs(scale);
|
||||
vec2 scaleSign = glm::sign(scale);
|
||||
vec2 pivotScaled = pivot * scaleAbsolute;
|
||||
vec2 sizeScaled = size * scaleAbsolute;
|
||||
|
||||
mat4 model(1.0f);
|
||||
model = glm::translate(model, vec3(position - pivotScaled, 0.0f));
|
||||
model = glm::translate(model, vec3(pivotScaled, 0.0f));
|
||||
model = glm::scale(model, vec3(scaleSign, 1.0f));
|
||||
model = glm::rotate(model, glm::radians(rotation), vec3(0, 0, 1));
|
||||
model = glm::translate(model, vec3(-pivotScaled, 0.0f));
|
||||
model = glm::scale(model, vec3(sizeScaled, 1.0f));
|
||||
return model;
|
||||
}
|
||||
|
||||
mat4 canvas_parent_model_get(vec2 position, vec2 pivot, vec2 scale, f32 rotation)
|
||||
{
|
||||
vec2 scaleSign = glm::sign(scale);
|
||||
vec2 scaleAbsolute = glm::abs(scale);
|
||||
f32 handedness = (scaleSign.x * scaleSign.y) < 0.0f ? -1.0f : 1.0f;
|
||||
|
||||
mat4 local(1.0f);
|
||||
local = glm::translate(local, vec3(pivot, 0.0f));
|
||||
local = glm::scale(local, vec3(scaleSign, 1.0f));
|
||||
local = glm::rotate(local, glm::radians(rotation) * handedness, vec3(0, 0, 1));
|
||||
local = glm::translate(local, vec3(-pivot, 0.0f));
|
||||
local = glm::scale(local, vec3(scaleAbsolute, 1.0f));
|
||||
|
||||
return glm::translate(mat4(1.0f), vec3(position, 0.0f)) * local;
|
||||
}
|
@@ -65,6 +65,11 @@ struct Canvas
|
||||
0, 1, uvMin.x, uvMax.y \
|
||||
}
|
||||
|
||||
#define ATLAS_UV_MIN(type) (ATLAS_POSITION(type) / TEXTURE_ATLAS_SIZE)
|
||||
#define ATLAS_UV_MAX(type) ((ATLAS_POSITION(type) + ATLAS_SIZE(type)) / TEXTURE_ATLAS_SIZE)
|
||||
#define ATLAS_UV_ARGS(type) ATLAS_UV_MIN(type), ATLAS_UV_MAX(type)
|
||||
#define ATLAS_UV_VERTICES(type) UV_VERTICES(ATLAS_UV_MIN(type), ATLAS_UV_MAX(type))
|
||||
|
||||
mat4 canvas_transform_get(Canvas* self, vec2 pan, f32 zoom, OriginType origin);
|
||||
void canvas_axes_draw(Canvas* self, GLuint& shader, mat4& transform, vec4& color);
|
||||
void canvas_bind(Canvas* self);
|
||||
@@ -77,8 +82,6 @@ void canvas_rect_draw(Canvas* self, const GLuint& shader, const mat4& transform,
|
||||
void canvas_framebuffer_resize_check(Canvas* self);
|
||||
void canvas_unbind(void);
|
||||
void canvas_viewport_set(Canvas* self);
|
||||
mat4 canvas_model_get(vec2 size = {}, vec2 position = {}, vec2 pivot = {}, vec2 scale = vec2(1.0f), f32 rotation = {});
|
||||
mat4 canvas_parent_model_get(vec2 position = {}, vec2 pivot = {}, vec2 scale = vec2(1.0f), f32 rotation = {});
|
||||
|
||||
void canvas_texture_draw
|
||||
(
|
||||
|
@@ -1,94 +1,105 @@
|
||||
#include "clipboard.h"
|
||||
|
||||
static void _clipboard_item_remove(ClipboardItem* self, Anm2* anm2)
|
||||
{
|
||||
switch (self->type)
|
||||
{
|
||||
case CLIPBOARD_FRAME:
|
||||
{
|
||||
Anm2FrameWithReference* frameWithReference = std::get_if<Anm2FrameWithReference>(&self->data);
|
||||
if (!frameWithReference) break;
|
||||
|
||||
anm2_frame_erase(anm2, &frameWithReference->reference);
|
||||
break;
|
||||
}
|
||||
case CLIPBOARD_ANIMATION:
|
||||
{
|
||||
Anm2AnimationWithID* animationWithID = std::get_if<Anm2AnimationWithID>(&self->data);
|
||||
if (!animationWithID) break;
|
||||
|
||||
for (auto & [id, animation] : anm2->animations)
|
||||
{
|
||||
if (id == animationWithID->id)
|
||||
{
|
||||
anm2->animations.erase(animationWithID->id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void _clipboard_item_paste(ClipboardItem* self, ClipboardLocation* location, Anm2* anm2)
|
||||
{
|
||||
switch (self->type)
|
||||
{
|
||||
case CLIPBOARD_FRAME:
|
||||
{
|
||||
Anm2FrameWithReference* frameWithReference = std::get_if<Anm2FrameWithReference>(&self->data);
|
||||
Anm2Reference* reference = std::get_if<Anm2Reference>(location);
|
||||
|
||||
if (!frameWithReference || !reference) break;
|
||||
if (frameWithReference->reference.itemType != reference->itemType) break;
|
||||
|
||||
Anm2Animation* animation = anm2_animation_from_reference(anm2, reference);
|
||||
Anm2Item* anm2Item = anm2_item_from_reference(anm2, reference);
|
||||
|
||||
if (!animation || !anm2Item) break;
|
||||
|
||||
anm2_frame_add(anm2, &frameWithReference->frame, reference, reference->frameIndex);
|
||||
|
||||
break;
|
||||
}
|
||||
case CLIPBOARD_ANIMATION:
|
||||
{
|
||||
Anm2AnimationWithID* animationWithID = std::get_if<Anm2AnimationWithID>(&self->data);
|
||||
if (!animationWithID) break;
|
||||
|
||||
s32 index = 0;
|
||||
|
||||
if (std::holds_alternative<s32>(*location))
|
||||
index = std::get<s32>(*location);
|
||||
else
|
||||
break;
|
||||
|
||||
index = std::clamp(index, 0, (s32)anm2->animations.size());
|
||||
|
||||
map_insert_shift(anm2->animations, index, animationWithID->animation);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void clipboard_copy(Clipboard* self)
|
||||
{
|
||||
self->item = self->hoveredItem;
|
||||
std::string clipboardText{};
|
||||
|
||||
auto clipboard_text_set = [&]()
|
||||
{
|
||||
if (!SDL_SetClipboardText(clipboardText.c_str()))
|
||||
log_warning(std::format(CLIPBOARD_TEXT_SET_WARNING, SDL_GetError()));
|
||||
};
|
||||
|
||||
switch (self->type)
|
||||
{
|
||||
case CLIPBOARD_FRAME:
|
||||
{
|
||||
Anm2Reference* reference = std::get_if<Anm2Reference>(&self->location);
|
||||
if (!reference) break;
|
||||
Anm2Frame* frame = anm2_frame_from_reference(self->anm2, reference);
|
||||
if (!frame) break;
|
||||
anm2_frame_serialize_to_string(frame, reference->itemType, &clipboardText);
|
||||
clipboard_text_set();
|
||||
break;
|
||||
}
|
||||
case CLIPBOARD_ANIMATION:
|
||||
{
|
||||
s32* id = std::get_if<s32>(&self->location);
|
||||
if (!id) break;
|
||||
Anm2Animation* animation = map_find(self->anm2->animations, *id);
|
||||
if (!animation) break;
|
||||
anm2_animation_serialize_to_string(animation, &clipboardText);
|
||||
clipboard_text_set();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void clipboard_cut(Clipboard* self)
|
||||
{
|
||||
self->item = self->hoveredItem;
|
||||
_clipboard_item_remove(&self->item, self->anm2);
|
||||
clipboard_copy(self);
|
||||
|
||||
switch (self->type)
|
||||
{
|
||||
case CLIPBOARD_FRAME:
|
||||
{
|
||||
Anm2Reference* reference = std::get_if<Anm2Reference>(&self->location);
|
||||
if (!reference) break;
|
||||
anm2_frame_remove(self->anm2, reference);
|
||||
break;
|
||||
}
|
||||
case CLIPBOARD_ANIMATION:
|
||||
{
|
||||
s32* id = std::get_if<s32>(&self->location);
|
||||
if (!id) break;
|
||||
anm2_animation_remove(self->anm2, *id);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void clipboard_paste(Clipboard* self)
|
||||
bool clipboard_paste(Clipboard* self)
|
||||
{
|
||||
_clipboard_item_paste(&self->item, &self->location, self->anm2);
|
||||
auto clipboard_string = [&]()
|
||||
{
|
||||
char* clipboardText = SDL_GetClipboardText();
|
||||
std::string clipboardString = std::string(clipboardText);
|
||||
SDL_free(clipboardText);
|
||||
return clipboardString;
|
||||
};
|
||||
|
||||
switch (self->type)
|
||||
{
|
||||
case CLIPBOARD_FRAME:
|
||||
{
|
||||
Anm2Reference* reference = std::get_if<Anm2Reference>(&self->location);
|
||||
if (!reference) break;
|
||||
Anm2Frame frame;
|
||||
if (anm2_frame_deserialize_from_xml(&frame, clipboard_string()))
|
||||
anm2_frame_add(self->anm2, &frame, reference);
|
||||
else return false;
|
||||
break;
|
||||
}
|
||||
case CLIPBOARD_ANIMATION:
|
||||
{
|
||||
s32* id = std::get_if<s32>(&self->location);
|
||||
if (!id) break;
|
||||
Anm2Animation animation;
|
||||
if (anm2_animation_deserialize_from_xml(&animation, clipboard_string()))
|
||||
anm2_animation_add(self->anm2, &animation, *id);
|
||||
else return false;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void clipboard_init(Clipboard* self, Anm2* anm2)
|
||||
@@ -96,3 +107,7 @@ void clipboard_init(Clipboard* self, Anm2* anm2)
|
||||
self->anm2 = anm2;
|
||||
}
|
||||
|
||||
bool clipboard_is_value(void)
|
||||
{
|
||||
return SDL_HasClipboardText();
|
||||
}
|
@@ -2,21 +2,13 @@
|
||||
|
||||
#include "anm2.h"
|
||||
|
||||
enum ClipboardItemType
|
||||
#define CLIPBOARD_TEXT_SET_WARNING "Unable to set clipboard text! ({})"
|
||||
|
||||
enum ClipboardType
|
||||
{
|
||||
CLIPBOARD_NONE,
|
||||
CLIPBOARD_FRAME,
|
||||
CLIPBOARD_ANIMATION,
|
||||
};
|
||||
|
||||
struct ClipboardItem
|
||||
{
|
||||
std::variant<std::monostate, Anm2FrameWithReference, Anm2AnimationWithID, Anm2EventWithID> data = std::monostate();
|
||||
ClipboardItemType type = CLIPBOARD_NONE;
|
||||
|
||||
ClipboardItem() = default;
|
||||
ClipboardItem(const Anm2FrameWithReference& frame) : data(frame), type(CLIPBOARD_FRAME) {}
|
||||
ClipboardItem(const Anm2AnimationWithID& animation) : data(animation), type(CLIPBOARD_ANIMATION) {}
|
||||
CLIPBOARD_ANIMATION
|
||||
};
|
||||
|
||||
using ClipboardLocation = std::variant<std::monostate, Anm2Reference, s32>;
|
||||
@@ -24,12 +16,12 @@ using ClipboardLocation = std::variant<std::monostate, Anm2Reference, s32>;
|
||||
struct Clipboard
|
||||
{
|
||||
Anm2* anm2 = nullptr;
|
||||
ClipboardItem item;
|
||||
ClipboardItem hoveredItem;
|
||||
ClipboardType type;
|
||||
ClipboardLocation location;
|
||||
};
|
||||
|
||||
bool clipboard_is_value(void);
|
||||
void clipboard_copy(Clipboard* self);
|
||||
void clipboard_cut(Clipboard* self);
|
||||
void clipboard_paste(Clipboard* self);
|
||||
bool clipboard_paste(Clipboard* self);
|
||||
void clipboard_init(Clipboard* self, Anm2* anm2);
|
@@ -30,7 +30,7 @@ void editor_draw(Editor* self)
|
||||
{
|
||||
Texture& texture = spritesheet->texture;
|
||||
|
||||
mat4 spritesheetTransform = transform * canvas_model_get(texture.size);
|
||||
mat4 spritesheetTransform = transform * quad_model_get(texture.size);
|
||||
canvas_texture_draw(&self->canvas, shaderTexture, texture.id, spritesheetTransform);
|
||||
|
||||
if (self->settings->editorIsBorder)
|
||||
@@ -40,10 +40,10 @@ void editor_draw(Editor* self)
|
||||
|
||||
if (frame)
|
||||
{
|
||||
mat4 cropTransform = transform * canvas_model_get(frame->size, frame->crop);
|
||||
mat4 cropTransform = transform * quad_model_get(frame->size, frame->crop);
|
||||
canvas_rect_draw(&self->canvas, shaderLine, cropTransform, EDITOR_FRAME_COLOR);
|
||||
|
||||
mat4 pivotTransform = transform * canvas_model_get(CANVAS_PIVOT_SIZE, frame->crop + frame->pivot, CANVAS_PIVOT_SIZE * 0.5f);
|
||||
mat4 pivotTransform = transform * quad_model_get(CANVAS_PIVOT_SIZE, frame->crop + frame->pivot, CANVAS_PIVOT_SIZE * 0.5f);
|
||||
f32 vertices[] = ATLAS_UV_VERTICES(ATLAS_PIVOT);
|
||||
canvas_texture_draw(&self->canvas, shaderTexture, self->resources->atlas.id, pivotTransform, vertices, EDITOR_PIVOT_COLOR);
|
||||
}
|
||||
|
@@ -1,10 +1,5 @@
|
||||
#include "ffmpeg.h"
|
||||
|
||||
static std::string ffmpeg_log_path_get(void)
|
||||
{
|
||||
return preferences_path_get() + FFMPEG_LOG_PATH;
|
||||
}
|
||||
|
||||
bool
|
||||
ffmpeg_render
|
||||
(
|
||||
@@ -35,13 +30,8 @@ ffmpeg_render
|
||||
break;
|
||||
}
|
||||
|
||||
// ffmpeg output will be piped into the log
|
||||
std::string logOutput = " 2>> \"" + ffmpeg_log_path_get() + "\"";
|
||||
|
||||
#if _WIN32
|
||||
command = string_quote(command) + logOutput;
|
||||
#else
|
||||
command += logOutput;
|
||||
command = string_quote(command);
|
||||
#endif
|
||||
|
||||
log_command(command);
|
||||
|
@@ -4,8 +4,6 @@
|
||||
#include "texture.h"
|
||||
|
||||
#define FFMPEG_POPEN_ERROR "popen() (for FFmpeg) failed!\n{}"
|
||||
#define FFMPEG_LOG_BUFFER_SIZE 256
|
||||
#define FFMPEG_LOG_PATH "ffmpeg.txt"
|
||||
|
||||
static constexpr const char* FFMPEG_GIF_FORMAT =
|
||||
"\"{0}\" -y "
|
||||
|
@@ -38,11 +38,12 @@ void generate_preview_draw(GeneratePreview* self)
|
||||
const s32 column = index % columns;
|
||||
vec2 crop = startPosition + vec2(size.x * column, size.y * row);
|
||||
|
||||
vec2 uvMin = crop / vec2(texture.size);
|
||||
vec2 uvMax = (crop + size) / vec2(texture.size);
|
||||
vec2 textureSize = vec2(texture.size);
|
||||
vec2 uvMin = (crop + vec2(0.5f)) / textureSize;
|
||||
vec2 uvMax = (crop + size - vec2(0.5f)) / textureSize;
|
||||
f32 vertices[] = UV_VERTICES(uvMin, uvMax);
|
||||
|
||||
mat4 generateTransform = transform * canvas_model_get(size, {}, pivot);
|
||||
mat4 generateTransform = transform * quad_model_get(size, {}, pivot);
|
||||
canvas_texture_draw(&self->canvas, shaderTexture, texture.id, generateTransform, vertices, COLOR_OPAQUE, COLOR_OFFSET_NONE);
|
||||
}
|
||||
}
|
||||
|
618
src/imgui.cpp
618
src/imgui.cpp
File diff suppressed because it is too large
Load Diff
399
src/imgui.h
399
src/imgui.h
@@ -59,19 +59,22 @@
|
||||
#define IMGUI_TIMELINE_FRAME_MULTIPLE 5
|
||||
#define IMGUI_TIMELINE_MERGE
|
||||
#define IMGUI_TOOL_COLOR_PICKER_DURATION 0.25f
|
||||
#define IMGUI_OPTION_POPUP_ROW_COUNT 2
|
||||
#define IMGUI_CONFIRM_POPUP_ROW_COUNT 2
|
||||
#define IMGUI_CHORD_REPEAT_TIME 0.25f
|
||||
|
||||
#define IMGUI_ACTION_FRAME_CROP "Frame Crop"
|
||||
#define IMGUI_ACTION_FRAME_SWAP "Frame Swap"
|
||||
#define IMGUI_ACTION_FRAME_TRANSFORM "Frame Transform"
|
||||
|
||||
#define IMGUI_ACTION_ANIMATION_SWAP "Animation Swap"
|
||||
#define IMGUI_ACTION_TRIGGER_MOVE "Trigger AtFrame"
|
||||
#define IMGUI_ACTION_TRIGGER_MOVE "Trigger At Frame"
|
||||
#define IMGUI_ACTION_FRAME_DELAY "Frame Delay"
|
||||
#define IMGUI_ACTION_MOVE_PLAYHEAD "Move Playhead"
|
||||
#define IMGUI_ACTION_DRAW "Draw"
|
||||
#define IMGUI_ACTION_ERASE "Erase"
|
||||
#define IMGUI_ACTION_RELOAD_SPRITESHEET "Reload Spritesheet(s)"
|
||||
#define IMGUI_ACTION_MOVE "Move"
|
||||
#define IMGUI_ACTION_SCALE "Scale"
|
||||
#define IMGUI_ACTION_ROTATE "Rotate"
|
||||
#define IMGUI_ACTION_CROP "Crop"
|
||||
#define IMGUI_ACTION_ADD_SPRITESHEET "Add Spritesheet"
|
||||
#define IMGUI_ACTION_REPLACE_SPRITESHEET "Replace Spritesheet"
|
||||
#define IMGUI_ACTION_OPEN_FILE "Open File"
|
||||
|
||||
@@ -92,6 +95,9 @@
|
||||
#define IMGUI_LOG_RENDER_ANIMATION_FFMPEG_ERROR "FFmpeg could not render animation! Check paths or your FFmpeg installation."
|
||||
#define IMGUI_LOG_SPRITESHEET_SAVE_FORMAT "Saved spritesheet #{} to: {}"
|
||||
#define IMGUI_LOG_DRAG_DROP_ERROR "Invalid file for dragging/dropping!"
|
||||
#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_RELOAD_SPRITESHEET "Reloaded spritesheet(s)."
|
||||
|
||||
#define IMGUI_NONE "None"
|
||||
#define IMGUI_ANIMATION_DEFAULT_FORMAT "(*) {}"
|
||||
@@ -106,13 +112,16 @@
|
||||
#define IMGUI_SPRITESHEET_FORMAT "#{} {}"
|
||||
#define IMGUI_SPRITESHEET_ID_FORMAT "#{}"
|
||||
#define IMGUI_TIMELINE_ITEM_CHILD_FORMAT "#{} {}"
|
||||
#define IMGUI_LAYER_FORMAT "#{} {}"
|
||||
#define IMGUI_NULL_FORMAT "#{} {}"
|
||||
#define IMGUI_TIMELINE_FRAME_LABEL_FORMAT "## {}"
|
||||
#define IMGUI_SELECTABLE_INPUT_INT_FORMAT "#{}"
|
||||
#define IMGUI_TIMELINE_ANIMATION_NONE "Select an animation to show timeline..."
|
||||
#define IMGUI_HOTKEY_CHANGE "Input new hotkey..."
|
||||
#define IMGUI_LABEL_SHORTCUT_FORMAT "({})"
|
||||
#define IMGUI_TOOLTIP_SHORTCUT_FORMAT "\n(Shortcut: {})"
|
||||
#define IMGUI_LABEL_HOTKEY_FORMAT " ({})"
|
||||
#define IMGUI_TOOLTIP_HOTKEY_FORMAT "\n(Hotkey: {})"
|
||||
#define IMGUI_INVISIBLE_FORMAT "## {}"
|
||||
#define IMGUI_RENDERING_FFMPEG_INFO_THRESHOLD 0.95f
|
||||
|
||||
#define IMGUI_TRIGGERS_FONT_SCALE 2.0
|
||||
|
||||
@@ -222,7 +231,7 @@ static void imgui_log_push(Imgui* self, const std::string& text)
|
||||
log_imgui(text);
|
||||
}
|
||||
|
||||
static inline void imgui_file_new(Imgui* self)
|
||||
static inline void imgui_anm2_new(Imgui* self)
|
||||
{
|
||||
anm2_reference_clear(self->reference);
|
||||
anm2_free(self->anm2);
|
||||
@@ -245,6 +254,14 @@ static inline void imgui_file_save(Imgui* self)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void imgui_file_new(Imgui* self)
|
||||
{
|
||||
std::string path = self->anm2->path;
|
||||
imgui_anm2_new(self);
|
||||
self->anm2->path = path;
|
||||
imgui_file_save(self);
|
||||
}
|
||||
|
||||
static inline void imgui_file_save_as(Imgui* self)
|
||||
{
|
||||
dialog_anm2_save(self->dialog);
|
||||
@@ -334,7 +351,15 @@ static inline void imgui_copy(Imgui* self)
|
||||
|
||||
static inline void imgui_paste(Imgui* self)
|
||||
{
|
||||
clipboard_paste(self->clipboard);
|
||||
if (!clipboard_paste(self->clipboard))
|
||||
{
|
||||
switch (self->clipboard->type)
|
||||
{
|
||||
case CLIPBOARD_FRAME: imgui_log_push(self, IMGUI_LOG_FRAME_PASTE_ERROR); break;
|
||||
case CLIPBOARD_ANIMATION: imgui_log_push(self, IMGUI_LOG_ANIMATION_PASTE_ERROR); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void imgui_onionskin_toggle(Imgui* self)
|
||||
@@ -520,10 +545,17 @@ static inline ImGuiKeyChord imgui_chord_from_string_get(const std::string& str)
|
||||
return chord;
|
||||
}
|
||||
|
||||
|
||||
static void imgui_contextual_actions_enable(Imgui* self) { self->isContextualActionsEnabled = true; }
|
||||
static void imgui_contextual_actions_disable(Imgui* self){ self->isContextualActionsEnabled = false; }
|
||||
static inline void imgui_keyboard_nav_enable(void) { ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; }
|
||||
static inline void imgui_keyboard_nav_disable(void) { ImGui::GetIO().ConfigFlags &= ~ImGuiConfigFlags_NavEnableKeyboard; }
|
||||
static inline void imgui_contextual_actions_enable(Imgui* self) { self->isContextualActionsEnabled = true; }
|
||||
static inline void imgui_contextual_actions_disable(Imgui* self){ self->isContextualActionsEnabled = false; }
|
||||
static inline bool imgui_is_popup_open(const std::string& label) { return ImGui::IsPopupOpen(label.c_str()); }
|
||||
|
||||
static inline bool imgui_is_any_popup_open(void)
|
||||
{
|
||||
return ImGui::IsPopupOpen(nullptr, ImGuiPopupFlags_AnyPopupId);
|
||||
}
|
||||
|
||||
static inline void imgui_open_popup(const std::string& label) { ImGui::OpenPopup(label.c_str()); }
|
||||
static inline void imgui_pending_popup_process(Imgui* self)
|
||||
{
|
||||
@@ -584,7 +616,7 @@ enum ImguiItemType
|
||||
IMGUI_DOCKSPACE,
|
||||
IMGUI_CHILD,
|
||||
IMGUI_TABLE,
|
||||
IMGUI_OPTION_POPUP,
|
||||
IMGUI_CONFIRM_POPUP,
|
||||
IMGUI_SELECTABLE,
|
||||
IMGUI_BUTTON,
|
||||
IMGUI_RADIO_BUTTON,
|
||||
@@ -611,6 +643,7 @@ struct ImguiItemOverride
|
||||
AtlasType atlas = ATLAS_NONE;
|
||||
bool isMnemonicDisabled{};
|
||||
s32 value{};
|
||||
s32 rowCount{};
|
||||
};
|
||||
|
||||
struct ImguiItem;
|
||||
@@ -656,7 +689,7 @@ struct ImguiItem
|
||||
bool isSelected = false;
|
||||
bool isUseItemActivated = false;
|
||||
bool isSizeToText = false;
|
||||
bool isShortcutInLabel = false;
|
||||
bool isHotkeyInLabel = false;
|
||||
bool isSameLine = false;
|
||||
bool isSeparator = false;
|
||||
s32 id = 0;
|
||||
@@ -673,6 +706,23 @@ struct ImguiItem
|
||||
s32 windowFlags{};
|
||||
s32 rowCount = 0;
|
||||
|
||||
bool is_border() const { return border != 0; }
|
||||
bool is_row() const { return rowCount != 0; }
|
||||
bool is_hotkey() const { return hotkey != HOTKEY_NONE; }
|
||||
bool is_chord() const { return chord != IMGUI_CHORD_NONE || is_hotkey(); }
|
||||
bool is_drag_drop() const { return !dragDrop.empty(); }
|
||||
bool is_focus_window() const { return !focusWindow.empty(); }
|
||||
bool is_popup() const { return !popup.empty(); }
|
||||
bool is_function() const { return function; }
|
||||
bool is_size() const { return size != ImVec2(); }
|
||||
bool is_popup_size() const { return popupSize != ImVec2(); }
|
||||
bool is_tooltip() const { return !tooltip.empty(); }
|
||||
bool is_undoable() const { return !snapshotAction.empty(); }
|
||||
bool is_mnemonic() const { return mnemonicKey != ImGuiKey_None; }
|
||||
bool is_range() const { return min != 0 || max != 0; }
|
||||
const char* drag_drop_get() const { return dragDrop.c_str(); }
|
||||
const char* text_get() const { return text.c_str(); }
|
||||
|
||||
void construct()
|
||||
{
|
||||
static s32 idNew = 0;
|
||||
@@ -717,6 +767,7 @@ struct ImguiItem
|
||||
if (override.size != ImVec2{}) out.size = override.size;
|
||||
if (override.max != 0) out.max = override.max;
|
||||
if (override.value != 0) out.value = override.value;
|
||||
if (override.rowCount != 0) out.rowCount = override.rowCount;
|
||||
if (override.atlas != ATLAS_NONE) out.atlas = override.atlas;
|
||||
if (override.isMnemonicDisabled) out.isMnemonicDisabled = override.isMnemonicDisabled;
|
||||
return out;
|
||||
@@ -728,24 +779,21 @@ struct ImguiItem
|
||||
return chord;
|
||||
}
|
||||
|
||||
bool is_border() const { return border != 0; }
|
||||
bool is_row() const { return rowCount != 0; }
|
||||
bool is_hotkey() const { return hotkey != HOTKEY_NONE; }
|
||||
bool is_chord() const { return chord != IMGUI_CHORD_NONE || is_hotkey(); }
|
||||
bool is_drag_drop() const { return !dragDrop.empty(); }
|
||||
bool is_focus_window() const { return !focusWindow.empty(); }
|
||||
bool is_popup() const { return !popup.empty(); }
|
||||
bool is_function() const { return function; }
|
||||
bool is_size() const { return size != ImVec2(); }
|
||||
bool is_popup_size() const { return popupSize != ImVec2(); }
|
||||
bool is_tooltip() const { return !tooltip.empty(); }
|
||||
bool is_undoable() const { return !snapshotAction.empty(); }
|
||||
bool is_mnemonic() const { return mnemonicKey != ImGuiKey_None; }
|
||||
bool is_range() const { return min != 0 || max != 0; }
|
||||
const char* label_get() const { return label.c_str(); }
|
||||
const char* drag_drop_get() const { return dragDrop.c_str(); }
|
||||
const char* tooltip_get() const { return tooltip.c_str(); }
|
||||
const char* text_get() const { return text.c_str(); }
|
||||
std::string label_get() const
|
||||
{
|
||||
std::string newLabel = label;
|
||||
if (isHotkeyInLabel)
|
||||
newLabel += std::format(IMGUI_LABEL_HOTKEY_FORMAT, imgui_string_from_chord_get(chord_get()));
|
||||
return newLabel;
|
||||
}
|
||||
|
||||
std::string tooltip_get() const
|
||||
{
|
||||
std::string newTooltip = tooltip;
|
||||
if (is_chord())
|
||||
newTooltip += std::format(IMGUI_TOOLTIP_HOTKEY_FORMAT, imgui_string_from_chord_get(chord_get()));
|
||||
return newTooltip;
|
||||
}
|
||||
};
|
||||
|
||||
#define IMGUI_ITEM(NAME, ...) const inline ImguiItem NAME = []{ ImguiItem self; __VA_ARGS__; self.construct(); return self; }()
|
||||
@@ -797,7 +845,7 @@ IMGUI_ITEM(IMGUI_NEW,
|
||||
self.function = imgui_file_new,
|
||||
self.hotkey = HOTKEY_NEW,
|
||||
self.isSizeToText = true,
|
||||
self.isShortcutInLabel = true
|
||||
self.isHotkeyInLabel = true
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_OPEN,
|
||||
@@ -806,7 +854,7 @@ IMGUI_ITEM(IMGUI_OPEN,
|
||||
self.function = imgui_file_open,
|
||||
self.hotkey = HOTKEY_OPEN,
|
||||
self.isSizeToText = true,
|
||||
self.isShortcutInLabel = true
|
||||
self.isHotkeyInLabel = true
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_SAVE,
|
||||
@@ -815,7 +863,7 @@ IMGUI_ITEM(IMGUI_SAVE,
|
||||
self.function = imgui_file_save,
|
||||
self.hotkey = HOTKEY_SAVE,
|
||||
self.isSizeToText = true,
|
||||
self.isShortcutInLabel = true
|
||||
self.isHotkeyInLabel = true
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_SAVE_AS,
|
||||
@@ -824,7 +872,7 @@ IMGUI_ITEM(IMGUI_SAVE_AS,
|
||||
self.function = imgui_file_save_as,
|
||||
self.hotkey = HOTKEY_SAVE_AS,
|
||||
self.isSizeToText = true,
|
||||
self.isShortcutInLabel = true
|
||||
self.isHotkeyInLabel = true
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_EXPLORE_ANM2_LOCATION,
|
||||
@@ -841,7 +889,7 @@ IMGUI_ITEM(IMGUI_EXIT,
|
||||
self.function = imgui_quit,
|
||||
self.hotkey = HOTKEY_EXIT,
|
||||
self.isSizeToText = true,
|
||||
self.isShortcutInLabel = true
|
||||
self.isHotkeyInLabel = true
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_EXIT_CONFIRMATION,
|
||||
@@ -854,6 +902,11 @@ IMGUI_ITEM(IMGUI_OPEN_CONFIRMATION,
|
||||
self.text = "Unsaved changes will be lost!\nAre you sure you open a new file?"
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_NO_ANM2_PATH_CONFIRMATION,
|
||||
self.label = "No Anm2 Path",
|
||||
self.text = "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.",
|
||||
@@ -962,7 +1015,7 @@ IMGUI_ITEM(IMGUI_GENERATE_ANIMATION_FROM_GRID_GENERATE,
|
||||
self.label = "Generate",
|
||||
self.tooltip = "Generate an animation with the used settings.",
|
||||
self.snapshotAction = "Generate Animation from Grid",
|
||||
self.rowCount = IMGUI_OPTION_POPUP_ROW_COUNT,
|
||||
self.rowCount = IMGUI_CONFIRM_POPUP_ROW_COUNT,
|
||||
self.isSameLine = true
|
||||
);
|
||||
|
||||
@@ -1042,7 +1095,7 @@ IMGUI_ITEM(IMGUI_CHANGE_ALL_FRAME_PROPERTIES_CANCEL,
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_SCALE_ANM2,
|
||||
self.label = "&Scale Anm2",
|
||||
self.label = "S&cale Anm2",
|
||||
self.tooltip = "Scale up all size and position-related frame properties in the anm2.",
|
||||
self.popup = "Scale Anm2",
|
||||
self.popupType = IMGUI_POPUP_CENTER_WINDOW,
|
||||
@@ -1069,7 +1122,7 @@ IMGUI_ITEM(IMGUI_SCALE_ANM2_SCALE,
|
||||
self.label = "Scale",
|
||||
self.tooltip = "Scale the anm2 with the value specified.",
|
||||
self.snapshotAction = "Scale Anm2",
|
||||
self.rowCount = IMGUI_OPTION_POPUP_ROW_COUNT,
|
||||
self.rowCount = IMGUI_CONFIRM_POPUP_ROW_COUNT,
|
||||
self.isSameLine = true
|
||||
);
|
||||
|
||||
@@ -1077,12 +1130,20 @@ IMGUI_ITEM(IMGUI_RENDER_ANIMATION,
|
||||
self.label = "&Render Animation",
|
||||
self.tooltip = "Renders the current animation preview; output options can be customized.",
|
||||
self.popup = "Render Animation",
|
||||
self.popupSize = {600, 125}
|
||||
self.popupSize = {600, 150},
|
||||
self.popupType = IMGUI_POPUP_CENTER_WINDOW
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_RENDER_ANIMATION_CHILD,
|
||||
self.label = "## Render Animation Child",
|
||||
self.size = {600, 125}
|
||||
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",
|
||||
self.size = {IMGUI_RENDER_ANIMATION.popupSize.x, IMGUI_FOOTER_CHILD.size.y},
|
||||
self.flags = true
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_RENDER_ANIMATION_LOCATION_BROWSE,
|
||||
@@ -1115,8 +1176,7 @@ IMGUI_ITEM(IMGUI_RENDER_ANIMATION_OUTPUT,
|
||||
self.label = "Output",
|
||||
self.tooltip = "Select the rendered animation output.\nIt can either be 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.isSeparator = true
|
||||
self.value = RENDER_PNG
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_RENDER_ANIMATION_FORMAT,
|
||||
@@ -1132,9 +1192,16 @@ IMGUI_ITEM(IMGUI_RENDER_ANIMATION_CONFIRM,
|
||||
self.popupType = IMGUI_POPUP_CENTER_WINDOW,
|
||||
self.popupSize = {300, 60},
|
||||
self.isSameLine = true,
|
||||
self.rowCount = IMGUI_OPTION_POPUP_ROW_COUNT
|
||||
self.rowCount = IMGUI_CONFIRM_POPUP_ROW_COUNT
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_RENDERING_ANIMATION_CHILD,
|
||||
self.label = "##Rendering Child",
|
||||
self.size = {400.0f, 65.0f},
|
||||
self.flags = true
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_RENDERING_ANIMATION_INFO, self.label = "Recording frames. Once done, the program may halt\nas FFmpeg renders the animation. Please be patient!");
|
||||
IMGUI_ITEM(IMGUI_RENDERING_ANIMATION_CANCEL,
|
||||
self.label = "Cancel",
|
||||
self.tooltip = "Cancel rendering the animation.",
|
||||
@@ -1218,6 +1285,77 @@ IMGUI_ITEM(IMGUI_DEFAULT_SETTINGS,
|
||||
self.isSizeToText = true
|
||||
);
|
||||
|
||||
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_LAYER,
|
||||
self.label = "## Layer Item",
|
||||
self.dragDrop = "## Layer Drag Drop",
|
||||
self.atlas = ATLAS_LAYER,
|
||||
self.idOffset = 3000
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_LAYER_SPRITESHEET_ID,
|
||||
self.label = "## Spritesheet ID",
|
||||
self.tooltip = "Change the spritesheet ID this layer uses.",
|
||||
self.atlas = ATLAS_SPRITESHEET,
|
||||
self.size = {50, 0}
|
||||
);
|
||||
|
||||
#define IMGUI_LAYERS_OPTIONS_ROW_COUNT 2
|
||||
IMGUI_ITEM(IMGUI_LAYER_ADD,
|
||||
self.label = "Add",
|
||||
self.tooltip = "Adds a new layer.",
|
||||
self.snapshotAction = "Add Layer",
|
||||
self.rowCount = IMGUI_LAYERS_OPTIONS_ROW_COUNT,
|
||||
self.isSameLine = true
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_LAYER_REMOVE,
|
||||
self.label = "Remove",
|
||||
self.tooltip = "Removes the selected layer.\nThis will remove all layer animations that use this layer from all animations.",
|
||||
self.snapshotAction = "Remove Layer",
|
||||
self.chord = ImGuiKey_Delete,
|
||||
self.focusWindow = IMGUI_LAYERS.label,
|
||||
self.rowCount = IMGUI_LAYERS_OPTIONS_ROW_COUNT
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_NULLS,
|
||||
self.label = "Nulls",
|
||||
self.flags = ImGuiWindowFlags_NoScrollbar |
|
||||
ImGuiWindowFlags_NoScrollWithMouse
|
||||
);
|
||||
IMGUI_ITEM(IMGUI_NULLS_CHILD, self.label = "## Nulls Child", self.flags = true);
|
||||
|
||||
IMGUI_ITEM(IMGUI_NULL,
|
||||
self.label = "## Null Item",
|
||||
self.dragDrop = "## Null Drag Drop",
|
||||
self.atlas = ATLAS_NULL,
|
||||
self.idOffset = 4000
|
||||
);
|
||||
|
||||
#define IMGUI_NULLS_OPTIONS_ROW_COUNT 2
|
||||
IMGUI_ITEM(IMGUI_NULL_ADD,
|
||||
self.label = "Add",
|
||||
self.tooltip = "Adds a null layer.",
|
||||
self.snapshotAction = "Add Null",
|
||||
self.rowCount = IMGUI_NULLS_OPTIONS_ROW_COUNT,
|
||||
self.isSameLine = true
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_NULL_REMOVE,
|
||||
self.label = "Remove",
|
||||
self.tooltip = "Removes the selected null.\nThis will remove all null animations that use this null from all animations.",
|
||||
self.snapshotAction = "Remove Null",
|
||||
self.chord = ImGuiKey_Delete,
|
||||
self.focusWindow = IMGUI_NULLS.label,
|
||||
self.rowCount = IMGUI_NULLS_OPTIONS_ROW_COUNT
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_ANIMATIONS,
|
||||
self.label = "Animations",
|
||||
self.flags = ImGuiWindowFlags_NoScrollbar |
|
||||
@@ -1227,7 +1365,6 @@ IMGUI_ITEM(IMGUI_ANIMATIONS_CHILD, self.label = "## Animations Child", self.flag
|
||||
|
||||
IMGUI_ITEM(IMGUI_ANIMATION,
|
||||
self.label = "## Animation Item",
|
||||
self.snapshotAction = "Select Animation",
|
||||
self.dragDrop = "## Animation Drag Drop",
|
||||
self.atlas = ATLAS_ANIMATION,
|
||||
self.idOffset = 2000
|
||||
@@ -1314,7 +1451,7 @@ 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_OPTION_POPUP_ROW_COUNT,
|
||||
self.rowCount = IMGUI_CONFIRM_POPUP_ROW_COUNT,
|
||||
self.isSameLine = true
|
||||
);
|
||||
|
||||
@@ -1400,15 +1537,15 @@ IMGUI_ITEM(IMGUI_SPRITESHEETS_FOOTER_CHILD,
|
||||
#define IMGUI_SPRITESHEETS_OPTIONS_SECOND_ROW_COUNT 3
|
||||
IMGUI_ITEM(IMGUI_SPRITESHEET_ADD,
|
||||
self.label = "Add",
|
||||
self.tooltip = "Select an image to add as a spritesheet.",
|
||||
self.tooltip = "Select a .png image to add as a spritesheet.",
|
||||
self.rowCount = IMGUI_SPRITESHEETS_OPTIONS_FIRST_ROW_COUNT,
|
||||
self.isSameLine = true
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_SPRITESHEETS_RELOAD,
|
||||
self.label = "Reload",
|
||||
self.tooltip = "Reload the selected spritesheet.",
|
||||
self.snapshotAction = "Reload Spritesheet",
|
||||
self.tooltip = "Reload the selected spritesheet(s).",
|
||||
self.snapshotAction = "Reload Spritesheet(s)",
|
||||
self.rowCount = IMGUI_SPRITESHEETS_OPTIONS_FIRST_ROW_COUNT,
|
||||
self.isSameLine = true
|
||||
);
|
||||
@@ -1450,7 +1587,9 @@ const ImVec2 IMGUI_CANVAS_CHILD_SIZE = {230, 85};
|
||||
IMGUI_ITEM(IMGUI_CANVAS_GRID_CHILD,
|
||||
self.label = "## Canvas Grid Child",
|
||||
self.size = IMGUI_CANVAS_CHILD_SIZE,
|
||||
self.flags = true
|
||||
self.flags = true,
|
||||
self.windowFlags = ImGuiWindowFlags_NoScrollbar |
|
||||
ImGuiWindowFlags_NoScrollWithMouse
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_CANVAS_GRID,
|
||||
@@ -1485,7 +1624,9 @@ IMGUI_ITEM(IMGUI_CANVAS_GRID_OFFSET,
|
||||
IMGUI_ITEM(IMGUI_CANVAS_VIEW_CHILD,
|
||||
self.label = "## View Child",
|
||||
self.size = IMGUI_CANVAS_CHILD_SIZE,
|
||||
self.flags = true
|
||||
self.flags = true,
|
||||
self.windowFlags = ImGuiWindowFlags_NoScrollbar |
|
||||
ImGuiWindowFlags_NoScrollWithMouse
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_CANVAS_ZOOM,
|
||||
@@ -1497,12 +1638,12 @@ IMGUI_ITEM(IMGUI_CANVAS_ZOOM,
|
||||
self.value = CANVAS_ZOOM_DEFAULT
|
||||
);
|
||||
|
||||
|
||||
|
||||
IMGUI_ITEM(IMGUI_CANVAS_VISUAL_CHILD,
|
||||
self.label = "## Animation Preview Visual Child",
|
||||
self.size = IMGUI_CANVAS_CHILD_SIZE,
|
||||
self.flags = true
|
||||
self.flags = true,
|
||||
self.windowFlags = ImGuiWindowFlags_NoScrollbar |
|
||||
ImGuiWindowFlags_NoScrollWithMouse
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_CANVAS_BACKGROUND_COLOR,
|
||||
@@ -1526,7 +1667,9 @@ IMGUI_ITEM(IMGUI_CANVAS_ANIMATION_OVERLAY_TRANSPARENCY,
|
||||
IMGUI_ITEM(IMGUI_CANVAS_HELPER_CHILD,
|
||||
self.label = "## Animation Preview Helper Child",
|
||||
self.size = IMGUI_CANVAS_CHILD_SIZE,
|
||||
self.flags = true
|
||||
self.flags = true,
|
||||
self.windowFlags = ImGuiWindowFlags_NoScrollbar |
|
||||
ImGuiWindowFlags_NoScrollWithMouse
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_CANVAS_AXES,
|
||||
@@ -1558,10 +1701,10 @@ IMGUI_ITEM(IMGUI_CANVAS_PIVOTS,
|
||||
self.value = SETTINGS_PREVIEW_IS_PIVOTS_DEFAULT
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_CANVAS_TARGETS,
|
||||
self.label = "Targets",
|
||||
self.tooltip = "Toggles drawing the targets (the colored root/null icons).",
|
||||
self.value = SETTINGS_PREVIEW_IS_TARGETS_DEFAULT
|
||||
IMGUI_ITEM(IMGUI_CANVAS_ICONS,
|
||||
self.label = "Icons",
|
||||
self.tooltip = "Toggles drawing the the colored root/null icons.",
|
||||
self.value = SETTINGS_PREVIEW_IS_ICONS_DEFAULT
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_CANVAS_ALT_ICONS,
|
||||
@@ -1581,12 +1724,22 @@ IMGUI_ITEM(IMGUI_ANIMATION_PREVIEW,
|
||||
self.flags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse
|
||||
);
|
||||
|
||||
#define IMGUI_ANIMATION_PREVIEW_VIEW_ROW_COUNT 2
|
||||
IMGUI_ITEM(IMGUI_ANIMATION_PREVIEW_CENTER_VIEW,
|
||||
self.label = "Center View",
|
||||
self.tooltip = "Centers the current view on the animation preview.",
|
||||
self.hotkey = HOTKEY_CENTER_VIEW,
|
||||
self.focusWindow = IMGUI_ANIMATION_PREVIEW.label,
|
||||
self.size = {-FLT_MIN, 0}
|
||||
self.rowCount = IMGUI_ANIMATION_PREVIEW_VIEW_ROW_COUNT,
|
||||
self.isSameLine = true
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_ANIMATION_PREVIEW_FIT,
|
||||
self.label = "Fit",
|
||||
self.tooltip = "Adjust the view/pan based on the size of the animation, to fit the canvas' size.",
|
||||
self.hotkey = HOTKEY_FIT,
|
||||
self.focusWindow = IMGUI_ANIMATION_PREVIEW.label,
|
||||
self.rowCount = IMGUI_ANIMATION_PREVIEW_VIEW_ROW_COUNT
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_SPRITESHEET_EDITOR,
|
||||
@@ -1594,12 +1747,22 @@ IMGUI_ITEM(IMGUI_SPRITESHEET_EDITOR,
|
||||
self.flags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse
|
||||
);
|
||||
|
||||
#define IMGUI_SPRITESHEET_EDITOR_VIEW_ROW_COUNT 2
|
||||
IMGUI_ITEM(IMGUI_SPRITESHEET_EDITOR_CENTER_VIEW,
|
||||
self.label = "Center View",
|
||||
self.tooltip = "Centers the current view on the spritesheet editor.",
|
||||
self.hotkey = HOTKEY_CENTER_VIEW,
|
||||
self.focusWindow = IMGUI_SPRITESHEET_EDITOR.label,
|
||||
self.size = {-FLT_MIN, 0}
|
||||
self.rowCount = IMGUI_SPRITESHEET_EDITOR_VIEW_ROW_COUNT,
|
||||
self.isSameLine = true
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_SPRITESHEET_EDITOR_FIT,
|
||||
self.label = "Fit",
|
||||
self.tooltip = "Adjust the view/pan based on the size of the spritesheet, to fit the canvas' size.",
|
||||
self.hotkey = HOTKEY_FIT,
|
||||
self.focusWindow = IMGUI_SPRITESHEET_EDITOR.label,
|
||||
self.rowCount = IMGUI_SPRITESHEET_EDITOR_VIEW_ROW_COUNT
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_FRAME_PROPERTIES, self.label = "Frame Properties");
|
||||
@@ -1672,12 +1835,12 @@ IMGUI_ITEM(IMGUI_FRAME_PROPERTIES_COLOR_OFFSET,
|
||||
self.value = 0
|
||||
);
|
||||
|
||||
const ImVec2 IMGUI_FRAME_PROPERTIES_FLIP_BUTTON_SIZE = {75, 0};
|
||||
#define IMGUI_FRAME_PROPERTIES_FLIP_ROW_COUNT 2
|
||||
IMGUI_ITEM(IMGUI_FRAME_PROPERTIES_FLIP_X,
|
||||
self.label = "Flip X",
|
||||
self.tooltip = "Change the sign of the X scale, to cheat flipping the layer horizontally.\n(Anm2 doesn't support flipping directly.)",
|
||||
self.snapshotAction = "Frame Flip X",
|
||||
self.size = IMGUI_FRAME_PROPERTIES_FLIP_BUTTON_SIZE,
|
||||
self.rowCount = IMGUI_FRAME_PROPERTIES_FLIP_ROW_COUNT,
|
||||
self.isSameLine = true
|
||||
);
|
||||
|
||||
@@ -1685,7 +1848,7 @@ IMGUI_ITEM(IMGUI_FRAME_PROPERTIES_FLIP_Y,
|
||||
self.label = "Flip Y",
|
||||
self.tooltip = "Change the sign of the Y scale, to cheat flipping the layer vertically.\n(Anm2 doesn't support flipping directly.)",
|
||||
self.snapshotAction = "Frame Flip Y",
|
||||
self.size = IMGUI_FRAME_PROPERTIES_FLIP_BUTTON_SIZE
|
||||
self.rowCount = IMGUI_FRAME_PROPERTIES_FLIP_ROW_COUNT
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_FRAME_PROPERTIES_VISIBLE,
|
||||
@@ -1700,9 +1863,16 @@ IMGUI_ITEM(IMGUI_FRAME_PROPERTIES_INTERPOLATED,
|
||||
self.label = "Interpolation",
|
||||
self.tooltip = "Toggles the interpolation of the selected frame.",
|
||||
self.snapshotAction = "Frame Interpolation",
|
||||
self.isSameLine = true,
|
||||
self.value = true
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_FRAME_PROPERTIES_ROUND,
|
||||
self.label = "Round",
|
||||
self.tooltip = "Values will be rounded to the nearest integer.",
|
||||
self.value = SETTINGS_PROPERTIES_IS_ROUND_DEFAULT
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_FRAME_PROPERTIES_EVENT,
|
||||
self.label = "Event",
|
||||
self.tooltip = "Change the event the trigger uses.",
|
||||
@@ -1727,7 +1897,7 @@ IMGUI_ITEM(IMGUI_TOOL_PAN,
|
||||
|
||||
IMGUI_ITEM(IMGUI_TOOL_MOVE,
|
||||
self.label = "## Move",
|
||||
self.tooltip = "Use the move tool.\nWill move the selected item as the cursor is dragged, or directional keys are pressed.\n(Animation Preview only.)",
|
||||
self.tooltip = "Use the move tool.\nWhen in animation preview, will move the position of the frame.\nWhen in spritesheet editor, will move the pivot instead.\nUse mouse or directional keys to change the value.",
|
||||
self.function = imgui_tool_move_set,
|
||||
self.hotkey = HOTKEY_MOVE,
|
||||
self.atlas = ATLAS_MOVE
|
||||
@@ -1751,7 +1921,7 @@ IMGUI_ITEM(IMGUI_TOOL_SCALE,
|
||||
|
||||
IMGUI_ITEM(IMGUI_TOOL_CROP,
|
||||
self.label = "## Crop",
|
||||
self.tooltip = "Use the crop tool.\nWill produce a crop rectangle based on how the cursor is dragged.\n(Spritesheet Editor only.)",
|
||||
self.tooltip = "Use the crop tool.\nWill produce a crop rectangle based on how the cursor is dragged.\nAlternatively, you can use the arrow keys and Ctrl/Shift to move the size/position, respectively.\n(Spritesheet Editor only.)",
|
||||
self.function = imgui_tool_crop_set,
|
||||
self.hotkey = HOTKEY_CROP,
|
||||
self.atlas = ATLAS_CROP
|
||||
@@ -1907,7 +2077,6 @@ IMGUI_ITEM(IMGUI_TIMELINE_ITEM_SELECTABLE,
|
||||
IMGUI_ITEM(IMGUI_TIMELINE_ITEM_ROOT_SELECTABLE,
|
||||
self.label = "Root",
|
||||
self.tooltip = "The root item of an animation.\nChanging its properties will transform the rest of the animation.",
|
||||
self.snapshotAction = "Root Item Select",
|
||||
self.atlas = ATLAS_ROOT,
|
||||
self.size = IMGUI_TIMELINE_ITEM_SELECTABLE_SIZE
|
||||
);
|
||||
@@ -1915,7 +2084,6 @@ IMGUI_ITEM(IMGUI_TIMELINE_ITEM_ROOT_SELECTABLE,
|
||||
IMGUI_ITEM(IMGUI_TIMELINE_ITEM_LAYER_SELECTABLE,
|
||||
self.label = "## Layer Selectable",
|
||||
self.tooltip = "A layer item.\nA graphical item within the animation.",
|
||||
self.snapshotAction = "Layer Item Select",
|
||||
self.dragDrop = "## Layer Drag Drop",
|
||||
self.atlas = ATLAS_LAYER,
|
||||
self.size = IMGUI_TIMELINE_ITEM_SELECTABLE_SIZE
|
||||
@@ -1924,7 +2092,6 @@ IMGUI_ITEM(IMGUI_TIMELINE_ITEM_LAYER_SELECTABLE,
|
||||
IMGUI_ITEM(IMGUI_TIMELINE_ITEM_NULL_SELECTABLE,
|
||||
self.label = "## Null Selectable",
|
||||
self.tooltip = "A null item.\nAn invisible item within the animation that is accessible via a game engine.",
|
||||
self.snapshotAction = "Null Item Select",
|
||||
self.dragDrop = "## Null Drag Drop",
|
||||
self.atlas = ATLAS_NULL,
|
||||
self.size = IMGUI_TIMELINE_ITEM_SELECTABLE_SIZE
|
||||
@@ -1933,7 +2100,6 @@ IMGUI_ITEM(IMGUI_TIMELINE_ITEM_NULL_SELECTABLE,
|
||||
IMGUI_ITEM(IMGUI_TIMELINE_ITEM_TRIGGERS_SELECTABLE,
|
||||
self.label = "Triggers",
|
||||
self.tooltip = "The animation's triggers.\nWill fire based on an event.",
|
||||
self.snapshotAction = "Triggers Item Select",
|
||||
self.atlas = ATLAS_TRIGGERS,
|
||||
self.size = IMGUI_TIMELINE_ITEM_SELECTABLE_SIZE
|
||||
);
|
||||
@@ -1947,6 +2113,20 @@ const inline ImguiItem* IMGUI_TIMELINE_ITEM_SELECTABLES[ANM2_COUNT]
|
||||
&IMGUI_TIMELINE_ITEM_TRIGGERS_SELECTABLE
|
||||
};
|
||||
|
||||
IMGUI_ITEM(IMGUI_TIMELINE_SHOW_UNUSED,
|
||||
self.label = "## Show Unused",
|
||||
self.tooltip = "Layers/nulls without any frames will be hidden.",
|
||||
self.snapshotAction = "Hide Unused",
|
||||
self.atlas = ATLAS_SHOW_UNUSED
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_TIMELINE_HIDE_UNUSED,
|
||||
self.label = "## Hide Unused",
|
||||
self.tooltip = "Layers/nulls without any frames will be shown.",
|
||||
self.snapshotAction = "Show Unused",
|
||||
self.atlas = ATLAS_HIDE_UNUSED
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_TIMELINE_ITEM_VISIBLE,
|
||||
self.label = "## Visible",
|
||||
self.tooltip = "The item is visible.\nPress to set to invisible.",
|
||||
@@ -1975,12 +2155,6 @@ IMGUI_ITEM(IMGUI_TIMELINE_ITEM_HIDE_RECT,
|
||||
self.atlas = ATLAS_HIDE_RECT
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_TIMELINE_SPRITESHEET_ID,
|
||||
self.label = "## Spritesheet ID",
|
||||
self.tooltip = "Change the spritesheet ID this item uses.",
|
||||
self.atlas = ATLAS_SPRITESHEET,
|
||||
self.size = {32, 0}
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_TIMELINE_FRAMES_CHILD,
|
||||
self.label = "## Timeline Frames Child",
|
||||
@@ -1998,7 +2172,6 @@ IMGUI_ITEM(IMGUI_TIMELINE_FRAME, self.label = "## Frame");
|
||||
static const vec4 IMGUI_FRAME_BORDER_COLOR = {1.0f, 1.0f, 1.0f, 0.25f};
|
||||
IMGUI_ITEM(IMGUI_TIMELINE_ROOT_FRAME,
|
||||
self.label = "## Root Frame",
|
||||
self.snapshotAction = "Root Frame Select",
|
||||
self.color = {{0.14f, 0.27f, 0.39f, 1.0f}, {0.28f, 0.54f, 0.78f, 1.0f}, {0.36f, 0.70f, 0.95f, 1.0f}, IMGUI_FRAME_BORDER_COLOR},
|
||||
self.size = IMGUI_TIMELINE_FRAME_SIZE,
|
||||
self.atlasOffset = IMGUI_TIMELINE_FRAME_ATLAS_OFFSET,
|
||||
@@ -2007,7 +2180,6 @@ IMGUI_ITEM(IMGUI_TIMELINE_ROOT_FRAME,
|
||||
|
||||
IMGUI_ITEM(IMGUI_TIMELINE_LAYER_FRAME,
|
||||
self.label = "## Layer Frame",
|
||||
self.snapshotAction = "Layer Frame Select",
|
||||
self.dragDrop = "## Layer Frame Drag Drop",
|
||||
self.color = {{0.45f, 0.18f, 0.07f, 1.0f}, {0.78f, 0.32f, 0.12f, 1.0f}, {0.95f, 0.40f, 0.15f, 1.0f}, IMGUI_FRAME_BORDER_COLOR},
|
||||
self.size = IMGUI_TIMELINE_FRAME_SIZE,
|
||||
@@ -2017,7 +2189,6 @@ IMGUI_ITEM(IMGUI_TIMELINE_LAYER_FRAME,
|
||||
|
||||
IMGUI_ITEM(IMGUI_TIMELINE_NULL_FRAME,
|
||||
self.label = "## Null Frame",
|
||||
self.snapshotAction = "Null Frame Select",
|
||||
self.dragDrop = "## Null Frame Drag Drop",
|
||||
self.color = {{0.17f, 0.33f, 0.17f, 1.0f}, {0.34f, 0.68f, 0.34f, 1.0f}, {0.44f, 0.88f, 0.44f, 1.0f}, IMGUI_FRAME_BORDER_COLOR},
|
||||
self.size = IMGUI_TIMELINE_FRAME_SIZE,
|
||||
@@ -2027,7 +2198,6 @@ IMGUI_ITEM(IMGUI_TIMELINE_NULL_FRAME,
|
||||
|
||||
IMGUI_ITEM(IMGUI_TIMELINE_TRIGGERS_FRAME,
|
||||
self.label = "## Triggers Frame",
|
||||
self.snapshotAction = "Trigger Select",
|
||||
self.color = {{0.36f, 0.14f, 0.24f, 1.0f}, {0.72f, 0.28f, 0.48f, 1.0f}, {0.92f, 0.36f, 0.60f, 1.0f}, IMGUI_FRAME_BORDER_COLOR},
|
||||
self.size = IMGUI_TIMELINE_FRAME_SIZE,
|
||||
self.atlasOffset = IMGUI_TIMELINE_FRAME_ATLAS_OFFSET,
|
||||
@@ -2046,43 +2216,76 @@ const inline ImguiItem* IMGUI_TIMELINE_FRAMES[ANM2_COUNT]
|
||||
IMGUI_ITEM(IMGUI_TIMELINE_ITEM_FOOTER_CHILD,
|
||||
self.label = "## Item Footer Child",
|
||||
self.size = {IMGUI_TIMELINE_ITEM_CHILD.size.x, IMGUI_FOOTER_CHILD.size.y},
|
||||
self.flags = true
|
||||
self.flags = true,
|
||||
self.windowFlags = ImGuiWindowFlags_NoScrollbar |
|
||||
ImGuiWindowFlags_NoScrollWithMouse
|
||||
);
|
||||
IMGUI_ITEM(IMGUI_TIMELINE_OPTIONS_FOOTER_CHILD,
|
||||
self.label = "## Options Footer Child",
|
||||
self.size = {0, IMGUI_FOOTER_CHILD.size.y},
|
||||
self.flags = true
|
||||
self.flags = true,
|
||||
self.windowFlags = ImGuiWindowFlags_NoScrollbar |
|
||||
ImGuiWindowFlags_NoScrollWithMouse
|
||||
);
|
||||
|
||||
#define IMGUI_TIMELINE_FOOTER_ITEM_CHILD_ITEM_COUNT 2
|
||||
IMGUI_ITEM(IMGUI_TIMELINE_ADD_ITEM,
|
||||
self.label = "Add",
|
||||
self.tooltip = "Adds an item (layer or null) to the animation.",
|
||||
self.popup = "## Add Item Popup",
|
||||
self.popupType = IMGUI_POPUP_BY_ITEM,
|
||||
self.tooltip = "Adds an item (layer or null) to the animation.\nMake sure to add a Layer/Null first in the Layers or Nulls windows.",
|
||||
self.popup = "Add Item",
|
||||
self.popupType = IMGUI_POPUP_CENTER_WINDOW,
|
||||
self.popupSize = {300, 350},
|
||||
self.rowCount = IMGUI_TIMELINE_FOOTER_ITEM_CHILD_ITEM_COUNT,
|
||||
self.isSameLine = true
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_TIMELINE_ADD_ITEM_TYPE_CHILD,
|
||||
self.label = "## Add Item Type Child",
|
||||
self.size = {IMGUI_TIMELINE_ADD_ITEM.popupSize.x, 35},
|
||||
self.flags = true
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_TIMELINE_ADD_ITEM_LAYER,
|
||||
self.label = "Layer",
|
||||
self.tooltip = "Adds a layer item.\nA layer item is a primary graphical item, using a spritesheet.",
|
||||
self.snapshotAction = "Add Layer",
|
||||
self.isSizeToText = true
|
||||
self.isSizeToText = true,
|
||||
self.value = ANM2_LAYER,
|
||||
self.isSameLine = true
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_TIMELINE_ADD_ITEM_NULL,
|
||||
self.label = "Null",
|
||||
self.tooltip = "Adds a null item.\nA null item is an invisible item, often accessed by the game engine.",
|
||||
self.snapshotAction = "Add Null",
|
||||
self.isSizeToText = true
|
||||
self.tooltip = "Adds a null item.\nA null item is an invisible item, often accessed by a game engine.",
|
||||
self.isSizeToText = true,
|
||||
self.value = ANM2_NULL
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_TIMELINE_ADD_ITEM_ITEMS_CHILD,
|
||||
self.label = "## Add Item Items",
|
||||
self.size = {IMGUI_TIMELINE_ADD_ITEM.popupSize.x, 250},
|
||||
self.flags = true
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_TIMELINE_ADD_ITEM_OPTIONS_CHILD,
|
||||
self.label = "## Add Item Options Child",
|
||||
self.size = {IMGUI_TIMELINE_ADD_ITEM.popupSize.x, 35},
|
||||
self.flags = true
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_TIMELINE_ADD_ITEM_ADD,
|
||||
self.label = "Add",
|
||||
self.tooltip = "Add the selected item.",
|
||||
self.snapshotAction = "Add Animation",
|
||||
self.rowCount = IMGUI_CONFIRM_POPUP_ROW_COUNT,
|
||||
self.isSameLine = true
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_TIMELINE_REMOVE_ITEM,
|
||||
self.label = "Remove",
|
||||
self.tooltip = "Removes the selected item (layer or null) from the animation.",
|
||||
self.snapshotAction = "Remove Item",
|
||||
self.focusWindow = IMGUI_TIMELINE.label,
|
||||
self.chord = ImGuiKey_Delete,
|
||||
self.focusWindow = IMGUI_TIMELINE_ITEMS_CHILD.label,
|
||||
self.rowCount = IMGUI_TIMELINE_FOOTER_ITEM_CHILD_ITEM_COUNT
|
||||
);
|
||||
|
||||
@@ -2161,7 +2364,7 @@ IMGUI_ITEM(IMGUI_BAKE_CONFIRM,
|
||||
self.label = "Bake",
|
||||
self.tooltip = "Bake the selected frame with the options selected.",
|
||||
self.snapshotAction = "Bake Frames",
|
||||
self.rowCount = IMGUI_OPTION_POPUP_ROW_COUNT,
|
||||
self.rowCount = IMGUI_CONFIRM_POPUP_ROW_COUNT,
|
||||
self.isSameLine = true
|
||||
);
|
||||
|
||||
@@ -2221,13 +2424,13 @@ IMGUI_ITEM(IMGUI_ONIONSKIN_ENABLED,
|
||||
self.isSeparator = true
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_ONIONSKIN_BEFORE, self.label = "-- Before-- ");
|
||||
IMGUI_ITEM(IMGUI_ONIONSKIN_BEFORE, self.label = "-- Before -- ");
|
||||
IMGUI_ITEM(IMGUI_ONIONSKIN_AFTER, self.label = "-- After -- ");
|
||||
|
||||
IMGUI_ITEM(IMGUI_ONIONSKIN_COUNT,
|
||||
self.label = "Count",
|
||||
self.tooltip = "Set the number of previewed frames appearing.",
|
||||
self.min = 1,
|
||||
self.min = 0,
|
||||
self.max = 100,
|
||||
self.value = SETTINGS_ONIONSKIN_BEFORE_COUNT_DEFAULT,
|
||||
self.rowCount = IMGUI_ONIONSKIN_ROW_COUNT,
|
||||
@@ -2303,17 +2506,17 @@ IMGUI_ITEM(IMGUI_CHANGE_INPUT_INT,
|
||||
self.step = 0
|
||||
);
|
||||
|
||||
#define IMGUI_OPTION_POPUP_ROW_COUNT 2
|
||||
#define IMGUI_CONFIRM_POPUP_ROW_COUNT 2
|
||||
IMGUI_ITEM(IMGUI_POPUP_OK,
|
||||
self.label = "OK",
|
||||
self.tooltip = "Confirm the action.",
|
||||
self.rowCount = IMGUI_OPTION_POPUP_ROW_COUNT
|
||||
self.rowCount = IMGUI_CONFIRM_POPUP_ROW_COUNT
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_POPUP_CANCEL,
|
||||
self.label = "Cancel",
|
||||
self.tooltip = "Cancel the action.",
|
||||
self.rowCount = IMGUI_OPTION_POPUP_ROW_COUNT
|
||||
self.rowCount = IMGUI_CONFIRM_POPUP_ROW_COUNT
|
||||
);
|
||||
|
||||
IMGUI_ITEM(IMGUI_LOG_WINDOW,
|
||||
|
16
src/main.cpp
16
src/main.cpp
@@ -4,7 +4,7 @@ static bool _anm2_rescale(const std::string& file, f32 scale)
|
||||
{
|
||||
Anm2 anm2;
|
||||
|
||||
if (!anm2_deserialize(&anm2, file)) return false;
|
||||
if (!anm2_deserialize(&anm2, file, false)) return false;
|
||||
anm2_scale(&anm2, scale);
|
||||
return anm2_serialize(&anm2, file);
|
||||
}
|
||||
@@ -35,9 +35,19 @@ main(s32 argc, char* argv[])
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
else if (std::string(argv[1]) == ARGUMENT_TEST && argv[2])
|
||||
{
|
||||
if (anm2_deserialize(&state.anm2, std::string(argv[2]), false)) return EXIT_SUCCESS;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
else if (std::string(argv[1]) == ARGUMENT_TEST_GL && argv[2])
|
||||
{
|
||||
if (!sdl_init(&state, true)) return EXIT_FAILURE;
|
||||
if (anm2_deserialize(&state.anm2, std::string(argv[2]))) return EXIT_SUCCESS;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
else
|
||||
if (argv[1])
|
||||
state.argument = argv[1];
|
||||
if (argv[1]) state.argument = argv[1];
|
||||
}
|
||||
|
||||
init(&state);
|
||||
|
@@ -2,6 +2,9 @@
|
||||
|
||||
#include <SDL3/SDL_main.h>
|
||||
|
||||
#define ARGUMENT_TEST "--test"
|
||||
#define ARGUMENT_TEST_GL "--test-gl"
|
||||
|
||||
#define ARGUMENT_RESCALE "--rescale"
|
||||
#define ARGUMENT_RESCALE_ARGUMENT_ERROR "--rescale: specify both anm2 and scale arguments"
|
||||
#define ARGUMENT_RESCALE_ANM2_ERROR "Unable to rescale anm2 {} by value {}. Make sure the file is valid."
|
||||
|
@@ -40,7 +40,7 @@ void preview_tick(Preview* self)
|
||||
glReadPixels(0, 0, size.x, size.y, GL_RGBA, GL_UNSIGNED_BYTE, framebufferPixels.data());
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
|
||||
texture_from_rgba_init(&frameTexture, size, TEXTURE_CHANNELS, framebufferPixels.data());
|
||||
texture_from_rgba_init(&frameTexture, size, framebufferPixels.data());
|
||||
self->renderFrames.push_back(frameTexture);
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ void preview_draw(Preview* self)
|
||||
|
||||
auto root_draw = [&](Anm2Frame root, vec3 colorOffset = {}, f32 alphaOffset = {}, bool isOnionskin = {})
|
||||
{
|
||||
mat4 model = canvas_model_get(PREVIEW_TARGET_SIZE, root.position, PREVIEW_TARGET_SIZE * 0.5f, PERCENT_TO_UNIT(root.scale), root.rotation);
|
||||
mat4 model = quad_model_get(PREVIEW_TARGET_SIZE, root.position, PREVIEW_TARGET_SIZE * 0.5f, PERCENT_TO_UNIT(root.scale), root.rotation);
|
||||
mat4 rootTransform = transform * model;
|
||||
vec4 color = isOnionskin ? vec4(colorOffset, 1.0f - alphaOffset) : PREVIEW_ROOT_COLOR;
|
||||
AtlasType atlas = self->settings->previewIsAltIcons ? ATLAS_TARGET_ALT : ATLAS_TARGET;
|
||||
@@ -122,7 +122,7 @@ void preview_draw(Preview* self)
|
||||
anm2_frame_from_time(self->anm2, &frame, Anm2Reference{animationID, ANM2_LAYER, id}, time);
|
||||
if (!frame.isVisible) return;
|
||||
|
||||
mat4 model = canvas_model_get(frame.size, frame.position, frame.pivot, PERCENT_TO_UNIT(frame.scale), frame.rotation);
|
||||
mat4 model = quad_model_get(frame.size, frame.position, frame.pivot, PERCENT_TO_UNIT(frame.scale), frame.rotation);
|
||||
mat4 layerTransform = transform * (rootModel * model);
|
||||
vec3 frameColorOffset = frame.offsetRGB + colorOffset;
|
||||
vec4 frameTint = frame.tintRGBA;
|
||||
@@ -134,8 +134,9 @@ void preview_draw(Preview* self)
|
||||
Texture& texture = spritesheet->texture;
|
||||
if (texture.isInvalid) return;
|
||||
|
||||
vec2 uvMin = frame.crop / vec2(texture.size);
|
||||
vec2 uvMax = (frame.crop + frame.size) / vec2(texture.size);
|
||||
vec2 inset = 0.5f / vec2(texture.size);
|
||||
vec2 uvMin = frame.crop / vec2(texture.size) + inset;
|
||||
vec2 uvMax = (frame.crop + frame.size) / vec2(texture.size) - inset;
|
||||
f32 vertices[] = UV_VERTICES(uvMin, uvMax);
|
||||
canvas_texture_draw(&self->canvas, shaderTexture, texture.id, layerTransform, vertices, frameTint, frameColorOffset);
|
||||
|
||||
@@ -149,7 +150,7 @@ void preview_draw(Preview* self)
|
||||
{
|
||||
vec4 pivotColor = isOnionskin ? vec4(colorOffset, 1.0f - alphaOffset) : PREVIEW_PIVOT_COLOR;
|
||||
f32 vertices[] = ATLAS_UV_VERTICES(ATLAS_PIVOT);
|
||||
mat4 pivotModel = canvas_model_get(CANVAS_PIVOT_SIZE, frame.position, CANVAS_PIVOT_SIZE * 0.5f, PERCENT_TO_UNIT(frame.scale), frame.rotation);
|
||||
mat4 pivotModel = quad_model_get(CANVAS_PIVOT_SIZE, frame.position, CANVAS_PIVOT_SIZE * 0.5f, PERCENT_TO_UNIT(frame.scale), frame.rotation);
|
||||
mat4 pivotTransform = transform * (rootModel * pivotModel);
|
||||
canvas_texture_draw(&self->canvas, shaderTexture, self->resources->atlas.id, pivotTransform, vertices, pivotColor);
|
||||
}
|
||||
@@ -173,7 +174,7 @@ void preview_draw(Preview* self)
|
||||
vec2 size = null.isShowRect ? CANVAS_PIVOT_SIZE : PREVIEW_TARGET_SIZE;
|
||||
AtlasType atlas = null.isShowRect ? ATLAS_SQUARE : self->settings->previewIsAltIcons ? ATLAS_TARGET_ALT : ATLAS_TARGET;
|
||||
|
||||
mat4 model = canvas_model_get(size, frame.position, size * 0.5f, PERCENT_TO_UNIT(frame.scale), frame.rotation);
|
||||
mat4 model = quad_model_get(size, frame.position, size * 0.5f, PERCENT_TO_UNIT(frame.scale), frame.rotation);
|
||||
mat4 nullTransform = transform * (rootModel * model);
|
||||
|
||||
f32 vertices[] = ATLAS_UV_VERTICES(atlas);
|
||||
@@ -182,7 +183,7 @@ void preview_draw(Preview* self)
|
||||
|
||||
if (null.isShowRect)
|
||||
{
|
||||
mat4 rectModel = canvas_model_get(PREVIEW_NULL_RECT_SIZE, frame.position, PREVIEW_NULL_RECT_SIZE * 0.5f, PERCENT_TO_UNIT(frame.scale), frame.rotation);
|
||||
mat4 rectModel = quad_model_get(PREVIEW_NULL_RECT_SIZE, frame.position, PREVIEW_NULL_RECT_SIZE * 0.5f, PERCENT_TO_UNIT(frame.scale), frame.rotation);
|
||||
mat4 rectTransform = transform * (rootModel * rectModel);
|
||||
canvas_rect_draw(&self->canvas, shaderLine, rectTransform, color);
|
||||
}
|
||||
@@ -194,15 +195,15 @@ void preview_draw(Preview* self)
|
||||
anm2_frame_from_time(self->anm2, &root, Anm2Reference{animationID, ANM2_ROOT}, time);
|
||||
|
||||
mat4 rootModel = self->settings->previewIsRootTransform ?
|
||||
canvas_parent_model_get(root.position, {}, PERCENT_TO_UNIT(root.scale), root.rotation) : mat4(1.0f);
|
||||
quad_model_parent_get(root.position, {}, PERCENT_TO_UNIT(root.scale), root.rotation) : mat4(1.0f);
|
||||
|
||||
if (self->settings->previewIsTargets && animation->rootAnimation.isVisible && root.isVisible)
|
||||
if (self->settings->previewIsIcons && animation->rootAnimation.isVisible && root.isVisible)
|
||||
root_draw(root, colorOffset, alphaOffset, isOnionskin);
|
||||
|
||||
for (auto [i, id] : self->anm2->layerMap)
|
||||
for (auto id : animation->layerOrder)
|
||||
layer_draw(rootModel, id, time, colorOffset, alphaOffset, isOnionskin);
|
||||
|
||||
if (self->settings->previewIsTargets)
|
||||
if (self->settings->previewIsIcons)
|
||||
for (auto& [id, _] : animation->nullAnimations)
|
||||
null_draw(rootModel, id, time, colorOffset, alphaOffset, isOnionskin);
|
||||
};
|
||||
|
@@ -42,8 +42,6 @@ struct Preview
|
||||
f32 time{};
|
||||
};
|
||||
|
||||
|
||||
|
||||
void preview_init(Preview* self, Anm2* anm2, Anm2Reference* reference, Resources* resources, Settings* settings);
|
||||
void preview_draw(Preview* self);
|
||||
void preview_tick(Preview* self);
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
void resources_init(Resources* self)
|
||||
{
|
||||
texture_from_encoded_data_init(&self->atlas, TEXTURE_ATLAS_SIZE, TEXTURE_CHANNELS, (u8*)TEXTURE_ATLAS, TEXTURE_ATLAS_LENGTH);
|
||||
texture_from_encoded_data_init(&self->atlas, TEXTURE_ATLAS_SIZE, (u8*)TEXTURE_ATLAS, TEXTURE_ATLAS_LENGTH);
|
||||
|
||||
for (s32 i = 0; i < SHADER_COUNT; i++)
|
||||
shader_init(&self->shaders[i], SHADER_DATA[i].vertex, SHADER_DATA[i].fragment);
|
||||
|
100
src/settings.h
100
src/settings.h
@@ -20,12 +20,19 @@
|
||||
#define SETTINGS_PATH "settings.ini"
|
||||
#define SETTINGS_TEMPORARY_EXTENSION ".tmp"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define SETTINGS_FFMPEG_PATH_VALUE_DEFAULT "C:\\ffmpeg\\bin\\ffmpeg.exe"
|
||||
#else
|
||||
#define SETTINGS_FFMPEG_PATH_VALUE_DEFAULT "/usr/bin/ffmpeg"
|
||||
#endif
|
||||
|
||||
#define SETTINGS_LIST \
|
||||
/* name, symbol, type, defaultValue */ \
|
||||
X(windowSize, WINDOW_SIZE, TYPE_IVEC2_WH, {1280, 720}) \
|
||||
X(windowSize, WINDOW_SIZE, TYPE_IVEC2_WH, {1600, 900}) \
|
||||
X(isVsync, IS_VSYNC, TYPE_BOOL, true) \
|
||||
\
|
||||
X(hotkeyCenterView, HOTKEY_CENTER_VIEW, TYPE_STRING, "Home") \
|
||||
X(hotkeyFit, HOTKEY_FIT, TYPE_STRING, "F") \
|
||||
X(hotkeyZoomIn, HOTKEY_ZOOM_IN, TYPE_STRING, "Ctrl++") \
|
||||
X(hotkeyZoomOut, HOTKEY_ZOOM_OUT, TYPE_STRING, "Ctrl+-") \
|
||||
X(hotkeyPlayPause, HOTKEY_PLAY_PAUSE, TYPE_STRING, "Space") \
|
||||
@@ -84,7 +91,7 @@
|
||||
X(previewIsRootTransform, PREVIEW_IS_ROOT_TRANSFORM, TYPE_BOOL, false) \
|
||||
X(previewIsTriggers, PREVIEW_IS_TRIGGERS, TYPE_BOOL, true) \
|
||||
X(previewIsPivots, PREVIEW_IS_PIVOTS, TYPE_BOOL, false) \
|
||||
X(previewIsTargets, PREVIEW_IS_TARGETS, TYPE_BOOL, true) \
|
||||
X(previewIsIcons, PREVIEW_IS_ICONS, TYPE_BOOL, true) \
|
||||
X(previewIsBorder, PREVIEW_IS_BORDER, TYPE_BOOL, false) \
|
||||
X(previewIsAltIcons, PREVIEW_IS_ALT_ICONS, TYPE_BOOL, false) \
|
||||
X(previewOverlayTransparency,PREVIEW_OVERLAY_TRANSPARENCY,TYPE_FLOAT, 255.0f) \
|
||||
@@ -96,6 +103,8 @@
|
||||
X(previewAxesColor, PREVIEW_AXES_COLOR, TYPE_VEC4, {1.0,1.0,1.0,0.125}) \
|
||||
X(previewBackgroundColor, PREVIEW_BACKGROUND_COLOR, TYPE_VEC4, {0.113,0.184,0.286,1.0}) \
|
||||
\
|
||||
X(propertiesIsRound, PROPERTIES_IS_ROUND, TYPE_BOOL, true) \
|
||||
\
|
||||
X(generateStartPosition, GENERATE_START_POSITION, TYPE_IVEC2, {}) \
|
||||
X(generateSize, GENERATE_SIZE, TYPE_IVEC2, {64,64}) \
|
||||
X(generatePivot, GENERATE_PIVOT, TYPE_IVEC2, {32,32}) \
|
||||
@@ -121,10 +130,13 @@
|
||||
X(bakeIsRoundScale, BAKE_IS_ROUND_SCALE, TYPE_BOOL, true) \
|
||||
X(bakeIsRoundRotation, BAKE_IS_ROUND_ROTATION, TYPE_BOOL, true) \
|
||||
\
|
||||
X(timelineAddItemType, TIMELINE_ADD_ITEM_TYPE, TYPE_INT, ANM2_LAYER) \
|
||||
X(timelineIsShowUnused, TIMELINE_IS_SHOW_UNUSED, TYPE_BOOL, true) \
|
||||
\
|
||||
X(onionskinIsEnabled, ONIONSKIN_IS_ENABLED, TYPE_BOOL, false) \
|
||||
X(onionskinDrawOrder, ONIONSKIN_DRAW_ORDER, TYPE_INT, ONIONSKIN_BELOW) \
|
||||
X(onionskinBeforeCount, ONIONSKIN_BEFORE_COUNT, TYPE_INT, 1) \
|
||||
X(onionskinAfterCount, ONIONSKIN_AFTER_COUNT, TYPE_INT, 1) \
|
||||
X(onionskinBeforeCount, ONIONSKIN_BEFORE_COUNT, TYPE_INT, 0) \
|
||||
X(onionskinAfterCount, ONIONSKIN_AFTER_COUNT, TYPE_INT, 0) \
|
||||
X(onionskinBeforeColorOffset,ONIONSKIN_BEFORE_COLOR_OFFSET,TYPE_VEC3, COLOR_RED) \
|
||||
X(onionskinAfterColorOffset, ONIONSKIN_AFTER_COLOR_OFFSET,TYPE_VEC3, COLOR_BLUE) \
|
||||
\
|
||||
@@ -134,7 +146,7 @@
|
||||
X(renderType, RENDER_TYPE, TYPE_INT, RENDER_PNG) \
|
||||
X(renderPath, RENDER_PATH, TYPE_STRING, ".") \
|
||||
X(renderFormat, RENDER_FORMAT, TYPE_STRING, "{}.png") \
|
||||
X(ffmpegPath, FFMPEG_PATH, TYPE_STRING, "")
|
||||
X(ffmpegPath, FFMPEG_PATH, TYPE_STRING, SETTINGS_FFMPEG_PATH_VALUE_DEFAULT)
|
||||
|
||||
#define X(name, symbol, type, ...) \
|
||||
const inline DATATYPE_TO_CTYPE(type) SETTINGS_##symbol##_DEFAULT = __VA_ARGS__;
|
||||
@@ -169,6 +181,7 @@ constexpr s32 SETTINGS_COUNT = (s32)std::size(SETTINGS_ENTRIES);
|
||||
#define HOTKEY_LIST \
|
||||
X(NONE, "None") \
|
||||
X(CENTER_VIEW, "Center View") \
|
||||
X(FIT, "Fit") \
|
||||
X(ZOOM_IN, "Zoom In") \
|
||||
X(ZOOM_OUT, "Zoom Out") \
|
||||
X(PLAY_PAUSE, "Play/Pause") \
|
||||
@@ -213,6 +226,7 @@ const inline HotkeyMember SETTINGS_HOTKEY_MEMBERS[HOTKEY_COUNT] =
|
||||
{
|
||||
nullptr,
|
||||
&Settings::hotkeyCenterView,
|
||||
&Settings::hotkeyFit,
|
||||
&Settings::hotkeyZoomIn,
|
||||
&Settings::hotkeyZoomOut,
|
||||
&Settings::hotkeyPlayPause,
|
||||
@@ -251,66 +265,86 @@ Collapsed=0
|
||||
|
||||
[Window][Tools]
|
||||
Pos=8,40
|
||||
Size=39,612
|
||||
Size=38,516
|
||||
Collapsed=0
|
||||
DockId=0x0000000B,0
|
||||
|
||||
[Window][Animations]
|
||||
Pos=1288,301
|
||||
Size=304,351
|
||||
Pos=1289,307
|
||||
Size=303,249
|
||||
Collapsed=0
|
||||
DockId=0x0000000A,0
|
||||
|
||||
[Window][Events]
|
||||
Pos=1005,353
|
||||
Size=281,299
|
||||
Pos=957,264
|
||||
Size=330,292
|
||||
Collapsed=0
|
||||
DockId=0x00000008,0
|
||||
DockId=0x00000008,2
|
||||
|
||||
[Window][Spritesheets]
|
||||
Pos=1288,40
|
||||
Size=304,259
|
||||
Pos=1289,40
|
||||
Size=303,265
|
||||
Collapsed=0
|
||||
DockId=0x00000009,0
|
||||
|
||||
[Window][Animation Preview]
|
||||
Pos=49,40
|
||||
Size=954,612
|
||||
Pos=48,40
|
||||
Size=907,516
|
||||
Collapsed=0
|
||||
DockId=0x0000000C,0
|
||||
|
||||
[Window][Spritesheet Editor]
|
||||
Pos=49,40
|
||||
Size=954,612
|
||||
Pos=48,40
|
||||
Size=907,516
|
||||
Collapsed=0
|
||||
DockId=0x0000000C,1
|
||||
|
||||
[Window][Timeline]
|
||||
Pos=8,654
|
||||
Size=1584,238
|
||||
Pos=8,558
|
||||
Size=1584,334
|
||||
Collapsed=0
|
||||
DockId=0x00000004,0
|
||||
|
||||
[Window][Frame Properties]
|
||||
Pos=1005,40
|
||||
Size=281,311
|
||||
Pos=957,40
|
||||
Size=330,222
|
||||
Collapsed=0
|
||||
DockId=0x00000007,0
|
||||
|
||||
[Window][Onionskin]
|
||||
Pos=957,264
|
||||
Size=330,292
|
||||
Collapsed=0
|
||||
DockId=0x00000008,3
|
||||
|
||||
[Window][Layers]
|
||||
Pos=957,264
|
||||
Size=330,292
|
||||
Collapsed=0
|
||||
DockId=0x00000008,0
|
||||
|
||||
[Window][Nulls]
|
||||
Pos=957,264
|
||||
Size=330,292
|
||||
Collapsed=0
|
||||
DockId=0x00000008,1
|
||||
|
||||
|
||||
[Docking][Data]
|
||||
DockSpace ID=0xFC02A410 Window=0x0E46F4F7 Pos=8,40 Size=1584,852 Split=Y
|
||||
DockNode ID=0x00000003 Parent=0xFC02A410 SizeRef=1902,612 Split=X
|
||||
DockNode ID=0x00000001 Parent=0x00000003 SizeRef=1278,1016 Split=X Selected=0x024430EF
|
||||
DockNode ID=0x00000005 Parent=0x00000001 SizeRef=995,654 Split=X Selected=0x024430EF
|
||||
DockNode ID=0x0000000B Parent=0x00000005 SizeRef=39,654 Selected=0x18A5FDB9
|
||||
DockNode ID=0x0000000C Parent=0x00000005 SizeRef=954,654 CentralNode=1 Selected=0x024430EF
|
||||
DockNode ID=0x00000006 Parent=0x00000001 SizeRef=281,654 Split=Y Selected=0x754E368F
|
||||
DockNode ID=0x00000007 Parent=0x00000006 SizeRef=631,311 Selected=0x754E368F
|
||||
DockNode ID=0x00000008 Parent=0x00000006 SizeRef=631,299 Selected=0x8A65D963
|
||||
DockNode ID=0x00000002 Parent=0x00000003 SizeRef=304,1016 Split=Y Selected=0x4EFD0020
|
||||
DockNode ID=0x00000009 Parent=0x00000002 SizeRef=634,259 Selected=0x4EFD0020
|
||||
DockNode ID=0x0000000A Parent=0x00000002 SizeRef=634,351 Selected=0xC1986EE2
|
||||
DockNode ID=0x00000004 Parent=0xFC02A410 SizeRef=1902,238 Selected=0x4F89F0DC
|
||||
DockNode ID=0x00000003 Parent=0xFC02A410 SizeRef=1902,680 Split=X
|
||||
DockNode ID=0x00000001 Parent=0x00000003 SizeRef=1017,1016 Split=X Selected=0x024430EF
|
||||
DockNode ID=0x00000005 Parent=0x00000001 SizeRef=1264,654 Split=X Selected=0x024430EF
|
||||
DockNode ID=0x0000000B Parent=0x00000005 SizeRef=38,654 Selected=0x18A5FDB9
|
||||
DockNode ID=0x0000000C Parent=0x00000005 SizeRef=1224,654 CentralNode=1 Selected=0x024430EF
|
||||
DockNode ID=0x00000006 Parent=0x00000001 SizeRef=330,654 Split=Y Selected=0x754E368F
|
||||
DockNode ID=0x00000007 Parent=0x00000006 SizeRef=631,293 Selected=0x754E368F
|
||||
DockNode ID=0x00000008 Parent=0x00000006 SizeRef=631,385 Selected=0xCD8384B1
|
||||
DockNode ID=0x00000002 Parent=0x00000003 SizeRef=303,1016 Split=Y Selected=0x4EFD0020
|
||||
DockNode ID=0x00000009 Parent=0x00000002 SizeRef=634,349 Selected=0x4EFD0020
|
||||
DockNode ID=0x0000000A Parent=0x00000002 SizeRef=634,329 Selected=0xC1986EE2
|
||||
DockNode ID=0x00000004 Parent=0xFC02A410 SizeRef=1902,334 Selected=0x4F89F0DC
|
||||
|
||||
)";
|
||||
|
||||
void settings_save(Settings* self);
|
||||
|
@@ -22,18 +22,16 @@ static void _draw(State* self)
|
||||
SDL_GL_SwapWindow(self->window);
|
||||
}
|
||||
|
||||
void init(State* self)
|
||||
bool sdl_init(State* self, bool isTestMode = false)
|
||||
{
|
||||
settings_init(&self->settings);
|
||||
|
||||
if (!SDL_Init(SDL_INIT_VIDEO))
|
||||
{
|
||||
log_error(std::format(STATE_SDL_INIT_ERROR, SDL_GetError()));
|
||||
quit(self);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
log_info(STATE_SDL_INIT_INFO);
|
||||
if (!isTestMode) log_info(STATE_SDL_INIT_INFO);
|
||||
|
||||
// Todo, when sdl3 mixer is released officially
|
||||
/*
|
||||
@@ -61,13 +59,35 @@ void init(State* self)
|
||||
log_info(STATE_MIX_INIT_INFO);
|
||||
*/
|
||||
|
||||
|
||||
if (isTestMode)
|
||||
{
|
||||
self->window = SDL_CreateWindow
|
||||
(
|
||||
WINDOW_TITLE,
|
||||
self->settings.windowSize.x,
|
||||
self->settings.windowSize.y,
|
||||
WINDOW_TEST_MODE_SIZE.x, WINDOW_TEST_MODE_SIZE.y,
|
||||
WINDOW_TEST_MODE_FLAGS
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
ivec2 windowSize = self->settings.windowSize;
|
||||
|
||||
// Fix for auto-fullscreen on Windows
|
||||
if (SDL_DisplayID* displayIDs = SDL_GetDisplays(nullptr))
|
||||
if (displayIDs[0])
|
||||
if (const SDL_DisplayMode* displayMode = SDL_GetDesktopDisplayMode(displayIDs[0]))
|
||||
if (windowSize.x == displayMode->w && windowSize.y == displayMode->h)
|
||||
windowSize -= ivec2(1, 1);
|
||||
|
||||
self->window = SDL_CreateWindow
|
||||
(
|
||||
WINDOW_TITLE,
|
||||
windowSize.x,
|
||||
windowSize.y,
|
||||
WINDOW_FLAGS
|
||||
);
|
||||
}
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, STATE_GL_VERSION_MAJOR);
|
||||
@@ -79,17 +99,17 @@ void init(State* self)
|
||||
{
|
||||
log_error(std::format(STATE_GL_CONTEXT_INIT_ERROR, SDL_GetError()));
|
||||
quit(self);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress))
|
||||
{
|
||||
log_error(std::format(STATE_GLAD_INIT_ERROR));
|
||||
quit(self);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
log_info(std::format(STATE_GL_CONTEXT_INIT_INFO, (const char*)glGetString(GL_VERSION)));
|
||||
if (!isTestMode) log_info(std::format(STATE_GL_CONTEXT_INIT_INFO, (const char*)glGetString(GL_VERSION)));
|
||||
|
||||
window_vsync_set(self->settings.isVsync);
|
||||
|
||||
@@ -100,6 +120,17 @@ void init(State* self)
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_LINE_SMOOTH);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void init(State* self)
|
||||
{
|
||||
log_info(STATE_INIT_INFO);
|
||||
|
||||
settings_init(&self->settings);
|
||||
|
||||
if (!sdl_init(self)) return;
|
||||
|
||||
if (!self->argument.empty())
|
||||
{
|
||||
anm2_deserialize(&self->anm2, self->argument);
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "imgui.h"
|
||||
|
||||
#define STATE_INIT_INFO "Initializing..."
|
||||
#define STATE_INIT_INFO "Initializing anm2ed (Version 1.1)"
|
||||
#define STATE_SDL_INIT_ERROR "Failed to initialize SDL! {}"
|
||||
#define STATE_SDL_INIT_INFO "Initialized SDL"
|
||||
#define STATE_MIX_INIT_WARNING "Unable to initialize SDL_mixer! {}"
|
||||
@@ -51,6 +51,7 @@ struct State
|
||||
bool isRunning = true;
|
||||
};
|
||||
|
||||
bool sdl_init(State* self, bool isTestMode);
|
||||
void init(State* state);
|
||||
void loop(State* state);
|
||||
void quit(State* state);
|
@@ -17,8 +17,7 @@
|
||||
|
||||
static void _texture_gl_set(Texture* self, const u8* data)
|
||||
{
|
||||
if (self->id == GL_ID_NONE)
|
||||
glGenTextures(1, &self->id);
|
||||
if (self->id == GL_ID_NONE) glGenTextures(1, &self->id);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, self->id);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, self->size.x, self->size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
@@ -35,6 +34,7 @@ std::vector<u8> texture_download(const Texture* self)
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, self->id);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
|
||||
|
||||
return pixels;
|
||||
@@ -42,17 +42,13 @@ std::vector<u8> texture_download(const Texture* self)
|
||||
|
||||
bool texture_from_path_init(Texture* self, const std::string& path)
|
||||
{
|
||||
u8* data = stbi_load(path.c_str(), &self->size.x, &self->size.y, &self->channels, TEXTURE_CHANNELS);
|
||||
u8* data = stbi_load(path.c_str(), &self->size.x, &self->size.y, nullptr, TEXTURE_CHANNELS);
|
||||
|
||||
if (!data)
|
||||
{
|
||||
data = stbi_load(path_canonical_resolve(path).c_str(), &self->size.x, &self->size.y, &self->channels, TEXTURE_CHANNELS);
|
||||
if (!data)
|
||||
{
|
||||
log_error(std::format(TEXTURE_INIT_ERROR, path));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
self->isInvalid = false;
|
||||
|
||||
@@ -63,13 +59,12 @@ bool texture_from_path_init(Texture* self, const std::string& path)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool texture_from_encoded_data_init(Texture* self, ivec2 size, s32 channels, const u8* data, u32 length)
|
||||
bool texture_from_encoded_data_init(Texture* self, ivec2 size, const u8* data, u32 length)
|
||||
{
|
||||
*self = Texture{};
|
||||
self->size = size;
|
||||
self->channels = channels;
|
||||
|
||||
u8* textureData = stbi_load_from_memory(data, length, &self->size.x, &self->size.y, &self->channels, TEXTURE_CHANNELS);
|
||||
u8* textureData = stbi_load_from_memory(data, length, &self->size.x, &self->size.y, nullptr, TEXTURE_CHANNELS);
|
||||
|
||||
if (!textureData)
|
||||
{
|
||||
@@ -82,11 +77,11 @@ bool texture_from_encoded_data_init(Texture* self, ivec2 size, s32 channels, con
|
||||
return true;
|
||||
}
|
||||
|
||||
bool texture_from_rgba_init(Texture* self, ivec2 size, s32 channels, const u8* data)
|
||||
bool texture_from_rgba_init(Texture* self, ivec2 size, const u8* data)
|
||||
{
|
||||
*self = Texture{};
|
||||
self->size = size;
|
||||
self->channels = channels;
|
||||
self->isInvalid = false;
|
||||
|
||||
_texture_gl_set(self, data);
|
||||
|
||||
@@ -96,13 +91,8 @@ bool texture_from_rgba_init(Texture* self, ivec2 size, s32 channels, const u8* d
|
||||
bool texture_from_rgba_write(const std::string& path, const u8* data, ivec2 size)
|
||||
{
|
||||
bool isSuccess = stbi_write_png(path.c_str(), size.x, size.y, TEXTURE_CHANNELS, data, size.x * TEXTURE_CHANNELS);
|
||||
if (!isSuccess)
|
||||
{
|
||||
isSuccess = stbi_write_png(path_canonical_resolve(path).c_str(), size.x, size.y, TEXTURE_CHANNELS, data, size.x * TEXTURE_CHANNELS);
|
||||
if (!isSuccess) log_info(std::format(TEXTURE_SAVE_ERROR, path));
|
||||
}
|
||||
|
||||
log_info(std::format(TEXTURE_SAVE_INFO, path));
|
||||
if (!isSuccess) log_error(std::format(TEXTURE_SAVE_ERROR, path));
|
||||
else log_info(std::format(TEXTURE_SAVE_INFO, path));
|
||||
|
||||
return isSuccess;
|
||||
}
|
||||
|
@@ -12,16 +12,14 @@ struct Texture
|
||||
{
|
||||
GLuint id = GL_ID_NONE;
|
||||
ivec2 size{};
|
||||
s32 channels = TEXTURE_CHANNELS;
|
||||
bool isInvalid = true;
|
||||
};
|
||||
|
||||
bool texture_from_encoded_data_init(Texture* self, ivec2 size, s32 channels, const u8* data, u32 length);
|
||||
bool texture_from_encoded_data_init(Texture* self, ivec2 size, const u8* data, u32 length);
|
||||
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_rgba_init(Texture* self, ivec2 size, s32 channels, const u8* data);
|
||||
bool texture_from_rgba_init(Texture* self, ivec2 size, const u8* data);
|
||||
bool texture_from_rgba_write(const std::string& path, const u8* data, ivec2 size);
|
||||
bool texture_pixel_set(Texture* self, ivec2 position, vec4 color);
|
||||
void texture_free(Texture* self);
|
||||
std::vector<u8> texture_download(const Texture* self);
|
||||
Texture texture_copy(Texture* self);
|
@@ -5,6 +5,9 @@
|
||||
#define WINDOW_TITLE "Anm2Ed"
|
||||
#define WINDOW_TITLE_FORMAT "Anm2Ed ({})"
|
||||
#define WINDOW_FLAGS SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL
|
||||
#define WINDOW_TEST_MODE_FLAGS WINDOW_FLAGS | SDL_WINDOW_HIDDEN
|
||||
|
||||
static const ivec2 WINDOW_TEST_MODE_SIZE = {1, 1};
|
||||
|
||||
void window_title_from_path_set(SDL_Window* self, const std::string& path);
|
||||
bool window_color_from_position_get(SDL_Window* self, vec2 position, vec4* color);
|
||||
|
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"dependencies": [
|
||||
"sdl3",
|
||||
"glew"
|
||||
"sdl3"
|
||||
]
|
||||
}
|
||||
|
48
workshop/metadata.xml
Normal file
48
workshop/metadata.xml
Normal file
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<metadata>
|
||||
<name>Anm2Ed (Animation Editor)</name>
|
||||
<directory>anm2ed</directory>
|
||||
<id>3567731616</id>
|
||||
<description>
|
||||
[h1]NOTE: THIS IS NOT A MOD! SUBSCRIBING TO THIS ISN'T NECESSARY (though it's appreciated)! It's recommended you head to the download page below![/h1]
|
||||
|
||||
[h2]Anm2Ed[/h2]
|
||||
|
||||
[img]https://files.catbox.moe/3bj6za.png[/img]
|
||||
|
||||
A reimplementation of [i]The Binding of Isaac: Rebirth[/i]'s proprietary animation editor. Manipulates the XML-based ".anm2" format, used for in-game tweened animations.
|
||||
|
||||
[h2]Features[/h2]
|
||||
[list]
|
||||
[*] Extended version of the original proprietary Nicalis animation editor
|
||||
[*] Smooth [url=https://github.com/ocornut/imgui]Dear ImGui[/url] interface; docking, dragging and dropping, etc. You might be familiar with it from [url=https://steamcommunity.com/sharedfiles/filedetails/?id=3127536138]Repentogon[/url].
|
||||
[*] New to this editor:
|
||||
[list]
|
||||
[*] Can output .webm. .mp4 or *.png sequence (with FFmpeg)
|
||||
[*] Cutting, copying and pasting frames/animations
|
||||
[*] Additional wizard options
|
||||
[*] Robust snapshot (undo/redo) system
|
||||
[*] Additional hotkeys/shortcuts (rebindable!)
|
||||
[*] Onionskinning
|
||||
[*] Settings that will preserve on exit (stored in %APPDATA% on Windows or ~/.local/share on Linux)
|
||||
[/list]
|
||||
[/list]
|
||||
|
||||
[h3]Note: Difference from Nicalis editor[/h3]
|
||||
Layers/nulls are handled differently (in their own window) and are not on the timeline! Add a layer/null in the Layers/Nulls window, and then add a LayerAnimation/NullAnimation in the timeline!
|
||||
|
||||
[h3]Note on Rendering Animations[/h3]
|
||||
You will need FFmpeg installed! Get it from [url=https://ffmpeg.org/download.html]here[/url] and point to the downloaded ffmpeg executable within the program!
|
||||
|
||||
[h2]Download (Windows)[/h2]
|
||||
https://github.com/ShweetsStuff/anm2ed/releases
|
||||
Extract with 7z and run .exe. Check that you have the latest [url=https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170]Microsoft C++ redistributable[/url] (if you play a lot of games on Steam, you likely will have it).
|
||||
|
||||
Alternatively, if you have subscribed to the mod, you can find the latest release inside the "resources" folder. Once downloaded, you can put it wherever you want.
|
||||
|
||||
[h3]Happy animating![/h3]
|
||||
[img]https://files.catbox.moe/4auc1c.gif[/img]
|
||||
</description>
|
||||
<version>1.1</version>
|
||||
<visibility>Public</visibility>
|
||||
</metadata>
|
BIN
workshop/preview.png
Normal file
BIN
workshop/preview.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 31 KiB |
Reference in New Issue
Block a user