9#include "../DataManager.h"
10#include "../system/system_utils.h"
11#include "../json_helper.h"
12#include "../GameEngine.h"
13#include "../third_party/imgui/imgui.h"
14#include "../third_party/imgui/backends/imgui_impl_sdl3.h"
15#include "../third_party/imgui/backends/imgui_impl_sdlrenderer3.h"
38 SYSTEM_LOG <<
"AnimationEditorWindow: Initialized\n";
44 SYSTEM_LOG <<
"AnimationEditorWindow: Destroyed\n";
69 SYSTEM_LOG <<
"AnimationEditorWindow: Opened\n";
90 SYSTEM_LOG <<
"AnimationEditorWindow: Closed\n";
148 ImGui::SetNextWindowPos(
ImVec2(0, 0));
149 ImGui::SetNextWindowSize(
io.DisplaySize);
165 if (!ImGui::Begin(
"Animation Editor",
nullptr,
windowFlags))
175 ImGui::BeginChild(
"LeftPanel",
ImVec2(200, 0),
true);
181 ImGui::BeginChild(
"MiddlePanel",
ImVec2(600, 0),
true);
183 if (ImGui::BeginTabBar(
"EditorTabs"))
185 if (ImGui::BeginTabItem(
"Spritesheets"))
192 if (ImGui::BeginTabItem(
"Sequences"))
205 ImGui::BeginChild(
"RightPanel",
ImVec2(0, 0),
true);
220 if (ImGui::BeginMenuBar())
222 if (ImGui::BeginMenu(
"File"))
224 if (ImGui::MenuItem(
"New Bank",
"Ctrl+N"))
229 if (ImGui::MenuItem(
"Open Bank",
"Ctrl+O"))
241 if (ImGui::MenuItem(
"Save As",
"Ctrl+Shift+S",
false,
m_hasBankLoaded))
248 if (ImGui::MenuItem(
"Close",
"Ctrl+W"))
256 if (ImGui::BeginMenu(
"Edit"))
258 if (ImGui::MenuItem(
"Add Spritesheet",
"Ctrl+Shift+A",
false,
m_hasBankLoaded))
285 if (ImGui::BeginMenu(
"View"))
298 ImGui::Text(
"Animation Banks");
301 if (ImGui::Button(
"+ New Bank",
ImVec2(-1, 0)))
309 ImGui::BeginChild(
"BankList",
ImVec2(0, 0),
false);
314 size_t lastSlash = filepath.find_last_of(
"/\\");
319 if (ImGui::Selectable(
filename.c_str(), isSelected))
342 ImGui::TextColored(
ImVec4(0.7f, 0.7f, 0.7f, 1.0f),
"No bank loaded. Create or open a bank.");
348 if (ImGui::Button(
"+ Add Spritesheet"))
356 ImGui::BeginChild(
"SpritesheetList",
ImVec2(250, 0),
true);
363 if (ImGui::Selectable(
sheet.id.c_str(), isSelected))
374 ImGui::BeginChild(
"SpritesheetProperties",
ImVec2(0, 0),
true);
380 ImGui::Text(
"Spritesheet Properties");
387 if (ImGui::InputText(
"ID",
idBuf,
sizeof(
idBuf)))
414 ImGui::Text(
"Grid Layout");
416 if (ImGui::InputInt(
"Frame Width", &
sheet.frameWidth))
421 if (ImGui::InputInt(
"Frame Height", &
sheet.frameHeight))
426 if (ImGui::InputInt(
"Columns", &
sheet.columns))
431 if (ImGui::InputInt(
"Rows", &
sheet.rows))
436 if (ImGui::InputInt(
"Total Frames", &
sheet.totalFrames))
441 if (ImGui::InputInt(
"Spacing", &
sheet.spacing))
446 if (ImGui::InputInt(
"Margin", &
sheet.margin))
451 if (ImGui::Button(
"Auto-Detect Grid"))
457 ImGui::Text(
"Hotspot");
459 if (ImGui::InputFloat(
"Hotspot X", &
sheet.hotspot.x))
464 if (ImGui::InputFloat(
"Hotspot Y", &
sheet.hotspot.y))
471 ImGui::Text(
"Preview");
492 ImVec2 p = ImGui::GetItemRectMin();
513 ImGui::TextColored(
ImVec4(1.0f, 0.5f, 0.5f, 1.0f),
"Texture not loaded");
522 ImGui::TextColored(
ImVec4(0.7f, 0.7f, 0.7f, 1.0f),
"Select a spritesheet to edit");
532 ImGui::TextColored(
ImVec4(0.7f, 0.7f, 0.7f, 1.0f),
"No bank loaded. Create or open a bank.");
538 if (ImGui::Button(
"+ Add Sequence"))
546 ImGui::BeginChild(
"SequenceList",
ImVec2(250, 0),
true);
551 const auto&
seq =
it->second;
554 if (ImGui::Selectable(
seq.name.c_str(), isSelected))
566 ImGui::BeginChild(
"SequenceProperties",
ImVec2(0, 0),
true);
572 auto&
seq =
it->second;
574 ImGui::Text(
"Sequence Properties");
602 ImGui::Text(
"Spritesheet");
604 if (ImGui::BeginCombo(
"##SpritesheetSelector",
seq.spritesheetId.c_str()))
608 bool isSelected = (
seq.spritesheetId ==
sheet.id);
609 if (ImGui::Selectable(
sheet.id.c_str(), isSelected))
617 ImGui::SetItemDefaultFocus();
624 ImGui::Text(
"Frame Range");
626 if (ImGui::InputInt(
"Start Frame", &
seq.startFrame))
628 if (
seq.startFrame < 0)
seq.startFrame = 0;
632 if (ImGui::InputInt(
"Frame Count", &
seq.frameCount))
634 if (
seq.frameCount < 1)
seq.frameCount = 1;
639 ImGui::Text(
"Playback Settings");
641 if (ImGui::InputFloat(
"Frame Duration (s)", &
seq.frameDuration))
643 if (
seq.frameDuration < 0.001f)
seq.frameDuration = 0.001f;
647 if (ImGui::Checkbox(
"Loop", &
seq.loop))
652 if (ImGui::SliderFloat(
"Speed", &
seq.speed, 0.1f, 5.0f))
668 ImGui::Text(
"Stats");
669 ImGui::Text(
"Total Duration: %.2f s",
seq.GetTotalDuration());
670 ImGui::Text(
"Effective FPS: %.2f",
seq.GetEffectiveFPS());
674 ImGui::TextColored(
ImVec4(0.7f, 0.7f, 0.7f, 1.0f),
"Select a sequence to edit");
682 ImGui::Text(
"Preview");
687 ImGui::TextColored(
ImVec4(0.7f, 0.7f, 0.7f, 1.0f),
"No bank loaded");
693 ImGui::TextColored(
ImVec4(0.7f, 0.7f, 0.7f, 1.0f),
"No sequence selected");
717 if (ImGui::Button(
"Stop"))
756 ImGui::TextColored(
ImVec4(1.0f, 0.5f, 0.5f, 1.0f),
"Spritesheet not found: %s",
seq.spritesheetId.c_str());
764 ImGui::TextColored(
ImVec4(1.0f, 0.5f, 0.5f, 1.0f),
"Failed to load texture: %s",
sheet->path.c_str());
778 float srcW =
static_cast<float>(
sheet->frameWidth);
779 float srcH =
static_cast<float>(
sheet->frameHeight);
806 ImGui::Text(
"Bank Properties");
811 ImGui::TextColored(
ImVec4(0.7f, 0.7f, 0.7f, 1.0f),
"No bank loaded");
882 SYSTEM_LOG <<
"AnimationEditorWindow: Created new bank\n";
917 SYSTEM_LOG <<
"AnimationEditorWindow: Failed to load JSON from " << filepath <<
"\n";
930 if (
j.contains(
"metadata"))
937 if (
meta.contains(
"tags") &&
meta[
"tags"].is_array())
939 for (
const auto& tag :
meta[
"tags"])
943 bank.tags.push_back(tag.get<std::string>());
950 if (
j.contains(
"spritesheets") &&
j[
"spritesheets"].is_array())
952 for (
const auto&
sheetJson :
j[
"spritesheets"])
977 if (
j.contains(
"sequences") &&
j[
"sequences"].is_array())
979 for (
const auto&
seqJson :
j[
"sequences"])
985 if (
seqJson.contains(
"frames"))
1007 SYSTEM_LOG <<
"AnimationEditorWindow: Loaded bank from " << filepath <<
"\n";
1009 catch (
const std::exception&
e)
1011 SYSTEM_LOG <<
"AnimationEditorWindow: Error parsing JSON: " <<
e.what() <<
"\n";
1019 json j = json::object();
1021 j[
"schema_version"] = 2;
1022 j[
"type"] =
"AnimationBank";
1047 j[
"metadata"] =
meta;
1065 json hotspot = json::object();
1066 hotspot[
"x"] =
sheet.hotspot.x;
1067 hotspot[
"y"] =
sheet.hotspot.y;
1078 const auto&
seq =
pair.second;
1081 seqJson[
"spritesheetId"] =
seq.spritesheetId;
1083 json frames = json::object();
1084 frames[
"start"] =
seq.startFrame;
1085 frames[
"count"] =
seq.frameCount;
1088 seqJson[
"frameDuration"] =
seq.frameDuration;
1091 seqJson[
"nextAnimation"] =
seq.nextAnimation;
1100 SYSTEM_LOG <<
"AnimationEditorWindow: Saved bank to " << filepath <<
"\n";
1102 catch (
const std::exception&
e)
1104 SYSTEM_LOG <<
"AnimationEditorWindow: Error exporting JSON: " <<
e.what() <<
"\n";
1110 std::vector<std::string>
files;
1158 sheet.frameWidth = 32;
1159 sheet.frameHeight = 32;
1162 sheet.totalFrames = 1;
1165 sheet.hotspot.x = 16.0f;
1166 sheet.hotspot.y = 16.0f;
1173 SYSTEM_LOG <<
"AnimationEditorWindow: Added spritesheet\n";
1186 SYSTEM_LOG <<
"AnimationEditorWindow: Removed spritesheet\n";
1195 SYSTEM_LOG <<
"AnimationEditorWindow: Cannot auto-detect grid - texture not loaded\n";
1206 if (
sheet.frameWidth > 0 &&
sheet.frameHeight > 0)
1214 SYSTEM_LOG <<
"AnimationEditorWindow: Auto-detected grid: " <<
sheet.columns <<
"x" <<
sheet.rows <<
" = " <<
sheet.totalFrames <<
" frames\n";
1225 return sprite ? sprite :
nullptr;
1239 seq.frameDuration = 0.1f;
1242 seq.nextAnimation =
"";
1249 SYSTEM_LOG <<
"AnimationEditorWindow: Added sequence\n";
1264 SYSTEM_LOG <<
"AnimationEditorWindow: Removed sequence\n";
1336 SYSTEM_LOG <<
"AnimationEditorWindow: Unsaved changes detected\n";
1353 SYSTEM_LOG <<
"[AnimationEditor] Separate window already exists\n";
1362 "Animation Editor - Olympe Engine",
1378 ImGui::StyleColorsDark();
1387 SYSTEM_LOG <<
"[AnimationEditor] Standalone window created\n";
1422 SYSTEM_LOG <<
"[AnimationEditor] Separate window destroyed\n";
Animation Editor window for creating and editing animation banks.
ComponentTypeID GetComponentTypeID_Static()
static DataManager & Get()
Sprite * GetSprite(const std::string &id, const std::string &path, ResourceCategory category=ResourceCategory::GameEntity)
void Toggle()
Toggle window visibility.
SDL_Window * m_separateWindow
void RenderSpritesheetPanel()
void ExportBankJSON(const std::string &filepath)
void RenderPropertiesPanel()
void RenderSeparateWindow()
std::string m_currentBankPath
bool PromptUnsavedChanges()
ImGuiContext * m_separateImGuiContext
void AutoDetectGrid(SpritesheetInfo &sheet)
void DestroySeparateWindow()
bool m_showOpenBankDialog
SDL_Renderer * m_separateRenderer
void RenderBankListPanel()
float m_previewFrameTimer
void RenderSequencePanel()
std::vector< std::string > ScanBankDirectory(const std::string &dirPath)
void UpdatePreview(float deltaTime)
Update preview animation (call every frame with deltaTime)
int m_selectedSpritesheetIndex
void Update(float deltaTime)
Update and render the editor window (separate window)
void RenderPreviewPanel()
void CreateSeparateWindow()
void RemoveSpritesheet(int index)
void ImportBankJSON(const std::string &filepath)
void RenderPreviewFrame()
void OpenBank(const std::string &filepath)
void Render()
Render the editor window.
void ProcessEvent(SDL_Event *event)
Process SDL events for the separate window.
int m_previewCurrentFrame
AnimationBank m_currentBank
void RemoveSequence(int index)
int m_selectedSequenceIndex
SDL_Texture * LoadSpritesheetTexture(const std::string &path)
std::string GetString(const json &j, const std::string &key, const std::string &defaultValue="")
Safely get a string value from JSON.
bool LoadJsonFromFile(const std::string &filepath, json &j)
Load and parse a JSON file.
int GetInt(const json &j, const std::string &key, int defaultValue=0)
Safely get an integer value from JSON.
float GetFloat(const json &j, const std::string &key, float defaultValue=0.0f)
Safely get a float value from JSON.
bool SaveJsonToFile(const std::string &filepath, const json &j, int indent=4)
Save a JSON object to a file with formatting.
bool GetBool(const json &j, const std::string &key, bool defaultValue=false)
Safely get a boolean value from JSON.
Collection of animations for an entity with multi-spritesheet support.
std::string bankId
Unique identifier for this animation bank.
std::vector< SpritesheetInfo > spritesheets
std::string lastModifiedDate
const SpritesheetInfo * GetSpritesheet(const std::string &id) const
Get spritesheet by ID.
std::vector< std::string > tags
std::unordered_map< std::string, AnimationSequence > animations
Defines a complete animation sequence.
int startFrame
Starting frame index (0-based)
std::string name
Animation name (e.g., "idle", "walk")
Metadata for a single spritesheet within an animation bank.
std::string id
Unique identifier (e.g., "thesee_idle")