diff --git a/.vscode/launch.json b/.vscode/launch.json index f29b4f0..cdfd141 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,8 @@ "name": "Debug", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/out/build/linux-debug/anm2ed", + "preLaunchTask": "build-debug", + "program": "${workspaceFolder}/out/build/linux-debug/bin/anm2ed", "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", @@ -28,7 +29,8 @@ "name": "Release", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/out/build/linux-release/anm2ed", + "preLaunchTask": "build-release", + "program": "${workspaceFolder}/out/build/linux-release/bin/anm2ed", "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", @@ -48,4 +50,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 3ac1dec..81fe5dd 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -2,17 +2,33 @@ "version": "2.0.0", "tasks": [ { - "label": "run-debug", + "label": "configure-debug", "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": [ "$gcc" ] }, { - "label": "build", + "label": "build-debug", "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": { "kind": "build", "isDefault": true @@ -22,9 +38,23 @@ ] }, { - "label": "run-release", + "label": "run-debug", "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": [ "$gcc" ] @@ -32,11 +62,27 @@ { "label": "build-release", "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", "problemMatcher": [ "$gcc" ] + }, + { + "label": "run-release", + "type": "shell", + "command": "./out/build/linux-release/bin/anm2ed", + "dependsOn": "build-release", + "problemMatcher": [] } ] -} \ No newline at end of file +} diff --git a/CMakeLists.txt b/CMakeLists.txt index e961728..74eda3d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,23 +87,30 @@ set(TINYXML2_SRC external/tinyxml2/tinyxml2.cpp) file(GLOB PROJECT_SRC CONFIGURE_DEPENDS src/anm2/*.cpp - src/anm2/*.h + src/anm2/*.hpp src/resource/*.cpp - src/resource/*.h + src/resource/*.hpp src/imgui/*.cpp - src/imgui/*.h + src/imgui/*.hpp src/imgui/window/*.cpp - src/imgui/window/*.h + src/imgui/window/*.hpp src/imgui/wizard/*.cpp - src/imgui/wizard/*.h + src/imgui/wizard/*.hpp src/util/*.cpp - src/util/*.h + src/util/*.hpp src/window/*.cpp - src/window/*.h + src/window/*.hpp src/*.cpp - src/*.h) + src/*.hpp) 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 IMGUI_ENABLE_DOCKING) diff --git a/CMakeSettings.json b/CMakeSettings.json index ec980c3..0694331 100644 --- a/CMakeSettings.json +++ b/CMakeSettings.json @@ -1,7 +1,7 @@ { "configurations": [ { - "name": "x64-Debug", + "name": "windows-debug", "generator": "Ninja", "configurationType": "Debug", "inheritEnvironments": [ @@ -12,7 +12,7 @@ "cmakeCommandArgs": "-DCMAKE_BUILD_TYPE=\"Debug\"" }, { - "name": "x64-Release", + "name": "windows-release", "generator": "Ninja", "configurationType": "Release", "inheritEnvironments": [ @@ -23,4 +23,4 @@ "cmakeCommandArgs": "-DCMAKE_BUILD_TYPE=\"Release\"" } ] -} \ No newline at end of file +} diff --git a/src/anm2/animation.cpp b/src/anm2/animation.cpp index 5dd221d..8808703 100644 --- a/src/anm2/animation.cpp +++ b/src/anm2/animation.cpp @@ -1,9 +1,9 @@ -#include "animation.h" +#include "animation.hpp" -#include "map_.h" -#include "math_.h" -#include "unordered_map_.h" -#include "xml_.h" +#include "map_.hpp" +#include "math_.hpp" +#include "unordered_map_.hpp" +#include "xml_.hpp" #include using namespace anm2ed::util; diff --git a/src/anm2/animation.h b/src/anm2/animation.hpp similarity index 97% rename from src/anm2/animation.h rename to src/anm2/animation.hpp index 9725a90..727f73e 100644 --- a/src/anm2/animation.h +++ b/src/anm2/animation.hpp @@ -3,7 +3,7 @@ #include #include -#include "item.h" +#include "item.hpp" namespace anm2ed::anm2 { diff --git a/src/anm2/animations.cpp b/src/anm2/animations.cpp index 10d9208..ff698e5 100644 --- a/src/anm2/animations.cpp +++ b/src/anm2/animations.cpp @@ -1,6 +1,6 @@ -#include "animations.h" +#include "animations.hpp" -#include "xml_.h" +#include "xml_.hpp" using namespace tinyxml2; using namespace anm2ed::types; diff --git a/src/anm2/animations.h b/src/anm2/animations.hpp similarity index 94% rename from src/anm2/animations.h rename to src/anm2/animations.hpp index 2db0454..29bf0f0 100644 --- a/src/anm2/animations.h +++ b/src/anm2/animations.hpp @@ -1,6 +1,6 @@ #pragma once -#include "animation.h" +#include "animation.hpp" namespace anm2ed::anm2 { diff --git a/src/anm2/anm2.cpp b/src/anm2/anm2.cpp index c642f5f..f72cea4 100644 --- a/src/anm2/anm2.cpp +++ b/src/anm2/anm2.cpp @@ -1,15 +1,15 @@ -#include "anm2.h" +#include "anm2.hpp" #include #include #include -#include "file_.h" -#include "map_.h" -#include "time_.h" -#include "vector_.h" -#include "working_directory.h" -#include "xml_.h" +#include "file_.hpp" +#include "map_.hpp" +#include "time_.hpp" +#include "vector_.hpp" +#include "working_directory.hpp" +#include "xml_.hpp" using namespace tinyxml2; using namespace anm2ed::types; diff --git a/src/anm2/anm2.h b/src/anm2/anm2.hpp similarity index 97% rename from src/anm2/anm2.h rename to src/anm2/anm2.hpp index 0469dbd..12c0b41 100644 --- a/src/anm2/anm2.h +++ b/src/anm2/anm2.hpp @@ -4,11 +4,11 @@ #include #include -#include "types.h" +#include "types.hpp" -#include "animations.h" -#include "content.h" -#include "info.h" +#include "animations.hpp" +#include "content.hpp" +#include "info.hpp" namespace anm2ed::anm2 { diff --git a/src/anm2/anm2_animations.cpp b/src/anm2/anm2_animations.cpp index 4920d5f..1cfb030 100644 --- a/src/anm2/anm2_animations.cpp +++ b/src/anm2/anm2_animations.cpp @@ -1,6 +1,6 @@ -#include "anm2.h" +#include "anm2.hpp" -#include "vector_.h" +#include "vector_.hpp" using namespace anm2ed::util; using namespace anm2ed::types; diff --git a/src/anm2/anm2_events.cpp b/src/anm2/anm2_events.cpp index d7ae12c..13a7300 100644 --- a/src/anm2/anm2_events.cpp +++ b/src/anm2/anm2_events.cpp @@ -1,8 +1,8 @@ -#include "anm2.h" +#include "anm2.hpp" #include -#include "map_.h" +#include "map_.hpp" using namespace anm2ed::types; using namespace anm2ed::util; diff --git a/src/anm2/anm2_items.cpp b/src/anm2/anm2_items.cpp index 712d4c8..47ba193 100644 --- a/src/anm2/anm2_items.cpp +++ b/src/anm2/anm2_items.cpp @@ -1,8 +1,8 @@ -#include "anm2.h" +#include "anm2.hpp" -#include "map_.h" -#include "types.h" -#include "unordered_map_.h" +#include "map_.hpp" +#include "types.hpp" +#include "unordered_map_.hpp" using namespace anm2ed::types; using namespace anm2ed::util; diff --git a/src/anm2/anm2_layers.cpp b/src/anm2/anm2_layers.cpp index 14ec4a1..1490abf 100644 --- a/src/anm2/anm2_layers.cpp +++ b/src/anm2/anm2_layers.cpp @@ -1,8 +1,8 @@ -#include "anm2.h" +#include "anm2.hpp" #include -#include "map_.h" +#include "map_.hpp" using namespace anm2ed::types; using namespace anm2ed::util; diff --git a/src/anm2/anm2_nulls.cpp b/src/anm2/anm2_nulls.cpp index 126c7a9..57ae2e0 100644 --- a/src/anm2/anm2_nulls.cpp +++ b/src/anm2/anm2_nulls.cpp @@ -1,8 +1,8 @@ -#include "anm2.h" +#include "anm2.hpp" #include -#include "map_.h" +#include "map_.hpp" using namespace anm2ed::types; using namespace anm2ed::util; diff --git a/src/anm2/anm2_sounds.cpp b/src/anm2/anm2_sounds.cpp index 5d7e146..425a457 100644 --- a/src/anm2/anm2_sounds.cpp +++ b/src/anm2/anm2_sounds.cpp @@ -1,8 +1,8 @@ -#include "anm2.h" +#include "anm2.hpp" -#include "map_.h" -#include "path_.h" -#include "working_directory.h" +#include "map_.hpp" +#include "path_.hpp" +#include "working_directory.hpp" using namespace anm2ed::types; using namespace anm2ed::util; diff --git a/src/anm2/anm2_spritesheets.cpp b/src/anm2/anm2_spritesheets.cpp index 45d1fff..b99a7b3 100644 --- a/src/anm2/anm2_spritesheets.cpp +++ b/src/anm2/anm2_spritesheets.cpp @@ -1,4 +1,4 @@ -#include "anm2.h" +#include "anm2.hpp" #include #include @@ -8,9 +8,9 @@ #include #include -#include "map_.h" -#include "path_.h" -#include "working_directory.h" +#include "map_.hpp" +#include "path_.hpp" +#include "working_directory.hpp" using namespace anm2ed::types; using namespace anm2ed::util; @@ -419,6 +419,7 @@ namespace anm2ed::anm2 std::unordered_map offsets{}; offsets[baseId] = {}; + auto baseTextureSize = base.texture.size; auto mergedTexture = base.texture; for (auto id : ids) { @@ -446,6 +447,20 @@ namespace anm2ed::anm2 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) { if (id == baseId) continue; diff --git a/src/anm2/anm2_type.h b/src/anm2/anm2_type.hpp similarity index 98% rename from src/anm2/anm2_type.h rename to src/anm2/anm2_type.hpp index 7ac3615..d80ced3 100644 --- a/src/anm2/anm2_type.h +++ b/src/anm2/anm2_type.hpp @@ -1,7 +1,7 @@ #pragma once -#include "icon.h" -#include "strings.h" +#include "icon.hpp" +#include "strings.hpp" #include #include diff --git a/src/anm2/content.cpp b/src/anm2/content.cpp index 6d0e25a..cd5f0ac 100644 --- a/src/anm2/content.cpp +++ b/src/anm2/content.cpp @@ -1,4 +1,4 @@ -#include "content.h" +#include "content.hpp" using namespace tinyxml2; diff --git a/src/anm2/content.h b/src/anm2/content.hpp similarity index 78% rename from src/anm2/content.h rename to src/anm2/content.hpp index 551aa44..17094bf 100644 --- a/src/anm2/content.h +++ b/src/anm2/content.hpp @@ -2,11 +2,11 @@ #include -#include "event.h" -#include "layer.h" -#include "null.h" -#include "sound.h" -#include "spritesheet.h" +#include "event.hpp" +#include "layer.hpp" +#include "null.hpp" +#include "sound.hpp" +#include "spritesheet.hpp" namespace anm2ed::anm2 { diff --git a/src/anm2/event.cpp b/src/anm2/event.cpp index 7427897..cfb9f03 100644 --- a/src/anm2/event.cpp +++ b/src/anm2/event.cpp @@ -1,6 +1,6 @@ -#include "event.h" +#include "event.hpp" -#include "xml_.h" +#include "xml_.hpp" using namespace anm2ed::util; using namespace tinyxml2; diff --git a/src/anm2/event.h b/src/anm2/event.hpp similarity index 100% rename from src/anm2/event.h rename to src/anm2/event.hpp diff --git a/src/anm2/frame.cpp b/src/anm2/frame.cpp index 52ec3c3..4415869 100644 --- a/src/anm2/frame.cpp +++ b/src/anm2/frame.cpp @@ -1,7 +1,7 @@ -#include "frame.h" +#include "frame.hpp" -#include "math_.h" -#include "xml_.h" +#include "math_.hpp" +#include "xml_.hpp" using namespace anm2ed::util; using namespace tinyxml2; diff --git a/src/anm2/frame.h b/src/anm2/frame.hpp similarity index 97% rename from src/anm2/frame.h rename to src/anm2/frame.hpp index c642296..bb33a1f 100644 --- a/src/anm2/frame.h +++ b/src/anm2/frame.hpp @@ -4,8 +4,8 @@ #include #include -#include "anm2_type.h" -#include "types.h" +#include "anm2_type.hpp" +#include "types.hpp" namespace anm2ed::anm2 { diff --git a/src/anm2/info.cpp b/src/anm2/info.cpp index 2ea0433..d137288 100644 --- a/src/anm2/info.cpp +++ b/src/anm2/info.cpp @@ -1,6 +1,6 @@ -#include "info.h" +#include "info.hpp" -#include "xml_.h" +#include "xml_.hpp" using namespace anm2ed::util; using namespace tinyxml2; diff --git a/src/anm2/info.h b/src/anm2/info.hpp similarity index 100% rename from src/anm2/info.h rename to src/anm2/info.hpp diff --git a/src/anm2/item.cpp b/src/anm2/item.cpp index 6c1afd7..08ba283 100644 --- a/src/anm2/item.cpp +++ b/src/anm2/item.cpp @@ -1,9 +1,9 @@ -#include "item.h" +#include "item.hpp" #include #include -#include "vector_.h" -#include "xml_.h" +#include "vector_.hpp" +#include "xml_.hpp" using namespace anm2ed::util; using namespace tinyxml2; diff --git a/src/anm2/item.h b/src/anm2/item.hpp similarity index 97% rename from src/anm2/item.h rename to src/anm2/item.hpp index 5e1e082..0ca0a12 100644 --- a/src/anm2/item.h +++ b/src/anm2/item.hpp @@ -3,7 +3,7 @@ #include #include -#include "frame.h" +#include "frame.hpp" namespace anm2ed::anm2 { diff --git a/src/anm2/layer.cpp b/src/anm2/layer.cpp index 5dbe7ba..3c29702 100644 --- a/src/anm2/layer.cpp +++ b/src/anm2/layer.cpp @@ -1,6 +1,6 @@ -#include "layer.h" +#include "layer.hpp" -#include "xml_.h" +#include "xml_.hpp" using namespace anm2ed::util; using namespace tinyxml2; diff --git a/src/anm2/layer.h b/src/anm2/layer.hpp similarity index 100% rename from src/anm2/layer.h rename to src/anm2/layer.hpp diff --git a/src/anm2/null.cpp b/src/anm2/null.cpp index 272228a..6873424 100644 --- a/src/anm2/null.cpp +++ b/src/anm2/null.cpp @@ -1,6 +1,6 @@ -#include "null.h" +#include "null.hpp" -#include "xml_.h" +#include "xml_.hpp" using namespace anm2ed::util; using namespace tinyxml2; diff --git a/src/anm2/null.h b/src/anm2/null.hpp similarity index 100% rename from src/anm2/null.h rename to src/anm2/null.hpp diff --git a/src/anm2/sound.cpp b/src/anm2/sound.cpp index 95c3323..b90ef4f 100644 --- a/src/anm2/sound.cpp +++ b/src/anm2/sound.cpp @@ -1,8 +1,8 @@ -#include "sound.h" +#include "sound.hpp" -#include "path_.h" -#include "working_directory.h" -#include "xml_.h" +#include "path_.hpp" +#include "working_directory.hpp" +#include "xml_.hpp" using namespace anm2ed::resource; using namespace anm2ed::util; diff --git a/src/anm2/sound.h b/src/anm2/sound.hpp similarity index 97% rename from src/anm2/sound.h rename to src/anm2/sound.hpp index 4a55e33..3271b58 100644 --- a/src/anm2/sound.h +++ b/src/anm2/sound.hpp @@ -3,7 +3,7 @@ #include #include -#include "audio.h" +#include "audio.hpp" namespace anm2ed::anm2 { diff --git a/src/anm2/spritesheet.cpp b/src/anm2/spritesheet.cpp index bd9a0c5..bd8f68e 100644 --- a/src/anm2/spritesheet.cpp +++ b/src/anm2/spritesheet.cpp @@ -1,4 +1,4 @@ -#include "spritesheet.h" +#include "spritesheet.hpp" #include #include @@ -6,10 +6,10 @@ #include #include -#include "map_.h" -#include "path_.h" -#include "working_directory.h" -#include "xml_.h" +#include "map_.hpp" +#include "path_.hpp" +#include "working_directory.hpp" +#include "xml_.hpp" using namespace anm2ed::resource; using namespace anm2ed::util; @@ -91,9 +91,10 @@ namespace anm2ed::anm2 Spritesheet::Spritesheet(const std::filesystem::path& directory, const std::filesystem::path& path) { 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::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) @@ -234,9 +235,10 @@ namespace anm2ed::anm2 void Spritesheet::reload(const std::filesystem::path& directory, const std::filesystem::path& path) { 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::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(); } diff --git a/src/anm2/spritesheet.h b/src/anm2/spritesheet.hpp similarity index 94% rename from src/anm2/spritesheet.h rename to src/anm2/spritesheet.hpp index b51ecf3..4a906f1 100644 --- a/src/anm2/spritesheet.h +++ b/src/anm2/spritesheet.hpp @@ -8,10 +8,10 @@ #include #include -#include "texture.h" -#include "anm2_type.h" -#include "types.h" -#include "origin.h" +#include "texture.hpp" +#include "anm2_type.hpp" +#include "types.hpp" +#include "origin.hpp" namespace anm2ed::anm2 { diff --git a/src/canvas.cpp b/src/canvas.cpp index 6ef189b..5d18447 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -1,4 +1,4 @@ -#include "canvas.h" +#include "canvas.hpp" #include #include @@ -6,7 +6,7 @@ #include #include -#include "math_.h" +#include "math_.hpp" using namespace glm; using namespace anm2ed::resource; diff --git a/src/canvas.h b/src/canvas.hpp similarity index 97% rename from src/canvas.h rename to src/canvas.hpp index 79a2cc6..f99dde7 100644 --- a/src/canvas.h +++ b/src/canvas.hpp @@ -3,10 +3,10 @@ #include #include -#include "framebuffer.h" -#include "shader.h" +#include "framebuffer.hpp" +#include "shader.hpp" -#include "types.h" +#include "types.hpp" namespace anm2ed { diff --git a/src/clipboard.cpp b/src/clipboard.cpp index 4aa232d..f5d1ec3 100644 --- a/src/clipboard.cpp +++ b/src/clipboard.cpp @@ -1,4 +1,4 @@ -#include "clipboard.h" +#include "clipboard.hpp" #include diff --git a/src/clipboard.h b/src/clipboard.hpp similarity index 100% rename from src/clipboard.h rename to src/clipboard.hpp diff --git a/src/dialog.cpp b/src/dialog.cpp index 895c018..520efca 100644 --- a/src/dialog.cpp +++ b/src/dialog.cpp @@ -1,19 +1,19 @@ -#include "dialog.h" +#include "dialog.hpp" #ifdef _WIN32 #include #elif __unix__ #else - #include "log.h" - #include "strings.h" - #include "toast.h" + #include "log.hpp" + #include "strings.hpp" + #include "toast.hpp" #endif #include #include #include -#include "path_.h" +#include "path_.hpp" using namespace anm2ed::util; diff --git a/src/dialog.h b/src/dialog.hpp similarity index 100% rename from src/dialog.h rename to src/dialog.hpp diff --git a/src/document.cpp b/src/document.cpp index fd280f8..ed7413e 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -1,13 +1,13 @@ -#include "document.h" +#include "document.hpp" #include #include -#include "log.h" -#include "path_.h" -#include "strings.h" -#include "toast.h" +#include "log.hpp" +#include "path_.hpp" +#include "strings.hpp" +#include "toast.hpp" using namespace anm2ed::anm2; using namespace anm2ed::imgui; diff --git a/src/document.h b/src/document.hpp similarity index 99% rename from src/document.h rename to src/document.hpp index 530a14e..5e16874 100644 --- a/src/document.h +++ b/src/document.hpp @@ -4,7 +4,7 @@ #include #include -#include "snapshots.h" +#include "snapshots.hpp" #include diff --git a/src/framebuffer.cpp b/src/framebuffer.cpp index 0ef0c25..eb393b7 100644 --- a/src/framebuffer.cpp +++ b/src/framebuffer.cpp @@ -1,6 +1,6 @@ -#include "framebuffer.h" +#include "framebuffer.hpp" -#include "texture.h" +#include "texture.hpp" using namespace anm2ed::resource; using namespace glm; diff --git a/src/framebuffer.h b/src/framebuffer.hpp similarity index 100% rename from src/framebuffer.h rename to src/framebuffer.hpp diff --git a/src/imgui/dockspace.cpp b/src/imgui/dockspace.cpp index 398982e..fe81350 100644 --- a/src/imgui/dockspace.cpp +++ b/src/imgui/dockspace.cpp @@ -1,4 +1,4 @@ -#include "dockspace.h" +#include "dockspace.hpp" namespace anm2ed::imgui { diff --git a/src/imgui/dockspace.h b/src/imgui/dockspace.hpp similarity index 52% rename from src/imgui/dockspace.h rename to src/imgui/dockspace.hpp index eca62f3..8bdfd90 100644 --- a/src/imgui/dockspace.h +++ b/src/imgui/dockspace.hpp @@ -1,21 +1,21 @@ #pragma once -#include "documents.h" -#include "taskbar.h" -#include "window/animation_preview.h" -#include "window/animations.h" -#include "window/regions.h" -#include "window/events.h" -#include "window/frame_properties.h" -#include "window/layers.h" -#include "window/nulls.h" -#include "window/onionskin.h" -#include "window/sounds.h" -#include "window/spritesheet_editor.h" -#include "window/spritesheets.h" -#include "window/timeline.h" -#include "window/tools.h" -#include "window/welcome.h" +#include "documents.hpp" +#include "taskbar.hpp" +#include "window/animation_preview.hpp" +#include "window/animations.hpp" +#include "window/regions.hpp" +#include "window/events.hpp" +#include "window/frame_properties.hpp" +#include "window/layers.hpp" +#include "window/nulls.hpp" +#include "window/onionskin.hpp" +#include "window/sounds.hpp" +#include "window/spritesheet_editor.hpp" +#include "window/spritesheets.hpp" +#include "window/timeline.hpp" +#include "window/tools.hpp" +#include "window/welcome.hpp" namespace anm2ed::imgui { diff --git a/src/imgui/documents.cpp b/src/imgui/documents.cpp index cdd442f..05b5d4d 100644 --- a/src/imgui/documents.cpp +++ b/src/imgui/documents.cpp @@ -1,13 +1,13 @@ -#include "documents.h" +#include "documents.hpp" #include #include -#include "path_.h" -#include "strings.h" -#include "time_.h" -#include "toast.h" -#include "log.h" +#include "path_.hpp" +#include "strings.hpp" +#include "time_.hpp" +#include "toast.hpp" +#include "log.hpp" using namespace anm2ed::resource; using namespace anm2ed::types; diff --git a/src/imgui/documents.h b/src/imgui/documents.hpp similarity index 71% rename from src/imgui/documents.h rename to src/imgui/documents.hpp index 3ac52a2..319cb2e 100644 --- a/src/imgui/documents.h +++ b/src/imgui/documents.hpp @@ -1,10 +1,10 @@ #pragma once -#include "manager.h" -#include "resources.h" -#include "settings.h" -#include "strings.h" -#include "taskbar.h" +#include "manager.hpp" +#include "resources.hpp" +#include "settings.hpp" +#include "strings.hpp" +#include "taskbar.hpp" namespace anm2ed::imgui { diff --git a/src/imgui/imgui_.cpp b/src/imgui/imgui_.cpp index 7aa98df..fc3f1d9 100644 --- a/src/imgui/imgui_.cpp +++ b/src/imgui/imgui_.cpp @@ -6,9 +6,9 @@ #include #include -#include "imgui_.h" -#include "path_.h" -#include "strings.h" +#include "imgui_.hpp" +#include "path_.hpp" +#include "strings.hpp" using namespace anm2ed::types; using namespace anm2ed::util; diff --git a/src/imgui/imgui_.h b/src/imgui/imgui_.hpp similarity index 99% rename from src/imgui/imgui_.h rename to src/imgui/imgui_.hpp index 9923156..cff5a5c 100644 --- a/src/imgui/imgui_.h +++ b/src/imgui/imgui_.hpp @@ -8,8 +8,8 @@ #include #include -#include "strings.h" -#include "types.h" +#include "strings.hpp" +#include "types.hpp" namespace anm2ed::imgui { diff --git a/src/imgui/taskbar.cpp b/src/imgui/taskbar.cpp index 1955c47..28ca282 100644 --- a/src/imgui/taskbar.cpp +++ b/src/imgui/taskbar.cpp @@ -1,4 +1,4 @@ -#include "taskbar.h" +#include "taskbar.hpp" #include #include @@ -7,12 +7,12 @@ #include -#include "document.h" -#include "log.h" -#include "path_.h" -#include "strings.h" -#include "toast.h" -#include "types.h" +#include "document.hpp" +#include "log.hpp" +#include "path_.hpp" +#include "strings.hpp" +#include "toast.hpp" +#include "types.hpp" using namespace anm2ed::resource; using namespace anm2ed::types; diff --git a/src/imgui/taskbar.h b/src/imgui/taskbar.hpp similarity index 73% rename from src/imgui/taskbar.h rename to src/imgui/taskbar.hpp index cd171e7..56e5a5d 100644 --- a/src/imgui/taskbar.h +++ b/src/imgui/taskbar.hpp @@ -1,18 +1,18 @@ #pragma once -#include "canvas.h" -#include "dialog.h" -#include "imgui_.h" -#include "manager.h" -#include "resources.h" -#include "settings.h" -#include "strings.h" +#include "canvas.hpp" +#include "dialog.hpp" +#include "imgui_.hpp" +#include "manager.hpp" +#include "resources.hpp" +#include "settings.hpp" +#include "strings.hpp" -#include "wizard/about.h" -#include "wizard/change_all_frame_properties.h" -#include "wizard/configure.h" -#include "wizard/generate_animation_from_grid.h" -#include "wizard/render_animation.h" +#include "wizard/about.hpp" +#include "wizard/change_all_frame_properties.hpp" +#include "wizard/configure.hpp" +#include "wizard/generate_animation_from_grid.hpp" +#include "wizard/render_animation.hpp" namespace anm2ed::imgui { diff --git a/src/imgui/toast.cpp b/src/imgui/toast.cpp index 39646f0..9e3274a 100644 --- a/src/imgui/toast.cpp +++ b/src/imgui/toast.cpp @@ -1,9 +1,9 @@ -#include "toast.h" +#include "toast.hpp" -#include "log.h" +#include "log.hpp" #include -#include "types.h" +#include "types.hpp" using namespace anm2ed::types; diff --git a/src/imgui/toast.h b/src/imgui/toast.hpp similarity index 100% rename from src/imgui/toast.h rename to src/imgui/toast.hpp diff --git a/src/imgui/window/animation_preview.cpp b/src/imgui/window/animation_preview.cpp index f530b20..be7ab06 100644 --- a/src/imgui/window/animation_preview.cpp +++ b/src/imgui/window/animation_preview.cpp @@ -1,23 +1,25 @@ -#include "animation_preview.h" +#include "animation_preview.hpp" #include #include +#include #include #include +#include #include #include #include #include -#include "imgui_.h" -#include "log.h" -#include "math_.h" -#include "path_.h" -#include "strings.h" -#include "toast.h" -#include "tool.h" -#include "types.h" +#include "imgui_.hpp" +#include "log.hpp" +#include "math_.hpp" +#include "path_.hpp" +#include "strings.hpp" +#include "toast.hpp" +#include "tool.hpp" +#include "types.hpp" using namespace anm2ed::types; 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); } } + bool render_audio_stream_generate(AudioStream& audioStream, std::map& sounds, + const std::vector& 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{}; + + 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()) {} @@ -118,6 +164,12 @@ namespace anm2ed::imgui auto& overlayIndex = document.overlayIndex; auto& pan = document.previewPan; + auto stop_all_sounds = [&]() + { + for (auto& sound : anm2.content.sounds | std::views::values) + sound.audio.stop(mixer); + }; + if (manager.isRecording) { auto& ffmpegPath = settings.renderFFmpegPath; @@ -127,6 +179,8 @@ namespace anm2ed::imgui if (playback.time > end || playback.isFinished) { + if (settings.timelineIsSound) audioStream.capture_end(mixer); + if (type == render::PNGS) { if (!renderTempFrames.empty()) @@ -206,7 +260,20 @@ namespace anm2ed::imgui } 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))); logger.info(std::vformat(localize.get(TOAST_EXPORT_RENDERED_ANIMATION, anm2ed::ENGLISH), @@ -225,9 +292,15 @@ namespace anm2ed::imgui { renderTempDirectory.clear(); renderTempFrames.clear(); + renderTempFrameDurations.clear(); + renderFrameSoundIDs.clear(); } else + { render_temp_cleanup(renderTempDirectory, renderTempFrames); + renderTempFrameDurations.clear(); + renderFrameSoundIDs.clear(); + } if (settings.renderIsRawAnimation) { @@ -241,8 +314,6 @@ namespace anm2ed::imgui isCheckerPanInitialized = false; } - if (settings.timelineIsSound) audioStream.capture_end(mixer); - playback.isPlaying = false; playback.isFinished = false; manager.isRecording = false; @@ -250,6 +321,28 @@ namespace anm2ed::imgui } 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(); auto pixels = pixels_get(); @@ -259,6 +352,24 @@ namespace anm2ed::imgui if (Texture::write_pixels_png(framePath, size, pixels.data())) { 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 { @@ -267,6 +378,8 @@ namespace anm2ed::imgui logger.error(std::vformat(localize.get(TOAST_EXPORT_RENDERED_ANIMATION_FAILED, anm2ed::ENGLISH), std::make_format_args(pathString))); if (type != render::PNGS) render_temp_cleanup(renderTempDirectory, renderTempFrames); + renderTempFrameDurations.clear(); + renderFrameSoundIDs.clear(); playback.isPlaying = false; playback.isFinished = false; manager.isRecording = false; @@ -281,18 +394,23 @@ namespace anm2ed::imgui auto& isSound = settings.timelineIsSound; auto& isOnlyShowLayers = settings.timelineIsOnlyShowLayers; - if (!anm2.content.sounds.empty() && isSound) + if (!manager.isRecording && !anm2.content.sounds.empty() && isSound) { if (auto animation = document.animation_get(); animation && animation->triggers.isVisible && (!isOnlyShowLayers || manager.isRecording)) { if (auto trigger = animation->triggers.frame_generate(playback.time, anm2::TRIGGER); trigger.isVisible) { - auto soundID = trigger.soundIDs.size() > 1 - ? (int)trigger.soundIDs[math::random_in_range(0, trigger.soundIDs.size())] - : (int)trigger.soundIDs.front(); + 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)) 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; } + + if (wasPlaybackPlaying && !playback.isPlaying) stop_all_sounds(); + wasPlaybackPlaying = playback.isPlaying; } void AnimationPreview::update(Manager& manager, Settings& settings, Resources& resources) @@ -492,8 +613,6 @@ namespace anm2ed::imgui { savedSettings = settings; - if (settings.timelineIsSound) audioStream.capture_begin(mixer); - if (settings.renderIsRawAnimation) { settings.previewBackgroundColor = vec4(); @@ -520,6 +639,9 @@ namespace anm2ed::imgui manager.isRecordingStart = false; manager.isRecording = true; renderTempFrames.clear(); + renderTempFrameDurations.clear(); + renderFrameSoundIDs.clear(); + renderCaptureCounterPrev = 0; if (settings.renderType == render::PNGS) { renderTempDirectory = settings.renderPath; @@ -1052,9 +1174,13 @@ namespace anm2ed::imgui { renderTempDirectory.clear(); renderTempFrames.clear(); + renderTempFrameDurations.clear(); } else + { render_temp_cleanup(renderTempDirectory, renderTempFrames); + renderTempFrameDurations.clear(); + } pan = savedPan; zoom = savedZoom; diff --git a/src/imgui/window/animation_preview.h b/src/imgui/window/animation_preview.hpp similarity index 75% rename from src/imgui/window/animation_preview.h rename to src/imgui/window/animation_preview.hpp index 7c0773b..b9dcd7a 100644 --- a/src/imgui/window/animation_preview.h +++ b/src/imgui/window/animation_preview.hpp @@ -2,11 +2,11 @@ #include -#include "audio_stream.h" -#include "canvas.h" -#include "manager.h" -#include "resources.h" -#include "settings.h" +#include "audio_stream.hpp" +#include "canvas.hpp" +#include "manager.hpp" +#include "resources.hpp" +#include "settings.hpp" namespace anm2ed::imgui { @@ -14,6 +14,7 @@ namespace anm2ed::imgui { MIX_Mixer* mixer = MIX_CreateMixerDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, nullptr); AudioStream audioStream = AudioStream(mixer); + bool wasPlaybackPlaying{}; bool isPreviewHovered{}; bool isSizeTrySet{true}; Settings savedSettings{}; @@ -30,6 +31,9 @@ namespace anm2ed::imgui glm::vec2 moveOffset{}; std::filesystem::path renderTempDirectory{}; std::vector renderTempFrames{}; + std::vector renderTempFrameDurations{}; + std::vector renderFrameSoundIDs{}; + Uint64 renderCaptureCounterPrev{}; public: AnimationPreview(); diff --git a/src/imgui/window/animations.cpp b/src/imgui/window/animations.cpp index 9d55ffc..52fcf6c 100644 --- a/src/imgui/window/animations.cpp +++ b/src/imgui/window/animations.cpp @@ -1,12 +1,12 @@ -#include "animations.h" +#include "animations.hpp" #include #include -#include "log.h" -#include "strings.h" -#include "toast.h" -#include "vector_.h" +#include "log.hpp" +#include "strings.hpp" +#include "toast.hpp" +#include "vector_.hpp" using namespace anm2ed::util; using namespace anm2ed::resource; diff --git a/src/imgui/window/animations.h b/src/imgui/window/animations.hpp similarity index 76% rename from src/imgui/window/animations.h rename to src/imgui/window/animations.hpp index 82be436..10fa2ff 100644 --- a/src/imgui/window/animations.h +++ b/src/imgui/window/animations.hpp @@ -1,10 +1,10 @@ #pragma once -#include "clipboard.h" -#include "manager.h" -#include "resources.h" -#include "settings.h" -#include "strings.h" +#include "clipboard.hpp" +#include "manager.hpp" +#include "resources.hpp" +#include "settings.hpp" +#include "strings.hpp" namespace anm2ed::imgui { diff --git a/src/imgui/window/events.cpp b/src/imgui/window/events.cpp index d7ed3f8..b0a9f59 100644 --- a/src/imgui/window/events.cpp +++ b/src/imgui/window/events.cpp @@ -1,11 +1,11 @@ -#include "events.h" +#include "events.hpp" #include -#include "log.h" -#include "map_.h" -#include "strings.h" -#include "toast.h" +#include "log.hpp" +#include "map_.hpp" +#include "strings.hpp" +#include "toast.hpp" using namespace anm2ed::util; using namespace anm2ed::resource; diff --git a/src/imgui/window/events.h b/src/imgui/window/events.hpp similarity index 71% rename from src/imgui/window/events.h rename to src/imgui/window/events.hpp index 5d956c5..710d284 100644 --- a/src/imgui/window/events.h +++ b/src/imgui/window/events.hpp @@ -1,9 +1,9 @@ #pragma once -#include "clipboard.h" -#include "manager.h" -#include "resources.h" -#include "settings.h" +#include "clipboard.hpp" +#include "manager.hpp" +#include "resources.hpp" +#include "settings.hpp" namespace anm2ed::imgui { diff --git a/src/imgui/window/frame_properties.cpp b/src/imgui/window/frame_properties.cpp index 8951f49..c40c214 100644 --- a/src/imgui/window/frame_properties.cpp +++ b/src/imgui/window/frame_properties.cpp @@ -1,13 +1,13 @@ -#include "frame_properties.h" +#include "frame_properties.hpp" #include #include #include #include -#include "math_.h" -#include "strings.h" -#include "types.h" +#include "math_.hpp" +#include "strings.hpp" +#include "types.hpp" using namespace anm2ed::util::math; using namespace anm2ed::types; diff --git a/src/imgui/window/frame_properties.h b/src/imgui/window/frame_properties.hpp similarity index 74% rename from src/imgui/window/frame_properties.h rename to src/imgui/window/frame_properties.hpp index a5d6640..3ff82b7 100644 --- a/src/imgui/window/frame_properties.h +++ b/src/imgui/window/frame_properties.hpp @@ -2,8 +2,8 @@ #include -#include "manager.h" -#include "wizard/change_all_frame_properties.h" +#include "manager.hpp" +#include "wizard/change_all_frame_properties.hpp" namespace anm2ed::imgui { diff --git a/src/imgui/window/layers.cpp b/src/imgui/window/layers.cpp index 0c2a5de..2fa8105 100644 --- a/src/imgui/window/layers.cpp +++ b/src/imgui/window/layers.cpp @@ -1,11 +1,11 @@ -#include "layers.h" +#include "layers.hpp" #include -#include "log.h" -#include "map_.h" -#include "strings.h" -#include "toast.h" +#include "log.hpp" +#include "map_.hpp" +#include "strings.hpp" +#include "toast.hpp" using namespace anm2ed::util; using namespace anm2ed::resource; diff --git a/src/imgui/window/layers.h b/src/imgui/window/layers.hpp similarity index 62% rename from src/imgui/window/layers.h rename to src/imgui/window/layers.hpp index f977fb9..4e190c5 100644 --- a/src/imgui/window/layers.h +++ b/src/imgui/window/layers.hpp @@ -1,9 +1,9 @@ #pragma once -#include "clipboard.h" -#include "manager.h" -#include "resources.h" -#include "settings.h" +#include "clipboard.hpp" +#include "manager.hpp" +#include "resources.hpp" +#include "settings.hpp" namespace anm2ed::imgui { diff --git a/src/imgui/window/nulls.cpp b/src/imgui/window/nulls.cpp index 4dad0ca..abb4c08 100644 --- a/src/imgui/window/nulls.cpp +++ b/src/imgui/window/nulls.cpp @@ -1,11 +1,11 @@ -#include "nulls.h" +#include "nulls.hpp" #include -#include "log.h" -#include "map_.h" -#include "strings.h" -#include "toast.h" +#include "log.hpp" +#include "map_.hpp" +#include "strings.hpp" +#include "toast.hpp" using namespace anm2ed::resource; using namespace anm2ed::util; diff --git a/src/imgui/window/nulls.h b/src/imgui/window/nulls.hpp similarity index 62% rename from src/imgui/window/nulls.h rename to src/imgui/window/nulls.hpp index de0c547..ceb32fe 100644 --- a/src/imgui/window/nulls.h +++ b/src/imgui/window/nulls.hpp @@ -1,9 +1,9 @@ #pragma once -#include "clipboard.h" -#include "manager.h" -#include "resources.h" -#include "settings.h" +#include "clipboard.hpp" +#include "manager.hpp" +#include "resources.hpp" +#include "settings.hpp" namespace anm2ed::imgui { diff --git a/src/imgui/window/onionskin.cpp b/src/imgui/window/onionskin.cpp index 1c460df..944cd12 100644 --- a/src/imgui/window/onionskin.cpp +++ b/src/imgui/window/onionskin.cpp @@ -1,9 +1,9 @@ -#include "onionskin.h" +#include "onionskin.hpp" #include -#include "imgui_.h" -#include "strings.h" +#include "imgui_.hpp" +#include "strings.hpp" using namespace anm2ed::types; using namespace glm; diff --git a/src/imgui/window/onionskin.h b/src/imgui/window/onionskin.hpp similarity index 83% rename from src/imgui/window/onionskin.h rename to src/imgui/window/onionskin.hpp index df3847c..dd9489d 100644 --- a/src/imgui/window/onionskin.h +++ b/src/imgui/window/onionskin.hpp @@ -1,6 +1,6 @@ #pragma once -#include "manager.h" +#include "manager.hpp" namespace anm2ed::imgui { diff --git a/src/imgui/window/regions.cpp b/src/imgui/window/regions.cpp index e3e6c44..261c3fb 100644 --- a/src/imgui/window/regions.cpp +++ b/src/imgui/window/regions.cpp @@ -1,19 +1,19 @@ -#include "regions.h" +#include "regions.hpp" #include #include #include -#include "document.h" -#include "log.h" -#include "map_.h" -#include "math_.h" -#include "strings.h" -#include "toast.h" -#include "vector_.h" +#include "document.hpp" +#include "log.hpp" +#include "map_.hpp" +#include "math_.hpp" +#include "strings.hpp" +#include "toast.hpp" +#include "vector_.hpp" -#include "../../util/map_.h" +#include "../../util/map_.hpp" using namespace anm2ed::types; using namespace anm2ed::resource; diff --git a/src/imgui/window/regions.h b/src/imgui/window/regions.hpp similarity index 77% rename from src/imgui/window/regions.h rename to src/imgui/window/regions.hpp index 8827467..54e3f28 100644 --- a/src/imgui/window/regions.h +++ b/src/imgui/window/regions.hpp @@ -1,9 +1,9 @@ #pragma once -#include "clipboard.h" -#include "manager.h" -#include "resources.h" -#include "settings.h" +#include "clipboard.hpp" +#include "manager.hpp" +#include "resources.hpp" +#include "settings.hpp" namespace anm2ed::imgui { diff --git a/src/imgui/window/sounds.cpp b/src/imgui/window/sounds.cpp index c0fd99d..3beb8d3 100644 --- a/src/imgui/window/sounds.cpp +++ b/src/imgui/window/sounds.cpp @@ -1,13 +1,13 @@ -#include "sounds.h" +#include "sounds.hpp" #include #include #include -#include "log.h" -#include "path_.h" -#include "strings.h" -#include "toast.h" +#include "log.hpp" +#include "path_.hpp" +#include "strings.hpp" +#include "toast.hpp" using namespace anm2ed::util; using namespace anm2ed::types; diff --git a/src/imgui/window/sounds.h b/src/imgui/window/sounds.hpp similarity index 59% rename from src/imgui/window/sounds.h rename to src/imgui/window/sounds.hpp index 6f61b7e..f5ab6f1 100644 --- a/src/imgui/window/sounds.h +++ b/src/imgui/window/sounds.hpp @@ -1,10 +1,10 @@ #pragma once -#include "clipboard.h" -#include "dialog.h" -#include "manager.h" -#include "resources.h" -#include "settings.h" +#include "clipboard.hpp" +#include "dialog.hpp" +#include "manager.hpp" +#include "resources.hpp" +#include "settings.hpp" namespace anm2ed::imgui { diff --git a/src/imgui/window/spritesheet_editor.cpp b/src/imgui/window/spritesheet_editor.cpp index 0c062d6..0801b25 100644 --- a/src/imgui/window/spritesheet_editor.cpp +++ b/src/imgui/window/spritesheet_editor.cpp @@ -1,15 +1,15 @@ -#include "spritesheet_editor.h" +#include "spritesheet_editor.hpp" #include #include #include -#include "imgui_.h" +#include "imgui_.hpp" #include "imgui_internal.h" -#include "math_.h" -#include "strings.h" -#include "tool.h" -#include "types.h" +#include "math_.hpp" +#include "strings.hpp" +#include "tool.hpp" +#include "types.hpp" using namespace anm2ed::types; using namespace anm2ed::resource; diff --git a/src/imgui/window/spritesheet_editor.h b/src/imgui/window/spritesheet_editor.hpp similarity index 82% rename from src/imgui/window/spritesheet_editor.h rename to src/imgui/window/spritesheet_editor.hpp index e1a1da5..857cccc 100644 --- a/src/imgui/window/spritesheet_editor.h +++ b/src/imgui/window/spritesheet_editor.hpp @@ -1,9 +1,9 @@ #pragma once -#include "canvas.h" -#include "manager.h" -#include "resources.h" -#include "settings.h" +#include "canvas.hpp" +#include "manager.hpp" +#include "resources.hpp" +#include "settings.hpp" namespace anm2ed::imgui { diff --git a/src/imgui/window/spritesheets.cpp b/src/imgui/window/spritesheets.cpp index f8b62f0..fef8bfd 100644 --- a/src/imgui/window/spritesheets.cpp +++ b/src/imgui/window/spritesheets.cpp @@ -1,4 +1,4 @@ -#include "spritesheets.h" +#include "spritesheets.hpp" #include #include @@ -8,12 +8,12 @@ #include #include -#include "document.h" -#include "log.h" -#include "path_.h" -#include "strings.h" -#include "toast.h" -#include "working_directory.h" +#include "document.hpp" +#include "log.hpp" +#include "path_.hpp" +#include "strings.hpp" +#include "toast.hpp" +#include "working_directory.hpp" using namespace anm2ed::types; using namespace anm2ed::resource; diff --git a/src/imgui/window/spritesheets.h b/src/imgui/window/spritesheets.hpp similarity index 83% rename from src/imgui/window/spritesheets.h rename to src/imgui/window/spritesheets.hpp index 595448a..878b53c 100644 --- a/src/imgui/window/spritesheets.h +++ b/src/imgui/window/spritesheets.hpp @@ -1,10 +1,10 @@ #pragma once -#include "clipboard.h" -#include "dialog.h" -#include "manager.h" -#include "resources.h" -#include "settings.h" +#include "clipboard.hpp" +#include "dialog.hpp" +#include "manager.hpp" +#include "resources.hpp" +#include "settings.hpp" namespace anm2ed::imgui { diff --git a/src/imgui/window/timeline.cpp b/src/imgui/window/timeline.cpp index f8e632e..81f1c38 100644 --- a/src/imgui/window/timeline.cpp +++ b/src/imgui/window/timeline.cpp @@ -1,4 +1,4 @@ -#include "timeline.h" +#include "timeline.hpp" #include #include @@ -6,10 +6,10 @@ #include -#include "log.h" -#include "toast.h" +#include "log.hpp" +#include "toast.hpp" -#include "vector_.h" +#include "vector_.hpp" using namespace anm2ed::resource; using namespace anm2ed::types; @@ -83,7 +83,6 @@ namespace anm2ed::imgui constexpr auto FRAME_DRAG_PAYLOAD_ID = "Frame Drag Drop"; 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 void Timeline::update(Manager& manager, Settings& settings, Resources& resources, Clipboard& clipboard) @@ -95,6 +94,8 @@ namespace anm2ed::imgui auto& frames = document.frames; auto& region = document.region; auto animation = document.animation_get(); + auto itemFrameChildHeight = (ImGui::GetTextLineHeightWithSpacing() + ImGui::GetStyle().WindowPadding.y * 1.5f) * + settings.timelineItemHeight; style = ImGui::GetStyle(); auto isLightTheme = settings.theme == theme::LIGHT; @@ -172,6 +173,13 @@ namespace anm2ed::imgui frameFocusRequested = reference.frameIndex >= 0; }; + auto playback_stop = [&]() + { + playback.isPlaying = false; + playback.isFinished = false; + playback.timing_reset(); + }; + auto frame_insert = [&](anm2::Item* item) { if (!item) return; @@ -597,7 +605,7 @@ namespace anm2ed::imgui ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing); 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)) { @@ -961,7 +969,7 @@ namespace anm2ed::imgui ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, style.WindowPadding); - auto childSize = ImVec2(width, ITEM_FRAME_CHILD_HEIGHT); + auto childSize = ImVec2(width, itemFrameChildHeight); ImGui::PopStyleVar(2); @@ -1046,7 +1054,10 @@ namespace anm2ed::imgui } if (ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) && ImGui::IsMouseDown(0)) + { + if (!isDragging) playback_stop(); isDragging = true; + } auto childPos = ImGui::GetWindowPos(); auto mousePos = ImGui::GetIO().MousePos; @@ -1497,12 +1508,11 @@ namespace anm2ed::imgui ImGui::GetTextLineHeightWithSpacing() + (ImGui::GetStyle().WindowPadding.y * 2)); auto playheadIndex = std::floor(playback.time); auto lineCenterX = cursorScreenPos.x + frameSize.x * (playheadIndex + 0.6f) - scroll.x; - float lineOffsetY = frameSize.y; 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), - viewListChildSize.y - frameSize.y - lineOffsetY - - (isHorizontalScroll ? ImGui::GetStyle().ScrollbarSize : 0.0f)); + viewListChildSize.y - frameSize.y - + (isHorizontalScroll ? ImGui::GetStyle().ScrollbarSize * 2.0f : 0.0f)); auto rectMin = windowDrawList->GetClipRectMin(); auto rectMax = windowDrawList->GetClipRectMax(); @@ -1623,7 +1633,8 @@ namespace anm2ed::imgui ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2()); if (ImGui::Begin(localize.get(LABEL_TIMELINE_WINDOW), &settings.windowIsTimeline)) { - isWindowHovered = ImGui::IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows); + isWindowHovered = ImGui::IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows | + ImGuiHoveredFlags_AllowWhenBlockedByActiveItem); frames_child(); items_child(); } @@ -1853,12 +1864,14 @@ namespace anm2ed::imgui if (shortcut(manager.chords[SHORTCUT_MOVE_PLAYHEAD_BACK], shortcut::GLOBAL)) { + playback_stop(); playback.decrement(settings.playbackIsClamp ? animation->frameNum : anm2::FRAME_NUM_MAX); document.frameTime = playback.time; } if (shortcut(manager.chords[SHORTCUT_MOVE_PLAYHEAD_FORWARD], shortcut::GLOBAL)) { + playback_stop(); playback.increment(settings.playbackIsClamp ? animation->frameNum : anm2::FRAME_NUM_MAX); document.frameTime = playback.time; } diff --git a/src/imgui/window/timeline.h b/src/imgui/window/timeline.hpp similarity index 91% rename from src/imgui/window/timeline.h rename to src/imgui/window/timeline.hpp index bf6c670..d75910c 100644 --- a/src/imgui/window/timeline.h +++ b/src/imgui/window/timeline.hpp @@ -2,11 +2,11 @@ #include -#include "clipboard.h" -#include "manager.h" -#include "resources.h" -#include "settings.h" -#include "strings.h" +#include "clipboard.hpp" +#include "manager.hpp" +#include "resources.hpp" +#include "settings.hpp" +#include "strings.hpp" namespace anm2ed::imgui { diff --git a/src/imgui/window/tools.cpp b/src/imgui/window/tools.cpp index b2773fa..3432da0 100644 --- a/src/imgui/window/tools.cpp +++ b/src/imgui/window/tools.cpp @@ -1,11 +1,11 @@ -#include "tools.h" +#include "tools.hpp" #include -#include "strings.h" -#include "tool.h" -#include "types.h" +#include "strings.hpp" +#include "tool.hpp" +#include "types.hpp" using namespace anm2ed::resource; using namespace anm2ed::types; diff --git a/src/imgui/window/tools.h b/src/imgui/window/tools.hpp similarity index 76% rename from src/imgui/window/tools.h rename to src/imgui/window/tools.hpp index 6f74f72..e6e8831 100644 --- a/src/imgui/window/tools.h +++ b/src/imgui/window/tools.hpp @@ -1,9 +1,9 @@ #pragma once -#include "manager.h" -#include "resources.h" -#include "settings.h" -#include "strings.h" +#include "manager.hpp" +#include "resources.hpp" +#include "settings.hpp" +#include "strings.hpp" namespace anm2ed::imgui { diff --git a/src/imgui/window/welcome.cpp b/src/imgui/window/welcome.cpp index 2d546fa..59b9524 100644 --- a/src/imgui/window/welcome.cpp +++ b/src/imgui/window/welcome.cpp @@ -1,9 +1,9 @@ -#include "welcome.h" +#include "welcome.hpp" #include -#include "path_.h" -#include "strings.h" +#include "path_.hpp" +#include "strings.hpp" using namespace anm2ed::util; using namespace anm2ed::resource; diff --git a/src/imgui/window/welcome.h b/src/imgui/window/welcome.hpp similarity index 72% rename from src/imgui/window/welcome.h rename to src/imgui/window/welcome.hpp index d0d8f9f..3a43f20 100644 --- a/src/imgui/window/welcome.h +++ b/src/imgui/window/welcome.hpp @@ -1,9 +1,9 @@ #pragma once -#include "documents.h" -#include "manager.h" -#include "strings.h" -#include "taskbar.h" +#include "documents.hpp" +#include "manager.hpp" +#include "strings.hpp" +#include "taskbar.hpp" namespace anm2ed::imgui { diff --git a/src/imgui/wizard/about.cpp b/src/imgui/wizard/about.cpp index 0d53840..301b6c4 100644 --- a/src/imgui/wizard/about.cpp +++ b/src/imgui/wizard/about.cpp @@ -1,10 +1,10 @@ -#include "about.h" +#include "about.hpp" #include #include #include -#include "strings.h" +#include "strings.hpp" using namespace anm2ed::resource; diff --git a/src/imgui/wizard/about.h b/src/imgui/wizard/about.hpp similarity index 94% rename from src/imgui/wizard/about.h rename to src/imgui/wizard/about.hpp index d1dcbcc..6722dd7 100644 --- a/src/imgui/wizard/about.h +++ b/src/imgui/wizard/about.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../../resources.h" +#include "../../resources.hpp" namespace anm2ed::imgui::wizard { diff --git a/src/imgui/wizard/change_all_frame_properties.cpp b/src/imgui/wizard/change_all_frame_properties.cpp index 4ce3e51..f346a20 100644 --- a/src/imgui/wizard/change_all_frame_properties.cpp +++ b/src/imgui/wizard/change_all_frame_properties.cpp @@ -1,9 +1,9 @@ -#include "change_all_frame_properties.h" +#include "change_all_frame_properties.hpp" #include #include -#include "math_.h" +#include "math_.hpp" using namespace anm2ed::util::math; using namespace glm; diff --git a/src/imgui/wizard/change_all_frame_properties.h b/src/imgui/wizard/change_all_frame_properties.hpp similarity index 77% rename from src/imgui/wizard/change_all_frame_properties.h rename to src/imgui/wizard/change_all_frame_properties.hpp index f5143ee..555472a 100644 --- a/src/imgui/wizard/change_all_frame_properties.h +++ b/src/imgui/wizard/change_all_frame_properties.hpp @@ -1,7 +1,7 @@ #pragma once -#include "document.h" -#include "settings.h" +#include "document.hpp" +#include "settings.hpp" namespace anm2ed::imgui::wizard { diff --git a/src/imgui/wizard/configure.cpp b/src/imgui/wizard/configure.cpp index 5c075d2..5e3dc0b 100644 --- a/src/imgui/wizard/configure.cpp +++ b/src/imgui/wizard/configure.cpp @@ -1,6 +1,6 @@ -#include "configure.h" +#include "configure.hpp" -#include "imgui_.h" +#include "imgui_.hpp" using namespace anm2ed::types; @@ -23,6 +23,9 @@ namespace anm2ed::imgui::wizard 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"); 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::SetItemTooltip("%s", localize.get(TOOLTIP_VSYNC)); @@ -205,4 +208,4 @@ namespace anm2ed::imgui::wizard if (ImGui::Button(localize.get(LABEL_CLOSE), widgetSize)) isSet = true; ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_CLOSE_SETTINGS)); } -} \ No newline at end of file +} diff --git a/src/imgui/wizard/configure.h b/src/imgui/wizard/configure.hpp similarity index 90% rename from src/imgui/wizard/configure.h rename to src/imgui/wizard/configure.hpp index 98840a5..9a4c4e5 100644 --- a/src/imgui/wizard/configure.h +++ b/src/imgui/wizard/configure.hpp @@ -1,6 +1,6 @@ #pragma once -#include "manager.h" +#include "manager.hpp" namespace anm2ed::imgui::wizard { diff --git a/src/imgui/wizard/generate_animation_from_grid.cpp b/src/imgui/wizard/generate_animation_from_grid.cpp index 97083c6..3c9ba64 100644 --- a/src/imgui/wizard/generate_animation_from_grid.cpp +++ b/src/imgui/wizard/generate_animation_from_grid.cpp @@ -1,7 +1,7 @@ -#include "generate_animation_from_grid.h" +#include "generate_animation_from_grid.hpp" -#include "math_.h" -#include "types.h" +#include "math_.hpp" +#include "types.hpp" using namespace anm2ed::types; using namespace anm2ed::util; diff --git a/src/imgui/wizard/generate_animation_from_grid.h b/src/imgui/wizard/generate_animation_from_grid.hpp similarity index 71% rename from src/imgui/wizard/generate_animation_from_grid.h rename to src/imgui/wizard/generate_animation_from_grid.hpp index ca398bf..88d0330 100644 --- a/src/imgui/wizard/generate_animation_from_grid.h +++ b/src/imgui/wizard/generate_animation_from_grid.hpp @@ -1,9 +1,9 @@ #pragma once -#include "canvas.h" -#include "document.h" -#include "resources.h" -#include "settings.h" +#include "canvas.hpp" +#include "document.hpp" +#include "resources.hpp" +#include "settings.hpp" namespace anm2ed::imgui::wizard { diff --git a/src/imgui/wizard/render_animation.cpp b/src/imgui/wizard/render_animation.cpp index a616b2a..1e976d9 100644 --- a/src/imgui/wizard/render_animation.cpp +++ b/src/imgui/wizard/render_animation.cpp @@ -1,13 +1,13 @@ -#include "render_animation.h" +#include "render_animation.hpp" #include #include -#include "imgui_.h" -#include "log.h" -#include "path_.h" -#include "process_.h" -#include "toast.h" +#include "imgui_.hpp" +#include "log.hpp" +#include "path_.hpp" +#include "process_.hpp" +#include "toast.hpp" using namespace anm2ed::resource; using namespace anm2ed::util; diff --git a/src/imgui/wizard/render_animation.h b/src/imgui/wizard/render_animation.hpp similarity index 82% rename from src/imgui/wizard/render_animation.h rename to src/imgui/wizard/render_animation.hpp index 77f20da..d80e460 100644 --- a/src/imgui/wizard/render_animation.h +++ b/src/imgui/wizard/render_animation.hpp @@ -1,8 +1,8 @@ #pragma once -#include "dialog.h" -#include "manager.h" -#include "resources.h" +#include "dialog.hpp" +#include "manager.hpp" +#include "resources.hpp" namespace anm2ed::imgui::wizard { diff --git a/src/loader.cpp b/src/loader.cpp index 85123ee..51c64b4 100644 --- a/src/loader.cpp +++ b/src/loader.cpp @@ -1,4 +1,4 @@ -#include "loader.h" +#include "loader.hpp" #include #include @@ -9,18 +9,18 @@ #include -#include "log.h" -#include "sdl.h" +#include "log.hpp" +#include "sdl.hpp" -#include "imgui_.h" +#include "imgui_.hpp" -#include "snapshots.h" -#include "socket.h" +#include "snapshots.hpp" +#include "socket.hpp" -#include "util/math_.h" +#include "util/math_.hpp" #ifdef _WIN32 - #include "util/path_.h" + #include "util/path_.hpp" #include #include #include diff --git a/src/loader.h b/src/loader.hpp similarity index 91% rename from src/loader.h rename to src/loader.hpp index 5caeaeb..8bf9d41 100644 --- a/src/loader.h +++ b/src/loader.hpp @@ -7,8 +7,8 @@ #include -#include "settings.h" -#include "socket.h" +#include "settings.hpp" +#include "socket.hpp" namespace anm2ed { diff --git a/src/log.cpp b/src/log.cpp index f5d105e..f5a3f24 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -1,9 +1,18 @@ -#include "log.h" +#include "log.hpp" +#include #include -#include "sdl.h" -#include "time_.h" +#include "path_.hpp" +#include "sdl.hpp" +#include "time_.hpp" + +#if _WIN32 + #include + #include +#else + #include +#endif using namespace anm2ed::util; @@ -11,6 +20,7 @@ namespace anm2ed { void Logger::write_raw(const std::string& message) { + std::lock_guard lock(mutex); std::println("{}", message); 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::fatal(const std::string& message) { write(FATAL, 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 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"; } @@ -39,6 +147,7 @@ namespace anm2ed Logger::~Logger() { info("Exiting Anm2Ed"); + stderr_redirect_stop(); if (file.is_open()) file.close(); } } diff --git a/src/log.h b/src/log.hpp similarity index 83% rename from src/log.h rename to src/log.hpp index f041520..dd7e692 100644 --- a/src/log.h +++ b/src/log.hpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include namespace anm2ed { @@ -44,6 +46,16 @@ namespace anm2ed class Logger { 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: static std::filesystem::path path(); diff --git a/src/main.cpp b/src/main.cpp index 4da1214..375faca 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,5 @@ -#include "loader.h" -#include "state.h" +#include "loader.hpp" +#include "state.hpp" #ifdef _WIN32 #define SDL_MAIN_HANDLED diff --git a/src/manager.cpp b/src/manager.cpp index b631d48..15c8f51 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -1,16 +1,16 @@ -#include "manager.h" +#include "manager.hpp" #include #include #include -#include "log.h" -#include "path_.h" -#include "sdl.h" -#include "strings.h" -#include "toast.h" -#include "vector_.h" +#include "log.hpp" +#include "path_.hpp" +#include "sdl.hpp" +#include "strings.hpp" +#include "toast.hpp" +#include "vector_.hpp" using namespace anm2ed::types; using namespace anm2ed::util; diff --git a/src/manager.h b/src/manager.hpp similarity index 97% rename from src/manager.h rename to src/manager.hpp index 2dad576..7514795 100644 --- a/src/manager.h +++ b/src/manager.hpp @@ -5,9 +5,9 @@ #include #include -#include "document.h" -#include "settings.h" -#include "strings.h" +#include "document.hpp" +#include "settings.hpp" +#include "strings.hpp" namespace anm2ed { diff --git a/src/playback.cpp b/src/playback.cpp index 55a80c8..1b6508e 100644 --- a/src/playback.cpp +++ b/src/playback.cpp @@ -1,4 +1,4 @@ -#include "playback.h" +#include "playback.hpp" #include #include diff --git a/src/playback.h b/src/playback.hpp similarity index 100% rename from src/playback.h rename to src/playback.hpp diff --git a/src/render.cpp b/src/render.cpp index e14a2ee..702d98e 100644 --- a/src/render.cpp +++ b/src/render.cpp @@ -1,4 +1,4 @@ -#include "render.h" +#include "render.hpp" #include #include @@ -8,11 +8,11 @@ #include #include -#include "log.h" -#include "path_.h" -#include "process_.h" -#include "sdl.h" -#include "string_.h" +#include "log.hpp" +#include "path_.hpp" +#include "process_.hpp" +#include "sdl.hpp" +#include "string_.hpp" using namespace anm2ed::util; @@ -35,10 +35,11 @@ namespace anm2ed } bool animation_render(const std::filesystem::path& ffmpegPath, const std::filesystem::path& path, - const std::vector& framePaths, AudioStream& audioStream, - render::Type type, int fps) + const std::vector& framePaths, + const std::vector& frameDurations, AudioStream& audioStream, render::Type type, int fps) { if (framePaths.empty() || ffmpegPath.empty() || path.empty()) return false; + (void)frameDurations; fps = std::max(fps, 1); auto pathString = path::to_utf8(path); @@ -56,6 +57,8 @@ namespace anm2ed std::string audioInputArguments{}; std::string audioOutputArguments{"-an"}; std::string command{}; + auto temporaryDirectory = framePaths.front().parent_path(); + if (temporaryDirectory.empty()) temporaryDirectory = std::filesystem::temp_directory_path(); auto audio_remove = [&]() { @@ -69,8 +72,8 @@ namespace anm2ed if (type != render::GIF && !audioStream.stream.empty() && audioStream.spec.freq > 0 && audioStream.spec.channels > 0) { - auto tempFilenameUtf8 = std::format("{}.f32", pathString); - audioPath = std::filesystem::temp_directory_path() / path::from_utf8(tempFilenameUtf8); + auto tempFilenameUtf8 = std::format("anm2ed_audio_{}_{}.f32", std::hash{}(pathString), SDL_GetTicks()); + audioPath = temporaryDirectory / path::from_utf8(tempFilenameUtf8); std::ofstream audioFile(audioPath, std::ios::binary); @@ -81,8 +84,16 @@ namespace anm2ed audioFile.write(data, byteCount); audioFile.close(); - audioInputArguments = std::format("-f f32le -ar {0} -ac {1} -i \"{2}\"", audioStream.spec.freq, - audioStream.spec.channels, path::to_utf8(audioPath)); + auto sampleRate = std::max(audioStream.spec.freq, 1); + auto channels = std::max(audioStream.spec.channels, 1); + auto audioDurationFilter = std::string{}; + auto frameCount = (double)std::max((int)framePaths.size(), 1); + auto expectedDurationSeconds = frameCount / (double)fps; + if (expectedDurationSeconds > 0.0) + audioDurationFilter += std::format("apad,atrim=duration={:.9f}", expectedDurationSeconds); + + audioInputArguments = + std::format("-f f32le -ar {0} -ac {1} -i \"{2}\"", sampleRate, channels, path::to_utf8(audioPath)); switch (type) { @@ -95,6 +106,9 @@ namespace anm2ed default: break; } + + if (!audioDurationFilter.empty()) + audioOutputArguments = std::format("-af \"{}\" {}", audioDurationFilter, audioOutputArguments); } else { @@ -103,7 +117,7 @@ namespace anm2ed } } - auto framesListPath = std::filesystem::temp_directory_path() / path::from_utf8(std::format( + auto framesListPath = temporaryDirectory / path::from_utf8(std::format( "anm2ed_frames_{}_{}.txt", std::hash{}(pathString), SDL_GetTicks())) ; std::ofstream framesListFile(framesListPath); if (!framesListFile) @@ -112,10 +126,12 @@ namespace anm2ed return false; } - auto frameDuration = 1.0 / (double)fps; - for (const auto& framePath : framePaths) + auto defaultFrameDuration = 1.0 / (double)fps; + for (std::size_t index = 0; index < framePaths.size(); ++index) { + auto framePath = framePaths[index]; auto framePathString = path::to_utf8(framePath); + auto frameDuration = defaultFrameDuration; framesListFile << "file '" << ffmpeg_concat_escape(framePathString) << "'\n"; framesListFile << "duration " << std::format("{:.9f}", frameDuration) << "\n"; } @@ -125,9 +141,9 @@ namespace anm2ed auto framesListPathString = path::to_utf8(framesListPath); command = std::format("\"{0}\" -y -f concat -safe 0 -i \"{1}\"", ffmpegPathString, framesListPathString); - command += std::format(" -fps_mode cfr -r {}", fps); if (!audioInputArguments.empty()) command += " " + audioInputArguments; + command += std::format(" -fps_mode cfr -r {}", fps); switch (type) { @@ -177,7 +193,15 @@ namespace anm2ed return false; } - process.close(); + auto ffmpegExitCode = process.close(); + if (ffmpegExitCode != 0) + { + logger.error(std::format("FFmpeg exited with code {} while exporting {}", ffmpegExitCode, pathString)); + std::error_code ec; + std::filesystem::remove(framesListPath, ec); + audio_remove(); + return false; + } std::error_code ec; std::filesystem::remove(framesListPath, ec); diff --git a/src/render.h b/src/render.hpp similarity index 89% rename from src/render.h rename to src/render.hpp index 5b41883..5c6639b 100644 --- a/src/render.h +++ b/src/render.hpp @@ -1,7 +1,7 @@ #pragma once -#include "audio_stream.h" -#include "texture.h" +#include "audio_stream.hpp" +#include "texture.hpp" namespace anm2ed::render { @@ -37,5 +37,6 @@ namespace anm2ed { std::filesystem::path ffmpeg_log_path(); bool animation_render(const std::filesystem::path&, const std::filesystem::path&, - const std::vector&, AudioStream&, render::Type, int); + const std::vector&, const std::vector&, AudioStream&, + render::Type, int); } diff --git a/src/resource/audio.cpp b/src/resource/audio.cpp index 41e45bc..9ea969f 100644 --- a/src/resource/audio.cpp +++ b/src/resource/audio.cpp @@ -1,9 +1,9 @@ -#include "audio.h" +#include "audio.hpp" #include #include -#include "file_.h" +#include "file_.hpp" using namespace anm2ed::util; @@ -117,6 +117,14 @@ namespace anm2ed::resource MIX_StopTrack(track, 0); } + void Audio::track_detach(MIX_Mixer* mixer) + { + if (!track) return; + if (mixer && MIX_GetTrackMixer(track) != mixer) return; + MIX_DestroyTrack(track); + track = nullptr; + } + bool Audio::is_playing() const { return track && MIX_TrackPlaying(track); } Audio::Audio(const Audio& other) diff --git a/src/resource/audio.h b/src/resource/audio.hpp similarity index 94% rename from src/resource/audio.h rename to src/resource/audio.hpp index 65301cc..f93773e 100644 --- a/src/resource/audio.h +++ b/src/resource/audio.hpp @@ -28,6 +28,7 @@ namespace anm2ed::resource bool is_valid(); void play(bool loop = false, MIX_Mixer* = nullptr); void stop(MIX_Mixer* = nullptr); + void track_detach(MIX_Mixer* = nullptr); bool is_playing() const; }; } diff --git a/src/resource/audio_stream.cpp b/src/resource/audio_stream.cpp index 885b1ce..d569d71 100644 --- a/src/resource/audio_stream.cpp +++ b/src/resource/audio_stream.cpp @@ -1,4 +1,6 @@ -#include "audio_stream.h" +#include "audio_stream.hpp" + +#include #if defined(__clang__) || defined(__GNUC__) #pragma GCC diagnostic push @@ -10,16 +12,46 @@ namespace anm2ed void AudioStream::callback(void* userData, MIX_Mixer* mixer, const SDL_AudioSpec* spec, float* pcm, int samples) { auto self = (AudioStream*)userData; + if (!self->isFirstCallbackCaptured) + { + self->firstCallbackCounter = SDL_GetPerformanceCounter(); + self->isFirstCallbackCaptured = true; + } + self->callbackSamples = samples; self->stream.insert(self->stream.end(), pcm, pcm + samples); } AudioStream::AudioStream(MIX_Mixer* mixer) { MIX_GetMixerFormat(mixer, &spec); } - void AudioStream::capture_begin(MIX_Mixer* mixer) { MIX_SetPostMixCallback(mixer, callback, this); } + void AudioStream::capture_begin(MIX_Mixer* mixer) + { + stream.clear(); + callbackSamples = 0; + captureStartCounter = SDL_GetPerformanceCounter(); + firstCallbackCounter = 0; + isFirstCallbackCaptured = false; + MIX_SetPostMixCallback(mixer, callback, this); + } void AudioStream::capture_end(MIX_Mixer* mixer) { MIX_SetPostMixCallback(mixer, nullptr, this); stream.clear(); } -} \ No newline at end of file + + double AudioStream::callback_latency_seconds_get() const + { + auto freq = std::max(spec.freq, 1); + auto channels = std::max(spec.channels, 1); + auto framesPerCallback = (double)callbackSamples / (double)channels; + return framesPerCallback / (double)freq; + } + + double AudioStream::capture_start_delay_seconds_get() const + { + if (!isFirstCallbackCaptured || captureStartCounter == 0 || firstCallbackCounter < captureStartCounter) return 0.0; + auto frequency = SDL_GetPerformanceFrequency(); + if (frequency == 0) return 0.0; + return (double)(firstCallbackCounter - captureStartCounter) / (double)frequency; + } +} diff --git a/src/resource/audio_stream.h b/src/resource/audio_stream.hpp similarity index 60% rename from src/resource/audio_stream.h rename to src/resource/audio_stream.hpp index 1cbb90f..f5fe532 100644 --- a/src/resource/audio_stream.h +++ b/src/resource/audio_stream.hpp @@ -12,9 +12,15 @@ namespace anm2ed public: std::vector stream{}; SDL_AudioSpec spec{}; + int callbackSamples{}; + Uint64 captureStartCounter{}; + Uint64 firstCallbackCounter{}; + bool isFirstCallbackCaptured{}; AudioStream(MIX_Mixer*); void capture_begin(MIX_Mixer*); void capture_end(MIX_Mixer*); + double callback_latency_seconds_get() const; + double capture_start_delay_seconds_get() const; }; -} \ No newline at end of file +} diff --git a/src/resource/font.cpp b/src/resource/font.cpp index 371ee6b..4be013d 100644 --- a/src/resource/font.cpp +++ b/src/resource/font.cpp @@ -1,4 +1,4 @@ -#include "font.h" +#include "font.hpp" namespace anm2ed::resource { diff --git a/src/resource/font.h b/src/resource/font.hpp similarity index 100% rename from src/resource/font.h rename to src/resource/font.hpp diff --git a/src/resource/icon.h b/src/resource/icon.hpp similarity index 100% rename from src/resource/icon.h rename to src/resource/icon.hpp diff --git a/src/resource/music.h b/src/resource/music.hpp similarity index 100% rename from src/resource/music.h rename to src/resource/music.hpp diff --git a/src/resource/shader.cpp b/src/resource/shader.cpp index ba1e234..db0631a 100644 --- a/src/resource/shader.cpp +++ b/src/resource/shader.cpp @@ -1,6 +1,6 @@ -#include "shader.h" +#include "shader.hpp" -#include "log.h" +#include "log.hpp" namespace anm2ed::resource { diff --git a/src/resource/shader.h b/src/resource/shader.hpp similarity index 100% rename from src/resource/shader.h rename to src/resource/shader.hpp diff --git a/src/resource/strings.cpp b/src/resource/strings.cpp index 9e2557c..1bd224d 100644 --- a/src/resource/strings.cpp +++ b/src/resource/strings.cpp @@ -1,3 +1,3 @@ -#include "strings.h" +#include "strings.hpp" anm2ed::Localizer localize; diff --git a/src/resource/strings.h b/src/resource/strings.hpp similarity index 99% rename from src/resource/strings.h rename to src/resource/strings.hpp index 646166b..b2ce13e 100644 --- a/src/resource/strings.h +++ b/src/resource/strings.hpp @@ -372,6 +372,7 @@ namespace anm2ed X(LABEL_TRANSPARENT, "Transparent", "Transparentes", "Прозрачный", "透明", "투명도") \ X(LABEL_TYPE, "Type", "Tipo", "Тип", "类型", "유형") \ X(LABEL_UI_SCALE, "UI Scale", "Escala de la Interfaz", "Размер UI", "界面缩放", "UI 비율") \ + X(LABEL_ITEM_HEIGHT, "Item Height", "Altura del Item", "Высота элемента", "项目高度", "항목 높이") \ X(LABEL_USE_DEFAULT_SETTINGS, "Use Default Settings", "Usar Opciones Predeterminadas", "Изпользовать настройки по умолчанию", "使用默认设置", "기본값으로 사용") \ X(LABEL_VALUE_COLUMN, "Value", "Valor", "Значение", "数值", "값") \ X(LABEL_VSYNC, "Vsync", "Vsync", "Вертикальная синхронизация (V-sync)", "垂直同步", "수직 동기화") \ @@ -618,7 +619,7 @@ namespace anm2ed X(TOOLTIP_SET_TO_RECOMMENDED, "Use a recommended value for rows/columns.", "Usa un valor recomendado para las filas/columnas.", "Использовать рекомендованное значение для рядов/колонн.", "应用列/行的推荐值.", "행/열에 권장값을 사용합니다.") \ X(TOOLTIP_SPLIT, "Based on the playhead time, split the selected frame into two.", "Basado en tiempo del encabezado de reproduccion, divide el Frame seleccionado en dos.", "С учётом позиции ползунка воспроизведения разделяет выбранный кадр на два.", "根据播放头位置,将所选帧拆分成两个。", "재생 헤드 시간에 따라 선택한 프레임을 두 개로 분할합니다.") \ X(TOOLTIP_SIZE, "Change the crop size the frame uses.", "Cambia el tamaño de recorte que usa el Frame.", "Изменить размер обрезки, который использует этот кадр.", "更改此帧的裁剪大小.", "프레임에 대응되는 스프라이트 시트의 사용 영역의 크기를 변경합니다.") \ - X(TOOLTIP_SOUND, "Toggle sounds playing with triggers.\nBind sounds to events in the Events window.", "Alterna los sonidos reproduciendoce con triggers.\nEnlaza sonidos a eventos en la Ventana de Eventos.", "Переключить воспроизведения звуков с помощью триггеров.\nПривязывайте звуки к событиям в окне событий.", "切换是否在触发器触发时播放声音.\n可以在事件窗口里链接声音与事件.", "트리거와 함께 사운드를 재생할지 정합니다.\n사운드는 이벤트 창에서 이벤트에 연결하세요.") \ + X(TOOLTIP_SOUND, "Toggle sounds playing with triggers.\nSet a trigger's sounds in Frame Properties.", "Alterna los sonidos reproducidos con triggers.\nConfigura los sonidos de un trigger en Propiedades de Frame.", "Переключить воспроизведение звуков у триггеров.\nНастраивайте звуки триггера в свойствах кадра.", "切换是否在触发器触发时播放声音.\n可在帧属性中设置触发器的声音.", "트리거와 함께 사운드를 재생할지 정합니다.\n트리거 사운드는 프레임 속성에서 설정하세요.") \ X(TEXT_SOUND_PLAY, "Click to play.", "Click para reproducir.", "Нажмите, чтобы возпроизвести.", "点击播放.", "클릭하여 재생합니다.") \ X(TOOLTIP_SOUND_INVALID, "This sound could not be loaded. Replace the file.", "Este sonido no se pudo cargar. Reemplaza el archivo.", "Этот звук не удалось загрузить. Замените файл.", "无法加载此声音。请替换文件。", "이 사운드를 불러올 수 없습니다. 파일을 교체하세요.") \ X(TOOLTIP_SOUND_ADD, "Add a sound.", "Añadir un sonido.", "Добавить звук.", "添加一个声音.", "사운드를 추가합니다.") \ @@ -650,6 +651,7 @@ namespace anm2ed X(TOOLTIP_REMOVE_TRIGGER_SOUND, "Remove the last trigger sound.", "Remover el último sonido del trigger.", "Удалить последний звук триггера.", "移除最后一个事件触发器声音.", "마지막 트리거 사운드를 제거합니다.") \ X(TOOLTIP_TRIGGER_VISIBILITY, "Toggle the trigger's visibility.", "Alterna la visibilidad del trigger.", "Переключить видимость триггера.", "切换触发器是否可见.", "트리거를 표시하거나 숨깁니다.") \ X(TOOLTIP_UI_SCALE, "Change the scale of the UI.", "Cambia la escala de la interfaz de usuario.", "Изменить масштаб пользовательского интерфейса.", "更改界面(UI)的缩放.", "UI 비율을 변경합니다.") \ + X(TOOLTIP_ITEM_HEIGHT, "Set the height of items in Timeline.", "Establece la altura de los items en la Línea de tiempo.", "Установить высоту элементов на таймлайне.", "设置时间轴中项目的高度.", "타임라인 항목의 높이를 설정합니다.") \ X(TOOLTIP_UNUSED_ITEMS_HIDDEN, "Unused layers/nulls are hidden. Press to show them.", "Las capas/nulls no utilizados estan ocultos. Presiona para hacerlos visibles", "Неиспользуемые слои/нули скрыты. Нажмите, чтобы их показать.", "正在隐藏未使用的动画层/Null. 点击以显示它们.", "사용되지 않는 레이어/Null이 숨겨져 있습니다. 표시하려면 누르세요.") \ X(TOOLTIP_UNUSED_ITEMS_SHOWN, "Unused layers/nulls are shown. Press to hide them.", "Las capas/nulls no utilizados estan visibles. Presiona para ocultarlos", "Неиспользуемые слои/нули видимы. Нажмите, чтобы их скрыть.", "正在显示未使用的动画层/Null. 点击以隐藏它们.", "사용되지 않는 레이어/Null이 표시되어 있습니다. 숨기려면 누르세요.") \ X(TOOLTIP_USE_DEFAULT_SETTINGS, "Reset the settings to their defaults.", "Reinicia las configuraciones a sus predeterminados.", "Сбросить настройки на настройки по умолчанию.", "重设所有设置为默认.", "설정을 기본값으로 재설정합니다.") \ diff --git a/src/resource/texture.cpp b/src/resource/texture.cpp index 381f8a9..122bef3 100644 --- a/src/resource/texture.cpp +++ b/src/resource/texture.cpp @@ -1,4 +1,4 @@ -#include "texture.h" +#include "texture.hpp" #include #include @@ -23,8 +23,8 @@ #pragma GCC diagnostic pop #endif -#include "file_.h" -#include "math_.h" +#include "file_.hpp" +#include "math_.hpp" using namespace anm2ed::resource::texture; using namespace anm2ed::util::math; diff --git a/src/resource/texture.h b/src/resource/texture.hpp similarity index 100% rename from src/resource/texture.h rename to src/resource/texture.hpp diff --git a/src/resources.cpp b/src/resources.cpp index 6bf5168..58e5bfe 100644 --- a/src/resources.cpp +++ b/src/resources.cpp @@ -1,9 +1,9 @@ -#include "resources.h" +#include "resources.hpp" #include -#include "log.h" -#include "music.h" +#include "log.hpp" +#include "music.hpp" using namespace anm2ed::resource; diff --git a/src/resources.h b/src/resources.hpp similarity index 80% rename from src/resources.h rename to src/resources.hpp index 7e7a0d8..8e9b20f 100644 --- a/src/resources.h +++ b/src/resources.hpp @@ -2,11 +2,11 @@ #include -#include "audio.h" -#include "font.h" -#include "icon.h" -#include "shader.h" -#include "texture.h" +#include "audio.hpp" +#include "font.hpp" +#include "icon.hpp" +#include "shader.hpp" +#include "texture.hpp" namespace anm2ed { diff --git a/src/settings.cpp b/src/settings.cpp index 643d119..be984d5 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1,10 +1,10 @@ -#include "settings.h" +#include "settings.hpp" #include #include -#include "log.h" -#include "path_.h" +#include "log.hpp" +#include "path_.hpp" using namespace anm2ed::util; using namespace glm; diff --git a/src/settings.h b/src/settings.hpp similarity index 99% rename from src/settings.h rename to src/settings.hpp index a14cc19..bc6cf49 100644 --- a/src/settings.h +++ b/src/settings.hpp @@ -5,11 +5,11 @@ #include -#include "anm2/anm2_type.h" -#include "origin.h" -#include "render.h" -#include "strings.h" -#include "types.h" +#include "anm2/anm2_type.hpp" +#include "origin.hpp" +#include "render.hpp" +#include "strings.hpp" +#include "types.hpp" namespace anm2ed { @@ -55,6 +55,7 @@ namespace anm2ed X(WINDOW_POSITION, windowPosition, STRING_UNDEFINED, IVEC2, glm::ivec2()) \ X(IS_VSYNC, isVsync, STRING_UNDEFINED, BOOL, true) \ X(UI_SCALE, uiScale, STRING_UNDEFINED, FLOAT, 1.0f) \ + X(TIMELINE_ITEM_HEIGHT, timelineItemHeight, STRING_UNDEFINED, FLOAT, 1.0f) \ X(THEME, theme, STRING_UNDEFINED, INT, types::theme::DARK) \ X(LANGUAGE, language, STRING_UNDEFINED, INT, ENGLISH) \ \ diff --git a/src/snapshots.cpp b/src/snapshots.cpp index 08c304d..5ffdf6a 100644 --- a/src/snapshots.cpp +++ b/src/snapshots.cpp @@ -1,4 +1,4 @@ -#include "snapshots.h" +#include "snapshots.hpp" #include diff --git a/src/snapshots.h b/src/snapshots.hpp similarity index 94% rename from src/snapshots.h rename to src/snapshots.hpp index 62a2230..a5fce63 100644 --- a/src/snapshots.h +++ b/src/snapshots.hpp @@ -3,9 +3,9 @@ #include #include -#include "anm2/anm2.h" -#include "playback.h" -#include "storage.h" +#include "anm2/anm2.hpp" +#include "playback.hpp" +#include "storage.hpp" namespace anm2ed::snapshots { diff --git a/src/socket.cpp b/src/socket.cpp index e4bc500..33025c3 100644 --- a/src/socket.cpp +++ b/src/socket.cpp @@ -1,4 +1,4 @@ -#include "socket.h" +#include "socket.hpp" #include diff --git a/src/socket.h b/src/socket.hpp similarity index 100% rename from src/socket.h rename to src/socket.hpp diff --git a/src/state.cpp b/src/state.cpp index 5c1e12a..8668bcc 100644 --- a/src/state.cpp +++ b/src/state.cpp @@ -1,4 +1,4 @@ -#include "state.h" +#include "state.hpp" #include @@ -7,10 +7,10 @@ #include #include -#include "log.h" -#include "path_.h" -#include "strings.h" -#include "toast.h" +#include "log.hpp" +#include "path_.hpp" +#include "strings.hpp" +#include "toast.hpp" using namespace anm2ed::imgui; using namespace anm2ed::util; @@ -37,6 +37,30 @@ namespace anm2ed void State::update(SDL_Window*& window, Settings& settings) { + /* + ImGui_ImplSDL3_NewFrame(); + ImGui_ImplOpenGL3_NewFrame(); + ImGui::NewFrame(); + + SDL_GetWindowSize(window, &settings.windowSize.x, &settings.windowSize.y); + SDL_GetWindowPosition(window, &settings.windowPosition.x, &settings.windowPosition.y); + + SDL_Event event{}; + + while (SDL_PollEvent(&event)) + { + switch (event.type) + { + case SDL_EVENT_QUIT: + isQuit = true; + default: + break; + } + } + + dockspace.update(taskbar, documents, manager, settings, resources, dialog, clipboard); + */ + SDL_Event event{}; while (SDL_PollEvent(&event)) @@ -135,6 +159,31 @@ namespace anm2ed { auto currentTick = SDL_GetTicks(); auto currentUpdate = SDL_GetTicks(); + auto isRecording = manager.isRecording; + auto tickIntervalMs = (double)TICK_INTERVAL; + + if (isRecording) + { + if (auto document = manager.get()) + { + auto fps = std::max(document->anm2.info.fps, 1); + tickIntervalMs = std::max(1.0, 1000.0 / (double)fps); + } + } + + if (isRecording != wasRecording) + { + // Drop any accumulated backlog when entering/leaving recording mode. + tickAccumulatorMs = 0.0; + previousTick = currentTick; + wasRecording = isRecording; + } + + if (previousTick == 0) previousTick = currentTick; + auto tickDeltaMs = currentTick - previousTick; + tickDeltaMs = std::min(tickDeltaMs, 250); + tickAccumulatorMs += (double)tickDeltaMs; + previousTick = currentTick; if (currentUpdate - previousUpdate >= UPDATE_INTERVAL) { @@ -143,10 +192,10 @@ namespace anm2ed previousUpdate = currentUpdate; } - if (currentTick - previousTick >= TICK_INTERVAL) + if (tickAccumulatorMs >= tickIntervalMs) { tick(settings); - previousTick = currentTick; + tickAccumulatorMs -= tickIntervalMs; } SDL_Delay(1); diff --git a/src/state.h b/src/state.hpp similarity index 88% rename from src/state.h rename to src/state.hpp index d36270e..200791e 100644 --- a/src/state.h +++ b/src/state.hpp @@ -2,7 +2,7 @@ #include -#include "dockspace.h" +#include "dockspace.hpp" namespace anm2ed { @@ -26,6 +26,8 @@ namespace anm2ed uint64_t previousTick{}; uint64_t previousUpdate{}; + double tickAccumulatorMs{}; + bool wasRecording{}; State(SDL_Window*&, Settings& settings, std::vector&); diff --git a/src/storage.cpp b/src/storage.cpp index 8001965..98e1a81 100644 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -1,4 +1,4 @@ -#include "storage.h" +#include "storage.hpp" #include diff --git a/src/storage.h b/src/storage.hpp similarity index 94% rename from src/storage.h rename to src/storage.hpp index dd0dc04..f8382f7 100644 --- a/src/storage.h +++ b/src/storage.hpp @@ -1,6 +1,6 @@ #pragma once -#include "imgui_.h" +#include "imgui_.hpp" namespace anm2ed { diff --git a/src/tool.h b/src/tool.hpp similarity index 96% rename from src/tool.h rename to src/tool.hpp index 478e128..74266c7 100644 --- a/src/tool.h +++ b/src/tool.hpp @@ -1,8 +1,8 @@ #pragma once -#include "icon.h" -#include "settings.h" -#include "strings.h" +#include "icon.hpp" +#include "settings.hpp" +#include "strings.hpp" namespace anm2ed::tool { diff --git a/src/types.h b/src/types.hpp similarity index 99% rename from src/types.h rename to src/types.hpp index cd7c4d8..f85f154 100644 --- a/src/types.h +++ b/src/types.hpp @@ -4,7 +4,7 @@ #include #include -#include "strings.h" +#include "strings.hpp" namespace anm2ed::types::theme { diff --git a/src/util/file_.cpp b/src/util/file_.cpp index f67887b..f41ae11 100644 --- a/src/util/file_.cpp +++ b/src/util/file_.cpp @@ -1,4 +1,4 @@ -#include "file_.h" +#include "file_.hpp" namespace anm2ed::util { diff --git a/src/util/file_.h b/src/util/file_.hpp similarity index 100% rename from src/util/file_.h rename to src/util/file_.hpp diff --git a/src/util/map_.h b/src/util/map_.hpp similarity index 100% rename from src/util/map_.h rename to src/util/map_.hpp diff --git a/src/util/math_.cpp b/src/util/math_.cpp index f553fa9..fb0f158 100644 --- a/src/util/math_.cpp +++ b/src/util/math_.cpp @@ -1,4 +1,4 @@ -#include "math.h" +#include "math_.hpp" #include #include @@ -80,4 +80,4 @@ namespace anm2ed::util::math float random() { return (float)rand() / RAND_MAX; } float random_in_range(float min, float max) { return min + random() * (max - min); } void random_seed_set() { srand(std::time(nullptr)); } -} \ No newline at end of file +} diff --git a/src/util/math_.h b/src/util/math_.hpp similarity index 100% rename from src/util/math_.h rename to src/util/math_.hpp diff --git a/src/util/origin.h b/src/util/origin.hpp similarity index 100% rename from src/util/origin.h rename to src/util/origin.hpp diff --git a/src/util/path_.cpp b/src/util/path_.cpp index a98188a..b9baad2 100644 --- a/src/util/path_.cpp +++ b/src/util/path_.cpp @@ -1,4 +1,4 @@ -#include "path_.h" +#include "path_.hpp" #include #include diff --git a/src/util/path_.h b/src/util/path_.hpp similarity index 100% rename from src/util/path_.h rename to src/util/path_.hpp diff --git a/src/util/process_.cpp b/src/util/process_.cpp index fa4cfe3..2a74ee8 100644 --- a/src/util/process_.cpp +++ b/src/util/process_.cpp @@ -1,4 +1,4 @@ -#include "process_.h" +#include "process_.hpp" #ifdef WIN32 #include diff --git a/src/util/process_.h b/src/util/process_.hpp similarity index 100% rename from src/util/process_.h rename to src/util/process_.hpp diff --git a/src/util/sdl.cpp b/src/util/sdl.cpp index a4ff66a..4a229bf 100644 --- a/src/util/sdl.cpp +++ b/src/util/sdl.cpp @@ -1,8 +1,8 @@ -#include "sdl.h" +#include "sdl.hpp" #include -#include "path_.h" +#include "path_.hpp" namespace anm2ed::util::sdl { diff --git a/src/util/sdl.h b/src/util/sdl.hpp similarity index 100% rename from src/util/sdl.h rename to src/util/sdl.hpp diff --git a/src/util/string_.cpp b/src/util/string_.cpp index ae1af0a..4bb3da2 100644 --- a/src/util/string_.cpp +++ b/src/util/string_.cpp @@ -1,4 +1,4 @@ -#include "string_.h" +#include "string_.hpp" #include diff --git a/src/util/string_.h b/src/util/string_.hpp similarity index 100% rename from src/util/string_.h rename to src/util/string_.hpp diff --git a/src/util/time_.cpp b/src/util/time_.cpp index 96021c4..f16b9e4 100644 --- a/src/util/time_.cpp +++ b/src/util/time_.cpp @@ -1,4 +1,4 @@ -#include "time_.h" +#include "time_.hpp" #include diff --git a/src/util/time_.h b/src/util/time_.hpp similarity index 100% rename from src/util/time_.h rename to src/util/time_.hpp diff --git a/src/util/unordered_map_.h b/src/util/unordered_map_.hpp similarity index 100% rename from src/util/unordered_map_.h rename to src/util/unordered_map_.hpp diff --git a/src/util/vector_.h b/src/util/vector_.hpp similarity index 100% rename from src/util/vector_.h rename to src/util/vector_.hpp diff --git a/src/util/working_directory.cpp b/src/util/working_directory.cpp index 42118cf..644940c 100644 --- a/src/util/working_directory.cpp +++ b/src/util/working_directory.cpp @@ -1,9 +1,9 @@ -#include "working_directory.h" +#include "working_directory.hpp" #include -#include "log.h" -#include "path_.h" +#include "log.hpp" +#include "path_.hpp" namespace anm2ed::util { diff --git a/src/util/working_directory.h b/src/util/working_directory.hpp similarity index 100% rename from src/util/working_directory.h rename to src/util/working_directory.hpp diff --git a/src/util/xml_.cpp b/src/util/xml_.cpp index 787ce72..24d709e 100644 --- a/src/util/xml_.cpp +++ b/src/util/xml_.cpp @@ -1,7 +1,7 @@ -#include "xml_.h" +#include "xml_.hpp" -#include "math_.h" -#include "path_.h" +#include "math_.hpp" +#include "path_.hpp" using namespace anm2ed::util; using namespace tinyxml2; diff --git a/src/util/xml_.h b/src/util/xml_.hpp similarity index 100% rename from src/util/xml_.h rename to src/util/xml_.hpp