60Hz
This commit is contained in:
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
namespace anm2ed::imgui
|
namespace anm2ed::imgui
|
||||||
{
|
{
|
||||||
void Dockspace::tick(Manager& manager, Settings& settings)
|
void Dockspace::tick(Manager& manager, Settings& settings, float deltaSeconds)
|
||||||
{
|
{
|
||||||
if (auto document = manager.get(); document)
|
if (auto document = manager.get(); document)
|
||||||
if (settings.windowIsAnimationPreview) animationPreview.tick(manager, settings);
|
if (settings.windowIsAnimationPreview) animationPreview.tick(manager, settings, deltaSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dockspace::update(Taskbar& taskbar, Documents& documents, Manager& manager, Settings& settings,
|
void Dockspace::update(Taskbar& taskbar, Documents& documents, Manager& manager, Settings& settings,
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ namespace anm2ed::imgui
|
|||||||
Welcome welcome;
|
Welcome welcome;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void tick(Manager&, Settings&);
|
void tick(Manager&, Settings&, float);
|
||||||
void update(Taskbar&, Documents&, Manager&, Settings&, Resources&, Dialog&, Clipboard&);
|
void update(Taskbar&, Documents&, Manager&, Settings&, Resources&, Dialog&, Clipboard&);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,8 +34,6 @@ namespace anm2ed::imgui
|
|||||||
constexpr auto POINT_SIZE = vec2(4, 4);
|
constexpr auto POINT_SIZE = vec2(4, 4);
|
||||||
constexpr auto TRIGGER_TEXT_COLOR_DARK = ImVec4(1.0f, 1.0f, 1.0f, 0.5f);
|
constexpr auto TRIGGER_TEXT_COLOR_DARK = ImVec4(1.0f, 1.0f, 1.0f, 0.5f);
|
||||||
constexpr auto TRIGGER_TEXT_COLOR_LIGHT = ImVec4(0.0f, 0.0f, 0.0f, 0.5f);
|
constexpr auto TRIGGER_TEXT_COLOR_LIGHT = ImVec4(0.0f, 0.0f, 0.0f, 0.5f);
|
||||||
constexpr auto PLAYBACK_TICK_RATE = 30.0f;
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
std::filesystem::path render_destination_directory(const std::filesystem::path& path, int type)
|
std::filesystem::path render_destination_directory(const std::filesystem::path& path, int type)
|
||||||
@@ -153,7 +151,7 @@ namespace anm2ed::imgui
|
|||||||
|
|
||||||
AnimationPreview::AnimationPreview() : Canvas(vec2()) {}
|
AnimationPreview::AnimationPreview() : Canvas(vec2()) {}
|
||||||
|
|
||||||
void AnimationPreview::tick(Manager& manager, Settings& settings)
|
void AnimationPreview::tick(Manager& manager, Settings& settings, float deltaSeconds)
|
||||||
{
|
{
|
||||||
auto& document = *manager.get();
|
auto& document = *manager.get();
|
||||||
auto& anm2 = document.anm2;
|
auto& anm2 = document.anm2;
|
||||||
@@ -176,8 +174,9 @@ namespace anm2ed::imgui
|
|||||||
auto& path = settings.renderPath;
|
auto& path = settings.renderPath;
|
||||||
auto pathString = path::to_utf8(path);
|
auto pathString = path::to_utf8(path);
|
||||||
auto& type = settings.renderType;
|
auto& type = settings.renderType;
|
||||||
|
auto renderFrameRate = std::max(settings.playbackTickRate, 1);
|
||||||
|
|
||||||
if (playback.time > end || playback.isFinished)
|
if (playback.time >= (float)end + 1.0f || playback.isFinished)
|
||||||
{
|
{
|
||||||
if (settings.timelineIsSound) audioStream.capture_end(mixer);
|
if (settings.timelineIsSound) audioStream.capture_end(mixer);
|
||||||
|
|
||||||
@@ -262,7 +261,7 @@ namespace anm2ed::imgui
|
|||||||
{
|
{
|
||||||
if (settings.timelineIsSound && type != render::GIF)
|
if (settings.timelineIsSound && type != render::GIF)
|
||||||
{
|
{
|
||||||
if (!render_audio_stream_generate(audioStream, anm2.content.sounds, renderFrameSoundIDs, anm2.info.fps))
|
if (!render_audio_stream_generate(audioStream, anm2.content.sounds, renderFrameSoundIDs, renderFrameRate))
|
||||||
{
|
{
|
||||||
toasts.push(localize.get(TOAST_EXPORT_RENDERED_ANIMATION_FAILED));
|
toasts.push(localize.get(TOAST_EXPORT_RENDERED_ANIMATION_FAILED));
|
||||||
logger.error("Failed to generate deterministic render audio stream; exporting without audio.");
|
logger.error("Failed to generate deterministic render audio stream; exporting without audio.");
|
||||||
@@ -273,7 +272,7 @@ namespace anm2ed::imgui
|
|||||||
audioStream.stream.clear();
|
audioStream.stream.clear();
|
||||||
|
|
||||||
if (animation_render(ffmpegPath, path, renderTempFrames, renderTempFrameDurations, audioStream,
|
if (animation_render(ffmpegPath, path, renderTempFrames, renderTempFrameDurations, audioStream,
|
||||||
(render::Type)type, anm2.info.fps))
|
(render::Type)type, renderFrameRate))
|
||||||
{
|
{
|
||||||
toasts.push(std::vformat(localize.get(TOAST_EXPORT_RENDERED_ANIMATION), std::make_format_args(pathString)));
|
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),
|
logger.info(std::vformat(localize.get(TOAST_EXPORT_RENDERED_ANIMATION, anm2ed::ENGLISH),
|
||||||
@@ -325,8 +324,10 @@ namespace anm2ed::imgui
|
|||||||
auto frameSoundID = -1;
|
auto frameSoundID = -1;
|
||||||
if (settings.timelineIsSound && !anm2.content.sounds.empty())
|
if (settings.timelineIsSound && !anm2.content.sounds.empty())
|
||||||
{
|
{
|
||||||
if (auto animation = document.animation_get();
|
auto soundTime = (int)std::floor(playback.time);
|
||||||
animation && animation->triggers.isVisible && (!settings.timelineIsOnlyShowLayers || manager.isRecording))
|
if (auto animation = document.animation_get(); soundTime != renderFrameSoundTimePrev && animation &&
|
||||||
|
animation->triggers.isVisible &&
|
||||||
|
(!settings.timelineIsOnlyShowLayers || manager.isRecording))
|
||||||
{
|
{
|
||||||
if (auto trigger = animation->triggers.frame_generate(playback.time, anm2::TRIGGER); trigger.isVisible)
|
if (auto trigger = animation->triggers.frame_generate(playback.time, anm2::TRIGGER); trigger.isVisible)
|
||||||
{
|
{
|
||||||
@@ -341,6 +342,7 @@ namespace anm2ed::imgui
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
renderFrameSoundTimePrev = soundTime;
|
||||||
}
|
}
|
||||||
renderFrameSoundIDs.push_back(frameSoundID);
|
renderFrameSoundIDs.push_back(frameSoundID);
|
||||||
|
|
||||||
@@ -352,24 +354,8 @@ namespace anm2ed::imgui
|
|||||||
if (Texture::write_pixels_png(framePath, size, pixels.data()))
|
if (Texture::write_pixels_png(framePath, size, pixels.data()))
|
||||||
{
|
{
|
||||||
renderTempFrames.push_back(framePath);
|
renderTempFrames.push_back(framePath);
|
||||||
auto nowCounter = SDL_GetPerformanceCounter();
|
auto fallbackDuration = 1.0 / (double)renderFrameRate;
|
||||||
auto counterFrequency = SDL_GetPerformanceFrequency();
|
renderTempFrameDurations.push_back(fallbackDuration);
|
||||||
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
|
else
|
||||||
{
|
{
|
||||||
@@ -416,7 +402,6 @@ namespace anm2ed::imgui
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto fps = std::max(anm2.info.fps, 1);
|
auto fps = std::max(anm2.info.fps, 1);
|
||||||
auto deltaSeconds = manager.isRecording ? (1.0f / (float)fps) : (1.0f / PLAYBACK_TICK_RATE);
|
|
||||||
playback.tick(fps, animation->frameNum, (animation->isLoop || settings.playbackIsLoop) && !manager.isRecording,
|
playback.tick(fps, animation->frameNum, (animation->isLoop || settings.playbackIsLoop) && !manager.isRecording,
|
||||||
deltaSeconds);
|
deltaSeconds);
|
||||||
|
|
||||||
@@ -657,7 +642,7 @@ namespace anm2ed::imgui
|
|||||||
renderTempFrames.clear();
|
renderTempFrames.clear();
|
||||||
renderTempFrameDurations.clear();
|
renderTempFrameDurations.clear();
|
||||||
renderFrameSoundIDs.clear();
|
renderFrameSoundIDs.clear();
|
||||||
renderCaptureCounterPrev = 0;
|
renderFrameSoundTimePrev = -1;
|
||||||
if (settings.renderType == render::PNGS)
|
if (settings.renderType == render::PNGS)
|
||||||
{
|
{
|
||||||
renderTempDirectory = settings.renderPath;
|
renderTempDirectory = settings.renderPath;
|
||||||
|
|||||||
@@ -33,11 +33,11 @@ namespace anm2ed::imgui
|
|||||||
std::vector<std::filesystem::path> renderTempFrames{};
|
std::vector<std::filesystem::path> renderTempFrames{};
|
||||||
std::vector<double> renderTempFrameDurations{};
|
std::vector<double> renderTempFrameDurations{};
|
||||||
std::vector<int> renderFrameSoundIDs{};
|
std::vector<int> renderFrameSoundIDs{};
|
||||||
Uint64 renderCaptureCounterPrev{};
|
int renderFrameSoundTimePrev{-1};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AnimationPreview();
|
AnimationPreview();
|
||||||
void tick(Manager&, Settings&);
|
void tick(Manager&, Settings&, float);
|
||||||
void update(Manager&, Settings&, Resources&);
|
void update(Manager&, Settings&, Resources&);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1312,7 +1312,7 @@ namespace anm2ed::imgui
|
|||||||
document.frameTime = playback.time;
|
document.frameTime = playback.time;
|
||||||
}
|
}
|
||||||
|
|
||||||
playback.clamp(settings.playbackIsClamp ? length : anm2::FRAME_NUM_MAX);
|
if (!playback.isPlaying) playback.clamp(settings.playbackIsClamp ? length : anm2::FRAME_NUM_MAX);
|
||||||
|
|
||||||
if (ImGui::IsMouseReleased(ImGuiMouseButton_Left)) isDragging = false;
|
if (ImGui::IsMouseReleased(ImGuiMouseButton_Left)) isDragging = false;
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,13 @@ namespace anm2ed::imgui::wizard
|
|||||||
ImGui::Checkbox(localize.get(LABEL_VSYNC), &temporary.isVsync);
|
ImGui::Checkbox(localize.get(LABEL_VSYNC), &temporary.isVsync);
|
||||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_VSYNC));
|
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_VSYNC));
|
||||||
|
|
||||||
|
ImGui::SeparatorText(localize.get(LABEL_PLAYBACK_MENU));
|
||||||
|
ImGui::RadioButton("30 Hz", &temporary.playbackTickRate, 30);
|
||||||
|
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_PLAYBACK_TICK_RATE));
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::RadioButton("60 Hz", &temporary.playbackTickRate, 60);
|
||||||
|
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_PLAYBACK_TICK_RATE));
|
||||||
|
|
||||||
ImGui::SeparatorText(localize.get(LABEL_LOCALIZATION));
|
ImGui::SeparatorText(localize.get(LABEL_LOCALIZATION));
|
||||||
ImGui::Combo(localize.get(LABEL_LANGUAGE), &temporary.language, LANGUAGE_STRINGS, LANGUAGE_COUNT);
|
ImGui::Combo(localize.get(LABEL_LANGUAGE), &temporary.language, LANGUAGE_STRINGS, LANGUAGE_COUNT);
|
||||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_LANGUAGE));
|
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_LANGUAGE));
|
||||||
|
|||||||
+15
-18
@@ -21,30 +21,27 @@ namespace anm2ed
|
|||||||
|
|
||||||
void Playback::tick(int fps, int length, bool isLoop, float deltaSeconds)
|
void Playback::tick(int fps, int length, bool isLoop, float deltaSeconds)
|
||||||
{
|
{
|
||||||
|
if (isLoop) isFinished = false;
|
||||||
if (isFinished || !isPlaying || fps <= 0 || length <= 0) return;
|
if (isFinished || !isPlaying || fps <= 0 || length <= 0) return;
|
||||||
if (deltaSeconds <= 0.0f) return;
|
if (deltaSeconds <= 0.0f) return;
|
||||||
|
|
||||||
auto frameDuration = 1.0f / (float)fps;
|
time += deltaSeconds * (float)fps;
|
||||||
tickAccumulator += deltaSeconds;
|
|
||||||
auto steps = (int)std::floor(tickAccumulator / frameDuration);
|
|
||||||
if (steps <= 0) return;
|
|
||||||
tickAccumulator -= frameDuration * (float)steps;
|
|
||||||
|
|
||||||
time += (float)steps;
|
if (!std::isfinite(time)) time = 0.0f;
|
||||||
|
|
||||||
if (time > (float)length - 1.0f)
|
if (isLoop)
|
||||||
{
|
{
|
||||||
if (isLoop)
|
time = std::fmod(time, (float)length);
|
||||||
{
|
if (time < 0.0f) time += (float)length;
|
||||||
time = std::fmod(time, (float)length);
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
if (time >= (float)length)
|
||||||
time = (float)length - 1.0f;
|
{
|
||||||
isPlaying = false;
|
time = (float)length - 1.0f;
|
||||||
isFinished = true;
|
isPlaying = false;
|
||||||
timing_reset();
|
isFinished = true;
|
||||||
}
|
timing_reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -39,7 +39,6 @@ namespace anm2ed
|
|||||||
const std::vector<double>& frameDurations, AudioStream& audioStream, render::Type type, int fps)
|
const std::vector<double>& frameDurations, AudioStream& audioStream, render::Type type, int fps)
|
||||||
{
|
{
|
||||||
if (framePaths.empty() || ffmpegPath.empty() || path.empty()) return false;
|
if (framePaths.empty() || ffmpegPath.empty() || path.empty()) return false;
|
||||||
(void)frameDurations;
|
|
||||||
fps = std::max(fps, 1);
|
fps = std::max(fps, 1);
|
||||||
|
|
||||||
auto pathString = path::to_utf8(path);
|
auto pathString = path::to_utf8(path);
|
||||||
@@ -132,6 +131,7 @@ namespace anm2ed
|
|||||||
auto framePath = framePaths[index];
|
auto framePath = framePaths[index];
|
||||||
auto framePathString = path::to_utf8(framePath);
|
auto framePathString = path::to_utf8(framePath);
|
||||||
auto frameDuration = defaultFrameDuration;
|
auto frameDuration = defaultFrameDuration;
|
||||||
|
if (index < frameDurations.size() && frameDurations[index] > 0.0) frameDuration = frameDurations[index];
|
||||||
framesListFile << "file '" << ffmpeg_concat_escape(framePathString) << "'\n";
|
framesListFile << "file '" << ffmpeg_concat_escape(framePathString) << "'\n";
|
||||||
framesListFile << "duration " << std::format("{:.9f}", frameDuration) << "\n";
|
framesListFile << "duration " << std::format("{:.9f}", frameDuration) << "\n";
|
||||||
}
|
}
|
||||||
@@ -143,11 +143,12 @@ namespace anm2ed
|
|||||||
command = std::format("\"{0}\" -y -f concat -safe 0 -i \"{1}\"", ffmpegPathString, framesListPathString);
|
command = std::format("\"{0}\" -y -f concat -safe 0 -i \"{1}\"", ffmpegPathString, framesListPathString);
|
||||||
|
|
||||||
if (!audioInputArguments.empty()) command += " " + audioInputArguments;
|
if (!audioInputArguments.empty()) command += " " + audioInputArguments;
|
||||||
command += std::format(" -fps_mode cfr -r {}", fps);
|
if (type != render::GIF) command += std::format(" -fps_mode cfr -r {}", fps);
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case render::GIF:
|
case render::GIF:
|
||||||
|
command += " -fps_mode vfr";
|
||||||
command +=
|
command +=
|
||||||
" -lavfi \"split[s0][s1];[s0]palettegen=stats_mode=full:reserve_transparent=1[p];"
|
" -lavfi \"split[s0][s1];[s0]palettegen=stats_mode=full:reserve_transparent=1[p];"
|
||||||
"[s1][p]paletteuse=dither=floyd_steinberg:alpha_threshold=128\""
|
"[s1][p]paletteuse=dither=floyd_steinberg:alpha_threshold=128\""
|
||||||
|
|||||||
@@ -606,6 +606,7 @@ namespace anm2ed
|
|||||||
X(TOOLTIP_PIVOTS, "Toggle the visibility of the animation's pivots.", "Alterna la visibilidad de los pivotes de la animacion.", "Переключить видимость точек поворота анимации.", "切换动画枢轴是否可见.", "애니메이션의 중심점을 표시하거나 숨깁니다.") \
|
X(TOOLTIP_PIVOTS, "Toggle the visibility of the animation's pivots.", "Alterna la visibilidad de los pivotes de la animacion.", "Переключить видимость точек поворота анимации.", "切换动画枢轴是否可见.", "애니메이션의 중심점을 표시하거나 숨깁니다.") \
|
||||||
X(TOOLTIP_PLAYBACK_ALWAYS_LOOP, "Animations will always loop during playback, even if looping isn't set.", "Las animaciones siempre se loopearan durante la reproduccion, incluso si \"looping\" no esta activado.", "Анимации всегда будут циклично воспроизводиться во время воспроизведения, даже если цикличность не установлена.", "动画预放时也会循环, 即使循环并未被设置.", "반복 설정이 켜져 있지 않아도 애니메이션이 항상 반복 재생됩니다.") \
|
X(TOOLTIP_PLAYBACK_ALWAYS_LOOP, "Animations will always loop during playback, even if looping isn't set.", "Las animaciones siempre se loopearan durante la reproduccion, incluso si \"looping\" no esta activado.", "Анимации всегда будут циклично воспроизводиться во время воспроизведения, даже если цикличность не установлена.", "动画预放时也会循环, 即使循环并未被设置.", "반복 설정이 켜져 있지 않아도 애니메이션이 항상 반복 재생됩니다.") \
|
||||||
X(TOOLTIP_PLAYBACK_CLAMP, "Operations will always be clamped to within the animation's bounds.\nFor example, dragging the playhead, or triggers.", "Las operaciones siempre se haran Clamp a las normas de la animacion.\nPor ejemplo: Arrastrar el Cabezal, o los triggers.", "Операции всегда будут ограничены границами анимации.\nНапример, перетаскивание воспроизводящей головки или триггеров.", "任何操作都会被限制在动画的区间内.\n比如, 拖拽播放指针或者触发器.", "작업이 항상 애니메이션 범위 내로 제한됩니다.\n예: 플레이헤드를 드래그하거나 트리거를 조작할 때.") \
|
X(TOOLTIP_PLAYBACK_CLAMP, "Operations will always be clamped to within the animation's bounds.\nFor example, dragging the playhead, or triggers.", "Las operaciones siempre se haran Clamp a las normas de la animacion.\nPor ejemplo: Arrastrar el Cabezal, o los triggers.", "Операции всегда будут ограничены границами анимации.\nНапример, перетаскивание воспроизводящей головки или триггеров.", "任何操作都会被限制在动画的区间内.\n比如, 拖拽播放指针或者触发器.", "작업이 항상 애니메이션 범위 내로 제한됩니다.\n예: 플레이헤드를 드래그하거나 트리거를 조작할 때.") \
|
||||||
|
X(TOOLTIP_PLAYBACK_TICK_RATE, "Set how often animation playback updates while previewing.", "Ajusta con que frecuencia se actualiza la reproduccion de animacion durante la vista previa.", "Установить, как часто обновляется воспроизведение анимации в предпросмотре.", "设置动画预览播放时的更新频率。", "미리보기 중 애니메이션 재생이 업데이트되는 빈도를 설정합니다.") \
|
||||||
X(TOOLTIP_PLAY_ANIMATION, "Play the animation.", "Reproduce la animacion.", "Возпроизвести анимацию.", "播放动画.", "애니메이션을 재생합니다.") \
|
X(TOOLTIP_PLAY_ANIMATION, "Play the animation.", "Reproduce la animacion.", "Возпроизвести анимацию.", "播放动画.", "애니메이션을 재생합니다.") \
|
||||||
X(TOOLTIP_POSITION, "Change the position of the frame.", "Cambia la posicion del Frame.", "Изменить позицию кадра.", "更改此帧的位置.", "프레임의 위치를 변경합니다.") \
|
X(TOOLTIP_POSITION, "Change the position of the frame.", "Cambia la posicion del Frame.", "Изменить позицию кадра.", "更改此帧的位置.", "프레임의 위치를 변경합니다.") \
|
||||||
X(TOOLTIP_PREVIEW_ZOOM, "Change the zoom of the preview.", "Cambia el zoom de la vista previa.", "Изменить масштаб предпросмотра.", "更改预览视图的缩放.", "미리보기의 줌을 변경합니다.") \
|
X(TOOLTIP_PREVIEW_ZOOM, "Change the zoom of the preview.", "Cambia el zoom de la vista previa.", "Изменить масштаб предпросмотра.", "更改预览视图的缩放.", "미리보기의 줌을 변경합니다.") \
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ namespace anm2ed
|
|||||||
\
|
\
|
||||||
X(PLAYBACK_IS_LOOP, playbackIsLoop, STRING_UNDEFINED, BOOL, true) \
|
X(PLAYBACK_IS_LOOP, playbackIsLoop, STRING_UNDEFINED, BOOL, true) \
|
||||||
X(PLAYBACK_IS_CLAMP, playbackIsClamp, STRING_UNDEFINED, BOOL, true) \
|
X(PLAYBACK_IS_CLAMP, playbackIsClamp, STRING_UNDEFINED, BOOL, true) \
|
||||||
|
X(PLAYBACK_TICK_RATE, playbackTickRate, STRING_UNDEFINED, INT, 30) \
|
||||||
\
|
\
|
||||||
X(CHANGE_IS_CROP_X, changeIsCropX, STRING_UNDEFINED, BOOL, false) \
|
X(CHANGE_IS_CROP_X, changeIsCropX, STRING_UNDEFINED, BOOL, false) \
|
||||||
X(CHANGE_IS_CROP_Y, changeIsCropY, STRING_UNDEFINED, BOOL, false) \
|
X(CHANGE_IS_CROP_Y, changeIsCropY, STRING_UNDEFINED, BOOL, false) \
|
||||||
|
|||||||
+4
-14
@@ -18,8 +18,6 @@ using namespace anm2ed::types;
|
|||||||
|
|
||||||
namespace anm2ed
|
namespace anm2ed
|
||||||
{
|
{
|
||||||
constexpr auto TICK_RATE = 30;
|
|
||||||
constexpr auto TICK_INTERVAL = (1000 / TICK_RATE);
|
|
||||||
constexpr auto UPDATE_RATE = 120;
|
constexpr auto UPDATE_RATE = 120;
|
||||||
constexpr auto UPDATE_INTERVAL = (1000 / UPDATE_RATE);
|
constexpr auto UPDATE_INTERVAL = (1000 / UPDATE_RATE);
|
||||||
|
|
||||||
@@ -33,7 +31,7 @@ namespace anm2ed
|
|||||||
manager.chords_set(settings);
|
manager.chords_set(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
void State::tick(Settings& settings) { dockspace.tick(manager, settings); }
|
void State::tick(Settings& settings, float deltaSeconds) { dockspace.tick(manager, settings, deltaSeconds); }
|
||||||
|
|
||||||
void State::update(SDL_Window*& window, Settings& settings)
|
void State::update(SDL_Window*& window, Settings& settings)
|
||||||
{
|
{
|
||||||
@@ -160,16 +158,8 @@ namespace anm2ed
|
|||||||
auto currentTick = SDL_GetTicks();
|
auto currentTick = SDL_GetTicks();
|
||||||
auto currentUpdate = SDL_GetTicks();
|
auto currentUpdate = SDL_GetTicks();
|
||||||
auto isRecording = manager.isRecording;
|
auto isRecording = manager.isRecording;
|
||||||
auto tickIntervalMs = (double)TICK_INTERVAL;
|
auto tickRate = std::max(settings.playbackTickRate, 1);
|
||||||
|
auto tickIntervalMs = 1000.0 / (double)tickRate;
|
||||||
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)
|
if (isRecording != wasRecording)
|
||||||
{
|
{
|
||||||
@@ -194,7 +184,7 @@ namespace anm2ed
|
|||||||
|
|
||||||
if (tickAccumulatorMs >= tickIntervalMs)
|
if (tickAccumulatorMs >= tickIntervalMs)
|
||||||
{
|
{
|
||||||
tick(settings);
|
tick(settings, (float)(tickIntervalMs / 1000.0));
|
||||||
tickAccumulatorMs -= tickIntervalMs;
|
tickAccumulatorMs -= tickIntervalMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@ namespace anm2ed
|
|||||||
{
|
{
|
||||||
class State
|
class State
|
||||||
{
|
{
|
||||||
void tick(Settings&);
|
void tick(Settings&, float);
|
||||||
void update(SDL_Window*&, Settings&);
|
void update(SDL_Window*&, Settings&);
|
||||||
void render(SDL_Window*&, Settings&);
|
void render(SDL_Window*&, Settings&);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user