From 2d27b7e8fbe124a653231fa35255e8e7168b77a1 Mon Sep 17 00:00:00 2001 From: shweet Date: Mon, 9 Mar 2026 23:08:57 -0400 Subject: [PATCH 1/7] staging some future refactoring, .h -> hpp, fix for rendering w/ audio --- src/anm2/{animation.h => animation.hpp} | 0 src/anm2/{animations.h => animations.hpp} | 0 src/anm2/{anm2.h => anm2.hpp} | 0 src/anm2/{anm2_type.h => anm2_type.hpp} | 0 src/anm2/{content.h => content.hpp} | 0 src/anm2/{event.h => event.hpp} | 0 src/anm2/{frame.h => frame.hpp} | 0 src/anm2/{info.h => info.hpp} | 0 src/anm2/{item.h => item.hpp} | 0 src/anm2/{layer.h => layer.hpp} | 0 src/anm2/{null.h => null.hpp} | 0 src/anm2/{sound.h => sound.hpp} | 0 src/anm2/{spritesheet.h => spritesheet.hpp} | 0 src/{canvas.h => canvas.hpp} | 0 src/{clipboard.h => clipboard.hpp} | 0 src/{dialog.h => dialog.hpp} | 0 src/{document.h => document.hpp} | 0 src/{framebuffer.h => framebuffer.hpp} | 0 src/imgui/{dockspace.h => dockspace.hpp} | 0 src/imgui/{documents.h => documents.hpp} | 0 src/imgui/{imgui_.h => imgui_.hpp} | 0 src/imgui/{taskbar.h => taskbar.hpp} | 0 src/imgui/{toast.h => toast.hpp} | 0 src/imgui/window/{animation_preview.h => animation_preview.hpp} | 0 src/imgui/window/{animations.h => animations.hpp} | 0 src/imgui/window/{events.h => events.hpp} | 0 src/imgui/window/{frame_properties.h => frame_properties.hpp} | 0 src/imgui/window/{layers.h => layers.hpp} | 0 src/imgui/window/{nulls.h => nulls.hpp} | 0 src/imgui/window/{onionskin.h => onionskin.hpp} | 0 src/imgui/window/{regions.h => regions.hpp} | 0 src/imgui/window/{sounds.h => sounds.hpp} | 0 src/imgui/window/{spritesheet_editor.h => spritesheet_editor.hpp} | 0 src/imgui/window/{spritesheets.h => spritesheets.hpp} | 0 src/imgui/window/{timeline.h => timeline.hpp} | 0 src/imgui/window/{tools.h => tools.hpp} | 0 src/imgui/window/{welcome.h => welcome.hpp} | 0 src/imgui/wizard/{about.h => about.hpp} | 0 ...nge_all_frame_properties.h => change_all_frame_properties.hpp} | 0 src/imgui/wizard/{configure.h => configure.hpp} | 0 ...ate_animation_from_grid.h => generate_animation_from_grid.hpp} | 0 src/imgui/wizard/{render_animation.h => render_animation.hpp} | 0 src/{loader.h => loader.hpp} | 0 src/{log.h => log.hpp} | 0 src/{manager.h => manager.hpp} | 0 src/{playback.h => playback.hpp} | 0 src/{render.h => render.hpp} | 0 src/resource/{audio.h => audio.hpp} | 0 src/resource/{audio_stream.h => audio_stream.hpp} | 0 src/resource/{font.h => font.hpp} | 0 src/resource/{icon.h => icon.hpp} | 0 src/resource/{music.h => music.hpp} | 0 src/resource/{shader.h => shader.hpp} | 0 src/resource/{strings.h => strings.hpp} | 0 src/resource/{texture.h => texture.hpp} | 0 src/{resources.h => resources.hpp} | 0 src/{settings.h => settings.hpp} | 0 src/{snapshots.h => snapshots.hpp} | 0 src/{socket.h => socket.hpp} | 0 src/{state.h => state.hpp} | 0 src/{storage.h => storage.hpp} | 0 src/{tool.h => tool.hpp} | 0 src/{types.h => types.hpp} | 0 src/util/{file_.h => file_.hpp} | 0 src/util/{map_.h => map_.hpp} | 0 src/util/{math_.h => math_.hpp} | 0 src/util/{origin.h => origin.hpp} | 0 src/util/{path_.h => path_.hpp} | 0 src/util/{process_.h => process_.hpp} | 0 src/util/{sdl.h => sdl.hpp} | 0 src/util/{string_.h => string_.hpp} | 0 src/util/{time_.h => time_.hpp} | 0 src/util/{unordered_map_.h => unordered_map_.hpp} | 0 src/util/{vector_.h => vector_.hpp} | 0 src/util/{working_directory.h => working_directory.hpp} | 0 src/util/{xml_.h => xml_.hpp} | 0 76 files changed, 0 insertions(+), 0 deletions(-) rename src/anm2/{animation.h => animation.hpp} (100%) rename src/anm2/{animations.h => animations.hpp} (100%) rename src/anm2/{anm2.h => anm2.hpp} (100%) rename src/anm2/{anm2_type.h => anm2_type.hpp} (100%) rename src/anm2/{content.h => content.hpp} (100%) rename src/anm2/{event.h => event.hpp} (100%) rename src/anm2/{frame.h => frame.hpp} (100%) rename src/anm2/{info.h => info.hpp} (100%) rename src/anm2/{item.h => item.hpp} (100%) rename src/anm2/{layer.h => layer.hpp} (100%) rename src/anm2/{null.h => null.hpp} (100%) rename src/anm2/{sound.h => sound.hpp} (100%) rename src/anm2/{spritesheet.h => spritesheet.hpp} (100%) rename src/{canvas.h => canvas.hpp} (100%) rename src/{clipboard.h => clipboard.hpp} (100%) rename src/{dialog.h => dialog.hpp} (100%) rename src/{document.h => document.hpp} (100%) rename src/{framebuffer.h => framebuffer.hpp} (100%) rename src/imgui/{dockspace.h => dockspace.hpp} (100%) rename src/imgui/{documents.h => documents.hpp} (100%) rename src/imgui/{imgui_.h => imgui_.hpp} (100%) rename src/imgui/{taskbar.h => taskbar.hpp} (100%) rename src/imgui/{toast.h => toast.hpp} (100%) rename src/imgui/window/{animation_preview.h => animation_preview.hpp} (100%) rename src/imgui/window/{animations.h => animations.hpp} (100%) rename src/imgui/window/{events.h => events.hpp} (100%) rename src/imgui/window/{frame_properties.h => frame_properties.hpp} (100%) rename src/imgui/window/{layers.h => layers.hpp} (100%) rename src/imgui/window/{nulls.h => nulls.hpp} (100%) rename src/imgui/window/{onionskin.h => onionskin.hpp} (100%) rename src/imgui/window/{regions.h => regions.hpp} (100%) rename src/imgui/window/{sounds.h => sounds.hpp} (100%) rename src/imgui/window/{spritesheet_editor.h => spritesheet_editor.hpp} (100%) rename src/imgui/window/{spritesheets.h => spritesheets.hpp} (100%) rename src/imgui/window/{timeline.h => timeline.hpp} (100%) rename src/imgui/window/{tools.h => tools.hpp} (100%) rename src/imgui/window/{welcome.h => welcome.hpp} (100%) rename src/imgui/wizard/{about.h => about.hpp} (100%) rename src/imgui/wizard/{change_all_frame_properties.h => change_all_frame_properties.hpp} (100%) rename src/imgui/wizard/{configure.h => configure.hpp} (100%) rename src/imgui/wizard/{generate_animation_from_grid.h => generate_animation_from_grid.hpp} (100%) rename src/imgui/wizard/{render_animation.h => render_animation.hpp} (100%) rename src/{loader.h => loader.hpp} (100%) rename src/{log.h => log.hpp} (100%) rename src/{manager.h => manager.hpp} (100%) rename src/{playback.h => playback.hpp} (100%) rename src/{render.h => render.hpp} (100%) rename src/resource/{audio.h => audio.hpp} (100%) rename src/resource/{audio_stream.h => audio_stream.hpp} (100%) rename src/resource/{font.h => font.hpp} (100%) rename src/resource/{icon.h => icon.hpp} (100%) rename src/resource/{music.h => music.hpp} (100%) rename src/resource/{shader.h => shader.hpp} (100%) rename src/resource/{strings.h => strings.hpp} (100%) rename src/resource/{texture.h => texture.hpp} (100%) rename src/{resources.h => resources.hpp} (100%) rename src/{settings.h => settings.hpp} (100%) rename src/{snapshots.h => snapshots.hpp} (100%) rename src/{socket.h => socket.hpp} (100%) rename src/{state.h => state.hpp} (100%) rename src/{storage.h => storage.hpp} (100%) rename src/{tool.h => tool.hpp} (100%) rename src/{types.h => types.hpp} (100%) rename src/util/{file_.h => file_.hpp} (100%) rename src/util/{map_.h => map_.hpp} (100%) rename src/util/{math_.h => math_.hpp} (100%) rename src/util/{origin.h => origin.hpp} (100%) rename src/util/{path_.h => path_.hpp} (100%) rename src/util/{process_.h => process_.hpp} (100%) rename src/util/{sdl.h => sdl.hpp} (100%) rename src/util/{string_.h => string_.hpp} (100%) rename src/util/{time_.h => time_.hpp} (100%) rename src/util/{unordered_map_.h => unordered_map_.hpp} (100%) rename src/util/{vector_.h => vector_.hpp} (100%) rename src/util/{working_directory.h => working_directory.hpp} (100%) rename src/util/{xml_.h => xml_.hpp} (100%) diff --git a/src/anm2/animation.h b/src/anm2/animation.hpp similarity index 100% rename from src/anm2/animation.h rename to src/anm2/animation.hpp diff --git a/src/anm2/animations.h b/src/anm2/animations.hpp similarity index 100% rename from src/anm2/animations.h rename to src/anm2/animations.hpp diff --git a/src/anm2/anm2.h b/src/anm2/anm2.hpp similarity index 100% rename from src/anm2/anm2.h rename to src/anm2/anm2.hpp diff --git a/src/anm2/anm2_type.h b/src/anm2/anm2_type.hpp similarity index 100% rename from src/anm2/anm2_type.h rename to src/anm2/anm2_type.hpp diff --git a/src/anm2/content.h b/src/anm2/content.hpp similarity index 100% rename from src/anm2/content.h rename to src/anm2/content.hpp 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.h b/src/anm2/frame.hpp similarity index 100% rename from src/anm2/frame.h rename to src/anm2/frame.hpp 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.h b/src/anm2/item.hpp similarity index 100% rename from src/anm2/item.h rename to src/anm2/item.hpp 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.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.h b/src/anm2/sound.hpp similarity index 100% rename from src/anm2/sound.h rename to src/anm2/sound.hpp diff --git a/src/anm2/spritesheet.h b/src/anm2/spritesheet.hpp similarity index 100% rename from src/anm2/spritesheet.h rename to src/anm2/spritesheet.hpp diff --git a/src/canvas.h b/src/canvas.hpp similarity index 100% rename from src/canvas.h rename to src/canvas.hpp 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.h b/src/dialog.hpp similarity index 100% rename from src/dialog.h rename to src/dialog.hpp diff --git a/src/document.h b/src/document.hpp similarity index 100% rename from src/document.h rename to src/document.hpp 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.h b/src/imgui/dockspace.hpp similarity index 100% rename from src/imgui/dockspace.h rename to src/imgui/dockspace.hpp diff --git a/src/imgui/documents.h b/src/imgui/documents.hpp similarity index 100% rename from src/imgui/documents.h rename to src/imgui/documents.hpp diff --git a/src/imgui/imgui_.h b/src/imgui/imgui_.hpp similarity index 100% rename from src/imgui/imgui_.h rename to src/imgui/imgui_.hpp diff --git a/src/imgui/taskbar.h b/src/imgui/taskbar.hpp similarity index 100% rename from src/imgui/taskbar.h rename to src/imgui/taskbar.hpp 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.h b/src/imgui/window/animation_preview.hpp similarity index 100% rename from src/imgui/window/animation_preview.h rename to src/imgui/window/animation_preview.hpp diff --git a/src/imgui/window/animations.h b/src/imgui/window/animations.hpp similarity index 100% rename from src/imgui/window/animations.h rename to src/imgui/window/animations.hpp diff --git a/src/imgui/window/events.h b/src/imgui/window/events.hpp similarity index 100% rename from src/imgui/window/events.h rename to src/imgui/window/events.hpp diff --git a/src/imgui/window/frame_properties.h b/src/imgui/window/frame_properties.hpp similarity index 100% rename from src/imgui/window/frame_properties.h rename to src/imgui/window/frame_properties.hpp diff --git a/src/imgui/window/layers.h b/src/imgui/window/layers.hpp similarity index 100% rename from src/imgui/window/layers.h rename to src/imgui/window/layers.hpp diff --git a/src/imgui/window/nulls.h b/src/imgui/window/nulls.hpp similarity index 100% rename from src/imgui/window/nulls.h rename to src/imgui/window/nulls.hpp diff --git a/src/imgui/window/onionskin.h b/src/imgui/window/onionskin.hpp similarity index 100% rename from src/imgui/window/onionskin.h rename to src/imgui/window/onionskin.hpp diff --git a/src/imgui/window/regions.h b/src/imgui/window/regions.hpp similarity index 100% rename from src/imgui/window/regions.h rename to src/imgui/window/regions.hpp diff --git a/src/imgui/window/sounds.h b/src/imgui/window/sounds.hpp similarity index 100% rename from src/imgui/window/sounds.h rename to src/imgui/window/sounds.hpp diff --git a/src/imgui/window/spritesheet_editor.h b/src/imgui/window/spritesheet_editor.hpp similarity index 100% rename from src/imgui/window/spritesheet_editor.h rename to src/imgui/window/spritesheet_editor.hpp diff --git a/src/imgui/window/spritesheets.h b/src/imgui/window/spritesheets.hpp similarity index 100% rename from src/imgui/window/spritesheets.h rename to src/imgui/window/spritesheets.hpp diff --git a/src/imgui/window/timeline.h b/src/imgui/window/timeline.hpp similarity index 100% rename from src/imgui/window/timeline.h rename to src/imgui/window/timeline.hpp diff --git a/src/imgui/window/tools.h b/src/imgui/window/tools.hpp similarity index 100% rename from src/imgui/window/tools.h rename to src/imgui/window/tools.hpp diff --git a/src/imgui/window/welcome.h b/src/imgui/window/welcome.hpp similarity index 100% rename from src/imgui/window/welcome.h rename to src/imgui/window/welcome.hpp diff --git a/src/imgui/wizard/about.h b/src/imgui/wizard/about.hpp similarity index 100% rename from src/imgui/wizard/about.h rename to src/imgui/wizard/about.hpp diff --git a/src/imgui/wizard/change_all_frame_properties.h b/src/imgui/wizard/change_all_frame_properties.hpp similarity index 100% rename from src/imgui/wizard/change_all_frame_properties.h rename to src/imgui/wizard/change_all_frame_properties.hpp diff --git a/src/imgui/wizard/configure.h b/src/imgui/wizard/configure.hpp similarity index 100% rename from src/imgui/wizard/configure.h rename to src/imgui/wizard/configure.hpp diff --git a/src/imgui/wizard/generate_animation_from_grid.h b/src/imgui/wizard/generate_animation_from_grid.hpp similarity index 100% rename from src/imgui/wizard/generate_animation_from_grid.h rename to src/imgui/wizard/generate_animation_from_grid.hpp diff --git a/src/imgui/wizard/render_animation.h b/src/imgui/wizard/render_animation.hpp similarity index 100% rename from src/imgui/wizard/render_animation.h rename to src/imgui/wizard/render_animation.hpp diff --git a/src/loader.h b/src/loader.hpp similarity index 100% rename from src/loader.h rename to src/loader.hpp diff --git a/src/log.h b/src/log.hpp similarity index 100% rename from src/log.h rename to src/log.hpp diff --git a/src/manager.h b/src/manager.hpp similarity index 100% rename from src/manager.h rename to src/manager.hpp 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.h b/src/render.hpp similarity index 100% rename from src/render.h rename to src/render.hpp diff --git a/src/resource/audio.h b/src/resource/audio.hpp similarity index 100% rename from src/resource/audio.h rename to src/resource/audio.hpp diff --git a/src/resource/audio_stream.h b/src/resource/audio_stream.hpp similarity index 100% rename from src/resource/audio_stream.h rename to src/resource/audio_stream.hpp 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.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.h b/src/resource/strings.hpp similarity index 100% rename from src/resource/strings.h rename to src/resource/strings.hpp 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.h b/src/resources.hpp similarity index 100% rename from src/resources.h rename to src/resources.hpp diff --git a/src/settings.h b/src/settings.hpp similarity index 100% rename from src/settings.h rename to src/settings.hpp diff --git a/src/snapshots.h b/src/snapshots.hpp similarity index 100% rename from src/snapshots.h rename to src/snapshots.hpp 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.h b/src/state.hpp similarity index 100% rename from src/state.h rename to src/state.hpp diff --git a/src/storage.h b/src/storage.hpp similarity index 100% rename from src/storage.h rename to src/storage.hpp diff --git a/src/tool.h b/src/tool.hpp similarity index 100% rename from src/tool.h rename to src/tool.hpp diff --git a/src/types.h b/src/types.hpp similarity index 100% rename from src/types.h rename to src/types.hpp 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_.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_.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_.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.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_.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_.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.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_.h b/src/util/xml_.hpp similarity index 100% rename from src/util/xml_.h rename to src/util/xml_.hpp From c11b404392933560a876e2f1c3cbdb62d4d15deb Mon Sep 17 00:00:00 2001 From: shweet Date: Mon, 9 Mar 2026 23:09:37 -0400 Subject: [PATCH 2/7] let's actually stage those changes... --- .vscode/launch.json | 6 +- .vscode/tasks.json | 12 +- CMakeLists.txt | 23 +- CMakeSettings.json | 6 +- src/anm2/animation.cpp | 10 +- src/anm2/animation.hpp | 2 +- src/anm2/animations.cpp | 4 +- src/anm2/animations.hpp | 2 +- src/anm2/anm2.cpp | 14 +- src/anm2/anm2.hpp | 8 +- src/anm2/anm2_animations.cpp | 4 +- src/anm2/anm2_events.cpp | 4 +- src/anm2/anm2_items.cpp | 8 +- src/anm2/anm2_layers.cpp | 4 +- src/anm2/anm2_nulls.cpp | 4 +- src/anm2/anm2_sounds.cpp | 8 +- src/anm2/anm2_spritesheets.cpp | 8 +- src/anm2/anm2_type.hpp | 4 +- src/anm2/content.cpp | 2 +- src/anm2/content.hpp | 10 +- src/anm2/event.cpp | 4 +- src/anm2/frame.cpp | 6 +- src/anm2/frame.hpp | 4 +- src/anm2/info.cpp | 4 +- src/anm2/item.cpp | 6 +- src/anm2/item.hpp | 2 +- src/anm2/layer.cpp | 4 +- src/anm2/null.cpp | 4 +- src/anm2/sound.cpp | 8 +- src/anm2/sound.hpp | 2 +- src/anm2/spritesheet.cpp | 10 +- src/anm2/spritesheet.hpp | 8 +- src/anm2_new/anm2.cpp | 603 ++++++++++++++++++ src/anm2_new/anm2.hpp | 90 +++ src/canvas.cpp | 4 +- src/canvas.hpp | 6 +- src/clipboard.cpp | 2 +- src/dialog.cpp | 10 +- src/document.cpp | 10 +- src/document.hpp | 2 +- src/framebuffer.cpp | 4 +- src/imgui/dockspace.cpp | 2 +- src/imgui/dockspace.hpp | 32 +- src/imgui/documents.cpp | 12 +- src/imgui/documents.hpp | 10 +- src/imgui/imgui_.cpp | 6 +- src/imgui/imgui_.hpp | 4 +- src/imgui/taskbar.cpp | 14 +- src/imgui/taskbar.hpp | 24 +- src/imgui/toast.cpp | 6 +- src/imgui/window/animation_preview.cpp | 31 +- src/imgui/window/animation_preview.hpp | 10 +- src/imgui/window/animations.cpp | 10 +- src/imgui/window/animations.hpp | 10 +- src/imgui/window/events.cpp | 10 +- src/imgui/window/events.hpp | 8 +- src/imgui/window/frame_properties.cpp | 8 +- src/imgui/window/frame_properties.hpp | 4 +- src/imgui/window/layers.cpp | 10 +- src/imgui/window/layers.hpp | 8 +- src/imgui/window/nulls.cpp | 10 +- src/imgui/window/nulls.hpp | 8 +- src/imgui/window/onionskin.cpp | 6 +- src/imgui/window/onionskin.hpp | 2 +- src/imgui/window/regions.cpp | 20 +- src/imgui/window/regions.hpp | 8 +- src/imgui/window/sounds.cpp | 10 +- src/imgui/window/sounds.hpp | 10 +- src/imgui/window/spritesheet_editor.cpp | 12 +- src/imgui/window/spritesheet_editor.hpp | 8 +- src/imgui/window/spritesheets.cpp | 14 +- src/imgui/window/spritesheets.hpp | 10 +- src/imgui/window/timeline.cpp | 8 +- src/imgui/window/timeline.hpp | 10 +- src/imgui/window/tools.cpp | 8 +- src/imgui/window/tools.hpp | 8 +- src/imgui/window/welcome.cpp | 6 +- src/imgui/window/welcome.hpp | 8 +- src/imgui/wizard/about.cpp | 4 +- src/imgui/wizard/about.hpp | 2 +- .../wizard/change_all_frame_properties.cpp | 4 +- .../wizard/change_all_frame_properties.hpp | 4 +- src/imgui/wizard/configure.cpp | 4 +- src/imgui/wizard/configure.hpp | 2 +- .../wizard/generate_animation_from_grid.cpp | 6 +- .../wizard/generate_animation_from_grid.hpp | 8 +- src/imgui/wizard/render_animation.cpp | 12 +- src/imgui/wizard/render_animation.hpp | 6 +- src/imgui_new/anm2_window.cpp | 16 + src/imgui_new/anm2_window.hpp | 12 + src/loader.cpp | 16 +- src/loader.hpp | 4 +- src/log.cpp | 6 +- src/main.cpp | 4 +- src/manager.cpp | 14 +- src/manager.hpp | 6 +- src/playback.cpp | 2 +- src/render.cpp | 30 +- src/render.hpp | 4 +- src/resource/audio.cpp | 4 +- src/resource/audio_stream.cpp | 2 +- src/resource/font.cpp | 2 +- src/resource/shader.cpp | 4 +- src/resource/strings.cpp | 2 +- src/resource/texture.cpp | 6 +- src/resources.cpp | 6 +- src/resources.hpp | 10 +- src/settings.cpp | 6 +- src/settings.hpp | 10 +- src/snapshots.cpp | 2 +- src/snapshots.hpp | 6 +- src/socket.cpp | 2 +- src/state.cpp | 34 +- src/state.hpp | 2 +- src/storage.cpp | 2 +- src/storage.hpp | 2 +- src/tool.hpp | 6 +- src/types.hpp | 2 +- src/util/file_.cpp | 2 +- src/util/math_.cpp | 4 +- src/util/path_.cpp | 2 +- src/util/process_.cpp | 2 +- src/util/sdl.cpp | 4 +- src/util/string_.cpp | 2 +- src/util/time_.cpp | 2 +- src/util/working_directory.cpp | 6 +- src/util/xml_.cpp | 6 +- 127 files changed, 1200 insertions(+), 427 deletions(-) create mode 100644 src/anm2_new/anm2.cpp create mode 100644 src/anm2_new/anm2.hpp create mode 100644 src/imgui_new/anm2_window.cpp create mode 100644 src/imgui_new/anm2_window.hpp diff --git a/.vscode/launch.json b/.vscode/launch.json index dd8dffe..ad226b0 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,7 @@ "name": "Debug", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/build/anm2ed", + "program": "${workspaceFolder}/out/build/linux-debug/bin/anm2ed", "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", @@ -28,7 +28,7 @@ "name": "Release", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/build-release/anm2ed", + "program": "${workspaceFolder}/out/build/linux-release/bin/anm2ed", "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", @@ -48,4 +48,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 98e27be..fb2d21f 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -2,9 +2,9 @@ "version": "2.0.0", "tasks": [ { - "label": "build", + "label": "build-debug", "type": "shell", - "command": "cmake --build build --target anm2ed", + "command": "cmake -S . -B out/build/linux-debug -DCMAKE_BUILD_TYPE=Debug && cmake --build out/build/linux-debug --target anm2ed", "group": { "kind": "build", "isDefault": true @@ -16,11 +16,17 @@ { "label": "build-release", "type": "shell", - "command": "cmake -S . -B build-release -DCMAKE_BUILD_TYPE=Release && cmake --build build-release --target anm2ed", + "command": "cmake -S . -B out/build/linux-release -DCMAKE_BUILD_TYPE=Release && cmake --build out/build/linux-release --target anm2ed", "group": "build", "problemMatcher": [ "$gcc" ] + }, + { + "label": "build", + "dependsOn": "build-debug", + "group": "build", + "problemMatcher": [] } ] } 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.hpp b/src/anm2/animation.hpp index 9725a90..727f73e 100644 --- a/src/anm2/animation.hpp +++ 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.hpp b/src/anm2/animations.hpp index 2db0454..29bf0f0 100644 --- a/src/anm2/animations.hpp +++ 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 9c80f54..c9e9585 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.hpp b/src/anm2/anm2.hpp index e931450..3ffe3ff 100644 --- a/src/anm2/anm2.hpp +++ 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 aed2f7b..b62cb87 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..e4b55ae 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; diff --git a/src/anm2/anm2_type.hpp b/src/anm2/anm2_type.hpp index 7ac3615..d80ced3 100644 --- a/src/anm2/anm2_type.hpp +++ 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.hpp b/src/anm2/content.hpp index 551aa44..17094bf 100644 --- a/src/anm2/content.hpp +++ 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/frame.cpp b/src/anm2/frame.cpp index 736c882..7295b97 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.hpp b/src/anm2/frame.hpp index c642296..bb33a1f 100644 --- a/src/anm2/frame.hpp +++ 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/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.hpp b/src/anm2/item.hpp index 5e1e082..0ca0a12 100644 --- a/src/anm2/item.hpp +++ 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/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/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.hpp b/src/anm2/sound.hpp index 4a55e33..3271b58 100644 --- a/src/anm2/sound.hpp +++ 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..5c9034f 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; diff --git a/src/anm2/spritesheet.hpp b/src/anm2/spritesheet.hpp index b51ecf3..4a906f1 100644 --- a/src/anm2/spritesheet.hpp +++ 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/anm2_new/anm2.cpp b/src/anm2_new/anm2.cpp new file mode 100644 index 0000000..ce237dd --- /dev/null +++ b/src/anm2_new/anm2.cpp @@ -0,0 +1,603 @@ +#include "anm2.hpp" + +#include +#include +#include +#include + +#include "../log.hpp" +#include "../util/path_.hpp" +#include "../util/working_directory.hpp" +#include "../util/xml_.hpp" + +using namespace tinyxml2; +using namespace anm2ed::util; + +namespace anm2ed::resource::anm2_new +{ + Anm2::Item::Item(XMLElement* element, Type _type) + { + if (!element) return; + + type = _type; + + auto isFrameOwnerType = + _type == ROOT_ANIMATION || _type == LAYER_ANIMATION || _type == NULL_ANIMATION || _type == TRIGGERS; + auto isFrameLikeElement = + element->Name() && (std::strcmp(element->Name(), "Frame") == 0 || std::strcmp(element->Name(), "Trigger") == 0); + + if (isFrameOwnerType && isFrameLikeElement) + { + ownerType = _type; + type = _type == TRIGGERS ? TRIGGER : FRAME; + + switch (_type) + { + case ROOT_ANIMATION: + case NULL_ANIMATION: + element->QueryFloatAttribute("XPosition", &position.x); + element->QueryFloatAttribute("YPosition", &position.y); + element->QueryFloatAttribute("XScale", &scale.x); + element->QueryFloatAttribute("YScale", &scale.y); + element->QueryIntAttribute("Delay", &duration); + element->QueryBoolAttribute("Visible", &isVisible); + xml::query_color_attribute(element, "RedTint", tint.r); + xml::query_color_attribute(element, "GreenTint", tint.g); + xml::query_color_attribute(element, "BlueTint", tint.b); + xml::query_color_attribute(element, "AlphaTint", tint.a); + xml::query_color_attribute(element, "RedOffset", colorOffset.r); + xml::query_color_attribute(element, "GreenOffset", colorOffset.g); + xml::query_color_attribute(element, "BlueOffset", colorOffset.b); + element->QueryFloatAttribute("Rotation", &rotation); + element->QueryBoolAttribute("Interpolated", &isInterpolated); + break; + case LAYER_ANIMATION: + element->QueryIntAttribute("RegionId", ®ionID); + element->QueryFloatAttribute("XPosition", &position.x); + element->QueryFloatAttribute("YPosition", &position.y); + element->QueryFloatAttribute("XPivot", &pivot.x); + element->QueryFloatAttribute("YPivot", &pivot.y); + element->QueryFloatAttribute("XCrop", &crop.x); + element->QueryFloatAttribute("YCrop", &crop.y); + element->QueryFloatAttribute("Width", &size.x); + element->QueryFloatAttribute("Height", &size.y); + element->QueryFloatAttribute("XScale", &scale.x); + element->QueryFloatAttribute("YScale", &scale.y); + element->QueryIntAttribute("Delay", &duration); + element->QueryBoolAttribute("Visible", &isVisible); + xml::query_color_attribute(element, "RedTint", tint.r); + xml::query_color_attribute(element, "GreenTint", tint.g); + xml::query_color_attribute(element, "BlueTint", tint.b); + xml::query_color_attribute(element, "AlphaTint", tint.a); + xml::query_color_attribute(element, "RedOffset", colorOffset.r); + xml::query_color_attribute(element, "GreenOffset", colorOffset.g); + xml::query_color_attribute(element, "BlueOffset", colorOffset.b); + element->QueryFloatAttribute("Rotation", &rotation); + element->QueryBoolAttribute("Interpolated", &isInterpolated); + break; + case TRIGGERS: + { + element->QueryIntAttribute("EventId", &eventID); + element->QueryIntAttribute("AtFrame", &atFrame); + int soundID{}; + if (element->QueryIntAttribute("SoundId", &soundID) == XML_SUCCESS) soundIDs.push_back(soundID); + for (auto* child = element->FirstChildElement("Sound"); child; child = child->NextSiblingElement("Sound")) + if (child->QueryIntAttribute("Id", &soundID) == XML_SUCCESS) soundIDs.push_back(soundID); + break; + } + default: + break; + } + + return; + } + + switch (_type) + { + case INFO: + xml::query_string_attribute(element, "CreatedBy", &createdBy); + xml::query_string_attribute(element, "CreatedOn", &createdOn); + element->QueryIntAttribute("Fps", &fps); + element->QueryIntAttribute("Version", &version); + break; + case SPRITESHEET: + element->QueryIntAttribute("Id", &id); + xml::query_path_attribute(element, "Path", &path); + path = util::path::lower_case_backslash_handle(path); + texture = Texture(path); + break; + case REGION: + { + element->QueryIntAttribute("Id", &id); + xml::query_string_attribute(element, "Name", &name); + element->QueryFloatAttribute("XCrop", &crop.x); + element->QueryFloatAttribute("YCrop", &crop.y); + element->QueryFloatAttribute("Width", &size.x); + element->QueryFloatAttribute("Height", &size.y); + + auto* origin = element->Attribute("Origin"); + if (origin && std::string(origin) == "TopLeft") + pivot = {}; + else if (origin && std::string(origin) == "Center") + pivot = glm::vec2((int)(size.x / 2.0f), (int)(size.y / 2.0f)); + else + { + element->QueryFloatAttribute("XPivot", &pivot.x); + element->QueryFloatAttribute("YPivot", &pivot.y); + } + break; + } + case LAYER: + element->QueryIntAttribute("Id", &id); + xml::query_string_attribute(element, "Name", &name); + element->QueryIntAttribute("SpritesheetId", &spritesheetID); + break; + case NULL_: + element->QueryIntAttribute("Id", &id); + xml::query_string_attribute(element, "Name", &name); + element->QueryBoolAttribute("ShowRect", &isShowRect); + break; + case EVENT: + element->QueryIntAttribute("Id", &id); + xml::query_string_attribute(element, "Name", &name); + break; + case SOUND: + element->QueryIntAttribute("Id", &id); + xml::query_path_attribute(element, "Path", &path); + path = util::path::lower_case_backslash_handle(path); + sound = Audio(path); + break; + case ANIMATION: + xml::query_string_attribute(element, "Name", &name); + element->QueryIntAttribute("FrameNum", &frameNum); + element->QueryBoolAttribute("Loop", &isLoop); + break; + case ROOT_ANIMATION: + case TRIGGERS: + break; + case LAYER_ANIMATION: + element->QueryIntAttribute("LayerId", &itemID); + element->QueryBoolAttribute("Visible", &isVisible); + break; + case NULL_ANIMATION: + element->QueryIntAttribute("NullId", &itemID); + element->QueryBoolAttribute("Visible", &isVisible); + break; + case FRAME: + case TRIGGER: + default: + break; + } + } + + XMLElement* Anm2::Item::to_element(XMLDocument& document) const + { + switch (type) + { + case INFO: + { + auto* element = document.NewElement("Info"); + element->SetAttribute("CreatedBy", createdBy.c_str()); + element->SetAttribute("CreatedOn", createdOn.c_str()); + element->SetAttribute("Fps", fps); + element->SetAttribute("Version", version); + return element; + } + case SPRITESHEET: + { + auto* element = document.NewElement("Spritesheet"); + element->SetAttribute("Id", id); + auto pathString = util::path::to_utf8(path); + element->SetAttribute("Path", pathString.c_str()); + return element; + } + case REGION: + { + auto* element = document.NewElement("Region"); + element->SetAttribute("Id", id); + element->SetAttribute("Name", name.c_str()); + element->SetAttribute("XCrop", crop.x); + element->SetAttribute("YCrop", crop.y); + element->SetAttribute("Width", size.x); + element->SetAttribute("Height", size.y); + element->SetAttribute("XPivot", pivot.x); + element->SetAttribute("YPivot", pivot.y); + return element; + } + case LAYER: + { + auto* element = document.NewElement("Layer"); + element->SetAttribute("Id", id); + element->SetAttribute("Name", name.c_str()); + element->SetAttribute("SpritesheetId", spritesheetID); + return element; + } + case NULL_: + { + auto* element = document.NewElement("Null"); + element->SetAttribute("Id", id); + element->SetAttribute("Name", name.c_str()); + if (isShowRect) element->SetAttribute("ShowRect", isShowRect); + return element; + } + case EVENT: + { + auto* element = document.NewElement("Event"); + element->SetAttribute("Id", id); + element->SetAttribute("Name", name.c_str()); + return element; + } + case SOUND: + { + auto* element = document.NewElement("Sound"); + element->SetAttribute("Id", id); + auto pathString = util::path::to_utf8(path); + element->SetAttribute("Path", pathString.c_str()); + return element; + } + case ANIMATION: + { + auto* element = document.NewElement("Animation"); + element->SetAttribute("Name", name.c_str()); + element->SetAttribute("FrameNum", frameNum); + element->SetAttribute("Loop", isLoop); + return element; + } + case ROOT_ANIMATION: + return document.NewElement("RootAnimation"); + case LAYER_ANIMATION: + { + auto* element = document.NewElement("LayerAnimation"); + element->SetAttribute("LayerId", itemID); + element->SetAttribute("Visible", isVisible); + return element; + } + case NULL_ANIMATION: + { + auto* element = document.NewElement("NullAnimation"); + element->SetAttribute("NullId", itemID); + element->SetAttribute("Visible", isVisible); + return element; + } + case TRIGGERS: + return document.NewElement("Triggers"); + case TRIGGER: + { + auto* element = document.NewElement("Trigger"); + if (eventID != -1) element->SetAttribute("EventId", eventID); + for (auto soundID : soundIDs) + { + if (soundID == -1) continue; + auto* soundElement = element->InsertNewChildElement("Sound"); + soundElement->SetAttribute("Id", soundID); + } + element->SetAttribute("AtFrame", atFrame); + return element; + } + case FRAME: + { + auto* element = document.NewElement("Frame"); + + if (ownerType == LAYER_ANIMATION && regionID != -1) element->SetAttribute("RegionId", regionID); + element->SetAttribute("XPosition", position.x); + element->SetAttribute("YPosition", position.y); + + if (ownerType == LAYER_ANIMATION) + { + element->SetAttribute("XPivot", pivot.x); + element->SetAttribute("YPivot", pivot.y); + element->SetAttribute("XCrop", crop.x); + element->SetAttribute("YCrop", crop.y); + element->SetAttribute("Width", size.x); + element->SetAttribute("Height", size.y); + } + + element->SetAttribute("XScale", scale.x); + element->SetAttribute("YScale", scale.y); + element->SetAttribute("Delay", duration); + element->SetAttribute("Visible", isVisible); + element->SetAttribute("RedTint", (int)glm::clamp(tint.r * 255.0f, 0.0f, 255.0f)); + element->SetAttribute("GreenTint", (int)glm::clamp(tint.g * 255.0f, 0.0f, 255.0f)); + element->SetAttribute("BlueTint", (int)glm::clamp(tint.b * 255.0f, 0.0f, 255.0f)); + element->SetAttribute("AlphaTint", (int)glm::clamp(tint.a * 255.0f, 0.0f, 255.0f)); + element->SetAttribute("RedOffset", (int)glm::clamp(colorOffset.r * 255.0f, 0.0f, 255.0f)); + element->SetAttribute("GreenOffset", (int)glm::clamp(colorOffset.g * 255.0f, 0.0f, 255.0f)); + element->SetAttribute("BlueOffset", (int)glm::clamp(colorOffset.b * 255.0f, 0.0f, 255.0f)); + element->SetAttribute("Rotation", rotation); + element->SetAttribute("Interpolated", isInterpolated); + + return element; + } + default: + break; + } + + return document.NewElement("Item"); + } + + std::string Anm2::Item::to_string() const + { + XMLDocument document; + document.InsertEndChild(to_element(document)); + return xml::document_to_string(document); + } + + Anm2::Anm2(const std::filesystem::path& path) + { + XMLDocument document; + auto pathString = util::path::to_utf8(path); + + if (document.LoadFile(pathString.c_str()) != XML_SUCCESS) + { + logger.error(std::format("Failed to initialize anm2: {} ({})", pathString, document.ErrorStr())); + isValid = false; + return; + } + + WorkingDirectory workingDirectory(path, WorkingDirectory::FILE); + + this->path = path; + isValid = true; + + auto item_add = [&](Item item) { items.emplace_back(std::move(item)); }; + + if (auto* root = document.RootElement()) + { + if (auto* infoElement = root->FirstChildElement("Info")) item_add(Item(infoElement, INFO)); + + if (auto* contentElement = root->FirstChildElement("Content")) + { + if (auto* spritesheetsElement = contentElement->FirstChildElement("Spritesheets")) + { + for (auto* child = spritesheetsElement->FirstChildElement("Spritesheet"); child; + child = child->NextSiblingElement("Spritesheet")) + { + auto spritesheet = Item(child, SPRITESHEET); + auto spritesheetID = spritesheet.id; + item_add(spritesheet); + + for (auto* regionChild = child->FirstChildElement("Region"); regionChild; + regionChild = regionChild->NextSiblingElement("Region")) + { + auto region = Item(regionChild, REGION); + region.itemID = spritesheetID; + item_add(region); + } + } + } + + if (auto* layersElement = contentElement->FirstChildElement("Layers")) + for (auto* child = layersElement->FirstChildElement("Layer"); child; + child = child->NextSiblingElement("Layer")) + item_add(Item(child, LAYER)); + + if (auto* nullsElement = contentElement->FirstChildElement("Nulls")) + for (auto* child = nullsElement->FirstChildElement("Null"); child; child = child->NextSiblingElement("Null")) + item_add(Item(child, NULL_)); + + if (auto* eventsElement = contentElement->FirstChildElement("Events")) + for (auto* child = eventsElement->FirstChildElement("Event"); child; + child = child->NextSiblingElement("Event")) + item_add(Item(child, EVENT)); + + if (auto* soundsElement = contentElement->FirstChildElement("Sounds")) + for (auto* child = soundsElement->FirstChildElement("Sound"); child; + child = child->NextSiblingElement("Sound")) + item_add(Item(child, SOUND)); + } + + if (auto* animationsElement = root->FirstChildElement("Animations")) + { + int animationIndex = 0; + for (auto* animationElement = animationsElement->FirstChildElement("Animation"); animationElement; + animationElement = animationElement->NextSiblingElement("Animation")) + { + auto animation = Item(animationElement, ANIMATION); + animation.id = animationIndex++; + item_add(animation); + + if (auto* rootAnimationElement = animationElement->FirstChildElement("RootAnimation")) + { + Item rootAnimation{}; + rootAnimation.type = ROOT_ANIMATION; + rootAnimation.animationID = animation.id; + item_add(rootAnimation); + + for (auto* frameElement = rootAnimationElement->FirstChildElement("Frame"); frameElement; + frameElement = frameElement->NextSiblingElement("Frame")) + { + auto frame = Item(frameElement, ROOT_ANIMATION); + frame.animationID = animation.id; + frame.ownerID = -1; + item_add(frame); + } + } + + if (auto* layerAnimationsElement = animationElement->FirstChildElement("LayerAnimations")) + { + for (auto* layerAnimationElement = layerAnimationsElement->FirstChildElement("LayerAnimation"); + layerAnimationElement; + layerAnimationElement = layerAnimationElement->NextSiblingElement("LayerAnimation")) + { + auto layerAnimation = Item(layerAnimationElement, LAYER_ANIMATION); + layerAnimation.animationID = animation.id; + item_add(layerAnimation); + + for (auto* frameElement = layerAnimationElement->FirstChildElement("Frame"); frameElement; + frameElement = frameElement->NextSiblingElement("Frame")) + { + auto frame = Item(frameElement, LAYER_ANIMATION); + frame.animationID = animation.id; + frame.ownerID = layerAnimation.itemID; + item_add(frame); + } + } + } + + if (auto* nullAnimationsElement = animationElement->FirstChildElement("NullAnimations")) + { + for (auto* nullAnimationElement = nullAnimationsElement->FirstChildElement("NullAnimation"); + nullAnimationElement; nullAnimationElement = nullAnimationElement->NextSiblingElement("NullAnimation")) + { + auto nullAnimation = Item(nullAnimationElement, NULL_ANIMATION); + nullAnimation.animationID = animation.id; + item_add(nullAnimation); + + for (auto* frameElement = nullAnimationElement->FirstChildElement("Frame"); frameElement; + frameElement = frameElement->NextSiblingElement("Frame")) + { + auto frame = Item(frameElement, NULL_ANIMATION); + frame.animationID = animation.id; + frame.ownerID = nullAnimation.itemID; + item_add(frame); + } + } + } + + if (auto* triggersElement = animationElement->FirstChildElement("Triggers")) + { + Item triggers{}; + triggers.type = TRIGGERS; + triggers.animationID = animation.id; + item_add(triggers); + + for (auto* triggerElement = triggersElement->FirstChildElement("Trigger"); triggerElement; + triggerElement = triggerElement->NextSiblingElement("Trigger")) + { + auto trigger = Item(triggerElement, TRIGGERS); + trigger.animationID = animation.id; + trigger.ownerID = -1; + item_add(trigger); + } + } + } + } + } + + logger.info(std::format("Initialized anm2: {}", pathString)); + } + + XMLElement* Anm2::to_element(XMLDocument& document) const + { + auto* root = document.NewElement("AnimatedActor"); + auto add_frames = [&](XMLElement* parent, Type ownerType, int animationID, int ownerID) + { + for (auto& item : items) + { + if (item.type != FRAME && item.type != TRIGGER) continue; + if (item.ownerType != ownerType) continue; + if (item.animationID != animationID) continue; + if (item.ownerID != ownerID) continue; + parent->InsertEndChild(item.to_element(document)); + } + }; + + const Item* info = nullptr; + for (auto& item : items) + if (item.type == INFO) + { + info = &item; + break; + } + if (info) root->InsertEndChild(info->to_element(document)); + + auto* contentElement = document.NewElement("Content"); + auto* spritesheetsElement = document.NewElement("Spritesheets"); + auto* layersElement = document.NewElement("Layers"); + auto* nullsElement = document.NewElement("Nulls"); + auto* eventsElement = document.NewElement("Events"); + auto* soundsElement = document.NewElement("Sounds"); + + for (auto& item : items) + { + if (item.type != SPRITESHEET) continue; + auto* spritesheetElement = item.to_element(document); + for (auto& region : items) + if (region.type == REGION && region.itemID == item.id) + spritesheetElement->InsertEndChild(region.to_element(document)); + spritesheetsElement->InsertEndChild(spritesheetElement); + } + + for (auto& item : items) + if (item.type == LAYER) layersElement->InsertEndChild(item.to_element(document)); + + for (auto& item : items) + if (item.type == NULL_) nullsElement->InsertEndChild(item.to_element(document)); + + for (auto& item : items) + if (item.type == EVENT) eventsElement->InsertEndChild(item.to_element(document)); + + for (auto& item : items) + if (item.type == SOUND) soundsElement->InsertEndChild(item.to_element(document)); + + contentElement->InsertEndChild(spritesheetsElement); + contentElement->InsertEndChild(layersElement); + contentElement->InsertEndChild(nullsElement); + contentElement->InsertEndChild(eventsElement); + if (soundsElement->FirstChildElement("Sound")) contentElement->InsertEndChild(soundsElement); + root->InsertEndChild(contentElement); + + auto* animationsElement = document.NewElement("Animations"); + + for (auto& animation : items) + { + if (animation.type != ANIMATION) continue; + auto* animationElement = animation.to_element(document); + + auto* rootAnimationElement = document.NewElement("RootAnimation"); + add_frames(rootAnimationElement, ROOT_ANIMATION, animation.id, -1); + animationElement->InsertEndChild(rootAnimationElement); + + auto* layerAnimationsElement = document.NewElement("LayerAnimations"); + for (auto& layerAnimation : items) + { + if (layerAnimation.type != LAYER_ANIMATION || layerAnimation.animationID != animation.id) continue; + auto* layerAnimationElement = layerAnimation.to_element(document); + add_frames(layerAnimationElement, LAYER_ANIMATION, animation.id, layerAnimation.itemID); + layerAnimationsElement->InsertEndChild(layerAnimationElement); + } + animationElement->InsertEndChild(layerAnimationsElement); + + auto* nullAnimationsElement = document.NewElement("NullAnimations"); + for (auto& nullAnimation : items) + { + if (nullAnimation.type != NULL_ANIMATION || nullAnimation.animationID != animation.id) continue; + auto* nullAnimationElement = nullAnimation.to_element(document); + add_frames(nullAnimationElement, NULL_ANIMATION, animation.id, nullAnimation.itemID); + nullAnimationsElement->InsertEndChild(nullAnimationElement); + } + animationElement->InsertEndChild(nullAnimationsElement); + + auto* triggersElement = document.NewElement("Triggers"); + add_frames(triggersElement, TRIGGERS, animation.id, -1); + animationElement->InsertEndChild(triggersElement); + + animationsElement->InsertEndChild(animationElement); + } + + root->InsertEndChild(animationsElement); + return root; + } + + bool Anm2::serialize(const std::filesystem::path& path, std::string* errorString) const + { + XMLDocument document; + document.InsertEndChild(to_element(document)); + + auto pathString = util::path::to_utf8(path); + if (document.SaveFile(pathString.c_str()) != XML_SUCCESS) + { + if (errorString) *errorString = document.ErrorStr(); + return false; + } + + return true; + } + + std::string Anm2::to_string() const + { + XMLDocument document; + document.InsertEndChild(to_element(document)); + return xml::document_to_string(document); + } +} diff --git a/src/anm2_new/anm2.hpp b/src/anm2_new/anm2.hpp new file mode 100644 index 0000000..ace6406 --- /dev/null +++ b/src/anm2_new/anm2.hpp @@ -0,0 +1,90 @@ +#pragma once + +#include +#include +#include +#include + +#include "../resource/audio.hpp" +#include "../resource/texture.hpp" + +#include + +namespace anm2ed::resource::anm2_new +{ + class Anm2 + { + public: + enum Type + { + NONE, + INFO, + SPRITESHEET, + REGION, + LAYER, + NULL_, + EVENT, + SOUND, + ANIMATION, + ROOT_ANIMATION, + LAYER_ANIMATION, + NULL_ANIMATION, + TRIGGERS, + FRAME, + TRIGGER + }; + + class Item + { + public: + Type type{NONE}; + Type ownerType{NONE}; + std::string name{}; + bool isInterpolated{false}; + bool isLoop{false}; + bool isVisible{false}; + bool isShowRect{false}; + glm::vec2 crop{}; + glm::vec2 pivot{}; + glm::vec2 position{}; + glm::vec2 scale{100, 100}; + glm::vec2 size{}; + glm::vec3 colorOffset{}; + glm::vec4 tint{1, 1, 1, 1}; + int atFrame{-1}; + int duration{1}; + int eventID{-1}; + int fps{30}; + int frameNum{1}; + int id{-1}; + int itemID{-1}; + int ownerID{-1}; + int animationID{-1}; + int spritesheetID{-1}; + int regionID{-1}; + int version{0}; + float rotation{}; + resource::Texture texture{}; + resource::Audio sound{}; + std::filesystem::path path{}; + std::string createdBy{}; + std::string createdOn{}; + std::vector soundIDs{}; + + Item() = default; + Item(tinyxml2::XMLElement*, Type); + tinyxml2::XMLElement* to_element(tinyxml2::XMLDocument&) const; + std::string to_string() const; + }; + + std::vector items{}; + std::filesystem::path path{}; + bool isValid{false}; + + Anm2() = default; + Anm2(const std::filesystem::path&); + tinyxml2::XMLElement* to_element(tinyxml2::XMLDocument&) const; + bool serialize(const std::filesystem::path&, std::string* = nullptr) const; + std::string to_string() const; + }; +} 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.hpp b/src/canvas.hpp index 79a2cc6..f99dde7 100644 --- a/src/canvas.hpp +++ 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/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/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.hpp b/src/document.hpp index 530a14e..5e16874 100644 --- a/src/document.hpp +++ 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/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.hpp b/src/imgui/dockspace.hpp index eca62f3..8bdfd90 100644 --- a/src/imgui/dockspace.hpp +++ 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.hpp b/src/imgui/documents.hpp index 3ac52a2..319cb2e 100644 --- a/src/imgui/documents.hpp +++ 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_.hpp b/src/imgui/imgui_.hpp index 9923156..cff5a5c 100644 --- a/src/imgui/imgui_.hpp +++ 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.hpp b/src/imgui/taskbar.hpp index cd171e7..56e5a5d 100644 --- a/src/imgui/taskbar.hpp +++ 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/window/animation_preview.cpp b/src/imgui/window/animation_preview.cpp index e821ba3..e4a7a20 100644 --- a/src/imgui/window/animation_preview.cpp +++ b/src/imgui/window/animation_preview.cpp @@ -1,4 +1,4 @@ -#include "animation_preview.h" +#include "animation_preview.hpp" #include #include @@ -10,14 +10,14 @@ #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; @@ -265,11 +265,16 @@ namespace anm2ed::imgui { 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); + } } } } diff --git a/src/imgui/window/animation_preview.hpp b/src/imgui/window/animation_preview.hpp index 7c0773b..7645a4f 100644 --- a/src/imgui/window/animation_preview.hpp +++ 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 { 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.hpp b/src/imgui/window/animations.hpp index 82be436..10fa2ff 100644 --- a/src/imgui/window/animations.hpp +++ 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.hpp b/src/imgui/window/events.hpp index 5d956c5..710d284 100644 --- a/src/imgui/window/events.hpp +++ 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.hpp b/src/imgui/window/frame_properties.hpp index a5d6640..3ff82b7 100644 --- a/src/imgui/window/frame_properties.hpp +++ 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.hpp b/src/imgui/window/layers.hpp index f977fb9..4e190c5 100644 --- a/src/imgui/window/layers.hpp +++ 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.hpp b/src/imgui/window/nulls.hpp index de0c547..ceb32fe 100644 --- a/src/imgui/window/nulls.hpp +++ 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.hpp b/src/imgui/window/onionskin.hpp index df3847c..dd9489d 100644 --- a/src/imgui/window/onionskin.hpp +++ 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 8be4840..38ef50e 100644 --- a/src/imgui/window/regions.cpp +++ b/src/imgui/window/regions.cpp @@ -1,4 +1,4 @@ -#include "regions.h" +#include "regions.hpp" #include #include @@ -6,16 +6,16 @@ #include #include -#include "document.h" -#include "log.h" -#include "map_.h" -#include "math_.h" -#include "path_.h" -#include "strings.h" -#include "toast.h" -#include "vector_.h" +#include "document.hpp" +#include "log.hpp" +#include "map_.hpp" +#include "math_.hpp" +#include "path_.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.hpp b/src/imgui/window/regions.hpp index 8827467..54e3f28 100644 --- a/src/imgui/window/regions.hpp +++ 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.hpp b/src/imgui/window/sounds.hpp index 6f61b7e..f5ab6f1 100644 --- a/src/imgui/window/sounds.hpp +++ 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.hpp b/src/imgui/window/spritesheet_editor.hpp index e1a1da5..857cccc 100644 --- a/src/imgui/window/spritesheet_editor.hpp +++ 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.hpp b/src/imgui/window/spritesheets.hpp index 595448a..878b53c 100644 --- a/src/imgui/window/spritesheets.hpp +++ 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 2c206c7..76288ab 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; diff --git a/src/imgui/window/timeline.hpp b/src/imgui/window/timeline.hpp index bf6c670..d75910c 100644 --- a/src/imgui/window/timeline.hpp +++ 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.hpp b/src/imgui/window/tools.hpp index 6f74f72..e6e8831 100644 --- a/src/imgui/window/tools.hpp +++ 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.hpp b/src/imgui/window/welcome.hpp index d0d8f9f..3a43f20 100644 --- a/src/imgui/window/welcome.hpp +++ 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.hpp b/src/imgui/wizard/about.hpp index d1dcbcc..6722dd7 100644 --- a/src/imgui/wizard/about.hpp +++ 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.hpp b/src/imgui/wizard/change_all_frame_properties.hpp index f5143ee..555472a 100644 --- a/src/imgui/wizard/change_all_frame_properties.hpp +++ 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..bf91bc4 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; diff --git a/src/imgui/wizard/configure.hpp b/src/imgui/wizard/configure.hpp index 98840a5..9a4c4e5 100644 --- a/src/imgui/wizard/configure.hpp +++ 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.hpp b/src/imgui/wizard/generate_animation_from_grid.hpp index ca398bf..88d0330 100644 --- a/src/imgui/wizard/generate_animation_from_grid.hpp +++ 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.hpp b/src/imgui/wizard/render_animation.hpp index 77f20da..d80e460 100644 --- a/src/imgui/wizard/render_animation.hpp +++ 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/imgui_new/anm2_window.cpp b/src/imgui_new/anm2_window.cpp new file mode 100644 index 0000000..1b3bb66 --- /dev/null +++ b/src/imgui_new/anm2_window.cpp @@ -0,0 +1,16 @@ +#include "anm2_window.hpp" + +#include "imgui.h" + +using namespace anm2ed::resource::anm2_new; + +namespace anm2ed::imgui_new +{ + void Window::update(Anm2& anm2, Anm2::Type type, Settings& settings) + { + if (ImGui::Begin("TestWindow", &settings.windowIsEvents)) + { + } + ImGui::End(); + } +} \ No newline at end of file diff --git a/src/imgui_new/anm2_window.hpp b/src/imgui_new/anm2_window.hpp new file mode 100644 index 0000000..196a877 --- /dev/null +++ b/src/imgui_new/anm2_window.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "../anm2_new/anm2.hpp" +#include "../settings.hpp" + +namespace anm2ed::imgui_new +{ + class Window + { + void update(anm2ed::resource::anm2_new::Anm2&, anm2ed::resource::anm2_new::Anm2::Type type, Settings&); + }; +} \ No newline at end of file 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.hpp b/src/loader.hpp index 5caeaeb..8bf9d41 100644 --- a/src/loader.hpp +++ 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..19374f4 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -1,9 +1,9 @@ -#include "log.h" +#include "log.hpp" #include -#include "sdl.h" -#include "time_.h" +#include "sdl.hpp" +#include "time_.hpp" using namespace anm2ed::util; 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.hpp b/src/manager.hpp index 2dad576..7514795 100644 --- a/src/manager.hpp +++ 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/render.cpp b/src/render.cpp index 9149458..74018f5 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; @@ -56,6 +56,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 +71,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); @@ -103,7 +105,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) @@ -176,7 +178,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.hpp b/src/render.hpp index 5b41883..95d1bd8 100644 --- a/src/render.hpp +++ 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 { diff --git a/src/resource/audio.cpp b/src/resource/audio.cpp index 41e45bc..79c3699 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; diff --git a/src/resource/audio_stream.cpp b/src/resource/audio_stream.cpp index 885b1ce..2ae3dfc 100644 --- a/src/resource/audio_stream.cpp +++ b/src/resource/audio_stream.cpp @@ -1,4 +1,4 @@ -#include "audio_stream.h" +#include "audio_stream.hpp" #if defined(__clang__) || defined(__GNUC__) #pragma GCC diagnostic push 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/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/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/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/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.hpp b/src/resources.hpp index 7e7a0d8..8e9b20f 100644 --- a/src/resources.hpp +++ 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.hpp b/src/settings.hpp index a14cc19..fdbc1d3 100644 --- a/src/settings.hpp +++ 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 { 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.hpp b/src/snapshots.hpp index 62a2230..a5fce63 100644 --- a/src/snapshots.hpp +++ 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/state.cpp b/src/state.cpp index 5c1e12a..9864ea2 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)) diff --git a/src/state.hpp b/src/state.hpp index d36270e..e911559 100644 --- a/src/state.hpp +++ b/src/state.hpp @@ -2,7 +2,7 @@ #include -#include "dockspace.h" +#include "dockspace.hpp" namespace anm2ed { 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.hpp b/src/storage.hpp index dd0dc04..f8382f7 100644 --- a/src/storage.hpp +++ b/src/storage.hpp @@ -1,6 +1,6 @@ #pragma once -#include "imgui_.h" +#include "imgui_.hpp" namespace anm2ed { diff --git a/src/tool.hpp b/src/tool.hpp index 478e128..74266c7 100644 --- a/src/tool.hpp +++ 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.hpp b/src/types.hpp index cd7c4d8..f85f154 100644 --- a/src/types.hpp +++ 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/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/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/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/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/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/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/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/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; From 1b5ba6b584fffc504ffdfec4d26710311fc31979 Mon Sep 17 00:00:00 2001 From: shweet Date: Tue, 10 Mar 2026 00:36:21 -0400 Subject: [PATCH 3/7] fix audio desync for realsies, stderr to log.txt --- compile_commands.json | 2 +- src/imgui/window/animation_preview.cpp | 125 +++++++++++++++++++++++-- src/imgui/window/animation_preview.hpp | 3 + src/log.cpp | 111 +++++++++++++++++++++- src/log.hpp | 12 +++ src/render.cpp | 28 ++++-- src/render.hpp | 3 +- src/resource/audio.cpp | 8 ++ src/resource/audio.hpp | 1 + src/resource/audio_stream.cpp | 36 ++++++- src/resource/audio_stream.hpp | 8 +- src/state.cpp | 29 +++++- src/state.hpp | 2 + 13 files changed, 347 insertions(+), 21 deletions(-) diff --git a/compile_commands.json b/compile_commands.json index 5e95284..bc0dce8 120000 --- a/compile_commands.json +++ b/compile_commands.json @@ -1 +1 @@ -/home/anon/sda/Personal/Repos/anm2ed/build/compile_commands.json \ No newline at end of file +/home/anon/sda/Personal/Repos/anm2ed/out/build/linux-debug/compile_commands.json \ No newline at end of file diff --git a/src/imgui/window/animation_preview.cpp b/src/imgui/window/animation_preview.cpp index e4a7a20..bdfe0d5 100644 --- a/src/imgui/window/animation_preview.cpp +++ b/src/imgui/window/animation_preview.cpp @@ -1,9 +1,11 @@ #include "animation_preview.hpp" #include +#include #include #include #include +#include #include #include #include @@ -82,6 +84,51 @@ namespace anm2ed::imgui directory.clear(); frames.clear(); } + + 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()) {} @@ -106,6 +153,8 @@ namespace anm2ed::imgui if (playback.time > end || playback.isFinished) { + if (settings.timelineIsSound) audioStream.capture_end(mixer); + if (type == render::PNGS) { if (!renderTempFrames.empty()) @@ -185,7 +234,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), @@ -204,9 +266,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) { @@ -220,8 +288,6 @@ namespace anm2ed::imgui isCheckerPanInitialized = false; } - if (settings.timelineIsSound) audioStream.capture_end(mixer); - playback.isPlaying = false; playback.isFinished = false; manager.isRecording = false; @@ -229,6 +295,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(); @@ -237,6 +325,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 { @@ -244,6 +350,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; @@ -258,7 +366,7 @@ 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)) @@ -474,8 +582,6 @@ namespace anm2ed::imgui { savedSettings = settings; - if (settings.timelineIsSound) audioStream.capture_begin(mixer); - if (settings.renderIsRawAnimation) { settings.previewBackgroundColor = vec4(); @@ -502,6 +608,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; @@ -1033,9 +1142,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.hpp b/src/imgui/window/animation_preview.hpp index 7645a4f..152a229 100644 --- a/src/imgui/window/animation_preview.hpp +++ b/src/imgui/window/animation_preview.hpp @@ -30,6 +30,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/log.cpp b/src/log.cpp index 19374f4..f5a3f24 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -1,16 +1,26 @@ #include "log.hpp" +#include #include +#include "path_.hpp" #include "sdl.hpp" #include "time_.hpp" +#if _WIN32 + #include + #include +#else + #include +#endif + using namespace anm2ed::util; 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.hpp b/src/log.hpp index f041520..dd7e692 100644 --- a/src/log.hpp +++ 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/render.cpp b/src/render.cpp index 74018f5..008b7bf 100644 --- a/src/render.cpp +++ b/src/render.cpp @@ -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); @@ -83,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) { @@ -97,6 +106,9 @@ namespace anm2ed default: break; } + + if (!audioDurationFilter.empty()) + audioOutputArguments = std::format("-af \"{}\" {}", audioDurationFilter, audioOutputArguments); } else { @@ -114,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"; } @@ -127,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) { diff --git a/src/render.hpp b/src/render.hpp index 95d1bd8..5c6639b 100644 --- a/src/render.hpp +++ b/src/render.hpp @@ -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 79c3699..9ea969f 100644 --- a/src/resource/audio.cpp +++ b/src/resource/audio.cpp @@ -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.hpp b/src/resource/audio.hpp index 65301cc..f93773e 100644 --- a/src/resource/audio.hpp +++ 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 2ae3dfc..d569d71 100644 --- a/src/resource/audio_stream.cpp +++ b/src/resource/audio_stream.cpp @@ -1,5 +1,7 @@ #include "audio_stream.hpp" +#include + #if defined(__clang__) || defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" @@ -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.hpp b/src/resource/audio_stream.hpp index 1cbb90f..f5fe532 100644 --- a/src/resource/audio_stream.hpp +++ 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/state.cpp b/src/state.cpp index 9864ea2..8668bcc 100644 --- a/src/state.cpp +++ b/src/state.cpp @@ -159,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) { @@ -167,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.hpp b/src/state.hpp index e911559..200791e 100644 --- a/src/state.hpp +++ b/src/state.hpp @@ -26,6 +26,8 @@ namespace anm2ed uint64_t previousTick{}; uint64_t previousUpdate{}; + double tickAccumulatorMs{}; + bool wasRecording{}; State(SDL_Window*&, Settings& settings, std::vector&); From bbfafd733142946b99669f5c309301110f4dbfdd Mon Sep 17 00:00:00 2001 From: shweet Date: Sun, 15 Mar 2026 13:22:53 -0400 Subject: [PATCH 4/7] Render animation fixes, vs code tasks --- .vscode/launch.json | 2 ++ .vscode/tasks.json | 48 ++++++++++++++++++++++++-- README.md | 3 ++ src/anm2/anm2.hpp | 2 +- src/anm2/anm2_items.cpp | 26 ++++++++++---- src/anm2/frame.cpp | 5 +-- src/imgui/window/animation_preview.cpp | 22 ++++++++++++ src/imgui/window/regions.cpp | 2 -- src/imgui/window/timeline.cpp | 5 +-- src/render.cpp | 3 +- 10 files changed, 102 insertions(+), 16 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index ad226b0..cdfd141 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,6 +5,7 @@ "name": "Debug", "type": "cppdbg", "request": "launch", + "preLaunchTask": "build-debug", "program": "${workspaceFolder}/out/build/linux-debug/bin/anm2ed", "args": [], "stopAtEntry": false, @@ -28,6 +29,7 @@ "name": "Release", "type": "cppdbg", "request": "launch", + "preLaunchTask": "build-release", "program": "${workspaceFolder}/out/build/linux-release/bin/anm2ed", "args": [], "stopAtEntry": false, diff --git a/.vscode/tasks.json b/.vscode/tasks.json index fb2d21f..87f59fa 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,10 +1,32 @@ { "version": "2.0.0", "tasks": [ + { + "label": "run-debug", + "type": "shell", + "command": "cmake", + "args": [ + "-S", + ".", + "-B", + "out/build/linux-debug", + "-DCMAKE_BUILD_TYPE=Debug" + ], + "problemMatcher": [ + "$gcc" + ] + }, { "label": "build-debug", "type": "shell", - "command": "cmake -S . -B out/build/linux-debug -DCMAKE_BUILD_TYPE=Debug && cmake --build out/build/linux-debug --target anm2ed", + "command": "cmake", + "args": [ + "--build", + "out/build/linux-debug", + "--target", + "anm2ed" + ], + "dependsOn": "run-debug", "group": { "kind": "build", "isDefault": true @@ -13,10 +35,32 @@ "$gcc" ] }, + { + "label": "run-release", + "type": "shell", + "command": "cmake", + "args": [ + "-S", + ".", + "-B", + "out/build/linux-release", + "-DCMAKE_BUILD_TYPE=Release" + ], + "problemMatcher": [ + "$gcc" + ] + }, { "label": "build-release", "type": "shell", - "command": "cmake -S . -B out/build/linux-release -DCMAKE_BUILD_TYPE=Release && cmake --build out/build/linux-release --target anm2ed", + "command": "cmake", + "args": [ + "--build", + "out/build/linux-release", + "--target", + "anm2ed" + ], + "dependsOn": "run-release", "group": "build", "problemMatcher": [ "$gcc" diff --git a/README.md b/README.md index a8303a6..868f536 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,9 @@ A reimplementation of *The Binding of Isaac: Rebirth*'s proprietary animation editor. Manipulates the XML-based ".anm2" format, used for in-game tweened animations. +### Clarification +This application was partly vibe-coded by an LLM (let's say 70% me/30% AI sloppa). Sorry not sorry, I'm just lazy. + ## Features - Extended version of the original proprietary Nicalis animation editor - Smooth [Dear ImGui](https://github.com/ocornut/imgui) interface; docking, dragging and dropping, etc. You might be familiar with it from [Repentogon](https://repentogon.com/). diff --git a/src/anm2/anm2.hpp b/src/anm2/anm2.hpp index 3ffe3ff..4ac11ad 100644 --- a/src/anm2/anm2.hpp +++ b/src/anm2/anm2.hpp @@ -80,7 +80,7 @@ namespace anm2ed::anm2 bool animations_deserialize(const std::string&, int, std::set&, std::string* = nullptr); Item* item_get(int, Type, int = -1); - Reference layer_animation_add(Reference = {}, std::string = {}, int = 0, + Reference layer_animation_add(Reference = {}, int = -1, std::string = {}, int = 0, types::destination::Type = types::destination::ALL); Reference null_animation_add(Reference = {}, std::string = {}, bool = false, types::destination::Type = types::destination::ALL); diff --git a/src/anm2/anm2_items.cpp b/src/anm2/anm2_items.cpp index b62cb87..47ba193 100644 --- a/src/anm2/anm2_items.cpp +++ b/src/anm2/anm2_items.cpp @@ -30,7 +30,7 @@ namespace anm2ed::anm2 return nullptr; } - Reference Anm2::layer_animation_add(Reference reference, std::string name, int spritesheetID, + Reference Anm2::layer_animation_add(Reference reference, int insertBeforeID, std::string name, int spritesheetID, destination::Type destination) { auto id = reference.itemID == -1 ? map::next_id_get(content.layers) : reference.itemID; @@ -39,21 +39,35 @@ namespace anm2ed::anm2 layer.name = !name.empty() ? name : layer.name; layer.spritesheetID = content.spritesheets.contains(spritesheetID) ? spritesheetID : 0; - auto add = [&](Animation* animation, int id) + auto add = [&](Animation* animation, int id, bool insertBeforeReference) { animation->layerAnimations[id] = Item(); + + if (insertBeforeReference && insertBeforeID != -1) + { + auto it = std::find(animation->layerOrder.begin(), animation->layerOrder.end(), insertBeforeID); + if (it != animation->layerOrder.end()) + { + animation->layerOrder.insert(it, id); + return; + } + } + animation->layerOrder.push_back(id); }; if (destination == destination::ALL) { - for (auto& animation : animations.items) - if (!animation.layerAnimations.contains(id)) add(&animation, id); + for (size_t index = 0; index < animations.items.size(); ++index) + { + auto& animation = animations.items[index]; + if (!animation.layerAnimations.contains(id)) add(&animation, id, true); + } } else if (destination == destination::THIS) { if (auto animation = animation_get(reference.animationIndex)) - if (!animation->layerAnimations.contains(id)) add(animation, id); + if (!animation->layerAnimations.contains(id)) add(animation, id, true); } return {reference.animationIndex, LAYER, id}; @@ -82,4 +96,4 @@ namespace anm2ed::anm2 return {reference.animationIndex, NULL_, id}; } -} \ No newline at end of file +} diff --git a/src/anm2/frame.cpp b/src/anm2/frame.cpp index 7295b97..4415869 100644 --- a/src/anm2/frame.cpp +++ b/src/anm2/frame.cpp @@ -104,9 +104,10 @@ namespace anm2ed::anm2 { bool noRegions = has_flag(flags, NO_REGIONS); bool frameNoRegionValues = has_flag(flags, FRAME_NO_REGION_VALUES); - bool writeRegionValues = !frameNoRegionValues || noRegions; + bool hasValidRegion = !noRegions && regionID != -1; + bool writeRegionValues = !frameNoRegionValues || !hasValidRegion; - if (!noRegions && regionID != -1) element->SetAttribute("RegionId", regionID); + if (hasValidRegion) element->SetAttribute("RegionId", regionID); element->SetAttribute("XPosition", position.x); element->SetAttribute("YPosition", position.y); if (writeRegionValues) diff --git a/src/imgui/window/animation_preview.cpp b/src/imgui/window/animation_preview.cpp index bdfe0d5..6167df7 100644 --- a/src/imgui/window/animation_preview.cpp +++ b/src/imgui/window/animation_preview.cpp @@ -85,6 +85,27 @@ namespace anm2ed::imgui frames.clear(); } + void pixels_unpremultiply_alpha(std::vector& pixels) + { + for (size_t index = 0; index + 3 < pixels.size(); index += 4) + { + auto alpha = pixels[index + 3]; + if (alpha == 0) + { + pixels[index + 0] = 0; + pixels[index + 1] = 0; + pixels[index + 2] = 0; + continue; + } + if (alpha == 255) continue; + + float alphaUnit = (float)alpha / 255.0f; + pixels[index + 0] = (uint8_t)glm::clamp((float)std::round((float)pixels[index + 0] / alphaUnit), 0.0f, 255.0f); + pixels[index + 1] = (uint8_t)glm::clamp((float)std::round((float)pixels[index + 1] / alphaUnit), 0.0f, 255.0f); + pixels[index + 2] = (uint8_t)glm::clamp((float)std::round((float)pixels[index + 2] / alphaUnit), 0.0f, 255.0f); + } + } + bool render_audio_stream_generate(AudioStream& audioStream, std::map& sounds, const std::vector& frameSoundIDs, int fps) { @@ -320,6 +341,7 @@ namespace anm2ed::imgui bind(); auto pixels = pixels_get(); + if (settings.renderIsRawAnimation) pixels_unpremultiply_alpha(pixels); auto frameIndex = (int)renderTempFrames.size(); auto framePath = renderTempDirectory / render_frame_filename(settings.renderFormat, frameIndex); if (Texture::write_pixels_png(framePath, size, pixels.data())) diff --git a/src/imgui/window/regions.cpp b/src/imgui/window/regions.cpp index 38ef50e..261c3fb 100644 --- a/src/imgui/window/regions.cpp +++ b/src/imgui/window/regions.cpp @@ -3,14 +3,12 @@ #include #include -#include #include #include "document.hpp" #include "log.hpp" #include "map_.hpp" #include "math_.hpp" -#include "path_.hpp" #include "strings.hpp" #include "toast.hpp" #include "vector_.hpp" diff --git a/src/imgui/window/timeline.cpp b/src/imgui/window/timeline.cpp index 76288ab..986aa42 100644 --- a/src/imgui/window/timeline.cpp +++ b/src/imgui/window/timeline.cpp @@ -1780,11 +1780,12 @@ namespace anm2ed::imgui if (ImGui::Button(localize.get(BASIC_ADD), widgetSize)) { anm2::Reference addReference{}; + int insertBeforeID = reference.itemType == anm2::LAYER ? reference.itemID : -1; document.snapshot(localize.get(EDIT_ADD_ITEM)); if (type == anm2::LAYER) - addReference = anm2.layer_animation_add({reference.animationIndex, anm2::LAYER, addItemID}, addItemName, - addItemSpritesheetID, (destination::Type)destination); + addReference = anm2.layer_animation_add({reference.animationIndex, anm2::LAYER, addItemID}, insertBeforeID, + addItemName, addItemSpritesheetID, (destination::Type)destination); else if (type == anm2::NULL_) addReference = anm2.null_animation_add({reference.animationIndex, anm2::NULL_, addItemID}, addItemName, addItemIsShowRect, (destination::Type)destination); diff --git a/src/render.cpp b/src/render.cpp index 008b7bf..702d98e 100644 --- a/src/render.cpp +++ b/src/render.cpp @@ -149,7 +149,8 @@ namespace anm2ed { case render::GIF: command += - " -lavfi \"split[s0][s1];[s0]palettegen=stats_mode=full[p];[s1][p]paletteuse=dither=floyd_steinberg\"" + " -lavfi \"split[s0][s1];[s0]palettegen=stats_mode=full:reserve_transparent=1[p];" + "[s1][p]paletteuse=dither=floyd_steinberg:alpha_threshold=128\"" " -loop 0"; command += std::format(" \"{}\"", pathString); break; From a83dbd5b6c2e9e0530547def86ad99248f35a4eb Mon Sep 17 00:00:00 2001 From: shweet Date: Sun, 15 Mar 2026 13:22:53 -0400 Subject: [PATCH 5/7] Render animation fixes, vs code tasks --- .vscode/launch.json | 8 ++++ .vscode/tasks.json | 23 +++++++++- src/anm2/anm2.cpp | 63 +++++++++++++++++++++----- src/anm2/anm2.hpp | 1 + src/imgui/window/animation_preview.cpp | 9 +++- src/imgui/window/regions.cpp | 10 ++++ 6 files changed, 100 insertions(+), 14 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index cdfd141..dcdee9f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,8 +5,12 @@ "name": "Debug", "type": "cppdbg", "request": "launch", +<<<<<<< HEAD "preLaunchTask": "build-debug", "program": "${workspaceFolder}/out/build/linux-debug/bin/anm2ed", +======= + "program": "${workspaceFolder}/out/build/linux-debug/anm2ed", +>>>>>>> f58d894 (Render animation fixes, vs code tasks) "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", @@ -29,8 +33,12 @@ "name": "Release", "type": "cppdbg", "request": "launch", +<<<<<<< HEAD "preLaunchTask": "build-release", "program": "${workspaceFolder}/out/build/linux-release/bin/anm2ed", +======= + "program": "${workspaceFolder}/out/build/linux-release/anm2ed", +>>>>>>> f58d894 (Render animation fixes, vs code tasks) "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 87f59fa..546a48d 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -3,6 +3,7 @@ "tasks": [ { "label": "run-debug", +<<<<<<< HEAD "type": "shell", "command": "cmake", "args": [ @@ -27,6 +28,18 @@ "anm2ed" ], "dependsOn": "run-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", + "problemMatcher": [ + "$gcc" + ] + }, + { + "label": "build", + "type": "shell", + "command": "cmake -S . -B out/build/linux-debug -DCMAKE_BUILD_TYPE=Debug && cmake --build out/build/linux-debug --parallel 8 --target anm2ed", +>>>>>>> f58d894 (Render animation fixes, vs code tasks) "group": { "kind": "build", "isDefault": true @@ -38,6 +51,7 @@ { "label": "run-release", "type": "shell", +<<<<<<< HEAD "command": "cmake", "args": [ "-S", @@ -46,6 +60,9 @@ "out/build/linux-release", "-DCMAKE_BUILD_TYPE=Release" ], +======= + "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", +>>>>>>> f58d894 (Render animation fixes, vs code tasks) "problemMatcher": [ "$gcc" ] @@ -53,6 +70,7 @@ { "label": "build-release", "type": "shell", +<<<<<<< HEAD "command": "cmake", "args": [ "--build", @@ -61,6 +79,9 @@ "anm2ed" ], "dependsOn": "run-release", +======= + "command": "cmake -S . -B out/build/linux-release -DCMAKE_BUILD_TYPE=Release && cmake --build out/build/linux-release --parallel 8 --target anm2ed", +>>>>>>> f58d894 (Render animation fixes, vs code tasks) "group": "build", "problemMatcher": [ "$gcc" @@ -73,4 +94,4 @@ "problemMatcher": [] } ] -} +} \ No newline at end of file diff --git a/src/anm2/anm2.cpp b/src/anm2/anm2.cpp index c9e9585..f72cea4 100644 --- a/src/anm2/anm2.cpp +++ b/src/anm2/anm2.cpp @@ -18,6 +18,13 @@ using namespace glm; namespace { + int remap_id(const std::unordered_map& table, int value) + { + if (value < 0) return value; + if (auto it = table.find(value); it != table.end()) return it->second; + return value; + } + void region_frames_sync(anm2ed::anm2::Anm2& anm2, bool clearInvalid) { for (auto& animation : anm2.animations.items) @@ -84,12 +91,13 @@ namespace anm2ed::anm2 XMLElement* Anm2::to_element(XMLDocument& document, Flags flags) { - region_frames_sync(*this, true); + auto normalized = normalized_for_serialize(); + region_frames_sync(normalized, true); auto element = document.NewElement("AnimatedActor"); - info.serialize(document, element); - content.serialize(document, element, flags); - animations.serialize(document, element, flags); + normalized.info.serialize(document, element); + normalized.content.serialize(document, element, flags); + normalized.animations.serialize(document, element, flags); return element; } @@ -123,6 +131,46 @@ namespace anm2ed::anm2 uint64_t Anm2::hash() { return std::hash{}(to_string()); } + Anm2 Anm2::normalized_for_serialize() const + { + auto normalized = *this; + std::unordered_map layerRemap{}; + + int normalizedID = 0; + for (auto& [layerID, layer] : content.layers) + { + layerRemap[layerID] = normalizedID; + ++normalizedID; + } + + normalized.content.layers.clear(); + for (auto& [layerID, layer] : content.layers) + normalized.content.layers[remap_id(layerRemap, layerID)] = layer; + + for (auto& animation : normalized.animations.items) + { + std::unordered_map layerAnimations{}; + std::vector layerOrder{}; + + for (auto layerID : animation.layerOrder) + { + auto mappedID = remap_id(layerRemap, layerID); + if (mappedID >= 0) layerOrder.push_back(mappedID); + } + + for (auto& [layerID, item] : animation.layerAnimations) + { + auto mappedID = remap_id(layerRemap, layerID); + if (mappedID >= 0) layerAnimations[mappedID] = item; + } + + animation.layerAnimations = std::move(layerAnimations); + animation.layerOrder = std::move(layerOrder); + } + + return normalized; + } + Frame* Anm2::frame_get(int animationIndex, Type itemType, int frameIndex, int itemID) { if (auto item = item_get(animationIndex, itemType, itemID); item) @@ -177,13 +225,6 @@ namespace anm2ed::anm2 return original; }; - auto remap_id = [](const auto& table, int value) - { - if (value < 0) return value; - if (auto it = table.find(value); it != table.end()) return it->second; - return value; - }; - std::unordered_map spritesheetRemap{}; std::unordered_map layerRemap{}; std::unordered_map nullRemap{}; diff --git a/src/anm2/anm2.hpp b/src/anm2/anm2.hpp index 4ac11ad..12c0b41 100644 --- a/src/anm2/anm2.hpp +++ b/src/anm2/anm2.hpp @@ -36,6 +36,7 @@ namespace anm2ed::anm2 std::string to_string(Flags = 0); Anm2(const std::filesystem::path&, std::string* = nullptr); uint64_t hash(); + Anm2 normalized_for_serialize() const; Spritesheet* spritesheet_get(int); bool spritesheet_add(const std::filesystem::path&, const std::filesystem::path&, int&); diff --git a/src/imgui/window/animation_preview.cpp b/src/imgui/window/animation_preview.cpp index 6167df7..b6602c5 100644 --- a/src/imgui/window/animation_preview.cpp +++ b/src/imgui/window/animation_preview.cpp @@ -105,6 +105,7 @@ namespace anm2ed::imgui pixels[index + 2] = (uint8_t)glm::clamp((float)std::round((float)pixels[index + 2] / alphaUnit), 0.0f, 255.0f); } } +<<<<<<< HEAD bool render_audio_stream_generate(AudioStream& audioStream, std::map& sounds, const std::vector& frameSoundIDs, int fps) @@ -150,6 +151,8 @@ namespace anm2ed::imgui MIX_DestroyMixer(mixer); return true; } +======= +>>>>>>> f58d894 (Render animation fixes, vs code tasks) } AnimationPreview::AnimationPreview() : Canvas(vec2()) {} @@ -368,7 +371,8 @@ namespace anm2ed::imgui } else { - toasts.push(std::vformat(localize.get(TOAST_EXPORT_RENDERED_ANIMATION_FAILED), std::make_format_args(pathString))); + toasts.push( + std::vformat(localize.get(TOAST_EXPORT_RENDERED_ANIMATION_FAILED), std::make_format_args(pathString))); 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); @@ -649,7 +653,8 @@ namespace anm2ed::imgui if (renderTempDirectory.empty()) { auto pathString = path::to_utf8(settings.renderPath); - toasts.push(std::vformat(localize.get(TOAST_EXPORT_RENDERED_ANIMATION_FAILED), std::make_format_args(pathString))); + toasts.push( + std::vformat(localize.get(TOAST_EXPORT_RENDERED_ANIMATION_FAILED), std::make_format_args(pathString))); logger.error(std::vformat(localize.get(TOAST_EXPORT_RENDERED_ANIMATION_FAILED, anm2ed::ENGLISH), std::make_format_args(pathString))); manager.isRecording = false; diff --git a/src/imgui/window/regions.cpp b/src/imgui/window/regions.cpp index 261c3fb..e125644 100644 --- a/src/imgui/window/regions.cpp +++ b/src/imgui/window/regions.cpp @@ -5,6 +5,7 @@ #include +<<<<<<< HEAD #include "document.hpp" #include "log.hpp" #include "map_.hpp" @@ -12,6 +13,15 @@ #include "strings.hpp" #include "toast.hpp" #include "vector_.hpp" +======= +#include "document.h" +#include "log.h" +#include "map_.h" +#include "math_.h" +#include "strings.h" +#include "toast.h" +#include "vector_.h" +>>>>>>> f58d894 (Render animation fixes, vs code tasks) #include "../../util/map_.hpp" From 4f5966dad6b7f9c848f4ee117aee7502349383b2 Mon Sep 17 00:00:00 2001 From: shweet Date: Tue, 17 Mar 2026 00:47:36 -0400 Subject: [PATCH 6/7] fix path issues --- compile_commands.json | 2 +- src/anm2/spritesheet.cpp | 6 ++++-- src/imgui/window/animation_preview.cpp | 5 +---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/compile_commands.json b/compile_commands.json index bc0dce8..5e95284 120000 --- a/compile_commands.json +++ b/compile_commands.json @@ -1 +1 @@ -/home/anon/sda/Personal/Repos/anm2ed/out/build/linux-debug/compile_commands.json \ No newline at end of file +/home/anon/sda/Personal/Repos/anm2ed/build/compile_commands.json \ No newline at end of file diff --git a/src/anm2/spritesheet.cpp b/src/anm2/spritesheet.cpp index 5c9034f..bd8f68e 100644 --- a/src/anm2/spritesheet.cpp +++ b/src/anm2/spritesheet.cpp @@ -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/imgui/window/animation_preview.cpp b/src/imgui/window/animation_preview.cpp index b6602c5..78b817c 100644 --- a/src/imgui/window/animation_preview.cpp +++ b/src/imgui/window/animation_preview.cpp @@ -1,8 +1,8 @@ #include "animation_preview.hpp" #include -#include #include +#include #include #include #include @@ -105,7 +105,6 @@ namespace anm2ed::imgui pixels[index + 2] = (uint8_t)glm::clamp((float)std::round((float)pixels[index + 2] / alphaUnit), 0.0f, 255.0f); } } -<<<<<<< HEAD bool render_audio_stream_generate(AudioStream& audioStream, std::map& sounds, const std::vector& frameSoundIDs, int fps) @@ -151,8 +150,6 @@ namespace anm2ed::imgui MIX_DestroyMixer(mixer); return true; } -======= ->>>>>>> f58d894 (Render animation fixes, vs code tasks) } AnimationPreview::AnimationPreview() : Canvas(vec2()) {} From ad125c15a29d614c40d970a19d06ad4911f18b74 Mon Sep 17 00:00:00 2001 From: shweet Date: Thu, 19 Mar 2026 03:46:42 -0400 Subject: [PATCH 7/7] queue oh el --- .vscode/launch.json | 8 - .vscode/tasks.json | 49 +- compile_commands.json | 2 +- src/anm2/anm2_spritesheets.cpp | 15 + src/anm2_new/anm2.cpp | 603 ------------------------- src/anm2_new/anm2.hpp | 90 ---- src/imgui/window/animation_preview.cpp | 9 + src/imgui/window/animation_preview.hpp | 1 + src/imgui/window/regions.cpp | 10 - src/imgui/window/timeline.cpp | 29 +- src/imgui/wizard/configure.cpp | 5 +- src/imgui_new/anm2_window.cpp | 16 - src/imgui_new/anm2_window.hpp | 12 - src/resource/strings.hpp | 4 +- src/settings.hpp | 1 + 15 files changed, 75 insertions(+), 779 deletions(-) delete mode 100644 src/anm2_new/anm2.cpp delete mode 100644 src/anm2_new/anm2.hpp delete mode 100644 src/imgui_new/anm2_window.cpp delete mode 100644 src/imgui_new/anm2_window.hpp diff --git a/.vscode/launch.json b/.vscode/launch.json index dcdee9f..cdfd141 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,12 +5,8 @@ "name": "Debug", "type": "cppdbg", "request": "launch", -<<<<<<< HEAD "preLaunchTask": "build-debug", "program": "${workspaceFolder}/out/build/linux-debug/bin/anm2ed", -======= - "program": "${workspaceFolder}/out/build/linux-debug/anm2ed", ->>>>>>> f58d894 (Render animation fixes, vs code tasks) "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", @@ -33,12 +29,8 @@ "name": "Release", "type": "cppdbg", "request": "launch", -<<<<<<< HEAD "preLaunchTask": "build-release", "program": "${workspaceFolder}/out/build/linux-release/bin/anm2ed", -======= - "program": "${workspaceFolder}/out/build/linux-release/anm2ed", ->>>>>>> f58d894 (Render animation fixes, vs code tasks) "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 546a48d..81fe5dd 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -2,8 +2,7 @@ "version": "2.0.0", "tasks": [ { - "label": "run-debug", -<<<<<<< HEAD + "label": "configure-debug", "type": "shell", "command": "cmake", "args": [ @@ -24,22 +23,12 @@ "args": [ "--build", "out/build/linux-debug", + "--parallel", + "8", "--target", "anm2ed" ], - "dependsOn": "run-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", - "problemMatcher": [ - "$gcc" - ] - }, - { - "label": "build", - "type": "shell", - "command": "cmake -S . -B out/build/linux-debug -DCMAKE_BUILD_TYPE=Debug && cmake --build out/build/linux-debug --parallel 8 --target anm2ed", ->>>>>>> f58d894 (Render animation fixes, vs code tasks) + "dependsOn": "configure-debug", "group": { "kind": "build", "isDefault": true @@ -49,9 +38,15 @@ ] }, { - "label": "run-release", + "label": "run-debug", + "type": "shell", + "command": "./out/build/linux-debug/bin/anm2ed", + "dependsOn": "build-debug", + "problemMatcher": [] + }, + { + "label": "configure-release", "type": "shell", -<<<<<<< HEAD "command": "cmake", "args": [ "-S", @@ -60,9 +55,6 @@ "out/build/linux-release", "-DCMAKE_BUILD_TYPE=Release" ], -======= - "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", ->>>>>>> f58d894 (Render animation fixes, vs code tasks) "problemMatcher": [ "$gcc" ] @@ -70,28 +62,27 @@ { "label": "build-release", "type": "shell", -<<<<<<< HEAD "command": "cmake", "args": [ "--build", "out/build/linux-release", + "--parallel", + "8", "--target", "anm2ed" ], - "dependsOn": "run-release", -======= - "command": "cmake -S . -B out/build/linux-release -DCMAKE_BUILD_TYPE=Release && cmake --build out/build/linux-release --parallel 8 --target anm2ed", ->>>>>>> f58d894 (Render animation fixes, vs code tasks) + "dependsOn": "configure-release", "group": "build", "problemMatcher": [ "$gcc" ] }, { - "label": "build", - "dependsOn": "build-debug", - "group": "build", + "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/compile_commands.json b/compile_commands.json index 5e95284..bc0dce8 120000 --- a/compile_commands.json +++ b/compile_commands.json @@ -1 +1 @@ -/home/anon/sda/Personal/Repos/anm2ed/build/compile_commands.json \ No newline at end of file +/home/anon/sda/Personal/Repos/anm2ed/out/build/linux-debug/compile_commands.json \ No newline at end of file diff --git a/src/anm2/anm2_spritesheets.cpp b/src/anm2/anm2_spritesheets.cpp index e4b55ae..b99a7b3 100644 --- a/src/anm2/anm2_spritesheets.cpp +++ b/src/anm2/anm2_spritesheets.cpp @@ -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_new/anm2.cpp b/src/anm2_new/anm2.cpp deleted file mode 100644 index ce237dd..0000000 --- a/src/anm2_new/anm2.cpp +++ /dev/null @@ -1,603 +0,0 @@ -#include "anm2.hpp" - -#include -#include -#include -#include - -#include "../log.hpp" -#include "../util/path_.hpp" -#include "../util/working_directory.hpp" -#include "../util/xml_.hpp" - -using namespace tinyxml2; -using namespace anm2ed::util; - -namespace anm2ed::resource::anm2_new -{ - Anm2::Item::Item(XMLElement* element, Type _type) - { - if (!element) return; - - type = _type; - - auto isFrameOwnerType = - _type == ROOT_ANIMATION || _type == LAYER_ANIMATION || _type == NULL_ANIMATION || _type == TRIGGERS; - auto isFrameLikeElement = - element->Name() && (std::strcmp(element->Name(), "Frame") == 0 || std::strcmp(element->Name(), "Trigger") == 0); - - if (isFrameOwnerType && isFrameLikeElement) - { - ownerType = _type; - type = _type == TRIGGERS ? TRIGGER : FRAME; - - switch (_type) - { - case ROOT_ANIMATION: - case NULL_ANIMATION: - element->QueryFloatAttribute("XPosition", &position.x); - element->QueryFloatAttribute("YPosition", &position.y); - element->QueryFloatAttribute("XScale", &scale.x); - element->QueryFloatAttribute("YScale", &scale.y); - element->QueryIntAttribute("Delay", &duration); - element->QueryBoolAttribute("Visible", &isVisible); - xml::query_color_attribute(element, "RedTint", tint.r); - xml::query_color_attribute(element, "GreenTint", tint.g); - xml::query_color_attribute(element, "BlueTint", tint.b); - xml::query_color_attribute(element, "AlphaTint", tint.a); - xml::query_color_attribute(element, "RedOffset", colorOffset.r); - xml::query_color_attribute(element, "GreenOffset", colorOffset.g); - xml::query_color_attribute(element, "BlueOffset", colorOffset.b); - element->QueryFloatAttribute("Rotation", &rotation); - element->QueryBoolAttribute("Interpolated", &isInterpolated); - break; - case LAYER_ANIMATION: - element->QueryIntAttribute("RegionId", ®ionID); - element->QueryFloatAttribute("XPosition", &position.x); - element->QueryFloatAttribute("YPosition", &position.y); - element->QueryFloatAttribute("XPivot", &pivot.x); - element->QueryFloatAttribute("YPivot", &pivot.y); - element->QueryFloatAttribute("XCrop", &crop.x); - element->QueryFloatAttribute("YCrop", &crop.y); - element->QueryFloatAttribute("Width", &size.x); - element->QueryFloatAttribute("Height", &size.y); - element->QueryFloatAttribute("XScale", &scale.x); - element->QueryFloatAttribute("YScale", &scale.y); - element->QueryIntAttribute("Delay", &duration); - element->QueryBoolAttribute("Visible", &isVisible); - xml::query_color_attribute(element, "RedTint", tint.r); - xml::query_color_attribute(element, "GreenTint", tint.g); - xml::query_color_attribute(element, "BlueTint", tint.b); - xml::query_color_attribute(element, "AlphaTint", tint.a); - xml::query_color_attribute(element, "RedOffset", colorOffset.r); - xml::query_color_attribute(element, "GreenOffset", colorOffset.g); - xml::query_color_attribute(element, "BlueOffset", colorOffset.b); - element->QueryFloatAttribute("Rotation", &rotation); - element->QueryBoolAttribute("Interpolated", &isInterpolated); - break; - case TRIGGERS: - { - element->QueryIntAttribute("EventId", &eventID); - element->QueryIntAttribute("AtFrame", &atFrame); - int soundID{}; - if (element->QueryIntAttribute("SoundId", &soundID) == XML_SUCCESS) soundIDs.push_back(soundID); - for (auto* child = element->FirstChildElement("Sound"); child; child = child->NextSiblingElement("Sound")) - if (child->QueryIntAttribute("Id", &soundID) == XML_SUCCESS) soundIDs.push_back(soundID); - break; - } - default: - break; - } - - return; - } - - switch (_type) - { - case INFO: - xml::query_string_attribute(element, "CreatedBy", &createdBy); - xml::query_string_attribute(element, "CreatedOn", &createdOn); - element->QueryIntAttribute("Fps", &fps); - element->QueryIntAttribute("Version", &version); - break; - case SPRITESHEET: - element->QueryIntAttribute("Id", &id); - xml::query_path_attribute(element, "Path", &path); - path = util::path::lower_case_backslash_handle(path); - texture = Texture(path); - break; - case REGION: - { - element->QueryIntAttribute("Id", &id); - xml::query_string_attribute(element, "Name", &name); - element->QueryFloatAttribute("XCrop", &crop.x); - element->QueryFloatAttribute("YCrop", &crop.y); - element->QueryFloatAttribute("Width", &size.x); - element->QueryFloatAttribute("Height", &size.y); - - auto* origin = element->Attribute("Origin"); - if (origin && std::string(origin) == "TopLeft") - pivot = {}; - else if (origin && std::string(origin) == "Center") - pivot = glm::vec2((int)(size.x / 2.0f), (int)(size.y / 2.0f)); - else - { - element->QueryFloatAttribute("XPivot", &pivot.x); - element->QueryFloatAttribute("YPivot", &pivot.y); - } - break; - } - case LAYER: - element->QueryIntAttribute("Id", &id); - xml::query_string_attribute(element, "Name", &name); - element->QueryIntAttribute("SpritesheetId", &spritesheetID); - break; - case NULL_: - element->QueryIntAttribute("Id", &id); - xml::query_string_attribute(element, "Name", &name); - element->QueryBoolAttribute("ShowRect", &isShowRect); - break; - case EVENT: - element->QueryIntAttribute("Id", &id); - xml::query_string_attribute(element, "Name", &name); - break; - case SOUND: - element->QueryIntAttribute("Id", &id); - xml::query_path_attribute(element, "Path", &path); - path = util::path::lower_case_backslash_handle(path); - sound = Audio(path); - break; - case ANIMATION: - xml::query_string_attribute(element, "Name", &name); - element->QueryIntAttribute("FrameNum", &frameNum); - element->QueryBoolAttribute("Loop", &isLoop); - break; - case ROOT_ANIMATION: - case TRIGGERS: - break; - case LAYER_ANIMATION: - element->QueryIntAttribute("LayerId", &itemID); - element->QueryBoolAttribute("Visible", &isVisible); - break; - case NULL_ANIMATION: - element->QueryIntAttribute("NullId", &itemID); - element->QueryBoolAttribute("Visible", &isVisible); - break; - case FRAME: - case TRIGGER: - default: - break; - } - } - - XMLElement* Anm2::Item::to_element(XMLDocument& document) const - { - switch (type) - { - case INFO: - { - auto* element = document.NewElement("Info"); - element->SetAttribute("CreatedBy", createdBy.c_str()); - element->SetAttribute("CreatedOn", createdOn.c_str()); - element->SetAttribute("Fps", fps); - element->SetAttribute("Version", version); - return element; - } - case SPRITESHEET: - { - auto* element = document.NewElement("Spritesheet"); - element->SetAttribute("Id", id); - auto pathString = util::path::to_utf8(path); - element->SetAttribute("Path", pathString.c_str()); - return element; - } - case REGION: - { - auto* element = document.NewElement("Region"); - element->SetAttribute("Id", id); - element->SetAttribute("Name", name.c_str()); - element->SetAttribute("XCrop", crop.x); - element->SetAttribute("YCrop", crop.y); - element->SetAttribute("Width", size.x); - element->SetAttribute("Height", size.y); - element->SetAttribute("XPivot", pivot.x); - element->SetAttribute("YPivot", pivot.y); - return element; - } - case LAYER: - { - auto* element = document.NewElement("Layer"); - element->SetAttribute("Id", id); - element->SetAttribute("Name", name.c_str()); - element->SetAttribute("SpritesheetId", spritesheetID); - return element; - } - case NULL_: - { - auto* element = document.NewElement("Null"); - element->SetAttribute("Id", id); - element->SetAttribute("Name", name.c_str()); - if (isShowRect) element->SetAttribute("ShowRect", isShowRect); - return element; - } - case EVENT: - { - auto* element = document.NewElement("Event"); - element->SetAttribute("Id", id); - element->SetAttribute("Name", name.c_str()); - return element; - } - case SOUND: - { - auto* element = document.NewElement("Sound"); - element->SetAttribute("Id", id); - auto pathString = util::path::to_utf8(path); - element->SetAttribute("Path", pathString.c_str()); - return element; - } - case ANIMATION: - { - auto* element = document.NewElement("Animation"); - element->SetAttribute("Name", name.c_str()); - element->SetAttribute("FrameNum", frameNum); - element->SetAttribute("Loop", isLoop); - return element; - } - case ROOT_ANIMATION: - return document.NewElement("RootAnimation"); - case LAYER_ANIMATION: - { - auto* element = document.NewElement("LayerAnimation"); - element->SetAttribute("LayerId", itemID); - element->SetAttribute("Visible", isVisible); - return element; - } - case NULL_ANIMATION: - { - auto* element = document.NewElement("NullAnimation"); - element->SetAttribute("NullId", itemID); - element->SetAttribute("Visible", isVisible); - return element; - } - case TRIGGERS: - return document.NewElement("Triggers"); - case TRIGGER: - { - auto* element = document.NewElement("Trigger"); - if (eventID != -1) element->SetAttribute("EventId", eventID); - for (auto soundID : soundIDs) - { - if (soundID == -1) continue; - auto* soundElement = element->InsertNewChildElement("Sound"); - soundElement->SetAttribute("Id", soundID); - } - element->SetAttribute("AtFrame", atFrame); - return element; - } - case FRAME: - { - auto* element = document.NewElement("Frame"); - - if (ownerType == LAYER_ANIMATION && regionID != -1) element->SetAttribute("RegionId", regionID); - element->SetAttribute("XPosition", position.x); - element->SetAttribute("YPosition", position.y); - - if (ownerType == LAYER_ANIMATION) - { - element->SetAttribute("XPivot", pivot.x); - element->SetAttribute("YPivot", pivot.y); - element->SetAttribute("XCrop", crop.x); - element->SetAttribute("YCrop", crop.y); - element->SetAttribute("Width", size.x); - element->SetAttribute("Height", size.y); - } - - element->SetAttribute("XScale", scale.x); - element->SetAttribute("YScale", scale.y); - element->SetAttribute("Delay", duration); - element->SetAttribute("Visible", isVisible); - element->SetAttribute("RedTint", (int)glm::clamp(tint.r * 255.0f, 0.0f, 255.0f)); - element->SetAttribute("GreenTint", (int)glm::clamp(tint.g * 255.0f, 0.0f, 255.0f)); - element->SetAttribute("BlueTint", (int)glm::clamp(tint.b * 255.0f, 0.0f, 255.0f)); - element->SetAttribute("AlphaTint", (int)glm::clamp(tint.a * 255.0f, 0.0f, 255.0f)); - element->SetAttribute("RedOffset", (int)glm::clamp(colorOffset.r * 255.0f, 0.0f, 255.0f)); - element->SetAttribute("GreenOffset", (int)glm::clamp(colorOffset.g * 255.0f, 0.0f, 255.0f)); - element->SetAttribute("BlueOffset", (int)glm::clamp(colorOffset.b * 255.0f, 0.0f, 255.0f)); - element->SetAttribute("Rotation", rotation); - element->SetAttribute("Interpolated", isInterpolated); - - return element; - } - default: - break; - } - - return document.NewElement("Item"); - } - - std::string Anm2::Item::to_string() const - { - XMLDocument document; - document.InsertEndChild(to_element(document)); - return xml::document_to_string(document); - } - - Anm2::Anm2(const std::filesystem::path& path) - { - XMLDocument document; - auto pathString = util::path::to_utf8(path); - - if (document.LoadFile(pathString.c_str()) != XML_SUCCESS) - { - logger.error(std::format("Failed to initialize anm2: {} ({})", pathString, document.ErrorStr())); - isValid = false; - return; - } - - WorkingDirectory workingDirectory(path, WorkingDirectory::FILE); - - this->path = path; - isValid = true; - - auto item_add = [&](Item item) { items.emplace_back(std::move(item)); }; - - if (auto* root = document.RootElement()) - { - if (auto* infoElement = root->FirstChildElement("Info")) item_add(Item(infoElement, INFO)); - - if (auto* contentElement = root->FirstChildElement("Content")) - { - if (auto* spritesheetsElement = contentElement->FirstChildElement("Spritesheets")) - { - for (auto* child = spritesheetsElement->FirstChildElement("Spritesheet"); child; - child = child->NextSiblingElement("Spritesheet")) - { - auto spritesheet = Item(child, SPRITESHEET); - auto spritesheetID = spritesheet.id; - item_add(spritesheet); - - for (auto* regionChild = child->FirstChildElement("Region"); regionChild; - regionChild = regionChild->NextSiblingElement("Region")) - { - auto region = Item(regionChild, REGION); - region.itemID = spritesheetID; - item_add(region); - } - } - } - - if (auto* layersElement = contentElement->FirstChildElement("Layers")) - for (auto* child = layersElement->FirstChildElement("Layer"); child; - child = child->NextSiblingElement("Layer")) - item_add(Item(child, LAYER)); - - if (auto* nullsElement = contentElement->FirstChildElement("Nulls")) - for (auto* child = nullsElement->FirstChildElement("Null"); child; child = child->NextSiblingElement("Null")) - item_add(Item(child, NULL_)); - - if (auto* eventsElement = contentElement->FirstChildElement("Events")) - for (auto* child = eventsElement->FirstChildElement("Event"); child; - child = child->NextSiblingElement("Event")) - item_add(Item(child, EVENT)); - - if (auto* soundsElement = contentElement->FirstChildElement("Sounds")) - for (auto* child = soundsElement->FirstChildElement("Sound"); child; - child = child->NextSiblingElement("Sound")) - item_add(Item(child, SOUND)); - } - - if (auto* animationsElement = root->FirstChildElement("Animations")) - { - int animationIndex = 0; - for (auto* animationElement = animationsElement->FirstChildElement("Animation"); animationElement; - animationElement = animationElement->NextSiblingElement("Animation")) - { - auto animation = Item(animationElement, ANIMATION); - animation.id = animationIndex++; - item_add(animation); - - if (auto* rootAnimationElement = animationElement->FirstChildElement("RootAnimation")) - { - Item rootAnimation{}; - rootAnimation.type = ROOT_ANIMATION; - rootAnimation.animationID = animation.id; - item_add(rootAnimation); - - for (auto* frameElement = rootAnimationElement->FirstChildElement("Frame"); frameElement; - frameElement = frameElement->NextSiblingElement("Frame")) - { - auto frame = Item(frameElement, ROOT_ANIMATION); - frame.animationID = animation.id; - frame.ownerID = -1; - item_add(frame); - } - } - - if (auto* layerAnimationsElement = animationElement->FirstChildElement("LayerAnimations")) - { - for (auto* layerAnimationElement = layerAnimationsElement->FirstChildElement("LayerAnimation"); - layerAnimationElement; - layerAnimationElement = layerAnimationElement->NextSiblingElement("LayerAnimation")) - { - auto layerAnimation = Item(layerAnimationElement, LAYER_ANIMATION); - layerAnimation.animationID = animation.id; - item_add(layerAnimation); - - for (auto* frameElement = layerAnimationElement->FirstChildElement("Frame"); frameElement; - frameElement = frameElement->NextSiblingElement("Frame")) - { - auto frame = Item(frameElement, LAYER_ANIMATION); - frame.animationID = animation.id; - frame.ownerID = layerAnimation.itemID; - item_add(frame); - } - } - } - - if (auto* nullAnimationsElement = animationElement->FirstChildElement("NullAnimations")) - { - for (auto* nullAnimationElement = nullAnimationsElement->FirstChildElement("NullAnimation"); - nullAnimationElement; nullAnimationElement = nullAnimationElement->NextSiblingElement("NullAnimation")) - { - auto nullAnimation = Item(nullAnimationElement, NULL_ANIMATION); - nullAnimation.animationID = animation.id; - item_add(nullAnimation); - - for (auto* frameElement = nullAnimationElement->FirstChildElement("Frame"); frameElement; - frameElement = frameElement->NextSiblingElement("Frame")) - { - auto frame = Item(frameElement, NULL_ANIMATION); - frame.animationID = animation.id; - frame.ownerID = nullAnimation.itemID; - item_add(frame); - } - } - } - - if (auto* triggersElement = animationElement->FirstChildElement("Triggers")) - { - Item triggers{}; - triggers.type = TRIGGERS; - triggers.animationID = animation.id; - item_add(triggers); - - for (auto* triggerElement = triggersElement->FirstChildElement("Trigger"); triggerElement; - triggerElement = triggerElement->NextSiblingElement("Trigger")) - { - auto trigger = Item(triggerElement, TRIGGERS); - trigger.animationID = animation.id; - trigger.ownerID = -1; - item_add(trigger); - } - } - } - } - } - - logger.info(std::format("Initialized anm2: {}", pathString)); - } - - XMLElement* Anm2::to_element(XMLDocument& document) const - { - auto* root = document.NewElement("AnimatedActor"); - auto add_frames = [&](XMLElement* parent, Type ownerType, int animationID, int ownerID) - { - for (auto& item : items) - { - if (item.type != FRAME && item.type != TRIGGER) continue; - if (item.ownerType != ownerType) continue; - if (item.animationID != animationID) continue; - if (item.ownerID != ownerID) continue; - parent->InsertEndChild(item.to_element(document)); - } - }; - - const Item* info = nullptr; - for (auto& item : items) - if (item.type == INFO) - { - info = &item; - break; - } - if (info) root->InsertEndChild(info->to_element(document)); - - auto* contentElement = document.NewElement("Content"); - auto* spritesheetsElement = document.NewElement("Spritesheets"); - auto* layersElement = document.NewElement("Layers"); - auto* nullsElement = document.NewElement("Nulls"); - auto* eventsElement = document.NewElement("Events"); - auto* soundsElement = document.NewElement("Sounds"); - - for (auto& item : items) - { - if (item.type != SPRITESHEET) continue; - auto* spritesheetElement = item.to_element(document); - for (auto& region : items) - if (region.type == REGION && region.itemID == item.id) - spritesheetElement->InsertEndChild(region.to_element(document)); - spritesheetsElement->InsertEndChild(spritesheetElement); - } - - for (auto& item : items) - if (item.type == LAYER) layersElement->InsertEndChild(item.to_element(document)); - - for (auto& item : items) - if (item.type == NULL_) nullsElement->InsertEndChild(item.to_element(document)); - - for (auto& item : items) - if (item.type == EVENT) eventsElement->InsertEndChild(item.to_element(document)); - - for (auto& item : items) - if (item.type == SOUND) soundsElement->InsertEndChild(item.to_element(document)); - - contentElement->InsertEndChild(spritesheetsElement); - contentElement->InsertEndChild(layersElement); - contentElement->InsertEndChild(nullsElement); - contentElement->InsertEndChild(eventsElement); - if (soundsElement->FirstChildElement("Sound")) contentElement->InsertEndChild(soundsElement); - root->InsertEndChild(contentElement); - - auto* animationsElement = document.NewElement("Animations"); - - for (auto& animation : items) - { - if (animation.type != ANIMATION) continue; - auto* animationElement = animation.to_element(document); - - auto* rootAnimationElement = document.NewElement("RootAnimation"); - add_frames(rootAnimationElement, ROOT_ANIMATION, animation.id, -1); - animationElement->InsertEndChild(rootAnimationElement); - - auto* layerAnimationsElement = document.NewElement("LayerAnimations"); - for (auto& layerAnimation : items) - { - if (layerAnimation.type != LAYER_ANIMATION || layerAnimation.animationID != animation.id) continue; - auto* layerAnimationElement = layerAnimation.to_element(document); - add_frames(layerAnimationElement, LAYER_ANIMATION, animation.id, layerAnimation.itemID); - layerAnimationsElement->InsertEndChild(layerAnimationElement); - } - animationElement->InsertEndChild(layerAnimationsElement); - - auto* nullAnimationsElement = document.NewElement("NullAnimations"); - for (auto& nullAnimation : items) - { - if (nullAnimation.type != NULL_ANIMATION || nullAnimation.animationID != animation.id) continue; - auto* nullAnimationElement = nullAnimation.to_element(document); - add_frames(nullAnimationElement, NULL_ANIMATION, animation.id, nullAnimation.itemID); - nullAnimationsElement->InsertEndChild(nullAnimationElement); - } - animationElement->InsertEndChild(nullAnimationsElement); - - auto* triggersElement = document.NewElement("Triggers"); - add_frames(triggersElement, TRIGGERS, animation.id, -1); - animationElement->InsertEndChild(triggersElement); - - animationsElement->InsertEndChild(animationElement); - } - - root->InsertEndChild(animationsElement); - return root; - } - - bool Anm2::serialize(const std::filesystem::path& path, std::string* errorString) const - { - XMLDocument document; - document.InsertEndChild(to_element(document)); - - auto pathString = util::path::to_utf8(path); - if (document.SaveFile(pathString.c_str()) != XML_SUCCESS) - { - if (errorString) *errorString = document.ErrorStr(); - return false; - } - - return true; - } - - std::string Anm2::to_string() const - { - XMLDocument document; - document.InsertEndChild(to_element(document)); - return xml::document_to_string(document); - } -} diff --git a/src/anm2_new/anm2.hpp b/src/anm2_new/anm2.hpp deleted file mode 100644 index ace6406..0000000 --- a/src/anm2_new/anm2.hpp +++ /dev/null @@ -1,90 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "../resource/audio.hpp" -#include "../resource/texture.hpp" - -#include - -namespace anm2ed::resource::anm2_new -{ - class Anm2 - { - public: - enum Type - { - NONE, - INFO, - SPRITESHEET, - REGION, - LAYER, - NULL_, - EVENT, - SOUND, - ANIMATION, - ROOT_ANIMATION, - LAYER_ANIMATION, - NULL_ANIMATION, - TRIGGERS, - FRAME, - TRIGGER - }; - - class Item - { - public: - Type type{NONE}; - Type ownerType{NONE}; - std::string name{}; - bool isInterpolated{false}; - bool isLoop{false}; - bool isVisible{false}; - bool isShowRect{false}; - glm::vec2 crop{}; - glm::vec2 pivot{}; - glm::vec2 position{}; - glm::vec2 scale{100, 100}; - glm::vec2 size{}; - glm::vec3 colorOffset{}; - glm::vec4 tint{1, 1, 1, 1}; - int atFrame{-1}; - int duration{1}; - int eventID{-1}; - int fps{30}; - int frameNum{1}; - int id{-1}; - int itemID{-1}; - int ownerID{-1}; - int animationID{-1}; - int spritesheetID{-1}; - int regionID{-1}; - int version{0}; - float rotation{}; - resource::Texture texture{}; - resource::Audio sound{}; - std::filesystem::path path{}; - std::string createdBy{}; - std::string createdOn{}; - std::vector soundIDs{}; - - Item() = default; - Item(tinyxml2::XMLElement*, Type); - tinyxml2::XMLElement* to_element(tinyxml2::XMLDocument&) const; - std::string to_string() const; - }; - - std::vector items{}; - std::filesystem::path path{}; - bool isValid{false}; - - Anm2() = default; - Anm2(const std::filesystem::path&); - tinyxml2::XMLElement* to_element(tinyxml2::XMLDocument&) const; - bool serialize(const std::filesystem::path&, std::string* = nullptr) const; - std::string to_string() const; - }; -} diff --git a/src/imgui/window/animation_preview.cpp b/src/imgui/window/animation_preview.cpp index 78b817c..82cea0d 100644 --- a/src/imgui/window/animation_preview.cpp +++ b/src/imgui/window/animation_preview.cpp @@ -165,6 +165,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; @@ -417,6 +423,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) diff --git a/src/imgui/window/animation_preview.hpp b/src/imgui/window/animation_preview.hpp index 152a229..b9dcd7a 100644 --- a/src/imgui/window/animation_preview.hpp +++ b/src/imgui/window/animation_preview.hpp @@ -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{}; diff --git a/src/imgui/window/regions.cpp b/src/imgui/window/regions.cpp index e125644..261c3fb 100644 --- a/src/imgui/window/regions.cpp +++ b/src/imgui/window/regions.cpp @@ -5,7 +5,6 @@ #include -<<<<<<< HEAD #include "document.hpp" #include "log.hpp" #include "map_.hpp" @@ -13,15 +12,6 @@ #include "strings.hpp" #include "toast.hpp" #include "vector_.hpp" -======= -#include "document.h" -#include "log.h" -#include "map_.h" -#include "math_.h" -#include "strings.h" -#include "toast.h" -#include "vector_.h" ->>>>>>> f58d894 (Render animation fixes, vs code tasks) #include "../../util/map_.hpp" diff --git a/src/imgui/window/timeline.cpp b/src/imgui/window/timeline.cpp index 986aa42..81f1c38 100644 --- a/src/imgui/window/timeline.cpp +++ b/src/imgui/window/timeline.cpp @@ -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/wizard/configure.cpp b/src/imgui/wizard/configure.cpp index bf91bc4..5e3dc0b 100644 --- a/src/imgui/wizard/configure.cpp +++ b/src/imgui/wizard/configure.cpp @@ -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_new/anm2_window.cpp b/src/imgui_new/anm2_window.cpp deleted file mode 100644 index 1b3bb66..0000000 --- a/src/imgui_new/anm2_window.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "anm2_window.hpp" - -#include "imgui.h" - -using namespace anm2ed::resource::anm2_new; - -namespace anm2ed::imgui_new -{ - void Window::update(Anm2& anm2, Anm2::Type type, Settings& settings) - { - if (ImGui::Begin("TestWindow", &settings.windowIsEvents)) - { - } - ImGui::End(); - } -} \ No newline at end of file diff --git a/src/imgui_new/anm2_window.hpp b/src/imgui_new/anm2_window.hpp deleted file mode 100644 index 196a877..0000000 --- a/src/imgui_new/anm2_window.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include "../anm2_new/anm2.hpp" -#include "../settings.hpp" - -namespace anm2ed::imgui_new -{ - class Window - { - void update(anm2ed::resource::anm2_new::Anm2&, anm2ed::resource::anm2_new::Anm2::Type type, Settings&); - }; -} \ No newline at end of file diff --git a/src/resource/strings.hpp b/src/resource/strings.hpp index 646166b..b2ce13e 100644 --- a/src/resource/strings.hpp +++ 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/settings.hpp b/src/settings.hpp index fdbc1d3..bc6cf49 100644 --- a/src/settings.hpp +++ b/src/settings.hpp @@ -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) \ \