...Anm2Ed 2.0
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
#include "animation_preview.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <filesystem>
|
||||
#include <ranges>
|
||||
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include "imgui_internal.h"
|
||||
#include "imgui_.h"
|
||||
#include "log.h"
|
||||
#include "math_.h"
|
||||
#include "toast.h"
|
||||
@@ -38,6 +38,7 @@ namespace anm2ed::imgui
|
||||
auto& frameTime = document.frameTime;
|
||||
auto& end = manager.recordingEnd;
|
||||
auto& zoom = document.previewZoom;
|
||||
auto& overlayIndex = document.overlayIndex;
|
||||
auto& pan = document.previewPan;
|
||||
|
||||
if (manager.isRecording)
|
||||
@@ -46,19 +47,17 @@ namespace anm2ed::imgui
|
||||
auto& path = settings.renderPath;
|
||||
auto& type = settings.renderType;
|
||||
|
||||
auto pixels = pixels_get();
|
||||
renderFrames.push_back(Texture(pixels.data(), size));
|
||||
|
||||
if (playback.time > end || playback.isFinished)
|
||||
{
|
||||
if (type == render::PNGS)
|
||||
{
|
||||
auto& format = settings.renderFormat;
|
||||
bool isSuccess{true};
|
||||
for (auto [i, frame] : std::views::enumerate(renderFrames))
|
||||
for (std::size_t index = 0; index < renderFrames.size(); ++index)
|
||||
{
|
||||
auto& frame = renderFrames[index];
|
||||
std::filesystem::path outputPath =
|
||||
std::filesystem::path(path) / std::vformat(format, std::make_format_args(i));
|
||||
std::filesystem::path(path) / std::vformat(format, std::make_format_args(index));
|
||||
|
||||
if (!frame.write_png(outputPath))
|
||||
{
|
||||
@@ -93,10 +92,11 @@ namespace anm2ed::imgui
|
||||
|
||||
std::vector<uint8_t> spritesheet((size_t)(spritesheetSize.x) * spritesheetSize.y * CHANNELS);
|
||||
|
||||
for (auto [i, frame] : std::views::enumerate(renderFrames))
|
||||
for (std::size_t index = 0; index < renderFrames.size(); ++index)
|
||||
{
|
||||
auto row = (int)(i / columns);
|
||||
auto column = (int)(i % columns);
|
||||
const auto& frame = renderFrames[index];
|
||||
auto row = (int)(index / columns);
|
||||
auto column = (int)(index % columns);
|
||||
if (row >= rows || column >= columns) break;
|
||||
if ((int)frame.pixels.size() < frameWidth * frameHeight * CHANNELS) continue;
|
||||
|
||||
@@ -131,6 +131,7 @@ namespace anm2ed::imgui
|
||||
pan = savedPan;
|
||||
zoom = savedZoom;
|
||||
settings = savedSettings;
|
||||
overlayIndex = savedOverlayIndex;
|
||||
isSizeTrySet = true;
|
||||
|
||||
if (settings.timelineIsSound) audioStream.capture_end(mixer);
|
||||
@@ -140,6 +141,13 @@ namespace anm2ed::imgui
|
||||
manager.isRecording = false;
|
||||
manager.progressPopup.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
bind();
|
||||
auto pixels = pixels_get();
|
||||
renderFrames.push_back(Texture(pixels.data(), size));
|
||||
}
|
||||
}
|
||||
|
||||
if (playback.isPlaying)
|
||||
@@ -247,7 +255,7 @@ namespace anm2ed::imgui
|
||||
|
||||
if (ImGui::BeginChild("##Background Child", childSize, true, ImGuiWindowFlags_HorizontalScrollbar))
|
||||
{
|
||||
ImGui::ColorEdit4("Background", value_ptr(backgroundColor), ImGuiColorEditFlags_NoInputs);
|
||||
ImGui::ColorEdit3("Background", value_ptr(backgroundColor), ImGuiColorEditFlags_NoInputs);
|
||||
ImGui::SetItemTooltip("Change the background color.");
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("Axes", &isAxes);
|
||||
@@ -311,6 +319,7 @@ namespace anm2ed::imgui
|
||||
settings.timelineIsOnlyShowLayers = true;
|
||||
settings.onionskinIsEnabled = false;
|
||||
|
||||
savedOverlayIndex = overlayIndex;
|
||||
savedZoom = zoom;
|
||||
savedPan = pan;
|
||||
|
||||
@@ -329,10 +338,12 @@ namespace anm2ed::imgui
|
||||
playback.time = manager.recordingStart;
|
||||
}
|
||||
|
||||
if (isSizeTrySet) size_set(to_vec2(ImGui::GetContentRegionAvail()));
|
||||
viewport_set();
|
||||
size_set(to_vec2(ImGui::GetContentRegionAvail()));
|
||||
|
||||
bind();
|
||||
clear();
|
||||
viewport_set();
|
||||
clear(manager.isRecording && settings.renderIsRawAnimation ? vec4() : vec4(backgroundColor, 1.0f));
|
||||
|
||||
if (isAxes) axes_render(shaderAxes, zoom, pan, axesColor);
|
||||
if (isGrid) grid_render(shaderGrid, zoom, pan, gridSize, gridOffset, gridColor);
|
||||
|
||||
@@ -468,9 +479,7 @@ namespace anm2ed::imgui
|
||||
|
||||
unbind();
|
||||
|
||||
ImGui::RenderColorRectWithAlphaCheckerboard(ImGui::GetWindowDrawList(), min, max, 0, CHECKER_SIZE,
|
||||
to_imvec2(-size + pan));
|
||||
ImGui::GetCurrentWindow()->DrawList->AddRectFilled(min, max, ImGui::GetColorU32(to_imvec4(backgroundColor)));
|
||||
render_checker_background(ImGui::GetWindowDrawList(), min, max, -size - pan, CHECKER_SIZE);
|
||||
ImGui::Image(texture, to_imvec2(size));
|
||||
|
||||
isPreviewHovered = ImGui::IsItemHovered();
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <future>
|
||||
|
||||
#include "audio_stream.h"
|
||||
#include "canvas.h"
|
||||
#include "manager.h"
|
||||
@@ -19,15 +17,13 @@ namespace anm2ed::imgui
|
||||
Settings savedSettings{};
|
||||
float savedZoom{};
|
||||
glm::vec2 savedPan{};
|
||||
int savedOverlayIndex{};
|
||||
glm::ivec2 mousePos{};
|
||||
std::vector<resource::Texture> renderFrames{};
|
||||
std::future<bool> renderFuture{};
|
||||
bool isRenderFutureValid{};
|
||||
std::string renderOutputPath{};
|
||||
|
||||
public:
|
||||
AnimationPreview();
|
||||
void tick(Manager&, Document&, Settings&);
|
||||
void tick(Manager&, Settings&);
|
||||
void update(Manager&, Settings&, Resources&);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "animations.h"
|
||||
|
||||
#include <ranges>
|
||||
#include <cstddef>
|
||||
|
||||
#include "toast.h"
|
||||
#include "vector_.h"
|
||||
@@ -24,6 +24,21 @@ namespace anm2ed::imgui
|
||||
|
||||
hovered = -1;
|
||||
|
||||
auto animations_remove = [&]()
|
||||
{
|
||||
if (!selection.empty())
|
||||
{
|
||||
for (auto it = selection.rbegin(); it != selection.rend(); ++it)
|
||||
{
|
||||
auto i = *it;
|
||||
if (overlayIndex == i) overlayIndex = -1;
|
||||
if (reference.animationIndex == i) reference.animationIndex = -1;
|
||||
anm2.animations.items.erase(anm2.animations.items.begin() + i);
|
||||
}
|
||||
selection.clear();
|
||||
}
|
||||
};
|
||||
|
||||
if (ImGui::Begin("Animations", &settings.windowIsAnimations))
|
||||
{
|
||||
auto childSize = size_without_footer_get();
|
||||
@@ -32,12 +47,13 @@ namespace anm2ed::imgui
|
||||
{
|
||||
selection.start(anm2.animations.items.size());
|
||||
|
||||
for (auto [i, animation] : std::views::enumerate(anm2.animations.items))
|
||||
for (std::size_t index = 0; index < anm2.animations.items.size(); ++index)
|
||||
{
|
||||
ImGui::PushID(i);
|
||||
auto& animation = anm2.animations.items[index];
|
||||
ImGui::PushID((int)index);
|
||||
|
||||
auto isDefault = anm2.animations.defaultAnimation == animation.name;
|
||||
auto isReferenced = reference.animationIndex == i;
|
||||
auto isReferenced = reference.animationIndex == (int)index;
|
||||
|
||||
auto font = isDefault && isReferenced ? font::BOLD_ITALICS
|
||||
: isDefault ? font::BOLD
|
||||
@@ -45,14 +61,14 @@ namespace anm2ed::imgui
|
||||
: font::REGULAR;
|
||||
|
||||
ImGui::PushFont(resources.fonts[font].get(), font::SIZE);
|
||||
ImGui::SetNextItemSelectionUserData((int)i);
|
||||
if (selectable_input_text(animation.name, std::format("###Document #{} Animation #{}", manager.selected, i),
|
||||
animation.name, selection.contains((int)i)))
|
||||
ImGui::SetNextItemSelectionUserData((int)index);
|
||||
if (selectable_input_text(animation.name, std::format("###Document #{} Animation #{}", manager.selected, index),
|
||||
animation.name, selection.contains((int)index)))
|
||||
{
|
||||
reference = {(int)i};
|
||||
reference = {(int)index};
|
||||
document.frames.clear();
|
||||
}
|
||||
if (ImGui::IsItemHovered()) hovered = (int)i;
|
||||
if (ImGui::IsItemHovered()) hovered = (int)index;
|
||||
ImGui::PopFont();
|
||||
|
||||
if (ImGui::BeginItemTooltip())
|
||||
@@ -121,23 +137,7 @@ namespace anm2ed::imgui
|
||||
auto cut = [&]()
|
||||
{
|
||||
copy();
|
||||
|
||||
auto remove = [&]()
|
||||
{
|
||||
if (!selection.empty())
|
||||
{
|
||||
for (auto& i : selection | std::views::reverse)
|
||||
anm2.animations.items.erase(anm2.animations.items.begin() + i);
|
||||
selection.clear();
|
||||
}
|
||||
else if (hovered > -1)
|
||||
{
|
||||
anm2.animations.items.erase(anm2.animations.items.begin() + hovered);
|
||||
hovered = -1;
|
||||
}
|
||||
};
|
||||
|
||||
DOCUMENT_EDIT(document, "Cut Animation(s)", Document::ANIMATIONS, remove());
|
||||
DOCUMENT_EDIT(document, "Cut Animation(s)", Document::ANIMATIONS, animations_remove());
|
||||
};
|
||||
|
||||
auto paste = [&]()
|
||||
@@ -275,19 +275,7 @@ namespace anm2ed::imgui
|
||||
|
||||
shortcut(manager.chords[SHORTCUT_REMOVE]);
|
||||
if (ImGui::Button("Remove", widgetSize))
|
||||
{
|
||||
auto remove = [&]()
|
||||
{
|
||||
for (auto& i : selection | std::views::reverse)
|
||||
{
|
||||
if (i == overlayIndex) overlayIndex = -1;
|
||||
anm2.animations.items.erase(anm2.animations.items.begin() + i);
|
||||
}
|
||||
selection.clear();
|
||||
};
|
||||
|
||||
DOCUMENT_EDIT(document, "Remove Animation(s)", Document::ANIMATIONS, remove());
|
||||
}
|
||||
DOCUMENT_EDIT(document, "Remove Animation(s)", Document::ANIMATIONS, animations_remove());
|
||||
set_item_tooltip_shortcut("Remove the selected animation(s).", settings.shortcutRemove);
|
||||
|
||||
ImGui::SameLine();
|
||||
@@ -328,14 +316,16 @@ namespace anm2ed::imgui
|
||||
{
|
||||
mergeSelection.start(anm2.animations.items.size());
|
||||
|
||||
for (auto [i, animation] : std::views::enumerate(anm2.animations.items))
|
||||
for (std::size_t index = 0; index < anm2.animations.items.size(); ++index)
|
||||
{
|
||||
if (i == mergeReference) continue;
|
||||
if ((int)index == mergeReference) continue;
|
||||
|
||||
ImGui::PushID(i);
|
||||
auto& animation = anm2.animations.items[index];
|
||||
|
||||
ImGui::SetNextItemSelectionUserData(i);
|
||||
ImGui::Selectable(animation.name.c_str(), mergeSelection.contains(i));
|
||||
ImGui::PushID((int)index);
|
||||
|
||||
ImGui::SetNextItemSelectionUserData((int)index);
|
||||
ImGui::Selectable(animation.name.c_str(), mergeSelection.contains((int)index));
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
@@ -399,4 +389,4 @@ namespace anm2ed::imgui
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#include "spritesheet_editor.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <format>
|
||||
#include <utility>
|
||||
|
||||
#include "imgui_.h"
|
||||
#include "imgui_internal.h"
|
||||
#include "math_.h"
|
||||
#include "tool.h"
|
||||
@@ -41,6 +43,7 @@ namespace anm2ed::imgui
|
||||
auto& isGridSnap = settings.editorIsGridSnap;
|
||||
auto& zoomStep = settings.viewZoomStep;
|
||||
auto& isBorder = settings.editorIsBorder;
|
||||
auto& isTransparent = settings.editorIsTransparent;
|
||||
auto spritesheet = document.spritesheet_get();
|
||||
auto& tool = settings.tool;
|
||||
auto& shaderGrid = resources.shaders[shader::GRID];
|
||||
@@ -101,22 +104,40 @@ namespace anm2ed::imgui
|
||||
|
||||
if (ImGui::BeginChild("##Background Child", childSize, true, ImGuiWindowFlags_HorizontalScrollbar))
|
||||
{
|
||||
ImGui::ColorEdit4("Background", value_ptr(backgroundColor), ImGuiColorEditFlags_NoInputs);
|
||||
ImGui::SetItemTooltip("Change the background color.");
|
||||
auto subChildSize = ImVec2(row_widget_width_get(2), ImGui::GetContentRegionAvail().y);
|
||||
|
||||
ImGui::Checkbox("Border", &isBorder);
|
||||
ImGui::SetItemTooltip("Toggle a border appearing around the spritesheet.");
|
||||
if (ImGui::BeginChild("##Background Child 1", subChildSize))
|
||||
{
|
||||
ImGui::ColorEdit3("Background", value_ptr(backgroundColor), ImGuiColorEditFlags_NoInputs);
|
||||
ImGui::SetItemTooltip("Change the background color.");
|
||||
|
||||
ImGui::Checkbox("Border", &isBorder);
|
||||
ImGui::SetItemTooltip("Toggle a border appearing around the spritesheet.");
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::BeginChild("##Background Child 2", subChildSize))
|
||||
{
|
||||
ImGui::Checkbox("Transparent", &isTransparent);
|
||||
ImGui::SetItemTooltip("Toggle the spritesheet editor being transparent.");
|
||||
}
|
||||
|
||||
ImGui::EndChild();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
auto drawList = ImGui::GetCurrentWindow()->DrawList;
|
||||
auto cursorScreenPos = ImGui::GetCursorScreenPos();
|
||||
auto min = ImGui::GetCursorScreenPos();
|
||||
auto max = to_imvec2(to_vec2(min) + size);
|
||||
|
||||
size_set(to_vec2(ImGui::GetContentRegionAvail()));
|
||||
|
||||
bind();
|
||||
viewport_set();
|
||||
clear();
|
||||
clear(isTransparent ? vec4() : vec4(backgroundColor, 1.0f));
|
||||
|
||||
auto frame = document.frame_get();
|
||||
|
||||
@@ -127,7 +148,11 @@ namespace anm2ed::imgui
|
||||
|
||||
auto spritesheetModel = math::quad_model_get(texture.size);
|
||||
auto spritesheetTransform = transform * spritesheetModel;
|
||||
|
||||
texture_render(shaderTexture, texture.id, spritesheetTransform);
|
||||
|
||||
if (isGrid) grid_render(shaderGrid, zoom, pan, gridSize, gridOffset, gridColor);
|
||||
|
||||
if (isBorder)
|
||||
rect_render(dashedShader, spritesheetTransform, spritesheetModel, color::WHITE, BORDER_DASH_LENGTH,
|
||||
BORDER_DASH_GAP, BORDER_DASH_OFFSET);
|
||||
@@ -145,14 +170,12 @@ namespace anm2ed::imgui
|
||||
}
|
||||
}
|
||||
|
||||
if (isGrid) grid_render(shaderGrid, zoom, pan, gridSize, gridOffset, gridColor);
|
||||
|
||||
unbind();
|
||||
|
||||
ImGui::RenderColorRectWithAlphaCheckerboard(ImGui::GetWindowDrawList(), min, max, 0, CHECKER_SIZE,
|
||||
to_imvec2(-size * 0.5f + pan));
|
||||
ImGui::GetCurrentWindow()->DrawList->AddRectFilled(min, max, ImGui::GetColorU32(to_imvec4(backgroundColor)));
|
||||
ImGui::Image(texture, to_imvec2(size));
|
||||
render_checker_background(drawList, min, max, -size * 0.5f - pan, CHECKER_SIZE);
|
||||
if (!isTransparent) drawList->AddRectFilled(min, max, ImGui::GetColorU32(to_imvec4(vec4(backgroundColor, 1.0f))));
|
||||
drawList->AddImage(texture, min, max);
|
||||
ImGui::InvisibleButton("##Spritesheet Editor", to_imvec2(size));
|
||||
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
@@ -325,13 +348,18 @@ namespace anm2ed::imgui
|
||||
}
|
||||
case tool::COLOR_PICKER:
|
||||
{
|
||||
if (isDuring)
|
||||
if (spritesheet && isDuring)
|
||||
{
|
||||
auto position = to_vec2(ImGui::GetMousePos());
|
||||
toolColor = pixel_read(position, {settings.windowSize.x, settings.windowSize.y});
|
||||
toolColor = spritesheet->texture.pixel_read(mousePos);
|
||||
if (ImGui::BeginTooltip())
|
||||
{
|
||||
ImGui::ColorButton("##Color Picker Button", to_imvec4(toolColor));
|
||||
ImGui::SameLine();
|
||||
auto rgba8 = glm::clamp(ivec4(toolColor * 255.0f + 0.5f), ivec4(0), ivec4(255));
|
||||
auto hex = std::format("#{:02X}{:02X}{:02X}{:02X}", rgba8.r, rgba8.g, rgba8.b, rgba8.a);
|
||||
ImGui::TextUnformatted(hex.c_str());
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("(%d, %d, %d, %d)", rgba8.r, rgba8.g, rgba8.b, rgba8.a);
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "timeline.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <ranges>
|
||||
#include <cstddef>
|
||||
|
||||
#include <imgui_internal.h>
|
||||
|
||||
@@ -53,8 +53,11 @@ namespace anm2ed::imgui
|
||||
{
|
||||
if (auto item = animation->item_get(reference.itemType, reference.itemID); item)
|
||||
{
|
||||
for (auto& i : frames.selection | std::views::reverse)
|
||||
for (auto it = frames.selection.rbegin(); it != frames.selection.rend(); ++it)
|
||||
{
|
||||
auto i = *it;
|
||||
item->frames.erase(item->frames.begin() + i);
|
||||
}
|
||||
|
||||
reference.frameIndex = -1;
|
||||
frames.clear();
|
||||
@@ -93,7 +96,12 @@ namespace anm2ed::imgui
|
||||
document.snapshot("Paste Frame(s)");
|
||||
std::set<int> indices{};
|
||||
std::string errorString{};
|
||||
auto insertIndex = reference.frameIndex == -1 ? item->frames.size() : reference.frameIndex + 1;
|
||||
int insertIndex = (int)item->frames.size();
|
||||
if (!frames.selection.empty())
|
||||
insertIndex = std::min((int)item->frames.size(), *frames.selection.rbegin() + 1);
|
||||
else if (reference.frameIndex >= 0 && reference.frameIndex < (int)item->frames.size())
|
||||
insertIndex = reference.frameIndex + 1;
|
||||
|
||||
auto start = reference.itemType == anm2::TRIGGER ? hoveredTime : insertIndex;
|
||||
if (item->frames_deserialize(clipboard.get(), reference.itemType, start, indices, &errorString))
|
||||
{
|
||||
@@ -249,7 +257,7 @@ namespace anm2ed::imgui
|
||||
ImGui::SetCursorPos(
|
||||
ImVec2(itemSize.x - ImGui::GetTextLineHeightWithSpacing() - ImGui::GetStyle().ItemSpacing.x,
|
||||
(itemSize.y - ImGui::GetTextLineHeightWithSpacing()) / 2));
|
||||
int visibleIcon = isVisible ? icon::VISIBLE : icon::INVISIBLE;
|
||||
int visibleIcon = item->isVisible ? icon::VISIBLE : icon::INVISIBLE;
|
||||
if (ImGui::ImageButton("##Visible Toggle", resources.icons[visibleIcon].id, icon_size_get()))
|
||||
DOCUMENT_EDIT(document, "Item Visibility", Document::FRAMES, item->isVisible = !item->isVisible);
|
||||
ImGui::SetItemTooltip(isVisible ? "The item is shown. Press to hide." : "The item is hidden. Press to show.");
|
||||
@@ -544,15 +552,17 @@ namespace anm2ed::imgui
|
||||
|
||||
frames.selection.start(item->frames.size(), ImGuiMultiSelectFlags_ClearOnEscape);
|
||||
|
||||
for (auto [i, frame] : std::views::enumerate(item->frames))
|
||||
for (std::size_t frameIndex = 0; frameIndex < item->frames.size(); ++frameIndex)
|
||||
{
|
||||
ImGui::PushID(i);
|
||||
auto& frame = item->frames[frameIndex];
|
||||
ImGui::PushID((int)frameIndex);
|
||||
|
||||
auto frameReference = anm2::Reference{reference.animationIndex, type, id, (int)i};
|
||||
auto frameReference = anm2::Reference{reference.animationIndex, type, id, (int)frameIndex};
|
||||
auto isFrameVisible = isVisible && frame.isVisible;
|
||||
auto isReferenced = reference == frameReference;
|
||||
auto isSelected =
|
||||
(frames.selection.contains(i) && reference.itemType == type && reference.itemID == id) || isReferenced;
|
||||
(frames.selection.contains((int)frameIndex) && reference.itemType == type && reference.itemID == id) ||
|
||||
isReferenced;
|
||||
|
||||
if (type == anm2::TRIGGER) frameTime = frame.atFrame;
|
||||
|
||||
@@ -569,7 +579,7 @@ namespace anm2ed::imgui
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, isFrameVisible ? colorHovered : colorHoveredHidden);
|
||||
|
||||
ImGui::SetNextItemAllowOverlap();
|
||||
ImGui::SetNextItemSelectionUserData((int)i);
|
||||
ImGui::SetNextItemSelectionUserData((int)frameIndex);
|
||||
if (ImGui::Selectable("##Frame Button", true, ImGuiSelectableFlags_None, buttonSize))
|
||||
{
|
||||
if (type == anm2::LAYER)
|
||||
@@ -785,9 +795,10 @@ namespace anm2ed::imgui
|
||||
draggedTrigger->atFrame = glm::clamp(
|
||||
hoveredTime, 0, settings.playbackIsClamp ? animation->frameNum - 1 : anm2::FRAME_NUM_MAX - 1);
|
||||
|
||||
for (auto&& [i, trigger] : std::views::enumerate(animation->triggers.frames))
|
||||
for (std::size_t triggerIndex = 0; triggerIndex < animation->triggers.frames.size(); ++triggerIndex)
|
||||
{
|
||||
if (i == draggedTriggerIndex) continue;
|
||||
if ((int)triggerIndex == draggedTriggerIndex) continue;
|
||||
auto& trigger = animation->triggers.frames[triggerIndex];
|
||||
if (trigger.atFrame == draggedTrigger->atFrame) draggedTrigger->atFrame--;
|
||||
}
|
||||
if (ImGui::IsMouseReleased(ImGuiMouseButton_Left))
|
||||
@@ -888,8 +899,9 @@ namespace anm2ed::imgui
|
||||
frames_child_row(anm2::LAYER, id);
|
||||
}
|
||||
|
||||
for (auto& id : animation->nullAnimations | std::views::keys)
|
||||
for (const auto& entry : animation->nullAnimations)
|
||||
{
|
||||
auto id = entry.first;
|
||||
if (auto item = animation->item_get(anm2::NULL_, id); item)
|
||||
if (!settings.timelineIsShowUnused && item->frames.empty()) continue;
|
||||
frames_child_row(anm2::NULL_, id);
|
||||
@@ -1259,9 +1271,12 @@ namespace anm2ed::imgui
|
||||
if (ImGui::Button("Bake", widgetSize))
|
||||
{
|
||||
if (auto item = document.item_get())
|
||||
for (auto i : frames.selection | std::views::reverse)
|
||||
for (auto it = frames.selection.rbegin(); it != frames.selection.rend(); ++it)
|
||||
{
|
||||
auto i = *it;
|
||||
DOCUMENT_EDIT(document, "Bake Frames", Document::FRAMES,
|
||||
item->frames_bake(i, interval, isRoundScale, isRoundRotation));
|
||||
}
|
||||
bakePopup.close();
|
||||
}
|
||||
ImGui::SetItemTooltip("Bake the selected frame(s) with the options selected.");
|
||||
@@ -1274,40 +1289,42 @@ namespace anm2ed::imgui
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if (shortcut(manager.chords[SHORTCUT_PLAY_PAUSE], shortcut::GLOBAL)) playback.toggle();
|
||||
|
||||
if (animation)
|
||||
{
|
||||
if (chord_repeating(manager.chords[SHORTCUT_PREVIOUS_FRAME]))
|
||||
if (shortcut(manager.chords[SHORTCUT_PLAY_PAUSE], shortcut::GLOBAL)) playback.toggle();
|
||||
|
||||
if (shortcut(manager.chords[SHORTCUT_PREVIOUS_FRAME], shortcut::GLOBAL, true))
|
||||
{
|
||||
playback.decrement(settings.playbackIsClamp ? animation->frameNum : anm2::FRAME_NUM_MAX);
|
||||
document.frameTime = playback.time;
|
||||
}
|
||||
|
||||
if (chord_repeating(manager.chords[SHORTCUT_NEXT_FRAME]))
|
||||
if (shortcut(manager.chords[SHORTCUT_NEXT_FRAME], shortcut::GLOBAL, true))
|
||||
{
|
||||
playback.increment(settings.playbackIsClamp ? animation->frameNum : anm2::FRAME_NUM_MAX);
|
||||
document.frameTime = playback.time;
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::IsKeyChordPressed(manager.chords[SHORTCUT_SHORTEN_FRAME])) document.snapshot("Shorten Frame");
|
||||
if (chord_repeating(manager.chords[SHORTCUT_SHORTEN_FRAME]))
|
||||
{
|
||||
if (auto frame = document.frame_get())
|
||||
if (shortcut(manager.chords[SHORTCUT_SHORTEN_FRAME], shortcut::GLOBAL)) document.snapshot("Shorten Frame");
|
||||
if (shortcut(manager.chords[SHORTCUT_SHORTEN_FRAME], shortcut::GLOBAL, true))
|
||||
{
|
||||
frame->shorten();
|
||||
document.change(Document::FRAMES);
|
||||
|
||||
if (auto frame = document.frame_get())
|
||||
{
|
||||
frame->shorten();
|
||||
document.change(Document::FRAMES);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::IsKeyChordPressed(manager.chords[SHORTCUT_EXTEND_FRAME])) document.snapshot("Extend Frame");
|
||||
if (chord_repeating(manager.chords[SHORTCUT_EXTEND_FRAME]))
|
||||
{
|
||||
if (auto frame = document.frame_get())
|
||||
if (shortcut(manager.chords[SHORTCUT_EXTEND_FRAME], shortcut::GLOBAL)) document.snapshot("Extend Frame");
|
||||
if (shortcut(manager.chords[SHORTCUT_EXTEND_FRAME], shortcut::GLOBAL, true))
|
||||
{
|
||||
frame->extend();
|
||||
document.change(Document::FRAMES);
|
||||
|
||||
if (auto frame = document.frame_get())
|
||||
{
|
||||
frame->extend();
|
||||
document.change(Document::FRAMES);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,8 @@ namespace anm2ed::imgui
|
||||
|
||||
if (ImGui::BeginChild("##Recent Files Child", {}, ImGuiChildFlags_Borders))
|
||||
{
|
||||
for (auto [i, file] : std::views::enumerate(manager.recentFiles))
|
||||
auto recentFiles = manager.recent_files_ordered();
|
||||
for (auto [i, file] : std::views::enumerate(recentFiles))
|
||||
{
|
||||
ImGui::PushID(i);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user