#include "state.hpp" #include #include #include #include #include "log.hpp" #include "path_.hpp" #include "strings.hpp" #include "toast.hpp" using namespace anm2ed::imgui; using namespace anm2ed::util; using namespace anm2ed::types; namespace anm2ed { constexpr auto TICK_RATE = 30; constexpr auto TICK_INTERVAL = (1000 / TICK_RATE); constexpr auto UPDATE_RATE = 120; constexpr auto UPDATE_INTERVAL = (1000 / UPDATE_RATE); State::State(SDL_Window*& window, Settings& settings, std::vector& arguments) { dialog = Dialog(window); for (const auto& argument : arguments) manager.open(path::from_utf8(argument)); manager.chords_set(settings); } void State::tick(Settings& settings) { dockspace.tick(manager, settings); } void State::update(SDL_Window*& window, Settings& settings) { /* ImGui_ImplSDL3_NewFrame(); ImGui_ImplOpenGL3_NewFrame(); ImGui::NewFrame(); SDL_GetWindowSize(window, &settings.windowSize.x, &settings.windowSize.y); SDL_GetWindowPosition(window, &settings.windowPosition.x, &settings.windowPosition.y); SDL_Event event{}; while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_EVENT_QUIT: isQuit = true; default: break; } } dockspace.update(taskbar, documents, manager, settings, resources, dialog, clipboard); */ SDL_Event event{}; while (SDL_PollEvent(&event)) { ImGui_ImplSDL3_ProcessEvent(&event); switch (event.type) { case SDL_EVENT_DROP_FILE: { std::string droppedFile = event.drop.data ? event.drop.data : ""; if (droppedFile.empty()) break; auto droppedPath = path::from_utf8(droppedFile); if (path::is_extension(droppedPath, "anm2")) { if (manager.documents.empty()) manager.open(droppedPath); else { if (std::find(manager.anm2DragDropPaths.begin(), manager.anm2DragDropPaths.end(), droppedPath) == manager.anm2DragDropPaths.end()) manager.anm2DragDropPaths.push_back(droppedPath); manager.isAnm2DragDrop = true; } SDL_FlashWindow(window, SDL_FLASH_UNTIL_FOCUSED); } else if (path::is_extension(droppedPath, "png")) { if (auto document = manager.get()) document->spritesheet_add(droppedPath); else { toasts.push(localize.get(TOAST_ADD_SPRITESHEET_FAILED)); logger.warning(localize.get(TOAST_ADD_SPRITESHEET_FAILED, anm2ed::ENGLISH)); } } else if (path::is_extension(droppedPath, "wav") || path::is_extension(droppedPath, "ogg")) { if (auto document = manager.get()) document->sound_add(droppedPath); else { toasts.push(localize.get(TOAST_ADD_SOUND_FAILED)); logger.warning(localize.get(TOAST_ADD_SOUND_FAILED, anm2ed::ENGLISH)); } } break; } case SDL_EVENT_USER: // Opening files { std::string droppedFile = event.user.data1 ? static_cast(event.user.data1) : ""; if (event.user.data1) SDL_free(event.user.data1); if (droppedFile.empty()) break; auto droppedPath = path::from_utf8(droppedFile); if (path::is_extension(droppedPath, "anm2")) { manager.open(droppedPath); SDL_FlashWindow(window, SDL_FLASH_UNTIL_FOCUSED); } break; } case SDL_EVENT_QUIT: isQuitting = true; break; default: break; } } ImGui_ImplSDL3_NewFrame(); ImGui_ImplOpenGL3_NewFrame(); ImGui::NewFrame(); taskbar.update(manager, settings, resources, dialog, isQuitting); documents.update(taskbar, manager, settings, resources, isQuitting); dockspace.update(taskbar, documents, manager, settings, resources, dialog, clipboard); toasts.update(); SDL_GetWindowSize(window, &settings.windowSize.x, &settings.windowSize.y); SDL_GetWindowPosition(window, &settings.windowPosition.x, &settings.windowPosition.y); if (isQuitting && manager.documents.empty()) isQuit = true; } void State::render(SDL_Window*& window, Settings& settings) { glViewport(0, 0, settings.windowSize.x, settings.windowSize.y); glClear(GL_COLOR_BUFFER_BIT); ImGui::Render(); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); SDL_GL_SwapWindow(window); SDL_GL_SetSwapInterval(settings.isVsync); } void State::loop(SDL_Window*& window, Settings& settings) { auto currentTick = SDL_GetTicks(); auto currentUpdate = SDL_GetTicks(); auto isRecording = manager.isRecording; auto tickIntervalMs = (double)TICK_INTERVAL; if (isRecording) { if (auto document = manager.get()) { auto fps = std::max(document->anm2.info.fps, 1); tickIntervalMs = std::max(1.0, 1000.0 / (double)fps); } } if (isRecording != wasRecording) { // Drop any accumulated backlog when entering/leaving recording mode. tickAccumulatorMs = 0.0; previousTick = currentTick; wasRecording = isRecording; } if (previousTick == 0) previousTick = currentTick; auto tickDeltaMs = currentTick - previousTick; tickDeltaMs = std::min(tickDeltaMs, 250); tickAccumulatorMs += (double)tickDeltaMs; previousTick = currentTick; if (currentUpdate - previousUpdate >= UPDATE_INTERVAL) { update(window, settings); render(window, settings); previousUpdate = currentUpdate; } if (tickAccumulatorMs >= tickIntervalMs) { tick(settings); tickAccumulatorMs -= tickIntervalMs; } SDL_Delay(1); } }