From f49eaa6a37de38fd79d0cb87ed66e8d7c0db89f8 Mon Sep 17 00:00:00 2001 From: shweet Date: Mon, 15 Sep 2025 11:14:58 -0400 Subject: [PATCH] Added animation bounds for rendering animations, redid float format stuff --- src/COMMON.h | 28 +++++++--------------------- src/imgui.cpp | 18 ++++++++++++------ src/imgui.h | 18 ++++++++++++++++-- src/preview.cpp | 23 +++++++++++++++++++++++ src/preview.h | 3 +++ src/settings.h | 15 +++++++++------ workshop/metadata.xml | 2 +- 7 files changed, 71 insertions(+), 36 deletions(-) diff --git a/src/COMMON.h b/src/COMMON.h index dae244b..4718041 100644 --- a/src/COMMON.h +++ b/src/COMMON.h @@ -114,39 +114,25 @@ static inline std::string string_to_lowercase(std::string string) { return string; } - -#define FLOAT_FORMAT_MAX_DECIMALS 9 -#define FLOAT_FORMAT_EPSILON 1e-9f +#define FLOAT_FORMAT_MAX_DECIMALS 5 +#define FLOAT_FORMAT_EPSILON 1e-5f static constexpr f32 FLOAT_FORMAT_POW10[] = { 1.f, 10.f, 100.f, 1000.f, 10000.f, - 100000.f, - 1000000.f, - 10000000.f, - 100000000.f, - 1000000000.f + 100000.f }; static inline s32 f32_decimals_needed(f32 value) { - f32 integerPart = 0.f; - f32 fractionalPart = modff(value, &integerPart); - fractionalPart = fabsf(fractionalPart); - - if (fractionalPart < FLOAT_FORMAT_EPSILON) - return 0; - - for (s32 decimalCount = 1; decimalCount <= FLOAT_FORMAT_MAX_DECIMALS; ++decimalCount) + for (s32 decimalCount = 0; decimalCount <= FLOAT_FORMAT_MAX_DECIMALS; ++decimalCount) { - f32 scaledFraction = fractionalPart * FLOAT_FORMAT_POW10[decimalCount]; - if (fabsf(scaledFraction - roundf(scaledFraction)) < - FLOAT_FORMAT_EPSILON * FLOAT_FORMAT_POW10[decimalCount]) - { + f32 scale = FLOAT_FORMAT_POW10[decimalCount]; + f32 rounded = roundf(value * scale) / scale; + if (fabsf(value - rounded) < FLOAT_FORMAT_EPSILON) return decimalCount; - } } return FLOAT_FORMAT_MAX_DECIMALS; } diff --git a/src/imgui.cpp b/src/imgui.cpp index 68f95bb..43321b8 100644 --- a/src/imgui.cpp +++ b/src/imgui.cpp @@ -1612,8 +1612,10 @@ static void _imgui_taskbar(Imgui* self) static DialogType& dialogType = self->dialog->type; static bool& dialogIsSelected = self->dialog->isSelected; static s32& type = self->settings->renderType; + static f32& scale = self->settings->renderScale; + static bool& isUseAnimationBounds = self->settings->renderIsUseAnimationBounds; static std::string& dialogPath = self->dialog->path; - static std::string& ffmpegPath = self->settings->ffmpegPath; + static std::string& ffmpegPath = self->settings->renderFFmpegPath; static std::string& format = self->settings->renderFormat; static std::string& path = self->settings->renderPath; @@ -1640,8 +1642,10 @@ static void _imgui_taskbar(Imgui* self) } _imgui_input_text(IMGUI_RENDER_ANIMATION_FFMPEG_PATH, self, ffmpegPath); - _imgui_input_text(IMGUI_RENDER_ANIMATION_FORMAT, self, format); _imgui_combo(IMGUI_RENDER_ANIMATION_OUTPUT, self, &type); + _imgui_input_text(IMGUI_RENDER_ANIMATION_FORMAT.copy({type != RENDER_PNG}), self, format); + _imgui_checkbox(IMGUI_RENDER_ANIMATION_IS_USE_ANIMATION_BOUNDS, self, isUseAnimationBounds); + _imgui_input_float(IMGUI_RENDER_ANIMATION_SCALE.copy({!isUseAnimationBounds}), self, scale); _imgui_end_child(); // IMGUI_RENDER_ANIMATION_CHILD @@ -1765,7 +1769,7 @@ static void _imgui_taskbar(Imgui* self) case RENDER_WEBM: case RENDER_MP4: { - std::string ffmpegPath = std::string(self->settings->ffmpegPath.c_str()); + std::string ffmpegPath = std::string(self->settings->renderFFmpegPath.c_str()); path = path_extension_change(path, RENDER_EXTENSIONS[self->settings->renderType]); if (ffmpeg_render(ffmpegPath, path, frames, self->preview->canvas.size, self->anm2->fps, (RenderType)type)) @@ -2463,8 +2467,8 @@ static void _imgui_animation_preview(Imgui* self) if (_imgui_button(IMGUI_ANIMATION_PREVIEW_CENTER_VIEW.copy({pan == vec2()}), self)) pan = vec2(); if (_imgui_button(IMGUI_ANIMATION_PREVIEW_FIT.copy({self->reference->animationID == ID_NONE}), self)) { - vec4 rect = anm2_animation_rect_get(self->anm2, self->reference, self->settings->previewIsRootTransform); - + vec4 rect = anm2_animation_rect_get(self->anm2, self->reference, self->settings->previewIsRootTransform); + if (rect != vec4(-1.0f) && (rect.z > 0 && rect.w > 0)) { f32 scaleX = self->preview->canvas.size.x / rect.z; @@ -2527,7 +2531,9 @@ static void _imgui_animation_preview(Imgui* self) _imgui_end_child(); // IMGUI_CANVAS_HELPER_CHILD ImVec2 previewCursorScreenPos = ImGui::GetCursorScreenPos(); - size = ivec2(vec2(ImGui::GetContentRegionAvail())); + + if (!self->preview->isRender) size = ivec2(vec2(ImGui::GetContentRegionAvail())); + preview_draw(self->preview); ImGui::Image(self->preview->canvas.framebuffer, vec2(size)); diff --git a/src/imgui.h b/src/imgui.h index 9549cb1..85d2cd8 100644 --- a/src/imgui.h +++ b/src/imgui.h @@ -1132,7 +1132,7 @@ IMGUI_ITEM(IMGUI_RENDER_ANIMATION, self.label = "&Render Animation", self.tooltip = "Renders the current animation preview; output options can be customized.", self.popup = "Render Animation", - self.popupSize = {600, 150}, + self.popupSize = {500, 170}, self.popupType = IMGUI_POPUP_CENTER_WINDOW ); @@ -1157,7 +1157,7 @@ IMGUI_ITEM(IMGUI_RENDER_ANIMATION_LOCATION_BROWSE, IMGUI_ITEM(IMGUI_RENDER_ANIMATION_LOCATION, self.label = "Location", - self.tooltip = "Select the location of the rendered animation.", + self.tooltip = "Select the location of the rendered animation.\nFor PNG images, this should be a directory, otherwise, a filepath.", self.max = 1024 ); @@ -1187,6 +1187,20 @@ IMGUI_ITEM(IMGUI_RENDER_ANIMATION_FORMAT, self.max = UCHAR_MAX ); +IMGUI_ITEM(IMGUI_RENDER_ANIMATION_IS_USE_ANIMATION_BOUNDS, + self.label = "Use Animation Bounds", + self.tooltip = "Instead of using the animation preview's bounds, the rendered animation will use the animation's bounds.\nNOTE: If you're looking to make a transparent animation, set the preview background to be transparent\nand toggle off other drawn things.", + self.value = SETTINGS_RENDER_IS_USE_ANIMATION_BOUNDS_DEFAULT, + self.isSameLine = true +); + +IMGUI_ITEM(IMGUI_RENDER_ANIMATION_SCALE, + self.label = "Scale", + self.tooltip = "Change the scale the animation will be rendered at.", + self.value = SETTINGS_RENDER_SCALE_DEFAULT, + self.size = {125, 0} +); + IMGUI_ITEM(IMGUI_RENDER_ANIMATION_CONFIRM, self.label = "Render", self.tooltip = "Render the animation, with the used settings.", diff --git a/src/preview.cpp b/src/preview.cpp index 8001854..48a8c00 100644 --- a/src/preview.cpp +++ b/src/preview.cpp @@ -242,6 +242,25 @@ void preview_render_start(Preview* self) self->isPlaying = true; self->time = 0.0f; _preview_render_textures_free(self); + + self->normalCanvasSize = self->canvas.size; + self->normalCanvasPan = self->settings->previewPan; + self->normalCanvasZoom = self->settings->previewZoom; + + if (self->settings->renderIsUseAnimationBounds) + { + vec4 rect = anm2_animation_rect_get(self->anm2, self->reference, self->settings->previewIsRootTransform); + + self->canvas.size = ivec2 + ( + ceilf(rect.z * self->settings->renderScale), + ceilf(rect.w * self->settings->renderScale) + ); + + vec2 rectCenter = vec2(rect.x + rect.z * 0.5f, rect.y + rect.w * 0.5f); + self->settings->previewPan = -rectCenter * self->settings->renderScale; + self->settings->previewZoom = UNIT_TO_PERCENT(self->settings->renderScale); + } } void preview_render_end(Preview* self) @@ -250,6 +269,10 @@ void preview_render_end(Preview* self) self->isPlaying = false; self->isRenderFinished = false; _preview_render_textures_free(self); + + self->canvas.size = self->normalCanvasSize; + self->settings->previewPan = self->normalCanvasPan; + self->settings->previewZoom = self->normalCanvasZoom; } void preview_free(Preview* self) diff --git a/src/preview.h b/src/preview.h index 926e694..7fcfa26 100644 --- a/src/preview.h +++ b/src/preview.h @@ -34,6 +34,9 @@ struct Preview Settings* settings = nullptr; s32 animationOverlayID = ID_NONE; Canvas canvas; + vec2 normalCanvasSize{}; + vec2 normalCanvasPan{}; + f32 normalCanvasZoom{}; bool isPlaying = false; bool isRender = false; bool isRenderFinished = false; diff --git a/src/settings.h b/src/settings.h index f9c0170..d72be3a 100644 --- a/src/settings.h +++ b/src/settings.h @@ -21,9 +21,9 @@ #define SETTINGS_TEMPORARY_EXTENSION ".tmp" #ifdef _WIN32 -#define SETTINGS_FFMPEG_PATH_VALUE_DEFAULT "C:\\ffmpeg\\bin\\ffmpeg.exe" +#define SETTINGS_RENDER_FFMPEG_PATH_VALUE_DEFAULT "C:\\ffmpeg\\bin\\ffmpeg.exe" #else -#define SETTINGS_FFMPEG_PATH_VALUE_DEFAULT "/usr/bin/ffmpeg" +#define SETTINGS_RENDER_FFMPEG_PATH_VALUE_DEFAULT "/usr/bin/ffmpeg" #endif #define SETTINGS_LIST \ @@ -143,10 +143,13 @@ X(tool, TOOL, TYPE_INT, TOOL_PAN) \ X(toolColor, TOOL_COLOR, TYPE_VEC4, {1.0,1.0,1.0,1.0}) \ \ - X(renderType, RENDER_TYPE, TYPE_INT, RENDER_PNG) \ - X(renderPath, RENDER_PATH, TYPE_STRING, ".") \ - X(renderFormat, RENDER_FORMAT, TYPE_STRING, "{}.png") \ - X(ffmpegPath, FFMPEG_PATH, TYPE_STRING, SETTINGS_FFMPEG_PATH_VALUE_DEFAULT) + X(renderType, RENDER_TYPE, TYPE_INT, RENDER_PNG) \ + X(renderPath, RENDER_PATH, TYPE_STRING, ".") \ + X(renderFormat, RENDER_FORMAT, TYPE_STRING, "{}.png") \ + X(renderIsUseAnimationBounds,RENDER_IS_USE_ANIMATION_BOUNDS,TYPE_BOOL, true) \ + X(renderIsTransparent, RENDER_IS_TRANSPARENT, TYPE_BOOL, true) \ + X(renderScale, RENDER_SCALE, TYPE_FLOAT, 1.0f) \ + X(renderFFmpegPath, RENDER_FFMPEG_PATH, TYPE_STRING, SETTINGS_RENDER_FFMPEG_PATH_VALUE_DEFAULT) #define X(name, symbol, type, ...) \ const inline DATATYPE_TO_CTYPE(type) SETTINGS_##symbol##_DEFAULT = __VA_ARGS__; diff --git a/workshop/metadata.xml b/workshop/metadata.xml index 97e1c32..44801ef 100644 --- a/workshop/metadata.xml +++ b/workshop/metadata.xml @@ -43,6 +43,6 @@ Alternatively, if you have subscribed to the mod, you can find the latest releas [h3]Happy animating![/h3] [img]https://files.catbox.moe/4auc1c.gif[/img] - 1.1 + 1.2 Public