Refactor + render animation tweaks + updated frame properties + bug fixes
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
#include "about.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <imgui.h>
|
||||
#include <vector>
|
||||
|
||||
using namespace anm2ed::resource;
|
||||
|
||||
namespace anm2ed::imgui::wizard
|
||||
{
|
||||
static constexpr auto CREDIT_DELAY = 1.0f;
|
||||
static constexpr auto CREDIT_SCROLL_SPEED = 25.0f;
|
||||
|
||||
static constexpr About::Credit CREDITS[] = {
|
||||
{"Anm2Ed", font::BOLD},
|
||||
{"License: GPLv3"},
|
||||
{""},
|
||||
{"Designer", font::BOLD},
|
||||
{"Shweet"},
|
||||
{""},
|
||||
{"Additional Help", font::BOLD},
|
||||
{"im-tem"},
|
||||
{""},
|
||||
{"Localization", font::BOLD},
|
||||
{"Gabriel Asencio (Spanish (Latin America))"},
|
||||
{"ExtremeThreat (Russian)"},
|
||||
{"CxRedix (Chinese)"},
|
||||
{"sawalk/사왈이 (Korean)"},
|
||||
{""},
|
||||
{"Based on the work of:", font::BOLD},
|
||||
{"Adrian Gavrilita"},
|
||||
{"Simon Parzer"},
|
||||
{"Matt Kapuszczak"},
|
||||
{""},
|
||||
{"XM Music", font::BOLD},
|
||||
{"Drozerix"},
|
||||
{"\"Keygen Wraith\""},
|
||||
{"https://modarchive.org/module.php?207854"},
|
||||
{"License: CC0"},
|
||||
{""},
|
||||
{"Libraries", font::BOLD},
|
||||
{"Dear ImGui"},
|
||||
{"https://github.com/ocornut/imgui"},
|
||||
{"License: MIT"},
|
||||
{""},
|
||||
{"SDL"},
|
||||
{"https://github.com/libsdl-org/SDL"},
|
||||
{"License: zlib"},
|
||||
{""},
|
||||
{"SDL_mixer"},
|
||||
{"https://github.com/libsdl-org/SDL_mixer"},
|
||||
{"License: zlib"},
|
||||
{""},
|
||||
{"tinyxml2"},
|
||||
{"https://github.com/leethomason/tinyxml2"},
|
||||
{"License: zlib"},
|
||||
{""},
|
||||
{"glm"},
|
||||
{"https://github.com/g-truc/glm"},
|
||||
{"License: MIT"},
|
||||
{""},
|
||||
{"lunasvg"},
|
||||
{"https://github.com/sammycage/lunasvg"},
|
||||
{"License: MIT"},
|
||||
{""},
|
||||
{"Icons", font::BOLD},
|
||||
{"Remix Icons"},
|
||||
{"remixicon.com"},
|
||||
{"License: Apache"},
|
||||
{""},
|
||||
{"Font", font::BOLD},
|
||||
{"Noto Sans"},
|
||||
{"https://fonts.google.com/noto/specimen/Noto+Sans"},
|
||||
{"License: OFL"},
|
||||
{""},
|
||||
{"Special Thanks", font::BOLD},
|
||||
{"Edmund McMillen"},
|
||||
{"Florian Himsl"},
|
||||
{"Tyrone Rodriguez"},
|
||||
{"The-Vinh Truong (_kilburn)"},
|
||||
{"Isaac Reflashed team"},
|
||||
{"Everyone who waited patiently for this to be finished"},
|
||||
{"Everyone else who has worked on The Binding of Isaac!"},
|
||||
{""},
|
||||
{""},
|
||||
{""},
|
||||
{""},
|
||||
{""},
|
||||
{""},
|
||||
{""},
|
||||
{""},
|
||||
{""},
|
||||
{"enjoy the jams :)"},
|
||||
{""},
|
||||
{""},
|
||||
{""},
|
||||
{""},
|
||||
{""},
|
||||
{""},
|
||||
{""},
|
||||
{""},
|
||||
{""},
|
||||
{""},
|
||||
};
|
||||
static constexpr auto CREDIT_COUNT = (int)(sizeof(CREDITS) / sizeof(About::Credit));
|
||||
|
||||
void About::reset(Resources& resources)
|
||||
{
|
||||
resources.music_track().play(true);
|
||||
creditsState = {};
|
||||
creditsState.spawnTimer = CREDIT_DELAY;
|
||||
}
|
||||
|
||||
void About::update(Resources& resources)
|
||||
{
|
||||
auto size = ImGui::GetContentRegionAvail();
|
||||
auto applicationLabel = localize.get(LABEL_APPLICATION_NAME);
|
||||
auto versionLabel = localize.get(LABEL_APPLICATION_VERSION);
|
||||
|
||||
ImGui::PushFont(resources.fonts[font::BOLD].get(), font::SIZE_LARGE);
|
||||
|
||||
ImGui::SetCursorPosX((size.x - ImGui::CalcTextSize(applicationLabel).x) / 2);
|
||||
ImGui::TextUnformatted(applicationLabel);
|
||||
|
||||
ImGui::SetCursorPosX((size.x - ImGui::CalcTextSize(versionLabel).x) / 2);
|
||||
ImGui::TextUnformatted(versionLabel);
|
||||
|
||||
ImGui::PopFont();
|
||||
|
||||
auto creditRegionPos = ImGui::GetCursorScreenPos();
|
||||
auto creditRegionSize = ImGui::GetContentRegionAvail();
|
||||
|
||||
if (creditRegionSize.y > 0.0f && creditRegionSize.x > 0.0f)
|
||||
{
|
||||
auto fontSize = ImGui::GetFontSize();
|
||||
auto drawList = ImGui::GetWindowDrawList();
|
||||
auto clipMax = ImVec2(creditRegionPos.x + creditRegionSize.x, creditRegionPos.y + creditRegionSize.y);
|
||||
drawList->PushClipRect(creditRegionPos, clipMax, true);
|
||||
|
||||
auto delta = ImGui::GetIO().DeltaTime;
|
||||
creditsState.spawnTimer -= delta;
|
||||
auto maxVisible = std::max(1, (int)std::floor(creditRegionSize.y / (float)fontSize));
|
||||
|
||||
while (creditsState.active.size() < (size_t)maxVisible && creditsState.spawnTimer <= 0.0f)
|
||||
{
|
||||
creditsState.active.push_back({creditsState.nextIndex, 0.0f});
|
||||
creditsState.nextIndex = (creditsState.nextIndex + 1) % CREDIT_COUNT;
|
||||
creditsState.spawnTimer += CREDIT_DELAY;
|
||||
}
|
||||
|
||||
auto baseY = clipMax.y - (float)fontSize;
|
||||
auto& baseColor = ImGui::GetStyleColorVec4(ImGuiCol_Text);
|
||||
auto fadeSpan = (float)fontSize * 2.0f;
|
||||
|
||||
for (auto it = creditsState.active.begin(); it != creditsState.active.end();)
|
||||
{
|
||||
it->offset += CREDIT_SCROLL_SPEED * delta;
|
||||
auto yPos = baseY - it->offset;
|
||||
if (yPos + fontSize < creditRegionPos.y)
|
||||
{
|
||||
it = creditsState.active.erase(it);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto& credit = CREDITS[it->index];
|
||||
auto fontPtr = resources.fonts[credit.font].get();
|
||||
auto textSize = fontPtr->CalcTextSizeA((float)fontSize, FLT_MAX, 0.0f, credit.string);
|
||||
auto xPos = creditRegionPos.x + (creditRegionSize.x - textSize.x) * 0.5f;
|
||||
|
||||
auto alpha = 1.0f;
|
||||
auto topDist = yPos - creditRegionPos.y;
|
||||
if (topDist < fadeSpan) alpha *= std::clamp(topDist / fadeSpan, 0.0f, 1.0f);
|
||||
auto bottomDist = (creditRegionPos.y + creditRegionSize.y) - (yPos + fontSize);
|
||||
if (bottomDist < fadeSpan) alpha *= std::clamp(bottomDist / fadeSpan, 0.0f, 1.0f);
|
||||
if (alpha <= 0.0f)
|
||||
{
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto color = baseColor;
|
||||
color.w *= alpha;
|
||||
|
||||
drawList->AddText(fontPtr, fontSize, ImVec2(xPos, yPos), ImGui::GetColorU32(color), credit.string);
|
||||
++it;
|
||||
}
|
||||
|
||||
drawList->PopClipRect();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../resources.h"
|
||||
|
||||
namespace anm2ed::imgui::wizard
|
||||
{
|
||||
class About
|
||||
{
|
||||
public:
|
||||
struct Credit
|
||||
{
|
||||
const char* string{};
|
||||
resource::font::Type font{resource::font::REGULAR};
|
||||
};
|
||||
|
||||
struct ScrollingCredit
|
||||
{
|
||||
int index{};
|
||||
float offset{};
|
||||
};
|
||||
|
||||
struct CreditsState
|
||||
{
|
||||
std::vector<ScrollingCredit> active{};
|
||||
float spawnTimer{1.0f};
|
||||
int nextIndex{};
|
||||
};
|
||||
|
||||
int creditsIndex{};
|
||||
CreditsState creditsState{};
|
||||
|
||||
void reset(Resources& resources);
|
||||
void update(Resources& resources);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
#include "change_all_frame_properties.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
|
||||
#include "math_.h"
|
||||
|
||||
using namespace anm2ed::util::math;
|
||||
using namespace glm;
|
||||
|
||||
namespace anm2ed::imgui::wizard
|
||||
{
|
||||
void ChangeAllFrameProperties::update(Document& document, Settings& settings)
|
||||
{
|
||||
isChanged = false;
|
||||
|
||||
auto& frames = document.frames.selection;
|
||||
auto& isCropX = settings.changeIsCropX;
|
||||
auto& isCropY = settings.changeIsCropY;
|
||||
auto& isSizeX = settings.changeIsSizeX;
|
||||
auto& isSizeY = settings.changeIsSizeY;
|
||||
auto& isPositionX = settings.changeIsPositionX;
|
||||
auto& isPositionY = settings.changeIsPositionY;
|
||||
auto& isPivotX = settings.changeIsPivotX;
|
||||
auto& isPivotY = settings.changeIsPivotY;
|
||||
auto& isScaleX = settings.changeIsScaleX;
|
||||
auto& isScaleY = settings.changeIsScaleY;
|
||||
auto& isRotation = settings.changeIsRotation;
|
||||
auto& isDuration = settings.changeIsDuration;
|
||||
auto& isTintR = settings.changeIsTintR;
|
||||
auto& isTintG = settings.changeIsTintG;
|
||||
auto& isTintB = settings.changeIsTintB;
|
||||
auto& isTintA = settings.changeIsTintA;
|
||||
auto& isColorOffsetR = settings.changeIsColorOffsetR;
|
||||
auto& isColorOffsetG = settings.changeIsColorOffsetG;
|
||||
auto& isColorOffsetB = settings.changeIsColorOffsetB;
|
||||
auto& isVisibleSet = settings.changeIsVisibleSet;
|
||||
auto& isInterpolatedSet = settings.changeIsInterpolatedSet;
|
||||
auto& crop = settings.changeCrop;
|
||||
auto& size = settings.changeSize;
|
||||
auto& position = settings.changePosition;
|
||||
auto& pivot = settings.changePivot;
|
||||
auto& scale = settings.changeScale;
|
||||
auto& rotation = settings.changeRotation;
|
||||
auto& duration = settings.changeDuration;
|
||||
auto& tint = settings.changeTint;
|
||||
auto& colorOffset = settings.changeColorOffset;
|
||||
auto& isVisible = settings.changeIsVisible;
|
||||
auto& isInterpolated = settings.changeIsInterpolated;
|
||||
|
||||
#define PROPERTIES_WIDGET(body, checkboxLabel, isEnabled) \
|
||||
ImGui::Checkbox(checkboxLabel, &isEnabled); \
|
||||
ImGui::SameLine(); \
|
||||
ImGui::BeginDisabled(!isEnabled); \
|
||||
body; \
|
||||
ImGui::EndDisabled();
|
||||
|
||||
auto bool_value = [&](const char* checkboxLabel, const char* valueLabel, bool& isEnabled, bool& value)
|
||||
{ PROPERTIES_WIDGET(ImGui::Checkbox(valueLabel, &value), checkboxLabel, isEnabled) };
|
||||
|
||||
auto color3_value = [&](const char* checkboxRLabel, const char* checkboxGLabel, const char* checkboxBLabel,
|
||||
const char* valueRLabel, const char* valueGLabel, const char* valueBLabel,
|
||||
const char* label, bool& isREnabled, bool& isGEnabled, bool& isBEnabled, vec3& value)
|
||||
{
|
||||
auto style = ImGui::GetStyle();
|
||||
|
||||
auto width = (ImGui::CalcItemWidth() - (ImGui::GetFrameHeightWithSpacing() * 2) - (style.ItemSpacing.x * 2) -
|
||||
ImGui::GetFrameHeight()) /
|
||||
3;
|
||||
|
||||
ivec3 valueAlt = {float_to_uint8(value.r), float_to_uint8(value.g), float_to_uint8(value.b)};
|
||||
|
||||
ImGui::PushItemWidth(width);
|
||||
|
||||
PROPERTIES_WIDGET(ImGui::DragInt(valueRLabel, &valueAlt.r, DRAG_SPEED, 0, 255, "R:%d"), checkboxRLabel,
|
||||
isREnabled);
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
PROPERTIES_WIDGET(ImGui::DragInt(valueGLabel, &valueAlt.g, DRAG_SPEED, 0, 255, "G:%d"), checkboxGLabel,
|
||||
isGEnabled);
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
PROPERTIES_WIDGET(ImGui::DragInt(valueBLabel, &valueAlt.b, DRAG_SPEED, 0, 255, "B:%d"), checkboxBLabel,
|
||||
isBEnabled);
|
||||
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
value = vec3(uint8_to_float(valueAlt.r), uint8_to_float(valueAlt.g), uint8_to_float(valueAlt.b));
|
||||
|
||||
ImVec4 buttonColor = {isREnabled ? value.r : 0, isGEnabled ? value.g : 0, isBEnabled ? value.b : 0, 1};
|
||||
|
||||
ImGui::ColorButton(label, buttonColor);
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::TextUnformatted(label);
|
||||
};
|
||||
|
||||
auto color4_value = [&](const char* checkboxRLabel, const char* checkboxGLabel, const char* checkboxBLabel,
|
||||
const char* checkboxALabel, const char* valueRLabel, const char* valueGLabel,
|
||||
const char* valueBLabel, const char* valueALabel, const char* label, bool& isREnabled,
|
||||
bool& isGEnabled, bool& isBEnabled, bool& isAEnabled, vec4& value)
|
||||
{
|
||||
auto style = ImGui::GetStyle();
|
||||
auto width = (ImGui::CalcItemWidth() - (ImGui::GetFrameHeightWithSpacing() * 3) - (style.ItemSpacing.x * 3) -
|
||||
ImGui::GetFrameHeight()) /
|
||||
4;
|
||||
ivec4 valueAlt = {float_to_uint8(value.r), float_to_uint8(value.g), float_to_uint8(value.b),
|
||||
float_to_uint8(value.a)};
|
||||
|
||||
ImGui::PushItemWidth(width);
|
||||
|
||||
PROPERTIES_WIDGET(ImGui::DragInt(valueRLabel, &valueAlt.r, DRAG_SPEED, 0, 255, "R:%d"), checkboxRLabel,
|
||||
isREnabled);
|
||||
ImGui::SameLine();
|
||||
|
||||
PROPERTIES_WIDGET(ImGui::DragInt(valueGLabel, &valueAlt.g, DRAG_SPEED, 0, 255, "G:%d"), checkboxGLabel,
|
||||
isGEnabled);
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
PROPERTIES_WIDGET(ImGui::DragInt(valueBLabel, &valueAlt.b, DRAG_SPEED, 0, 255, "B:%d"), checkboxBLabel,
|
||||
isBEnabled);
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
PROPERTIES_WIDGET(ImGui::DragInt(valueALabel, &valueAlt.a, DRAG_SPEED, 0, 255, "A:%d"), checkboxALabel,
|
||||
isAEnabled);
|
||||
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
value = vec4(uint8_to_float(valueAlt.r), uint8_to_float(valueAlt.g), uint8_to_float(valueAlt.b),
|
||||
uint8_to_float(valueAlt.a));
|
||||
|
||||
ImVec4 buttonColor = {isREnabled ? value.r : 0, isGEnabled ? value.g : 0, isBEnabled ? value.b : 0,
|
||||
isAEnabled ? value.a : 1};
|
||||
ImGui::ColorButton(label, buttonColor);
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::TextUnformatted(label);
|
||||
};
|
||||
|
||||
auto float_value = [&](const char* checkboxLabel, const char* valueLabel, bool& isEnabled, float& value)
|
||||
{
|
||||
PROPERTIES_WIDGET(ImGui::DragFloat(valueLabel, &value, DRAG_SPEED, 0.0f, 0.0f, float_format_get(value)),
|
||||
checkboxLabel, isEnabled);
|
||||
};
|
||||
|
||||
auto float2_value = [&](const char* checkboxXLabel, const char* checkboxYLabel, const char* valueXLabel,
|
||||
const char* valueYLabel, bool& isXEnabled, bool& isYEnabled, vec2& value)
|
||||
{
|
||||
auto style = ImGui::GetStyle();
|
||||
|
||||
auto width = (ImGui::CalcItemWidth() - ImGui::GetFrameHeightWithSpacing() - style.ItemSpacing.x) / 2;
|
||||
|
||||
ImGui::PushItemWidth(width);
|
||||
PROPERTIES_WIDGET(ImGui::DragFloat(valueXLabel, &value.x, DRAG_SPEED, 0.0f, 0.0f, float_format_get(value.x)),
|
||||
checkboxXLabel, isXEnabled);
|
||||
ImGui::SameLine();
|
||||
PROPERTIES_WIDGET(ImGui::DragFloat(valueYLabel, &value.y, DRAG_SPEED, 0.0f, 0.0f, float_format_get(value.y)),
|
||||
checkboxYLabel, isYEnabled);
|
||||
ImGui::PopItemWidth();
|
||||
};
|
||||
|
||||
auto duration_value = [&](const char* checkboxLabel, const char* valueLabel, bool& isEnabled, int& value)
|
||||
{
|
||||
PROPERTIES_WIDGET(
|
||||
input_int_range(valueLabel, value, anm2::FRAME_DURATION_MIN, anm2::FRAME_DURATION_MAX, STEP, STEP_FAST),
|
||||
checkboxLabel, isEnabled);
|
||||
};
|
||||
|
||||
#undef PROPERTIES_WIDGET
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImGui::GetStyle().ItemInnerSpacing);
|
||||
|
||||
float2_value("##Is Crop X", "##Is Crop Y", "##Crop X", localize.get(BASIC_CROP), isCropX, isCropY, crop);
|
||||
float2_value("##Is Size X", "##Is Size Y", "##Size X", localize.get(BASIC_SIZE), isSizeX, isSizeY, size);
|
||||
float2_value("##Is Position X", "##Is Position Y", "##Position X", localize.get(BASIC_POSITION), isPositionX,
|
||||
isPositionY, position);
|
||||
float2_value("##Is Pivot X", "##Is Pivot Y", "##Pivot X", localize.get(BASIC_PIVOT), isPivotX, isPivotY, pivot);
|
||||
float2_value("##Is Scale X", "##Is Scale Y", "##Scale X", localize.get(BASIC_SCALE), isScaleX, isScaleY, scale);
|
||||
float_value("##Is Rotation", localize.get(BASIC_ROTATION), isRotation, rotation);
|
||||
duration_value("##Is Duration", localize.get(BASIC_DURATION), isDuration, duration);
|
||||
color4_value("##Is Tint R", "##Is Tint G", "##Is Tint B", "##Is Tint A", "##Tint R", "##Tint G", "##Tint B",
|
||||
"##Tint A", localize.get(BASIC_TINT), isTintR, isTintG, isTintB, isTintA, tint);
|
||||
color3_value("##Is Color Offset R", "##Is Color Offset G", "##Is Color Offset B", "##Color Offset R",
|
||||
"##Color Offset B", "##Color Offset G", localize.get(BASIC_COLOR_OFFSET), isColorOffsetR,
|
||||
isColorOffsetG, isColorOffsetB, colorOffset);
|
||||
bool_value("##Is Visible", localize.get(BASIC_VISIBLE), isVisibleSet, isVisible);
|
||||
ImGui::SameLine();
|
||||
bool_value("##Is Interpolated", localize.get(BASIC_INTERPOLATED), isInterpolatedSet, isInterpolated);
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
auto frame_change = [&](anm2::ChangeType type)
|
||||
{
|
||||
anm2::FrameChange frameChange;
|
||||
if (isCropX) frameChange.cropX = crop.x;
|
||||
if (isCropY) frameChange.cropY = crop.y;
|
||||
if (isSizeX) frameChange.sizeX = size.x;
|
||||
if (isSizeY) frameChange.sizeY = size.y;
|
||||
if (isPositionX) frameChange.positionX = position.x;
|
||||
if (isPositionY) frameChange.positionY = position.y;
|
||||
if (isPivotX) frameChange.pivotX = pivot.x;
|
||||
if (isPivotY) frameChange.pivotY = pivot.y;
|
||||
if (isScaleX) frameChange.scaleX = scale.x;
|
||||
if (isScaleY) frameChange.scaleY = scale.y;
|
||||
if (isRotation) frameChange.rotation = std::make_optional(rotation);
|
||||
if (isDuration) frameChange.duration = std::make_optional(duration);
|
||||
if (isTintR) frameChange.tintR = tint.r;
|
||||
if (isTintG) frameChange.tintG = tint.g;
|
||||
if (isTintB) frameChange.tintB = tint.b;
|
||||
if (isTintA) frameChange.tintA = tint.a;
|
||||
if (isColorOffsetR) frameChange.colorOffsetR = colorOffset.r;
|
||||
if (isColorOffsetG) frameChange.colorOffsetG = colorOffset.g;
|
||||
if (isColorOffsetB) frameChange.colorOffsetB = colorOffset.b;
|
||||
if (isVisibleSet) frameChange.isVisible = std::make_optional(isVisible);
|
||||
if (isInterpolatedSet) frameChange.isInterpolated = std::make_optional(isInterpolated);
|
||||
|
||||
DOCUMENT_EDIT(document, localize.get(EDIT_CHANGE_FRAME_PROPERTIES), Document::FRAMES,
|
||||
document.item_get()->frames_change(frameChange, type, *frames.begin(), (int)frames.size()));
|
||||
|
||||
isChanged = true;
|
||||
};
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
bool isAnyProperty = isCropX || isCropY || isSizeX || isSizeY || isPositionX || isPositionY || isPivotX ||
|
||||
isPivotY || isScaleX || isScaleY || isRotation || isDuration || isTintR || isTintG ||
|
||||
isTintB || isTintA || isColorOffsetR || isColorOffsetG || isColorOffsetB || isVisibleSet ||
|
||||
isInterpolatedSet;
|
||||
|
||||
auto rowWidgetSize = widget_size_with_row_get(5);
|
||||
|
||||
ImGui::BeginDisabled(!isAnyProperty);
|
||||
|
||||
if (ImGui::Button(localize.get(LABEL_ADJUST), rowWidgetSize)) frame_change(anm2::ADJUST);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_ADJUST));
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button(localize.get(BASIC_ADD), rowWidgetSize)) frame_change(anm2::ADD);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_ADD_VALUES));
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button(localize.get(LABEL_SUBTRACT), rowWidgetSize)) frame_change(anm2::SUBTRACT);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_SUBTRACT_VALUES));
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button(localize.get(LABEL_MULTIPLY), rowWidgetSize)) frame_change(anm2::MULTIPLY);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_MULTIPLY_VALUES));
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button(localize.get(LABEL_DIVIDE), rowWidgetSize)) frame_change(anm2::DIVIDE);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_DIVIDE_VALUES));
|
||||
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "document.h"
|
||||
#include "settings.h"
|
||||
|
||||
namespace anm2ed::imgui::wizard
|
||||
{
|
||||
class ChangeAllFrameProperties
|
||||
{
|
||||
public:
|
||||
bool isChanged{};
|
||||
|
||||
void update(Document&, Settings&);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
#include "configure.h"
|
||||
|
||||
#include "imgui_.h"
|
||||
|
||||
using namespace anm2ed::types;
|
||||
|
||||
namespace anm2ed::imgui::wizard
|
||||
{
|
||||
void Configure::reset(Settings& settings) { temporary = settings; }
|
||||
|
||||
void Configure::update(Manager& manager, Settings& settings)
|
||||
{
|
||||
isSet = false;
|
||||
|
||||
auto childSize = size_without_footer_get(2);
|
||||
|
||||
if (ImGui::BeginTabBar("##Configure Tabs"))
|
||||
{
|
||||
if (ImGui::BeginTabItem(localize.get(LABEL_DISPLAY)))
|
||||
{
|
||||
if (ImGui::BeginChild("##Tab Child", childSize, true))
|
||||
{
|
||||
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));
|
||||
ImGui::Checkbox(localize.get(LABEL_VSYNC), &temporary.isVsync);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_VSYNC));
|
||||
|
||||
ImGui::SeparatorText(localize.get(LABEL_LOCALIZATION));
|
||||
ImGui::Combo(localize.get(LABEL_LANGUAGE), &temporary.language, LANGUAGE_STRINGS, LANGUAGE_COUNT);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_LANGUAGE));
|
||||
|
||||
ImGui::SeparatorText(localize.get(LABEL_THEME));
|
||||
|
||||
for (int i = 0; i < theme::COUNT; i++)
|
||||
{
|
||||
ImGui::RadioButton(localize.get(theme::STRINGS[i]), &temporary.theme, i);
|
||||
ImGui::SameLine();
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui::BeginTabItem(localize.get(LABEL_FILE_MENU)))
|
||||
{
|
||||
if (ImGui::BeginChild("##Tab Child", childSize, true))
|
||||
{
|
||||
ImGui::SeparatorText(localize.get(LABEL_AUTOSAVE));
|
||||
|
||||
ImGui::Checkbox(localize.get(BASIC_ENABLED), &temporary.fileIsAutosave);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_AUTOSAVE_ENABLED));
|
||||
|
||||
ImGui::BeginDisabled(!temporary.fileIsAutosave);
|
||||
input_int_range(localize.get(LABEL_TIME_MINUTES), temporary.fileAutosaveTime, 0, 10);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_AUTOSAVE_INTERVAL));
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::SeparatorText(localize.get(LABEL_SNAPSHOTS));
|
||||
input_int_range(localize.get(LABEL_STACK_SIZE), temporary.fileSnapshotStackSize, 0, 100);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_STACK_SIZE));
|
||||
|
||||
ImGui::SeparatorText(localize.get(LABEL_OPTIONS));
|
||||
ImGui::Checkbox(localize.get(LABEL_OVERWRITE_WARNING), &temporary.fileIsWarnOverwrite);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_OVERWRITE_WARNING));
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui::BeginTabItem(localize.get(LABEL_INPUT)))
|
||||
{
|
||||
if (ImGui::BeginChild("##Tab Child", childSize, true))
|
||||
{
|
||||
ImGui::SeparatorText(localize.get(LABEL_KEYBOARD));
|
||||
|
||||
input_float_range(localize.get(LABEL_REPEAT_DELAY), temporary.keyboardRepeatDelay, 0.05f, 1.0f, 0.05f, 0.05f,
|
||||
"%.2f");
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_REPEAT_DELAY));
|
||||
|
||||
input_float_range(localize.get(LABEL_REPEAT_RATE), temporary.keyboardRepeatRate, 0.005f, 1.0f, 0.005f, 0.005f,
|
||||
"%.3f");
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_REPEAT_DELAY));
|
||||
|
||||
ImGui::SeparatorText(localize.get(LABEL_ZOOM));
|
||||
|
||||
input_float_range(localize.get(LABEL_ZOOM_STEP), temporary.inputZoomStep, 10.0f, 250.0f, 10.0f, 10.0f,
|
||||
"%.0f%%");
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_ZOOM_STEP));
|
||||
|
||||
ImGui::SeparatorText(localize.get(LABEL_TOOL));
|
||||
|
||||
ImGui::Checkbox(localize.get(LABEL_MOVE_TOOL_SNAP), &temporary.inputIsMoveToolSnapToMouse);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_MOVE_TOOL_SNAP));
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui::BeginTabItem(localize.get(LABEL_SHORTCUTS_TAB)))
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2());
|
||||
|
||||
if (ImGui::BeginChild("##Tab Child", childSize, true))
|
||||
{
|
||||
if (ImGui::BeginTable(localize.get(LABEL_SHORTCUTS_TAB), 2,
|
||||
ImGuiTableFlags_Borders | ImGuiTableFlags_ScrollY))
|
||||
{
|
||||
ImGui::TableSetupScrollFreeze(0, 1);
|
||||
ImGui::TableSetupColumn(localize.get(LABEL_SHORTCUT_COLUMN));
|
||||
ImGui::TableSetupColumn(localize.get(LABEL_VALUE_COLUMN));
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
for (int i = 0; i < SHORTCUT_COUNT; ++i)
|
||||
{
|
||||
bool isSelected = selectedShortcut == i;
|
||||
|
||||
ShortcutMember member = SHORTCUT_MEMBERS[i];
|
||||
std::string* settingString = &(temporary.*member);
|
||||
std::string chordString = isSelected ? "" : *settingString;
|
||||
|
||||
ImGui::PushID(i);
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableSetColumnIndex(0);
|
||||
ImGui::TextUnformatted(localize.get(::anm2ed::SHORTCUT_STRING_TYPES[i]));
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
|
||||
if (ImGui::Selectable(chordString.c_str(), isSelected)) selectedShortcut = i;
|
||||
|
||||
ImGui::PopID();
|
||||
|
||||
if (isSelected)
|
||||
{
|
||||
ImGuiKeyChord chord{ImGuiKey_None};
|
||||
|
||||
if (ImGui::IsKeyDown(ImGuiMod_Ctrl)) chord |= ImGuiMod_Ctrl;
|
||||
if (ImGui::IsKeyDown(ImGuiMod_Shift)) chord |= ImGuiMod_Shift;
|
||||
if (ImGui::IsKeyDown(ImGuiMod_Alt)) chord |= ImGuiMod_Alt;
|
||||
if (ImGui::IsKeyDown(ImGuiMod_Super)) chord |= ImGuiMod_Super;
|
||||
|
||||
for (const auto& entry : KEY_MAP)
|
||||
{
|
||||
auto key = entry.second;
|
||||
if (ImGui::IsKeyPressed(key))
|
||||
{
|
||||
chord |= key;
|
||||
*settingString = chord_to_string(chord);
|
||||
selectedShortcut = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
|
||||
auto widgetSize = widget_size_with_row_get(3);
|
||||
|
||||
if (ImGui::Button(localize.get(BASIC_SAVE), widgetSize))
|
||||
{
|
||||
settings = temporary;
|
||||
|
||||
ImGui::GetIO().KeyRepeatDelay = settings.keyboardRepeatDelay;
|
||||
ImGui::GetIO().KeyRepeatRate = settings.keyboardRepeatRate;
|
||||
ImGui::GetStyle().FontScaleMain = settings.uiScale;
|
||||
SnapshotStack::max_size_set(settings.fileSnapshotStackSize);
|
||||
imgui::theme_set((theme::Type)settings.theme);
|
||||
localize.language = (Language)settings.language;
|
||||
manager.chords_set(settings);
|
||||
|
||||
for (auto& document : manager.documents)
|
||||
document.snapshots.apply_limit();
|
||||
|
||||
isSet = true;
|
||||
}
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_SETTINGS_SAVE));
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button(localize.get(LABEL_USE_DEFAULT_SETTINGS), widgetSize)) temporary = Settings();
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_USE_DEFAULT_SETTINGS));
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button(localize.get(LABEL_CLOSE), widgetSize)) isSet = true;
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_CLOSE_SETTINGS));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "manager.h"
|
||||
|
||||
namespace anm2ed::imgui::wizard
|
||||
{
|
||||
class Configure
|
||||
{
|
||||
Settings temporary{};
|
||||
int selectedShortcut{-1};
|
||||
|
||||
public:
|
||||
bool isSet{};
|
||||
|
||||
void reset(Settings&);
|
||||
void update(Manager&, Settings&);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
#include "generate_animation_from_grid.h"
|
||||
|
||||
#include "math_.h"
|
||||
#include "types.h"
|
||||
|
||||
using namespace anm2ed::types;
|
||||
using namespace anm2ed::util;
|
||||
using namespace glm;
|
||||
|
||||
namespace anm2ed::imgui::wizard
|
||||
{
|
||||
GenerateAnimationFromGrid::GenerateAnimationFromGrid() : Canvas(vec2()) {}
|
||||
|
||||
void GenerateAnimationFromGrid::update(Document& document, Resources& resources, Settings& settings)
|
||||
{
|
||||
isEnd = false;
|
||||
|
||||
auto& startPosition = settings.generateStartPosition;
|
||||
auto& size = settings.generateSize;
|
||||
auto& pivot = settings.generatePivot;
|
||||
auto& rows = settings.generateRows;
|
||||
auto& columns = settings.generateColumns;
|
||||
auto& count = settings.generateCount;
|
||||
auto& delay = settings.generateDuration;
|
||||
auto& zoom = settings.generateZoom;
|
||||
auto& zoomStep = settings.inputZoomStep;
|
||||
|
||||
auto childSize = ImVec2(row_widget_width_get(2), size_without_footer_get().y);
|
||||
|
||||
if (ImGui::BeginChild("##Options Child", childSize, ImGuiChildFlags_Borders))
|
||||
{
|
||||
ImGui::InputInt2(localize.get(LABEL_GENERATE_START_POSITION), value_ptr(startPosition));
|
||||
ImGui::InputInt2(localize.get(LABEL_GENERATE_FRAME_SIZE), value_ptr(size));
|
||||
ImGui::InputInt2(localize.get(BASIC_PIVOT), value_ptr(pivot));
|
||||
ImGui::InputInt(localize.get(LABEL_GENERATE_ROWS), &rows, STEP, STEP_FAST);
|
||||
ImGui::InputInt(localize.get(LABEL_GENERATE_COLUMNS), &columns, STEP, STEP_FAST);
|
||||
|
||||
input_int_range(localize.get(LABEL_GENERATE_COUNT), count, anm2::FRAME_NUM_MIN, rows * columns);
|
||||
|
||||
ImGui::InputInt(localize.get(BASIC_DURATION), &delay, STEP, STEP_FAST);
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::BeginChild("##Preview Child", childSize, ImGuiChildFlags_Borders))
|
||||
{
|
||||
auto& backgroundColor = settings.previewBackgroundColor;
|
||||
auto& shaderTexture = resources.shaders[resource::shader::TEXTURE];
|
||||
|
||||
auto previewSize = ImVec2(ImGui::GetContentRegionAvail().x, size_without_footer_get(2).y);
|
||||
|
||||
bind();
|
||||
size_set(to_vec2(previewSize));
|
||||
viewport_set();
|
||||
clear(vec4(backgroundColor, 1.0f));
|
||||
|
||||
if (document.reference.itemType == anm2::LAYER)
|
||||
{
|
||||
auto& texture =
|
||||
document.anm2.content.spritesheets[document.anm2.content.layers[document.reference.itemID].spritesheetID]
|
||||
.texture;
|
||||
|
||||
auto index = std::clamp((int)(time * (count - 1)), 0, (count - 1));
|
||||
auto row = index / columns;
|
||||
auto column = index % columns;
|
||||
auto crop = startPosition + ivec2(size.x * column, size.y * row);
|
||||
auto uvMin = (vec2(crop) + vec2(0.5f)) / vec2(texture.size);
|
||||
auto uvMax = (vec2(crop) + vec2(size) - vec2(0.5f)) / vec2(texture.size);
|
||||
|
||||
mat4 transform = transform_get(zoom) * math::quad_model_get(size, {}, pivot);
|
||||
|
||||
texture_render(shaderTexture, texture.id, transform, vec4(1.0f), {},
|
||||
math::uv_vertices_get(uvMin, uvMax).data());
|
||||
}
|
||||
|
||||
unbind();
|
||||
|
||||
ImGui::Image(texture, previewSize);
|
||||
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
ImGui::SliderFloat("##Time", &time, 0.0f, 1.0f, "");
|
||||
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
ImGui::InputFloat("##Zoom", &zoom, zoomStep, zoomStep, "%.0f%%");
|
||||
zoom = glm::clamp(zoom, ZOOM_MIN, ZOOM_MAX);
|
||||
}
|
||||
|
||||
ImGui::EndChild();
|
||||
|
||||
auto widgetSize = widget_size_with_row_get(2);
|
||||
|
||||
if (ImGui::Button(localize.get(LABEL_GENERATE), widgetSize))
|
||||
{
|
||||
auto generate_from_grid = [&]()
|
||||
{
|
||||
auto item = document.item_get();
|
||||
auto animation = document.animation_get();
|
||||
|
||||
if (item && animation)
|
||||
{
|
||||
item->frames_generate_from_grid(startPosition, size, pivot, columns, count, delay);
|
||||
animation->frameNum = animation->length();
|
||||
}
|
||||
};
|
||||
|
||||
DOCUMENT_EDIT(document, localize.get(EDIT_GENERATE_ANIMATION_FROM_GRID), Document::FRAMES, generate_from_grid());
|
||||
isEnd = true;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button(localize.get(BASIC_CANCEL), widgetSize)) isEnd = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "canvas.h"
|
||||
#include "document.h"
|
||||
#include "resources.h"
|
||||
#include "settings.h"
|
||||
|
||||
namespace anm2ed::imgui::wizard
|
||||
{
|
||||
class GenerateAnimationFromGrid : public Canvas
|
||||
{
|
||||
float time{};
|
||||
|
||||
public:
|
||||
bool isEnd{};
|
||||
|
||||
GenerateAnimationFromGrid();
|
||||
void update(Document&, Resources&, Settings&);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
#include "render_animation.h"
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include "log.h"
|
||||
#include "path_.h"
|
||||
#include "process_.h"
|
||||
#include "toast.h"
|
||||
|
||||
#include <ranges>
|
||||
|
||||
using namespace anm2ed::resource;
|
||||
using namespace anm2ed::util;
|
||||
|
||||
namespace anm2ed::imgui::wizard
|
||||
{
|
||||
void RenderAnimation::range_to_animation_set(Manager& manager, Document& document)
|
||||
{
|
||||
if (auto animation = document.animation_get())
|
||||
{
|
||||
manager.recordingStart = 0;
|
||||
manager.recordingEnd = animation->frameNum - 1;
|
||||
}
|
||||
}
|
||||
|
||||
void RenderAnimation::range_to_frames_set(Manager& manager, Document& document)
|
||||
{
|
||||
auto& frames = document.frames.selection;
|
||||
if (!frames.empty())
|
||||
{
|
||||
if (auto item = document.item_get())
|
||||
{
|
||||
int duration{};
|
||||
for (auto [i, frame] : std::views::enumerate(item->frames))
|
||||
{
|
||||
if ((int)i == *frames.begin()) manager.recordingStart = duration;
|
||||
if ((int)i == *frames.rbegin()) manager.recordingEnd = duration + frame.duration - 1;
|
||||
|
||||
duration += frame.duration;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderAnimation::reset(Manager& manager, Document& document, Settings& settings)
|
||||
{
|
||||
if (!manager.isRecordingRange) range_to_animation_set(manager, document);
|
||||
settings.renderPath.replace_extension(render::EXTENSIONS[settings.renderType]);
|
||||
}
|
||||
|
||||
void RenderAnimation::update(Manager& manager, Document& document, Resources& resources, Settings& settings,
|
||||
Dialog& dialog)
|
||||
{
|
||||
isEnd = false;
|
||||
|
||||
auto animation = document.animation_get();
|
||||
if (!animation) return;
|
||||
|
||||
auto& ffmpegPath = settings.renderFFmpegPath;
|
||||
auto& path = settings.renderPath;
|
||||
auto& format = settings.renderFormat;
|
||||
auto& scale = settings.renderScale;
|
||||
auto& isRaw = settings.renderIsRawAnimation;
|
||||
auto& type = settings.renderType;
|
||||
auto& start = manager.recordingStart;
|
||||
auto& end = manager.recordingEnd;
|
||||
auto& rows = settings.renderRows;
|
||||
auto& columns = settings.renderColumns;
|
||||
auto& isRange = manager.isRecordingRange;
|
||||
auto& frames = document.frames.selection;
|
||||
auto& reference = document.reference;
|
||||
auto& frameNum = animation->frameNum;
|
||||
|
||||
auto widgetSize = widget_size_with_row_get(2);
|
||||
auto dialogType = type == render::PNGS ? Dialog::PNG_DIRECTORY_SET
|
||||
: type == render::SPRITESHEET ? Dialog::PNG_PATH_SET
|
||||
: type == render::GIF ? Dialog::GIF_PATH_SET
|
||||
: type == render::WEBM ? Dialog::WEBM_PATH_SET
|
||||
: Dialog::NONE;
|
||||
|
||||
if (ImGui::ImageButton("##FFmpeg Path Set", resources.icons[icon::FOLDER].id, icon_size_get()))
|
||||
dialog.file_open(Dialog::FFMPEG_PATH_SET);
|
||||
ImGui::SameLine();
|
||||
input_text_path(localize.get(LABEL_FFMPEG_PATH), &ffmpegPath);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_FFMPEG_PATH));
|
||||
|
||||
if (dialog.is_selected(Dialog::FFMPEG_PATH_SET))
|
||||
{
|
||||
ffmpegPath = path::to_utf8(dialog.path);
|
||||
dialog.reset();
|
||||
}
|
||||
|
||||
if (ImGui::ImageButton("##Path Set", resources.icons[icon::FOLDER].id, icon_size_get()))
|
||||
{
|
||||
if (dialogType == Dialog::PNG_DIRECTORY_SET)
|
||||
dialog.folder_open(dialogType);
|
||||
else
|
||||
dialog.file_save(dialogType);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
auto pathLabel = type == render::PNGS ? LABEL_OUTPUT_DIRECTORY : LABEL_OUTPUT_PATH;
|
||||
input_text_path(localize.get(pathLabel), &path);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_OUTPUT_PATH));
|
||||
|
||||
if (dialog.is_selected(dialogType))
|
||||
{
|
||||
path = path::to_utf8(dialog.path);
|
||||
dialog.reset();
|
||||
}
|
||||
|
||||
if (ImGui::Combo(localize.get(LABEL_TYPE), &type, render::STRINGS, render::COUNT))
|
||||
path.replace_extension(render::EXTENSIONS[type]);
|
||||
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_RENDER_TYPE));
|
||||
|
||||
if (type == render::PNGS || type == render::SPRITESHEET) ImGui::Separator();
|
||||
|
||||
if (type == render::PNGS)
|
||||
{
|
||||
input_text_path(localize.get(LABEL_FORMAT), &format);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_FORMAT));
|
||||
}
|
||||
else if (type == render::SPRITESHEET)
|
||||
{
|
||||
input_int_range(localize.get(LABEL_GENERATE_ROWS), rows, 1, frameNum - 1);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_ROWS));
|
||||
|
||||
input_int_range(localize.get(LABEL_GENERATE_COLUMNS), columns, 1, frameNum - 1);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_COLUMNS));
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Checkbox(localize.get(LABEL_CUSTOM_RANGE), &isRange);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_CUSTOM_RANGE));
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::BeginDisabled(frames.empty() || reference.itemID == anm2::TRIGGER);
|
||||
if (ImGui::Button(localize.get(LABEL_TO_SELECTED_FRAMES))) range_to_frames_set(manager, document);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_TO_SELECTED_FRAMES));
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button(localize.get(LABEL_TO_ANIMATION_RANGE))) range_to_animation_set(manager, document);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_TO_ANIMATION_RANGE));
|
||||
|
||||
ImGui::BeginDisabled(!isRange);
|
||||
{
|
||||
input_int_range(localize.get(LABEL_START), start, 0, frameNum - 1);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_START));
|
||||
input_int_range(localize.get(LABEL_END), end, start, frameNum - 1);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_END));
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Checkbox(localize.get(LABEL_RAW), &isRaw);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_RAW));
|
||||
|
||||
ImGui::BeginDisabled(!isRaw);
|
||||
{
|
||||
input_float_range(localize.get(BASIC_SCALE), scale, 1.0f, 100.0f, STEP, STEP_FAST, "%.1fx");
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_SCALE_OUTPUT));
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Checkbox(localize.get(LABEL_SOUND), &settings.timelineIsSound);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_SOUND));
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::Button(localize.get(LABEL_RENDER), widgetSize))
|
||||
{
|
||||
path.replace_extension(render::EXTENSIONS[type]);
|
||||
|
||||
auto render_is_valid = [&]()
|
||||
{
|
||||
auto ffmpeg_is_valid = [&]()
|
||||
{
|
||||
if (!path::is_executable(ffmpegPath)) return false;
|
||||
|
||||
auto testCommand = ffmpegPath.string() + " -version";
|
||||
Process process(testCommand.c_str(), "r");
|
||||
auto result = process.output_get_and_close();
|
||||
|
||||
if (!result.contains("ffmpeg version")) return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
auto ffmpeg_valid_check = [&]()
|
||||
{
|
||||
if (!ffmpeg_is_valid())
|
||||
{
|
||||
toasts.push(localize.get(TOAST_INVALID_FFMPEG));
|
||||
logger.error(localize.get(TOAST_INVALID_FFMPEG, anm2ed::ENGLISH));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
auto png_format_valid_check = [&]()
|
||||
{
|
||||
if (!format.string().contains("{}"))
|
||||
{
|
||||
toasts.push(localize.get(TOAST_PNG_FORMAT_INVALID));
|
||||
logger.error(localize.get(TOAST_PNG_FORMAT_INVALID, anm2ed::ENGLISH));
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
auto path_valid_check = [&]()
|
||||
{
|
||||
if (path.empty())
|
||||
{
|
||||
toasts.push(localize.get(TOAST_RENDER_PATH_EMPTY));
|
||||
logger.error(localize.get(TOAST_RENDER_PATH_EMPTY, anm2ed::ENGLISH));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
auto png_directory_valid_check = [&]()
|
||||
{
|
||||
if (!path::ensure_directory(path))
|
||||
{
|
||||
toasts.push(localize.get(TOAST_PNG_DIRECTORY_INVALID));
|
||||
logger.error(localize.get(TOAST_PNG_DIRECTORY_INVALID, anm2ed::ENGLISH));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
auto spritesheet_valid_check = [&]()
|
||||
{
|
||||
if (rows <= 0 && columns <= 0)
|
||||
{
|
||||
toasts.push(localize.get(TOAST_RENDER_PATH_EMPTY));
|
||||
logger.error(localize.get(TOAST_RENDER_PATH_EMPTY, anm2ed::ENGLISH));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!path_valid_check()) return false;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case render::PNGS:
|
||||
if (!png_directory_valid_check()) return false;
|
||||
if (!png_format_valid_check()) return false;
|
||||
format.replace_extension(render::EXTENSIONS[render::SPRITESHEET]);
|
||||
break;
|
||||
case render::SPRITESHEET:
|
||||
if (!spritesheet_valid_check()) return false;
|
||||
break;
|
||||
case render::GIF:
|
||||
case render::WEBM:
|
||||
case render::MP4:
|
||||
if (!ffmpeg_valid_check()) return false;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
if (render_is_valid())
|
||||
{
|
||||
manager.isRecordingStart = true;
|
||||
manager.progressPopup.open();
|
||||
}
|
||||
|
||||
isEnd = true;
|
||||
}
|
||||
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_RENDER_BUTTON));
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button(localize.get(BASIC_CANCEL), widgetSize)) isEnd = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "dialog.h"
|
||||
#include "manager.h"
|
||||
#include "resources.h"
|
||||
|
||||
namespace anm2ed::imgui::wizard
|
||||
{
|
||||
class RenderAnimation
|
||||
{
|
||||
|
||||
public:
|
||||
bool isEnd{};
|
||||
|
||||
void range_to_frames_set(Manager&, Document&);
|
||||
void range_to_animation_set(Manager&, Document&);
|
||||
void reset(Manager&, Document&, Settings&);
|
||||
void update(Manager&, Document&, Resources&, Settings&, Dialog&);
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user