Merge branch 'staging'

# Conflicts:
#	.vscode/launch.json
#	.vscode/tasks.json
#	src/imgui/window/animation_preview.cpp
#	src/imgui/window/regions.cpp
This commit is contained in:
2026-03-19 03:51:13 -04:00
155 changed files with 928 additions and 463 deletions
+4 -2
View File
@@ -5,7 +5,8 @@
"name": "Debug", "name": "Debug",
"type": "cppdbg", "type": "cppdbg",
"request": "launch", "request": "launch",
"program": "${workspaceFolder}/out/build/linux-debug/anm2ed", "preLaunchTask": "build-debug",
"program": "${workspaceFolder}/out/build/linux-debug/bin/anm2ed",
"args": [], "args": [],
"stopAtEntry": false, "stopAtEntry": false,
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
@@ -28,7 +29,8 @@
"name": "Release", "name": "Release",
"type": "cppdbg", "type": "cppdbg",
"request": "launch", "request": "launch",
"program": "${workspaceFolder}/out/build/linux-release/anm2ed", "preLaunchTask": "build-release",
"program": "${workspaceFolder}/out/build/linux-release/bin/anm2ed",
"args": [], "args": [],
"stopAtEntry": false, "stopAtEntry": false,
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
+53 -7
View File
@@ -2,17 +2,33 @@
"version": "2.0.0", "version": "2.0.0",
"tasks": [ "tasks": [
{ {
"label": "run-debug", "label": "configure-debug",
"type": "shell", "type": "shell",
"command": "cmake -S . -B out/build/linux-debug -DCMAKE_BUILD_TYPE=Debug && cmake --build out/build/linux-debug --parallel 8 --target anm2ed && ./out/build/linux-debug/anm2ed", "command": "cmake",
"args": [
"-S",
".",
"-B",
"out/build/linux-debug",
"-DCMAKE_BUILD_TYPE=Debug"
],
"problemMatcher": [ "problemMatcher": [
"$gcc" "$gcc"
] ]
}, },
{ {
"label": "build", "label": "build-debug",
"type": "shell", "type": "shell",
"command": "cmake -S . -B out/build/linux-debug -DCMAKE_BUILD_TYPE=Debug && cmake --build out/build/linux-debug --parallel 8 --target anm2ed", "command": "cmake",
"args": [
"--build",
"out/build/linux-debug",
"--parallel",
"8",
"--target",
"anm2ed"
],
"dependsOn": "configure-debug",
"group": { "group": {
"kind": "build", "kind": "build",
"isDefault": true "isDefault": true
@@ -22,9 +38,23 @@
] ]
}, },
{ {
"label": "run-release", "label": "run-debug",
"type": "shell", "type": "shell",
"command": "cmake -S . -B out/build/linux-release -DCMAKE_BUILD_TYPE=Release && cmake --build out/build/linux-release --parallel 8 --target anm2ed && ./out/build/linux-release/anm2ed", "command": "./out/build/linux-debug/bin/anm2ed",
"dependsOn": "build-debug",
"problemMatcher": []
},
{
"label": "configure-release",
"type": "shell",
"command": "cmake",
"args": [
"-S",
".",
"-B",
"out/build/linux-release",
"-DCMAKE_BUILD_TYPE=Release"
],
"problemMatcher": [ "problemMatcher": [
"$gcc" "$gcc"
] ]
@@ -32,11 +62,27 @@
{ {
"label": "build-release", "label": "build-release",
"type": "shell", "type": "shell",
"command": "cmake -S . -B out/build/linux-release -DCMAKE_BUILD_TYPE=Release && cmake --build out/build/linux-release --parallel 8 --target anm2ed", "command": "cmake",
"args": [
"--build",
"out/build/linux-release",
"--parallel",
"8",
"--target",
"anm2ed"
],
"dependsOn": "configure-release",
"group": "build", "group": "build",
"problemMatcher": [ "problemMatcher": [
"$gcc" "$gcc"
] ]
},
{
"label": "run-release",
"type": "shell",
"command": "./out/build/linux-release/bin/anm2ed",
"dependsOn": "build-release",
"problemMatcher": []
} }
] ]
} }
+15 -8
View File
@@ -87,23 +87,30 @@ set(TINYXML2_SRC external/tinyxml2/tinyxml2.cpp)
file(GLOB PROJECT_SRC CONFIGURE_DEPENDS file(GLOB PROJECT_SRC CONFIGURE_DEPENDS
src/anm2/*.cpp src/anm2/*.cpp
src/anm2/*.h src/anm2/*.hpp
src/resource/*.cpp src/resource/*.cpp
src/resource/*.h src/resource/*.hpp
src/imgui/*.cpp src/imgui/*.cpp
src/imgui/*.h src/imgui/*.hpp
src/imgui/window/*.cpp src/imgui/window/*.cpp
src/imgui/window/*.h src/imgui/window/*.hpp
src/imgui/wizard/*.cpp src/imgui/wizard/*.cpp
src/imgui/wizard/*.h src/imgui/wizard/*.hpp
src/util/*.cpp src/util/*.cpp
src/util/*.h src/util/*.hpp
src/window/*.cpp src/window/*.cpp
src/window/*.h src/window/*.hpp
src/*.cpp src/*.cpp
src/*.h) src/*.hpp)
add_executable(${PROJECT_NAME} ${GLAD_SRC} ${IMGUI_SRC} ${TINYXML2_SRC} ${PROJECT_SRC}) add_executable(${PROJECT_NAME} ${GLAD_SRC} ${IMGUI_SRC} ${TINYXML2_SRC} ${PROJECT_SRC})
set_target_properties(
${PROJECT_NAME}
PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/bin"
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/bin"
RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}/bin"
RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_BINARY_DIR}/bin")
target_compile_definitions(${PROJECT_NAME} PRIVATE IMGUI_DISABLE_OBSOLETE_FUNCTIONS IMGUI_DEBUG_PARANOID target_compile_definitions(${PROJECT_NAME} PRIVATE IMGUI_DISABLE_OBSOLETE_FUNCTIONS IMGUI_DEBUG_PARANOID
IMGUI_ENABLE_DOCKING) IMGUI_ENABLE_DOCKING)
+2 -2
View File
@@ -1,7 +1,7 @@
{ {
"configurations": [ "configurations": [
{ {
"name": "x64-Debug", "name": "windows-debug",
"generator": "Ninja", "generator": "Ninja",
"configurationType": "Debug", "configurationType": "Debug",
"inheritEnvironments": [ "inheritEnvironments": [
@@ -12,7 +12,7 @@
"cmakeCommandArgs": "-DCMAKE_BUILD_TYPE=\"Debug\"" "cmakeCommandArgs": "-DCMAKE_BUILD_TYPE=\"Debug\""
}, },
{ {
"name": "x64-Release", "name": "windows-release",
"generator": "Ninja", "generator": "Ninja",
"configurationType": "Release", "configurationType": "Release",
"inheritEnvironments": [ "inheritEnvironments": [
+5 -5
View File
@@ -1,9 +1,9 @@
#include "animation.h" #include "animation.hpp"
#include "map_.h" #include "map_.hpp"
#include "math_.h" #include "math_.hpp"
#include "unordered_map_.h" #include "unordered_map_.hpp"
#include "xml_.h" #include "xml_.hpp"
#include <ranges> #include <ranges>
using namespace anm2ed::util; using namespace anm2ed::util;
@@ -3,7 +3,7 @@
#include <map> #include <map>
#include <string> #include <string>
#include "item.h" #include "item.hpp"
namespace anm2ed::anm2 namespace anm2ed::anm2
{ {
+2 -2
View File
@@ -1,6 +1,6 @@
#include "animations.h" #include "animations.hpp"
#include "xml_.h" #include "xml_.hpp"
using namespace tinyxml2; using namespace tinyxml2;
using namespace anm2ed::types; using namespace anm2ed::types;
@@ -1,6 +1,6 @@
#pragma once #pragma once
#include "animation.h" #include "animation.hpp"
namespace anm2ed::anm2 namespace anm2ed::anm2
{ {
+7 -7
View File
@@ -1,15 +1,15 @@
#include "anm2.h" #include "anm2.hpp"
#include <algorithm> #include <algorithm>
#include <filesystem> #include <filesystem>
#include <unordered_map> #include <unordered_map>
#include "file_.h" #include "file_.hpp"
#include "map_.h" #include "map_.hpp"
#include "time_.h" #include "time_.hpp"
#include "vector_.h" #include "vector_.hpp"
#include "working_directory.h" #include "working_directory.hpp"
#include "xml_.h" #include "xml_.hpp"
using namespace tinyxml2; using namespace tinyxml2;
using namespace anm2ed::types; using namespace anm2ed::types;
+4 -4
View File
@@ -4,11 +4,11 @@
#include <string> #include <string>
#include <tinyxml2/tinyxml2.h> #include <tinyxml2/tinyxml2.h>
#include "types.h" #include "types.hpp"
#include "animations.h" #include "animations.hpp"
#include "content.h" #include "content.hpp"
#include "info.h" #include "info.hpp"
namespace anm2ed::anm2 namespace anm2ed::anm2
{ {
+2 -2
View File
@@ -1,6 +1,6 @@
#include "anm2.h" #include "anm2.hpp"
#include "vector_.h" #include "vector_.hpp"
using namespace anm2ed::util; using namespace anm2ed::util;
using namespace anm2ed::types; using namespace anm2ed::types;
+2 -2
View File
@@ -1,8 +1,8 @@
#include "anm2.h" #include "anm2.hpp"
#include <ranges> #include <ranges>
#include "map_.h" #include "map_.hpp"
using namespace anm2ed::types; using namespace anm2ed::types;
using namespace anm2ed::util; using namespace anm2ed::util;
+4 -4
View File
@@ -1,8 +1,8 @@
#include "anm2.h" #include "anm2.hpp"
#include "map_.h" #include "map_.hpp"
#include "types.h" #include "types.hpp"
#include "unordered_map_.h" #include "unordered_map_.hpp"
using namespace anm2ed::types; using namespace anm2ed::types;
using namespace anm2ed::util; using namespace anm2ed::util;
+2 -2
View File
@@ -1,8 +1,8 @@
#include "anm2.h" #include "anm2.hpp"
#include <ranges> #include <ranges>
#include "map_.h" #include "map_.hpp"
using namespace anm2ed::types; using namespace anm2ed::types;
using namespace anm2ed::util; using namespace anm2ed::util;
+2 -2
View File
@@ -1,8 +1,8 @@
#include "anm2.h" #include "anm2.hpp"
#include <ranges> #include <ranges>
#include "map_.h" #include "map_.hpp"
using namespace anm2ed::types; using namespace anm2ed::types;
using namespace anm2ed::util; using namespace anm2ed::util;
+4 -4
View File
@@ -1,8 +1,8 @@
#include "anm2.h" #include "anm2.hpp"
#include "map_.h" #include "map_.hpp"
#include "path_.h" #include "path_.hpp"
#include "working_directory.h" #include "working_directory.hpp"
using namespace anm2ed::types; using namespace anm2ed::types;
using namespace anm2ed::util; using namespace anm2ed::util;
+19 -4
View File
@@ -1,4 +1,4 @@
#include "anm2.h" #include "anm2.hpp"
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
@@ -8,9 +8,9 @@
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include "map_.h" #include "map_.hpp"
#include "path_.h" #include "path_.hpp"
#include "working_directory.h" #include "working_directory.hpp"
using namespace anm2ed::types; using namespace anm2ed::types;
using namespace anm2ed::util; using namespace anm2ed::util;
@@ -419,6 +419,7 @@ namespace anm2ed::anm2
std::unordered_map<int, glm::ivec2> offsets{}; std::unordered_map<int, glm::ivec2> offsets{};
offsets[baseId] = {}; offsets[baseId] = {};
auto baseTextureSize = base.texture.size;
auto mergedTexture = base.texture; auto mergedTexture = base.texture;
for (auto id : ids) for (auto id : ids)
{ {
@@ -446,6 +447,20 @@ namespace anm2ed::anm2
base.regionOrder.push_back(id); base.regionOrder.push_back(id);
} }
auto baseLocationRegionID = map::next_id_get(base.regions);
auto baseFilename = path::to_utf8(base.path.stem());
auto baseLocationRegionName = baseFilename.empty() ? std::format("#{}", baseId) : baseFilename;
auto baseLocationRegionPivot =
regionOrigin == origin::ORIGIN_CENTER ? glm::vec2(baseTextureSize) * 0.5f : glm::vec2();
base.regions[baseLocationRegionID] = {
.name = baseLocationRegionName,
.crop = {},
.pivot = glm::ivec2(baseLocationRegionPivot),
.size = baseTextureSize,
.origin = regionOrigin,
};
base.regionOrder.push_back(baseLocationRegionID);
for (auto id : ids) for (auto id : ids)
{ {
if (id == baseId) continue; if (id == baseId) continue;
@@ -1,7 +1,7 @@
#pragma once #pragma once
#include "icon.h" #include "icon.hpp"
#include "strings.h" #include "strings.hpp"
#include <glm/glm/vec2.hpp> #include <glm/glm/vec2.hpp>
#include <glm/glm/vec3.hpp> #include <glm/glm/vec3.hpp>
+1 -1
View File
@@ -1,4 +1,4 @@
#include "content.h" #include "content.hpp"
using namespace tinyxml2; using namespace tinyxml2;
+5 -5
View File
@@ -2,11 +2,11 @@
#include <map> #include <map>
#include "event.h" #include "event.hpp"
#include "layer.h" #include "layer.hpp"
#include "null.h" #include "null.hpp"
#include "sound.h" #include "sound.hpp"
#include "spritesheet.h" #include "spritesheet.hpp"
namespace anm2ed::anm2 namespace anm2ed::anm2
{ {
+2 -2
View File
@@ -1,6 +1,6 @@
#include "event.h" #include "event.hpp"
#include "xml_.h" #include "xml_.hpp"
using namespace anm2ed::util; using namespace anm2ed::util;
using namespace tinyxml2; using namespace tinyxml2;
+3 -3
View File
@@ -1,7 +1,7 @@
#include "frame.h" #include "frame.hpp"
#include "math_.h" #include "math_.hpp"
#include "xml_.h" #include "xml_.hpp"
using namespace anm2ed::util; using namespace anm2ed::util;
using namespace tinyxml2; using namespace tinyxml2;
+2 -2
View File
@@ -4,8 +4,8 @@
#include <string> #include <string>
#include <tinyxml2/tinyxml2.h> #include <tinyxml2/tinyxml2.h>
#include "anm2_type.h" #include "anm2_type.hpp"
#include "types.h" #include "types.hpp"
namespace anm2ed::anm2 namespace anm2ed::anm2
{ {
+2 -2
View File
@@ -1,6 +1,6 @@
#include "info.h" #include "info.hpp"
#include "xml_.h" #include "xml_.hpp"
using namespace anm2ed::util; using namespace anm2ed::util;
using namespace tinyxml2; using namespace tinyxml2;
+3 -3
View File
@@ -1,9 +1,9 @@
#include "item.h" #include "item.hpp"
#include <algorithm> #include <algorithm>
#include <ranges> #include <ranges>
#include "vector_.h" #include "vector_.hpp"
#include "xml_.h" #include "xml_.hpp"
using namespace anm2ed::util; using namespace anm2ed::util;
using namespace tinyxml2; using namespace tinyxml2;
+1 -1
View File
@@ -3,7 +3,7 @@
#include <set> #include <set>
#include <vector> #include <vector>
#include "frame.h" #include "frame.hpp"
namespace anm2ed::anm2 namespace anm2ed::anm2
{ {
+2 -2
View File
@@ -1,6 +1,6 @@
#include "layer.h" #include "layer.hpp"
#include "xml_.h" #include "xml_.hpp"
using namespace anm2ed::util; using namespace anm2ed::util;
using namespace tinyxml2; using namespace tinyxml2;
+2 -2
View File
@@ -1,6 +1,6 @@
#include "null.h" #include "null.hpp"
#include "xml_.h" #include "xml_.hpp"
using namespace anm2ed::util; using namespace anm2ed::util;
using namespace tinyxml2; using namespace tinyxml2;
+4 -4
View File
@@ -1,8 +1,8 @@
#include "sound.h" #include "sound.hpp"
#include "path_.h" #include "path_.hpp"
#include "working_directory.h" #include "working_directory.hpp"
#include "xml_.h" #include "xml_.hpp"
using namespace anm2ed::resource; using namespace anm2ed::resource;
using namespace anm2ed::util; using namespace anm2ed::util;
+1 -1
View File
@@ -3,7 +3,7 @@
#include <filesystem> #include <filesystem>
#include <tinyxml2/tinyxml2.h> #include <tinyxml2/tinyxml2.h>
#include "audio.h" #include "audio.hpp"
namespace anm2ed::anm2 namespace anm2ed::anm2
{ {
+9 -7
View File
@@ -1,4 +1,4 @@
#include "spritesheet.h" #include "spritesheet.hpp"
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
@@ -6,10 +6,10 @@
#include <string_view> #include <string_view>
#include <vector> #include <vector>
#include "map_.h" #include "map_.hpp"
#include "path_.h" #include "path_.hpp"
#include "working_directory.h" #include "working_directory.hpp"
#include "xml_.h" #include "xml_.hpp"
using namespace anm2ed::resource; using namespace anm2ed::resource;
using namespace anm2ed::util; using namespace anm2ed::util;
@@ -91,9 +91,10 @@ namespace anm2ed::anm2
Spritesheet::Spritesheet(const std::filesystem::path& directory, const std::filesystem::path& path) Spritesheet::Spritesheet(const std::filesystem::path& directory, const std::filesystem::path& path)
{ {
WorkingDirectory workingDirectory(directory); WorkingDirectory workingDirectory(directory);
auto loadPath = !path.empty() ? path::lower_case_backslash_handle(path) : this->path;
this->path = !path.empty() ? path::make_relative(path) : this->path; this->path = !path.empty() ? path::make_relative(path) : this->path;
this->path = path::lower_case_backslash_handle(this->path); this->path = path::lower_case_backslash_handle(this->path);
texture = Texture(this->path); texture = Texture(!loadPath.empty() ? loadPath : this->path);
} }
XMLElement* Spritesheet::to_element(XMLDocument& document, int id, Flags flags) XMLElement* Spritesheet::to_element(XMLDocument& document, int id, Flags flags)
@@ -234,9 +235,10 @@ namespace anm2ed::anm2
void Spritesheet::reload(const std::filesystem::path& directory, const std::filesystem::path& path) void Spritesheet::reload(const std::filesystem::path& directory, const std::filesystem::path& path)
{ {
WorkingDirectory workingDirectory(directory); WorkingDirectory workingDirectory(directory);
auto loadPath = !path.empty() ? path::lower_case_backslash_handle(path) : this->path;
this->path = !path.empty() ? path::make_relative(path) : this->path; this->path = !path.empty() ? path::make_relative(path) : this->path;
this->path = path::lower_case_backslash_handle(this->path); this->path = path::lower_case_backslash_handle(this->path);
texture = Texture(this->path); texture = Texture(!loadPath.empty() ? loadPath : this->path);
} }
bool Spritesheet::is_valid() { return texture.is_valid(); } bool Spritesheet::is_valid() { return texture.is_valid(); }
@@ -8,10 +8,10 @@
#include <cstdint> #include <cstdint>
#include <tinyxml2/tinyxml2.h> #include <tinyxml2/tinyxml2.h>
#include "texture.h" #include "texture.hpp"
#include "anm2_type.h" #include "anm2_type.hpp"
#include "types.h" #include "types.hpp"
#include "origin.h" #include "origin.hpp"
namespace anm2ed::anm2 namespace anm2ed::anm2
{ {
+2 -2
View File
@@ -1,4 +1,4 @@
#include "canvas.h" #include "canvas.hpp"
#include <algorithm> #include <algorithm>
#include <glm/ext/matrix_clip_space.hpp> #include <glm/ext/matrix_clip_space.hpp>
@@ -6,7 +6,7 @@
#include <glm/gtc/matrix_inverse.hpp> #include <glm/gtc/matrix_inverse.hpp>
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
#include "math_.h" #include "math_.hpp"
using namespace glm; using namespace glm;
using namespace anm2ed::resource; using namespace anm2ed::resource;
+3 -3
View File
@@ -3,10 +3,10 @@
#include <glad/glad.h> #include <glad/glad.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include "framebuffer.h" #include "framebuffer.hpp"
#include "shader.h" #include "shader.hpp"
#include "types.h" #include "types.hpp"
namespace anm2ed namespace anm2ed
{ {
+1 -1
View File
@@ -1,4 +1,4 @@
#include "clipboard.h" #include "clipboard.hpp"
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
+5 -5
View File
@@ -1,19 +1,19 @@
#include "dialog.h" #include "dialog.hpp"
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h> #include <windows.h>
#elif __unix__ #elif __unix__
#else #else
#include "log.h" #include "log.hpp"
#include "strings.h" #include "strings.hpp"
#include "toast.h" #include "toast.hpp"
#endif #endif
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <format> #include <format>
#include "path_.h" #include "path_.hpp"
using namespace anm2ed::util; using namespace anm2ed::util;
View File
+5 -5
View File
@@ -1,13 +1,13 @@
#include "document.h" #include "document.hpp"
#include <utility> #include <utility>
#include <format> #include <format>
#include "log.h" #include "log.hpp"
#include "path_.h" #include "path_.hpp"
#include "strings.h" #include "strings.hpp"
#include "toast.h" #include "toast.hpp"
using namespace anm2ed::anm2; using namespace anm2ed::anm2;
using namespace anm2ed::imgui; using namespace anm2ed::imgui;
+1 -1
View File
@@ -4,7 +4,7 @@
#include <map> #include <map>
#include <unordered_map> #include <unordered_map>
#include "snapshots.h" #include "snapshots.hpp"
#include <glm/glm.hpp> #include <glm/glm.hpp>
+2 -2
View File
@@ -1,6 +1,6 @@
#include "framebuffer.h" #include "framebuffer.hpp"
#include "texture.h" #include "texture.hpp"
using namespace anm2ed::resource; using namespace anm2ed::resource;
using namespace glm; using namespace glm;
+1 -1
View File
@@ -1,4 +1,4 @@
#include "dockspace.h" #include "dockspace.hpp"
namespace anm2ed::imgui namespace anm2ed::imgui
{ {
@@ -1,21 +1,21 @@
#pragma once #pragma once
#include "documents.h" #include "documents.hpp"
#include "taskbar.h" #include "taskbar.hpp"
#include "window/animation_preview.h" #include "window/animation_preview.hpp"
#include "window/animations.h" #include "window/animations.hpp"
#include "window/regions.h" #include "window/regions.hpp"
#include "window/events.h" #include "window/events.hpp"
#include "window/frame_properties.h" #include "window/frame_properties.hpp"
#include "window/layers.h" #include "window/layers.hpp"
#include "window/nulls.h" #include "window/nulls.hpp"
#include "window/onionskin.h" #include "window/onionskin.hpp"
#include "window/sounds.h" #include "window/sounds.hpp"
#include "window/spritesheet_editor.h" #include "window/spritesheet_editor.hpp"
#include "window/spritesheets.h" #include "window/spritesheets.hpp"
#include "window/timeline.h" #include "window/timeline.hpp"
#include "window/tools.h" #include "window/tools.hpp"
#include "window/welcome.h" #include "window/welcome.hpp"
namespace anm2ed::imgui namespace anm2ed::imgui
{ {
+6 -6
View File
@@ -1,13 +1,13 @@
#include "documents.h" #include "documents.hpp"
#include <format> #include <format>
#include <vector> #include <vector>
#include "path_.h" #include "path_.hpp"
#include "strings.h" #include "strings.hpp"
#include "time_.h" #include "time_.hpp"
#include "toast.h" #include "toast.hpp"
#include "log.h" #include "log.hpp"
using namespace anm2ed::resource; using namespace anm2ed::resource;
using namespace anm2ed::types; using namespace anm2ed::types;
@@ -1,10 +1,10 @@
#pragma once #pragma once
#include "manager.h" #include "manager.hpp"
#include "resources.h" #include "resources.hpp"
#include "settings.h" #include "settings.hpp"
#include "strings.h" #include "strings.hpp"
#include "taskbar.h" #include "taskbar.hpp"
namespace anm2ed::imgui namespace anm2ed::imgui
{ {
+3 -3
View File
@@ -6,9 +6,9 @@
#include <sstream> #include <sstream>
#include <unordered_map> #include <unordered_map>
#include "imgui_.h" #include "imgui_.hpp"
#include "path_.h" #include "path_.hpp"
#include "strings.h" #include "strings.hpp"
using namespace anm2ed::types; using namespace anm2ed::types;
using namespace anm2ed::util; using namespace anm2ed::util;
+2 -2
View File
@@ -8,8 +8,8 @@
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include "strings.h" #include "strings.hpp"
#include "types.h" #include "types.hpp"
namespace anm2ed::imgui namespace anm2ed::imgui
{ {
+7 -7
View File
@@ -1,4 +1,4 @@
#include "taskbar.h" #include "taskbar.hpp"
#include <filesystem> #include <filesystem>
#include <format> #include <format>
@@ -7,12 +7,12 @@
#include <imgui/imgui.h> #include <imgui/imgui.h>
#include "document.h" #include "document.hpp"
#include "log.h" #include "log.hpp"
#include "path_.h" #include "path_.hpp"
#include "strings.h" #include "strings.hpp"
#include "toast.h" #include "toast.hpp"
#include "types.h" #include "types.hpp"
using namespace anm2ed::resource; using namespace anm2ed::resource;
using namespace anm2ed::types; using namespace anm2ed::types;
+12 -12
View File
@@ -1,18 +1,18 @@
#pragma once #pragma once
#include "canvas.h" #include "canvas.hpp"
#include "dialog.h" #include "dialog.hpp"
#include "imgui_.h" #include "imgui_.hpp"
#include "manager.h" #include "manager.hpp"
#include "resources.h" #include "resources.hpp"
#include "settings.h" #include "settings.hpp"
#include "strings.h" #include "strings.hpp"
#include "wizard/about.h" #include "wizard/about.hpp"
#include "wizard/change_all_frame_properties.h" #include "wizard/change_all_frame_properties.hpp"
#include "wizard/configure.h" #include "wizard/configure.hpp"
#include "wizard/generate_animation_from_grid.h" #include "wizard/generate_animation_from_grid.hpp"
#include "wizard/render_animation.h" #include "wizard/render_animation.hpp"
namespace anm2ed::imgui namespace anm2ed::imgui
{ {
+3 -3
View File
@@ -1,9 +1,9 @@
#include "toast.h" #include "toast.hpp"
#include "log.h" #include "log.hpp"
#include <imgui/imgui.h> #include <imgui/imgui.h>
#include "types.h" #include "types.hpp"
using namespace anm2ed::types; using namespace anm2ed::types;
+145 -19
View File
@@ -1,23 +1,25 @@
#include "animation_preview.h" #include "animation_preview.hpp"
#include <algorithm> #include <algorithm>
#include <chrono> #include <chrono>
#include <cmath>
#include <filesystem> #include <filesystem>
#include <format> #include <format>
#include <map>
#include <optional> #include <optional>
#include <ranges> #include <ranges>
#include <system_error> #include <system_error>
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
#include "imgui_.h" #include "imgui_.hpp"
#include "log.h" #include "log.hpp"
#include "math_.h" #include "math_.hpp"
#include "path_.h" #include "path_.hpp"
#include "strings.h" #include "strings.hpp"
#include "toast.h" #include "toast.hpp"
#include "tool.h" #include "tool.hpp"
#include "types.h" #include "types.hpp"
using namespace anm2ed::types; using namespace anm2ed::types;
using namespace anm2ed::util; using namespace anm2ed::util;
@@ -103,6 +105,50 @@ namespace anm2ed::imgui
pixels[index + 2] = (uint8_t)glm::clamp((float)std::round((float)pixels[index + 2] / alphaUnit), 0.0f, 255.0f); pixels[index + 2] = (uint8_t)glm::clamp((float)std::round((float)pixels[index + 2] / alphaUnit), 0.0f, 255.0f);
} }
} }
bool render_audio_stream_generate(AudioStream& audioStream, std::map<int, anm2::Sound>& sounds,
const std::vector<int>& frameSoundIDs, int fps)
{
audioStream.stream.clear();
if (frameSoundIDs.empty() || fps <= 0) return true;
SDL_AudioSpec mixSpec = audioStream.spec;
mixSpec.format = SDL_AUDIO_F32;
auto* mixer = MIX_CreateMixer(&mixSpec);
if (!mixer) return false;
auto channels = std::max(mixSpec.channels, 1);
auto sampleRate = std::max(mixSpec.freq, 1);
auto framesPerStep = (double)sampleRate / (double)fps;
auto sampleFrameAccumulator = 0.0;
auto frameBuffer = std::vector<float>{};
for (auto soundID : frameSoundIDs)
{
if (soundID != -1 && sounds.contains(soundID)) sounds.at(soundID).audio.play(false, mixer);
sampleFrameAccumulator += framesPerStep;
auto sampleFramesToGenerate = (int)std::floor(sampleFrameAccumulator);
sampleFramesToGenerate = std::max(sampleFramesToGenerate, 1);
sampleFrameAccumulator -= (double)sampleFramesToGenerate;
frameBuffer.resize((std::size_t)sampleFramesToGenerate * (std::size_t)channels);
if (!MIX_Generate(mixer, frameBuffer.data(), (int)(frameBuffer.size() * sizeof(float))))
{
for (auto& [_, sound] : sounds)
sound.audio.track_detach(mixer);
MIX_DestroyMixer(mixer);
audioStream.stream.clear();
return false;
}
audioStream.stream.insert(audioStream.stream.end(), frameBuffer.begin(), frameBuffer.end());
}
for (auto& [_, sound] : sounds)
sound.audio.track_detach(mixer);
MIX_DestroyMixer(mixer);
return true;
}
} }
AnimationPreview::AnimationPreview() : Canvas(vec2()) {} AnimationPreview::AnimationPreview() : Canvas(vec2()) {}
@@ -118,6 +164,12 @@ namespace anm2ed::imgui
auto& overlayIndex = document.overlayIndex; auto& overlayIndex = document.overlayIndex;
auto& pan = document.previewPan; auto& pan = document.previewPan;
auto stop_all_sounds = [&]()
{
for (auto& sound : anm2.content.sounds | std::views::values)
sound.audio.stop(mixer);
};
if (manager.isRecording) if (manager.isRecording)
{ {
auto& ffmpegPath = settings.renderFFmpegPath; auto& ffmpegPath = settings.renderFFmpegPath;
@@ -127,6 +179,8 @@ namespace anm2ed::imgui
if (playback.time > end || playback.isFinished) if (playback.time > end || playback.isFinished)
{ {
if (settings.timelineIsSound) audioStream.capture_end(mixer);
if (type == render::PNGS) if (type == render::PNGS)
{ {
if (!renderTempFrames.empty()) if (!renderTempFrames.empty())
@@ -206,7 +260,20 @@ namespace anm2ed::imgui
} }
else else
{ {
if (animation_render(ffmpegPath, path, renderTempFrames, audioStream, (render::Type)type, anm2.info.fps)) if (settings.timelineIsSound && type != render::GIF)
{
if (!render_audio_stream_generate(audioStream, anm2.content.sounds, renderFrameSoundIDs, anm2.info.fps))
{
toasts.push(localize.get(TOAST_EXPORT_RENDERED_ANIMATION_FAILED));
logger.error("Failed to generate deterministic render audio stream; exporting without audio.");
audioStream.stream.clear();
}
}
else
audioStream.stream.clear();
if (animation_render(ffmpegPath, path, renderTempFrames, renderTempFrameDurations, audioStream,
(render::Type)type, anm2.info.fps))
{ {
toasts.push(std::vformat(localize.get(TOAST_EXPORT_RENDERED_ANIMATION), std::make_format_args(pathString))); toasts.push(std::vformat(localize.get(TOAST_EXPORT_RENDERED_ANIMATION), std::make_format_args(pathString)));
logger.info(std::vformat(localize.get(TOAST_EXPORT_RENDERED_ANIMATION, anm2ed::ENGLISH), logger.info(std::vformat(localize.get(TOAST_EXPORT_RENDERED_ANIMATION, anm2ed::ENGLISH),
@@ -225,9 +292,15 @@ namespace anm2ed::imgui
{ {
renderTempDirectory.clear(); renderTempDirectory.clear();
renderTempFrames.clear(); renderTempFrames.clear();
renderTempFrameDurations.clear();
renderFrameSoundIDs.clear();
} }
else else
{
render_temp_cleanup(renderTempDirectory, renderTempFrames); render_temp_cleanup(renderTempDirectory, renderTempFrames);
renderTempFrameDurations.clear();
renderFrameSoundIDs.clear();
}
if (settings.renderIsRawAnimation) if (settings.renderIsRawAnimation)
{ {
@@ -241,8 +314,6 @@ namespace anm2ed::imgui
isCheckerPanInitialized = false; isCheckerPanInitialized = false;
} }
if (settings.timelineIsSound) audioStream.capture_end(mixer);
playback.isPlaying = false; playback.isPlaying = false;
playback.isFinished = false; playback.isFinished = false;
manager.isRecording = false; manager.isRecording = false;
@@ -250,6 +321,28 @@ namespace anm2ed::imgui
} }
else else
{ {
if (settings.timelineIsSound && renderTempFrames.empty()) audioStream.capture_begin(mixer);
auto frameSoundID = -1;
if (settings.timelineIsSound && !anm2.content.sounds.empty())
{
if (auto animation = document.animation_get();
animation && animation->triggers.isVisible && (!settings.timelineIsOnlyShowLayers || manager.isRecording))
{
if (auto trigger = animation->triggers.frame_generate(playback.time, anm2::TRIGGER); trigger.isVisible)
{
if (!trigger.soundIDs.empty())
{
auto soundIndex = trigger.soundIDs.size() > 1
? (size_t)math::random_in_range(0.0f, (float)trigger.soundIDs.size())
: (size_t)0;
soundIndex = std::min(soundIndex, trigger.soundIDs.size() - 1);
auto soundID = trigger.soundIDs[soundIndex];
if (anm2.content.sounds.contains(soundID)) frameSoundID = soundID;
}
}
}
}
renderFrameSoundIDs.push_back(frameSoundID);
bind(); bind();
auto pixels = pixels_get(); auto pixels = pixels_get();
@@ -259,6 +352,24 @@ namespace anm2ed::imgui
if (Texture::write_pixels_png(framePath, size, pixels.data())) if (Texture::write_pixels_png(framePath, size, pixels.data()))
{ {
renderTempFrames.push_back(framePath); renderTempFrames.push_back(framePath);
auto nowCounter = SDL_GetPerformanceCounter();
auto counterFrequency = SDL_GetPerformanceFrequency();
auto fallbackDuration = 1.0 / (double)std::max(anm2.info.fps, 1);
if (renderTempFrames.size() == 1)
{
renderCaptureCounterPrev = nowCounter;
renderTempFrameDurations.push_back(fallbackDuration);
}
else
{
auto elapsedCounter = nowCounter - renderCaptureCounterPrev;
auto frameDuration = counterFrequency > 0 ? (double)elapsedCounter / (double)counterFrequency : 0.0;
frameDuration = std::max(frameDuration, 1.0 / 1000.0);
renderTempFrameDurations.back() = frameDuration;
renderTempFrameDurations.push_back(frameDuration);
renderCaptureCounterPrev = nowCounter;
}
} }
else else
{ {
@@ -267,6 +378,8 @@ namespace anm2ed::imgui
logger.error(std::vformat(localize.get(TOAST_EXPORT_RENDERED_ANIMATION_FAILED, anm2ed::ENGLISH), logger.error(std::vformat(localize.get(TOAST_EXPORT_RENDERED_ANIMATION_FAILED, anm2ed::ENGLISH),
std::make_format_args(pathString))); std::make_format_args(pathString)));
if (type != render::PNGS) render_temp_cleanup(renderTempDirectory, renderTempFrames); if (type != render::PNGS) render_temp_cleanup(renderTempDirectory, renderTempFrames);
renderTempFrameDurations.clear();
renderFrameSoundIDs.clear();
playback.isPlaying = false; playback.isPlaying = false;
playback.isFinished = false; playback.isFinished = false;
manager.isRecording = false; manager.isRecording = false;
@@ -281,18 +394,23 @@ namespace anm2ed::imgui
auto& isSound = settings.timelineIsSound; auto& isSound = settings.timelineIsSound;
auto& isOnlyShowLayers = settings.timelineIsOnlyShowLayers; auto& isOnlyShowLayers = settings.timelineIsOnlyShowLayers;
if (!anm2.content.sounds.empty() && isSound) if (!manager.isRecording && !anm2.content.sounds.empty() && isSound)
{ {
if (auto animation = document.animation_get(); if (auto animation = document.animation_get();
animation && animation->triggers.isVisible && (!isOnlyShowLayers || manager.isRecording)) animation && animation->triggers.isVisible && (!isOnlyShowLayers || manager.isRecording))
{ {
if (auto trigger = animation->triggers.frame_generate(playback.time, anm2::TRIGGER); trigger.isVisible) if (auto trigger = animation->triggers.frame_generate(playback.time, anm2::TRIGGER); trigger.isVisible)
{ {
auto soundID = trigger.soundIDs.size() > 1 if (!trigger.soundIDs.empty())
? (int)trigger.soundIDs[math::random_in_range(0, trigger.soundIDs.size())] {
: (int)trigger.soundIDs.front(); auto soundIndex = trigger.soundIDs.size() > 1
? (size_t)math::random_in_range(0.0f, (float)trigger.soundIDs.size())
: (size_t)0;
soundIndex = std::min(soundIndex, trigger.soundIDs.size() - 1);
auto soundID = trigger.soundIDs[soundIndex];
if (anm2.content.sounds.contains(soundID)) anm2.content.sounds[soundID].audio.play(false, mixer); if (anm2.content.sounds.contains(soundID)) anm2.content.sounds[soundID].audio.play(false, mixer);
}
} }
} }
} }
@@ -304,6 +422,9 @@ namespace anm2ed::imgui
frameTime = playback.time; frameTime = playback.time;
} }
if (wasPlaybackPlaying && !playback.isPlaying) stop_all_sounds();
wasPlaybackPlaying = playback.isPlaying;
} }
void AnimationPreview::update(Manager& manager, Settings& settings, Resources& resources) void AnimationPreview::update(Manager& manager, Settings& settings, Resources& resources)
@@ -492,8 +613,6 @@ namespace anm2ed::imgui
{ {
savedSettings = settings; savedSettings = settings;
if (settings.timelineIsSound) audioStream.capture_begin(mixer);
if (settings.renderIsRawAnimation) if (settings.renderIsRawAnimation)
{ {
settings.previewBackgroundColor = vec4(); settings.previewBackgroundColor = vec4();
@@ -520,6 +639,9 @@ namespace anm2ed::imgui
manager.isRecordingStart = false; manager.isRecordingStart = false;
manager.isRecording = true; manager.isRecording = true;
renderTempFrames.clear(); renderTempFrames.clear();
renderTempFrameDurations.clear();
renderFrameSoundIDs.clear();
renderCaptureCounterPrev = 0;
if (settings.renderType == render::PNGS) if (settings.renderType == render::PNGS)
{ {
renderTempDirectory = settings.renderPath; renderTempDirectory = settings.renderPath;
@@ -1052,9 +1174,13 @@ namespace anm2ed::imgui
{ {
renderTempDirectory.clear(); renderTempDirectory.clear();
renderTempFrames.clear(); renderTempFrames.clear();
renderTempFrameDurations.clear();
} }
else else
{
render_temp_cleanup(renderTempDirectory, renderTempFrames); render_temp_cleanup(renderTempDirectory, renderTempFrames);
renderTempFrameDurations.clear();
}
pan = savedPan; pan = savedPan;
zoom = savedZoom; zoom = savedZoom;
@@ -2,11 +2,11 @@
#include <filesystem> #include <filesystem>
#include "audio_stream.h" #include "audio_stream.hpp"
#include "canvas.h" #include "canvas.hpp"
#include "manager.h" #include "manager.hpp"
#include "resources.h" #include "resources.hpp"
#include "settings.h" #include "settings.hpp"
namespace anm2ed::imgui namespace anm2ed::imgui
{ {
@@ -14,6 +14,7 @@ namespace anm2ed::imgui
{ {
MIX_Mixer* mixer = MIX_CreateMixerDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, nullptr); MIX_Mixer* mixer = MIX_CreateMixerDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, nullptr);
AudioStream audioStream = AudioStream(mixer); AudioStream audioStream = AudioStream(mixer);
bool wasPlaybackPlaying{};
bool isPreviewHovered{}; bool isPreviewHovered{};
bool isSizeTrySet{true}; bool isSizeTrySet{true};
Settings savedSettings{}; Settings savedSettings{};
@@ -30,6 +31,9 @@ namespace anm2ed::imgui
glm::vec2 moveOffset{}; glm::vec2 moveOffset{};
std::filesystem::path renderTempDirectory{}; std::filesystem::path renderTempDirectory{};
std::vector<std::filesystem::path> renderTempFrames{}; std::vector<std::filesystem::path> renderTempFrames{};
std::vector<double> renderTempFrameDurations{};
std::vector<int> renderFrameSoundIDs{};
Uint64 renderCaptureCounterPrev{};
public: public:
AnimationPreview(); AnimationPreview();
+5 -5
View File
@@ -1,12 +1,12 @@
#include "animations.h" #include "animations.hpp"
#include <format> #include <format>
#include <ranges> #include <ranges>
#include "log.h" #include "log.hpp"
#include "strings.h" #include "strings.hpp"
#include "toast.h" #include "toast.hpp"
#include "vector_.h" #include "vector_.hpp"
using namespace anm2ed::util; using namespace anm2ed::util;
using namespace anm2ed::resource; using namespace anm2ed::resource;
@@ -1,10 +1,10 @@
#pragma once #pragma once
#include "clipboard.h" #include "clipboard.hpp"
#include "manager.h" #include "manager.hpp"
#include "resources.h" #include "resources.hpp"
#include "settings.h" #include "settings.hpp"
#include "strings.h" #include "strings.hpp"
namespace anm2ed::imgui namespace anm2ed::imgui
{ {
+5 -5
View File
@@ -1,11 +1,11 @@
#include "events.h" #include "events.hpp"
#include <ranges> #include <ranges>
#include "log.h" #include "log.hpp"
#include "map_.h" #include "map_.hpp"
#include "strings.h" #include "strings.hpp"
#include "toast.h" #include "toast.hpp"
using namespace anm2ed::util; using namespace anm2ed::util;
using namespace anm2ed::resource; using namespace anm2ed::resource;
@@ -1,9 +1,9 @@
#pragma once #pragma once
#include "clipboard.h" #include "clipboard.hpp"
#include "manager.h" #include "manager.hpp"
#include "resources.h" #include "resources.hpp"
#include "settings.h" #include "settings.hpp"
namespace anm2ed::imgui namespace anm2ed::imgui
{ {
+4 -4
View File
@@ -1,13 +1,13 @@
#include "frame_properties.h" #include "frame_properties.hpp"
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
#include <limits> #include <limits>
#include <ranges> #include <ranges>
#include <vector> #include <vector>
#include "math_.h" #include "math_.hpp"
#include "strings.h" #include "strings.hpp"
#include "types.h" #include "types.hpp"
using namespace anm2ed::util::math; using namespace anm2ed::util::math;
using namespace anm2ed::types; using namespace anm2ed::types;
@@ -2,8 +2,8 @@
#include <glm/vec2.hpp> #include <glm/vec2.hpp>
#include "manager.h" #include "manager.hpp"
#include "wizard/change_all_frame_properties.h" #include "wizard/change_all_frame_properties.hpp"
namespace anm2ed::imgui namespace anm2ed::imgui
{ {
+5 -5
View File
@@ -1,11 +1,11 @@
#include "layers.h" #include "layers.hpp"
#include <ranges> #include <ranges>
#include "log.h" #include "log.hpp"
#include "map_.h" #include "map_.hpp"
#include "strings.h" #include "strings.hpp"
#include "toast.h" #include "toast.hpp"
using namespace anm2ed::util; using namespace anm2ed::util;
using namespace anm2ed::resource; using namespace anm2ed::resource;
@@ -1,9 +1,9 @@
#pragma once #pragma once
#include "clipboard.h" #include "clipboard.hpp"
#include "manager.h" #include "manager.hpp"
#include "resources.h" #include "resources.hpp"
#include "settings.h" #include "settings.hpp"
namespace anm2ed::imgui namespace anm2ed::imgui
{ {
+5 -5
View File
@@ -1,11 +1,11 @@
#include "nulls.h" #include "nulls.hpp"
#include <ranges> #include <ranges>
#include "log.h" #include "log.hpp"
#include "map_.h" #include "map_.hpp"
#include "strings.h" #include "strings.hpp"
#include "toast.h" #include "toast.hpp"
using namespace anm2ed::resource; using namespace anm2ed::resource;
using namespace anm2ed::util; using namespace anm2ed::util;
@@ -1,9 +1,9 @@
#pragma once #pragma once
#include "clipboard.h" #include "clipboard.hpp"
#include "manager.h" #include "manager.hpp"
#include "resources.h" #include "resources.hpp"
#include "settings.h" #include "settings.hpp"
namespace anm2ed::imgui namespace anm2ed::imgui
{ {
+3 -3
View File
@@ -1,9 +1,9 @@
#include "onionskin.h" #include "onionskin.hpp"
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
#include "imgui_.h" #include "imgui_.hpp"
#include "strings.h" #include "strings.hpp"
using namespace anm2ed::types; using namespace anm2ed::types;
using namespace glm; using namespace glm;
@@ -1,6 +1,6 @@
#pragma once #pragma once
#include "manager.h" #include "manager.hpp"
namespace anm2ed::imgui namespace anm2ed::imgui
{ {
+9 -9
View File
@@ -1,19 +1,19 @@
#include "regions.h" #include "regions.hpp"
#include <algorithm> #include <algorithm>
#include <ranges> #include <ranges>
#include <format> #include <format>
#include "document.h" #include "document.hpp"
#include "log.h" #include "log.hpp"
#include "map_.h" #include "map_.hpp"
#include "math_.h" #include "math_.hpp"
#include "strings.h" #include "strings.hpp"
#include "toast.h" #include "toast.hpp"
#include "vector_.h" #include "vector_.hpp"
#include "../../util/map_.h" #include "../../util/map_.hpp"
using namespace anm2ed::types; using namespace anm2ed::types;
using namespace anm2ed::resource; using namespace anm2ed::resource;
@@ -1,9 +1,9 @@
#pragma once #pragma once
#include "clipboard.h" #include "clipboard.hpp"
#include "manager.h" #include "manager.hpp"
#include "resources.h" #include "resources.hpp"
#include "settings.h" #include "settings.hpp"
namespace anm2ed::imgui namespace anm2ed::imgui
{ {
+5 -5
View File
@@ -1,13 +1,13 @@
#include "sounds.h" #include "sounds.hpp"
#include <algorithm> #include <algorithm>
#include <ranges> #include <ranges>
#include <vector> #include <vector>
#include "log.h" #include "log.hpp"
#include "path_.h" #include "path_.hpp"
#include "strings.h" #include "strings.hpp"
#include "toast.h" #include "toast.hpp"
using namespace anm2ed::util; using namespace anm2ed::util;
using namespace anm2ed::types; using namespace anm2ed::types;
@@ -1,10 +1,10 @@
#pragma once #pragma once
#include "clipboard.h" #include "clipboard.hpp"
#include "dialog.h" #include "dialog.hpp"
#include "manager.h" #include "manager.hpp"
#include "resources.h" #include "resources.hpp"
#include "settings.h" #include "settings.hpp"
namespace anm2ed::imgui namespace anm2ed::imgui
{ {
+6 -6
View File
@@ -1,15 +1,15 @@
#include "spritesheet_editor.h" #include "spritesheet_editor.hpp"
#include <cmath> #include <cmath>
#include <format> #include <format>
#include <utility> #include <utility>
#include "imgui_.h" #include "imgui_.hpp"
#include "imgui_internal.h" #include "imgui_internal.h"
#include "math_.h" #include "math_.hpp"
#include "strings.h" #include "strings.hpp"
#include "tool.h" #include "tool.hpp"
#include "types.h" #include "types.hpp"
using namespace anm2ed::types; using namespace anm2ed::types;
using namespace anm2ed::resource; using namespace anm2ed::resource;
@@ -1,9 +1,9 @@
#pragma once #pragma once
#include "canvas.h" #include "canvas.hpp"
#include "manager.h" #include "manager.hpp"
#include "resources.h" #include "resources.hpp"
#include "settings.h" #include "settings.hpp"
namespace anm2ed::imgui namespace anm2ed::imgui
{ {
+7 -7
View File
@@ -1,4 +1,4 @@
#include "spritesheets.h" #include "spritesheets.hpp"
#include <algorithm> #include <algorithm>
#include <ranges> #include <ranges>
@@ -8,12 +8,12 @@
#include <format> #include <format>
#include <functional> #include <functional>
#include "document.h" #include "document.hpp"
#include "log.h" #include "log.hpp"
#include "path_.h" #include "path_.hpp"
#include "strings.h" #include "strings.hpp"
#include "toast.h" #include "toast.hpp"
#include "working_directory.h" #include "working_directory.hpp"
using namespace anm2ed::types; using namespace anm2ed::types;
using namespace anm2ed::resource; using namespace anm2ed::resource;
@@ -1,10 +1,10 @@
#pragma once #pragma once
#include "clipboard.h" #include "clipboard.hpp"
#include "dialog.h" #include "dialog.hpp"
#include "manager.h" #include "manager.hpp"
#include "resources.h" #include "resources.hpp"
#include "settings.h" #include "settings.hpp"
namespace anm2ed::imgui namespace anm2ed::imgui
{ {
+25 -12
View File
@@ -1,4 +1,4 @@
#include "timeline.h" #include "timeline.hpp"
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
@@ -6,10 +6,10 @@
#include <imgui_internal.h> #include <imgui_internal.h>
#include "log.h" #include "log.hpp"
#include "toast.h" #include "toast.hpp"
#include "vector_.h" #include "vector_.hpp"
using namespace anm2ed::resource; using namespace anm2ed::resource;
using namespace anm2ed::types; using namespace anm2ed::types;
@@ -83,7 +83,6 @@ namespace anm2ed::imgui
constexpr auto FRAME_DRAG_PAYLOAD_ID = "Frame Drag Drop"; constexpr auto FRAME_DRAG_PAYLOAD_ID = "Frame Drag Drop";
constexpr auto FRAME_TOOLTIP_HOVER_DELAY = 0.75f; // Extra delay for frame info tooltip. constexpr auto FRAME_TOOLTIP_HOVER_DELAY = 0.75f; // Extra delay for frame info tooltip.
#define ITEM_FRAME_CHILD_HEIGHT ImGui::GetTextLineHeightWithSpacing() + (ImGui::GetStyle().WindowPadding.y * 1.5)
#define ITEM_CHILD_WIDTH ImGui::GetTextLineHeightWithSpacing() * 12.5 #define ITEM_CHILD_WIDTH ImGui::GetTextLineHeightWithSpacing() * 12.5
void Timeline::update(Manager& manager, Settings& settings, Resources& resources, Clipboard& clipboard) void Timeline::update(Manager& manager, Settings& settings, Resources& resources, Clipboard& clipboard)
@@ -95,6 +94,8 @@ namespace anm2ed::imgui
auto& frames = document.frames; auto& frames = document.frames;
auto& region = document.region; auto& region = document.region;
auto animation = document.animation_get(); auto animation = document.animation_get();
auto itemFrameChildHeight = (ImGui::GetTextLineHeightWithSpacing() + ImGui::GetStyle().WindowPadding.y * 1.5f) *
settings.timelineItemHeight;
style = ImGui::GetStyle(); style = ImGui::GetStyle();
auto isLightTheme = settings.theme == theme::LIGHT; auto isLightTheme = settings.theme == theme::LIGHT;
@@ -172,6 +173,13 @@ namespace anm2ed::imgui
frameFocusRequested = reference.frameIndex >= 0; frameFocusRequested = reference.frameIndex >= 0;
}; };
auto playback_stop = [&]()
{
playback.isPlaying = false;
playback.isFinished = false;
playback.timing_reset();
};
auto frame_insert = [&](anm2::Item* item) auto frame_insert = [&](anm2::Item* item)
{ {
if (!item) return; if (!item) return;
@@ -597,7 +605,7 @@ namespace anm2ed::imgui
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, style.WindowPadding); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, style.WindowPadding);
auto itemSize = ImVec2(ImGui::GetContentRegionAvail().x, ITEM_FRAME_CHILD_HEIGHT); auto itemSize = ImVec2(ImGui::GetContentRegionAvail().x, itemFrameChildHeight);
if (ImGui::BeginChild(label.c_str(), itemSize, ImGuiChildFlags_Borders, ImGuiWindowFlags_NoScrollWithMouse)) if (ImGui::BeginChild(label.c_str(), itemSize, ImGuiChildFlags_Borders, ImGuiWindowFlags_NoScrollWithMouse))
{ {
@@ -961,7 +969,7 @@ namespace anm2ed::imgui
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, style.WindowPadding); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, style.WindowPadding);
auto childSize = ImVec2(width, ITEM_FRAME_CHILD_HEIGHT); auto childSize = ImVec2(width, itemFrameChildHeight);
ImGui::PopStyleVar(2); ImGui::PopStyleVar(2);
@@ -1046,7 +1054,10 @@ namespace anm2ed::imgui
} }
if (ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) && ImGui::IsMouseDown(0)) if (ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) && ImGui::IsMouseDown(0))
{
if (!isDragging) playback_stop();
isDragging = true; isDragging = true;
}
auto childPos = ImGui::GetWindowPos(); auto childPos = ImGui::GetWindowPos();
auto mousePos = ImGui::GetIO().MousePos; auto mousePos = ImGui::GetIO().MousePos;
@@ -1497,12 +1508,11 @@ namespace anm2ed::imgui
ImGui::GetTextLineHeightWithSpacing() + (ImGui::GetStyle().WindowPadding.y * 2)); ImGui::GetTextLineHeightWithSpacing() + (ImGui::GetStyle().WindowPadding.y * 2));
auto playheadIndex = std::floor(playback.time); auto playheadIndex = std::floor(playback.time);
auto lineCenterX = cursorScreenPos.x + frameSize.x * (playheadIndex + 0.6f) - scroll.x; auto lineCenterX = cursorScreenPos.x + frameSize.x * (playheadIndex + 0.6f) - scroll.x;
float lineOffsetY = frameSize.y;
auto linePos = auto linePos =
ImVec2(lineCenterX - (PLAYHEAD_LINE_THICKNESS * 0.5f), cursorScreenPos.y + frameSize.y + lineOffsetY); ImVec2(lineCenterX - (PLAYHEAD_LINE_THICKNESS * 0.5f), cursorScreenPos.y + (frameSize.y * 2.0f));
auto lineSize = ImVec2((PLAYHEAD_LINE_THICKNESS / 2.0f), auto lineSize = ImVec2((PLAYHEAD_LINE_THICKNESS / 2.0f),
viewListChildSize.y - frameSize.y - lineOffsetY - viewListChildSize.y - frameSize.y -
(isHorizontalScroll ? ImGui::GetStyle().ScrollbarSize : 0.0f)); (isHorizontalScroll ? ImGui::GetStyle().ScrollbarSize * 2.0f : 0.0f));
auto rectMin = windowDrawList->GetClipRectMin(); auto rectMin = windowDrawList->GetClipRectMin();
auto rectMax = windowDrawList->GetClipRectMax(); auto rectMax = windowDrawList->GetClipRectMax();
@@ -1623,7 +1633,8 @@ namespace anm2ed::imgui
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2()); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2());
if (ImGui::Begin(localize.get(LABEL_TIMELINE_WINDOW), &settings.windowIsTimeline)) if (ImGui::Begin(localize.get(LABEL_TIMELINE_WINDOW), &settings.windowIsTimeline))
{ {
isWindowHovered = ImGui::IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows); isWindowHovered = ImGui::IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows |
ImGuiHoveredFlags_AllowWhenBlockedByActiveItem);
frames_child(); frames_child();
items_child(); items_child();
} }
@@ -1853,12 +1864,14 @@ namespace anm2ed::imgui
if (shortcut(manager.chords[SHORTCUT_MOVE_PLAYHEAD_BACK], shortcut::GLOBAL)) if (shortcut(manager.chords[SHORTCUT_MOVE_PLAYHEAD_BACK], shortcut::GLOBAL))
{ {
playback_stop();
playback.decrement(settings.playbackIsClamp ? animation->frameNum : anm2::FRAME_NUM_MAX); playback.decrement(settings.playbackIsClamp ? animation->frameNum : anm2::FRAME_NUM_MAX);
document.frameTime = playback.time; document.frameTime = playback.time;
} }
if (shortcut(manager.chords[SHORTCUT_MOVE_PLAYHEAD_FORWARD], shortcut::GLOBAL)) if (shortcut(manager.chords[SHORTCUT_MOVE_PLAYHEAD_FORWARD], shortcut::GLOBAL))
{ {
playback_stop();
playback.increment(settings.playbackIsClamp ? animation->frameNum : anm2::FRAME_NUM_MAX); playback.increment(settings.playbackIsClamp ? animation->frameNum : anm2::FRAME_NUM_MAX);
document.frameTime = playback.time; document.frameTime = playback.time;
} }
@@ -2,11 +2,11 @@
#include <vector> #include <vector>
#include "clipboard.h" #include "clipboard.hpp"
#include "manager.h" #include "manager.hpp"
#include "resources.h" #include "resources.hpp"
#include "settings.h" #include "settings.hpp"
#include "strings.h" #include "strings.hpp"
namespace anm2ed::imgui namespace anm2ed::imgui
{ {
+4 -4
View File
@@ -1,11 +1,11 @@
#include "tools.h" #include "tools.hpp"
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
#include "strings.h" #include "strings.hpp"
#include "tool.h" #include "tool.hpp"
#include "types.h" #include "types.hpp"
using namespace anm2ed::resource; using namespace anm2ed::resource;
using namespace anm2ed::types; using namespace anm2ed::types;
@@ -1,9 +1,9 @@
#pragma once #pragma once
#include "manager.h" #include "manager.hpp"
#include "resources.h" #include "resources.hpp"
#include "settings.h" #include "settings.hpp"
#include "strings.h" #include "strings.hpp"
namespace anm2ed::imgui namespace anm2ed::imgui
{ {
+3 -3
View File
@@ -1,9 +1,9 @@
#include "welcome.h" #include "welcome.hpp"
#include <ranges> #include <ranges>
#include "path_.h" #include "path_.hpp"
#include "strings.h" #include "strings.hpp"
using namespace anm2ed::util; using namespace anm2ed::util;
using namespace anm2ed::resource; using namespace anm2ed::resource;
@@ -1,9 +1,9 @@
#pragma once #pragma once
#include "documents.h" #include "documents.hpp"
#include "manager.h" #include "manager.hpp"
#include "strings.h" #include "strings.hpp"
#include "taskbar.h" #include "taskbar.hpp"
namespace anm2ed::imgui namespace anm2ed::imgui
{ {
+2 -2
View File
@@ -1,10 +1,10 @@
#include "about.h" #include "about.hpp"
#include <cmath> #include <cmath>
#include <imgui.h> #include <imgui.h>
#include <vector> #include <vector>
#include "strings.h" #include "strings.hpp"
using namespace anm2ed::resource; using namespace anm2ed::resource;
@@ -1,6 +1,6 @@
#pragma once #pragma once
#include "../../resources.h" #include "../../resources.hpp"
namespace anm2ed::imgui::wizard namespace anm2ed::imgui::wizard
{ {
@@ -1,9 +1,9 @@
#include "change_all_frame_properties.h" #include "change_all_frame_properties.hpp"
#include <string> #include <string>
#include <vector> #include <vector>
#include "math_.h" #include "math_.hpp"
using namespace anm2ed::util::math; using namespace anm2ed::util::math;
using namespace glm; using namespace glm;
@@ -1,7 +1,7 @@
#pragma once #pragma once
#include "document.h" #include "document.hpp"
#include "settings.h" #include "settings.hpp"
namespace anm2ed::imgui::wizard namespace anm2ed::imgui::wizard
{ {
+5 -2
View File
@@ -1,6 +1,6 @@
#include "configure.h" #include "configure.hpp"
#include "imgui_.h" #include "imgui_.hpp"
using namespace anm2ed::types; using namespace anm2ed::types;
@@ -23,6 +23,9 @@ namespace anm2ed::imgui::wizard
ImGui::SeparatorText(localize.get(LABEL_WINDOW_MENU)); ImGui::SeparatorText(localize.get(LABEL_WINDOW_MENU));
input_float_range(localize.get(LABEL_UI_SCALE), temporary.uiScale, 0.5f, 2.0f, 0.25f, 0.25f, "%.2f"); input_float_range(localize.get(LABEL_UI_SCALE), temporary.uiScale, 0.5f, 2.0f, 0.25f, 0.25f, "%.2f");
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_UI_SCALE)); ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_UI_SCALE));
input_float_range(localize.get(LABEL_ITEM_HEIGHT), temporary.timelineItemHeight, 0.75f, 1.25f, 0.05f, 0.05f,
"%.2f");
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_ITEM_HEIGHT));
ImGui::Checkbox(localize.get(LABEL_VSYNC), &temporary.isVsync); ImGui::Checkbox(localize.get(LABEL_VSYNC), &temporary.isVsync);
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_VSYNC)); ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_VSYNC));
@@ -1,6 +1,6 @@
#pragma once #pragma once
#include "manager.h" #include "manager.hpp"
namespace anm2ed::imgui::wizard namespace anm2ed::imgui::wizard
{ {
@@ -1,7 +1,7 @@
#include "generate_animation_from_grid.h" #include "generate_animation_from_grid.hpp"
#include "math_.h" #include "math_.hpp"
#include "types.h" #include "types.hpp"
using namespace anm2ed::types; using namespace anm2ed::types;
using namespace anm2ed::util; using namespace anm2ed::util;
@@ -1,9 +1,9 @@
#pragma once #pragma once
#include "canvas.h" #include "canvas.hpp"
#include "document.h" #include "document.hpp"
#include "resources.h" #include "resources.hpp"
#include "settings.h" #include "settings.hpp"
namespace anm2ed::imgui::wizard namespace anm2ed::imgui::wizard
{ {
+6 -6
View File
@@ -1,13 +1,13 @@
#include "render_animation.h" #include "render_animation.hpp"
#include <ranges> #include <ranges>
#include <string> #include <string>
#include "imgui_.h" #include "imgui_.hpp"
#include "log.h" #include "log.hpp"
#include "path_.h" #include "path_.hpp"
#include "process_.h" #include "process_.hpp"
#include "toast.h" #include "toast.hpp"
using namespace anm2ed::resource; using namespace anm2ed::resource;
using namespace anm2ed::util; using namespace anm2ed::util;
@@ -1,8 +1,8 @@
#pragma once #pragma once
#include "dialog.h" #include "dialog.hpp"
#include "manager.h" #include "manager.hpp"
#include "resources.h" #include "resources.hpp"
namespace anm2ed::imgui::wizard namespace anm2ed::imgui::wizard
{ {
+8 -8
View File
@@ -1,4 +1,4 @@
#include "loader.h" #include "loader.hpp"
#include <cerrno> #include <cerrno>
#include <cstdint> #include <cstdint>
@@ -9,18 +9,18 @@
#include <SDL3_mixer/SDL_mixer.h> #include <SDL3_mixer/SDL_mixer.h>
#include "log.h" #include "log.hpp"
#include "sdl.h" #include "sdl.hpp"
#include "imgui_.h" #include "imgui_.hpp"
#include "snapshots.h" #include "snapshots.hpp"
#include "socket.h" #include "socket.hpp"
#include "util/math_.h" #include "util/math_.hpp"
#ifdef _WIN32 #ifdef _WIN32
#include "util/path_.h" #include "util/path_.hpp"
#include <DbgHelp.h> #include <DbgHelp.h>
#include <format> #include <format>
#include <windows.h> #include <windows.h>
+2 -2
View File
@@ -7,8 +7,8 @@
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#include "settings.h" #include "settings.hpp"
#include "socket.h" #include "socket.hpp"
namespace anm2ed namespace anm2ed
{ {
+113 -4
View File
@@ -1,9 +1,18 @@
#include "log.h" #include "log.hpp"
#include <array>
#include <print> #include <print>
#include "sdl.h" #include "path_.hpp"
#include "time_.h" #include "sdl.hpp"
#include "time_.hpp"
#if _WIN32
#include <fcntl.h>
#include <io.h>
#else
#include <unistd.h>
#endif
using namespace anm2ed::util; using namespace anm2ed::util;
@@ -11,6 +20,7 @@ namespace anm2ed
{ {
void Logger::write_raw(const std::string& message) void Logger::write_raw(const std::string& message)
{ {
std::lock_guard lock(mutex);
std::println("{}", message); std::println("{}", message);
if (file.is_open()) file << message << '\n' << std::flush; if (file.is_open()) file << message << '\n' << std::flush;
} }
@@ -26,7 +36,105 @@ namespace anm2ed
void Logger::error(const std::string& message) { write(ERROR, message); } void Logger::error(const std::string& message) { write(ERROR, message); }
void Logger::fatal(const std::string& message) { write(FATAL, message); } void Logger::fatal(const std::string& message) { write(FATAL, message); }
void Logger::command(const std::string& message) { write(COMMAND, message); } void Logger::command(const std::string& message) { write(COMMAND, message); }
void Logger::open(const std::filesystem::path& path) { file.open(path, std::ios::out | std::ios::app); }
void Logger::stderr_pump()
{
std::string pending{};
std::array<char, 512> buffer{};
while (isStderrRedirecting)
{
int readBytes{};
#if _WIN32
readBytes = _read(stderrPipeReadFd, buffer.data(), (unsigned int)buffer.size());
#else
readBytes = (int)read(stderrPipeReadFd, buffer.data(), buffer.size());
#endif
if (readBytes <= 0) break;
pending.append(buffer.data(), (std::size_t)readBytes);
std::size_t lineEnd{};
while ((lineEnd = pending.find('\n')) != std::string::npos)
{
auto line = pending.substr(0, lineEnd);
if (!line.empty() && line.back() == '\r') line.pop_back();
if (!line.empty()) write_raw(line);
pending.erase(0, lineEnd + 1);
}
}
if (!pending.empty()) write_raw(pending);
}
void Logger::stderr_redirect_start()
{
if (isStderrRedirecting) return;
int pipeFds[2]{-1, -1};
#if _WIN32
if (_pipe(pipeFds, 4096, _O_BINARY) != 0) return;
stderrOriginalFd = _dup(_fileno(stderr));
if (stderrOriginalFd < 0 || _dup2(pipeFds[1], _fileno(stderr)) != 0)
{
_close(pipeFds[0]);
_close(pipeFds[1]);
return;
}
_close(pipeFds[1]);
#else
if (pipe(pipeFds) != 0) return;
stderrOriginalFd = dup(fileno(stderr));
if (stderrOriginalFd < 0 || dup2(pipeFds[1], fileno(stderr)) < 0)
{
close(pipeFds[0]);
close(pipeFds[1]);
return;
}
close(pipeFds[1]);
#endif
std::setvbuf(stderr, nullptr, _IONBF, 0);
stderrPipeReadFd = pipeFds[0];
isStderrRedirecting = true;
stderrThread = std::thread([this]() { stderr_pump(); });
}
void Logger::stderr_redirect_stop()
{
if (!isStderrRedirecting) return;
isStderrRedirecting = false;
if (stderrOriginalFd >= 0)
{
#if _WIN32
_dup2(stderrOriginalFd, _fileno(stderr));
_close(stderrOriginalFd);
#else
dup2(stderrOriginalFd, fileno(stderr));
close(stderrOriginalFd);
#endif
stderrOriginalFd = -1;
}
if (stderrPipeReadFd >= 0)
{
#if _WIN32
_close(stderrPipeReadFd);
#else
close(stderrPipeReadFd);
#endif
stderrPipeReadFd = -1;
}
if (stderrThread.joinable()) stderrThread.join();
}
void Logger::open(const std::filesystem::path& path)
{
file.open(path, std::ios::out | std::ios::app);
stderr_redirect_start();
}
std::filesystem::path Logger::path() { return sdl::preferences_directory_get() / "log.txt"; } std::filesystem::path Logger::path() { return sdl::preferences_directory_get() / "log.txt"; }
@@ -39,6 +147,7 @@ namespace anm2ed
Logger::~Logger() Logger::~Logger()
{ {
info("Exiting Anm2Ed"); info("Exiting Anm2Ed");
stderr_redirect_stop();
if (file.is_open()) file.close(); if (file.is_open()) file.close();
} }
} }
+12
View File
@@ -4,6 +4,8 @@
#include <fstream> #include <fstream>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <mutex>
#include <thread>
namespace anm2ed namespace anm2ed
{ {
@@ -44,6 +46,16 @@ namespace anm2ed
class Logger class Logger
{ {
std::ofstream file{}; std::ofstream file{};
std::mutex mutex{};
std::thread stderrThread{};
bool isStderrRedirecting{};
int stderrPipeReadFd{-1};
int stderrPipeWriteFd{-1};
int stderrOriginalFd{-1};
void stderr_redirect_start();
void stderr_redirect_stop();
void stderr_pump();
public: public:
static std::filesystem::path path(); static std::filesystem::path path();
+2 -2
View File
@@ -1,5 +1,5 @@
#include "loader.h" #include "loader.hpp"
#include "state.h" #include "state.hpp"
#ifdef _WIN32 #ifdef _WIN32
#define SDL_MAIN_HANDLED #define SDL_MAIN_HANDLED
+7 -7
View File
@@ -1,16 +1,16 @@
#include "manager.h" #include "manager.hpp"
#include <algorithm> #include <algorithm>
#include <unordered_set> #include <unordered_set>
#include <format> #include <format>
#include "log.h" #include "log.hpp"
#include "path_.h" #include "path_.hpp"
#include "sdl.h" #include "sdl.hpp"
#include "strings.h" #include "strings.hpp"
#include "toast.h" #include "toast.hpp"
#include "vector_.h" #include "vector_.hpp"
using namespace anm2ed::types; using namespace anm2ed::types;
using namespace anm2ed::util; using namespace anm2ed::util;

Some files were not shown because too many files have changed in this diff Show More