This commit is contained in:
2025-06-19 05:29:06 -04:00
parent 9929e69f22
commit 91190987ed
30 changed files with 2754 additions and 475 deletions

View File

@@ -1,5 +1,280 @@
#include "imgui.h"
static void _imgui_tooltip(const char* tooltip);
static void _imgui_timeline_element(Imgui* self, void* element, s32* id, s32* index, Anm2AnimationType type, Anm2AnimationType* selectType, s32* selectID);
/* Makes a tooltip! */
static void _imgui_tooltip(const char* tooltip)
{
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal))
ImGui::SetTooltip("%s", tooltip);
}
/* Displays each element of the timeline of a selected animation */
static void
_imgui_timeline_element(Imgui* self, void* element, s32* id, s32* index, Anm2AnimationType type, Anm2AnimationType* selectType, s32* selectID)
{
static s32 selectedElementIndex = -1;
static s32 selectedSpritesheetIndex = -1;
Anm2Layer* layer = NULL;
Anm2LayerAnimation* layerAnimation = NULL;
Anm2Null* null = NULL;
Anm2NullAnimation* nullAnimation = NULL;
Anm2RootAnimation* rootAnimation = NULL;
Anm2Triggers* triggers = NULL;
ImTextureID iconTexture = -1;
bool isArrows = false;
bool* isShowRect = NULL;
bool* isVisible = NULL;
char nameBuffer[ANM2_STRING_MAX] = STRING_EMPTY;
char nameVisible[ANM2_STRING_FORMATTED_MAX] = STRING_EMPTY;
char* namePointer = NULL;
s32* spritesheetID = NULL;
bool isSelected = selectedElementIndex == *index;
bool isChangeable = type != ANM2_ROOT_ANIMATION && type != ANM2_TRIGGERS;
switch (type)
{
case ANM2_ROOT_ANIMATION:
rootAnimation = (Anm2RootAnimation*)element;
iconTexture = self->packed->textures[PACKED_TEXTURE_ROOT].handle;
strncpy(nameVisible, STRING_IMGUI_TIMELINE_ROOT, ANM2_STRING_FORMATTED_MAX);
isVisible = &rootAnimation->isVisible;
break;
case ANM2_LAYER_ANIMATION:
layerAnimation = (Anm2LayerAnimation*)element;
layer = &self->anm2->layers[*id];
iconTexture = self->packed->textures[PACKED_TEXTURE_LAYER].handle;
isVisible = &layerAnimation->isVisible;
spritesheetID = &layer->spritesheetID;
namePointer = layer->name;
snprintf(nameBuffer, ANM2_STRING_MAX, "%s", namePointer);
snprintf(nameVisible, ANM2_STRING_FORMATTED_MAX, STRING_IMGUI_TIMELINE_ELEMENT_FORMAT, *id, namePointer);
break;
case ANM2_NULL_ANIMATION:
nullAnimation = (Anm2NullAnimation*)element;
null = &self->anm2->nulls[*id];
iconTexture = self->packed->textures[PACKED_TEXTURE_NULL].handle;
isVisible = &nullAnimation->isVisible;
isShowRect = &null->isShowRect;
namePointer = null->name;
snprintf(nameBuffer, ANM2_STRING_MAX, "%s", namePointer);
snprintf(nameVisible, ANM2_STRING_FORMATTED_MAX, STRING_IMGUI_TIMELINE_ELEMENT_FORMAT, *id, namePointer);
break;
case ANM2_TRIGGERS:
triggers = (Anm2Triggers*)element;
iconTexture = self->packed->textures[PACKED_TEXTURE_TRIGGER].handle;
strncpy(nameVisible, STRING_IMGUI_TIMELINE_TRIGGERS, ANM2_STRING_FORMATTED_MAX);
isVisible = &triggers->isVisible;
break;
default:
break;
}
ImGui::BeginChild(nameVisible, IMGUI_TIMELINE_ELEMENT_SIZE, true, ImGuiWindowFlags_NoScrollbar);
ImGui::PushID(*index);
/* Shift arrows */
if (isChangeable)
{
bool isSwap = false;
bool isReversed = (type == ANM2_LAYER_ANIMATION);
auto arrows_draw = [&](auto it, auto begin, auto end, auto& map, bool* didSwap, bool isReversed)
{
bool canMoveUp = isReversed ? (std::next(it) != end) : (it != begin);
bool canMoveDown = isReversed ? (it != begin) : (std::next(it) != end);
isArrows = canMoveUp || canMoveDown;
if (isArrows)
ImGui::BeginChild(STRING_IMGUI_TIMELINE_ELEMENT_SHIFT_ARROWS_LABEL, IMGUI_TIMELINE_SHIFT_ARROWS_SIZE);
if (canMoveUp)
{
auto target = isReversed ? std::next(it) : std::prev(it);
if (target != map.end() && ImGui::ImageButton(STRING_IMGUI_TIMELINE_ELEMENT_SHIFT_ABOVE, self->packed->textures[PACKED_TEXTURE_ARROW_UP].handle, IMGUI_ICON_SIZE))
{
map_swap(map, it->first, target->first);
*didSwap = true;
}
_imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_SHIFT_UP);
}
if (canMoveDown)
{
if (!canMoveUp)
ImGui::Dummy(IMGUI_ICON_BUTTON_SIZE);
auto target = isReversed ? std::prev(it) : std::next(it);
if (target != map.end() && ImGui::ImageButton(STRING_IMGUI_TIMELINE_ELEMENT_SHIFT_BELOW, self->packed->textures[PACKED_TEXTURE_ARROW_DOWN].handle, IMGUI_ICON_SIZE))
{
map_swap(map, it->first, target->first);
*didSwap = true;
}
_imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_SHIFT_DOWN);
}
if (isArrows)
{
ImGui::EndChild();
ImGui::SameLine();
}
};
if (type == ANM2_LAYER_ANIMATION)
{
auto it = std::find_if(self->anm2->layers.begin(), self->anm2->layers.end(),
[&](const auto& pair) { return &pair.second == layer; });
if (it != self->anm2->layers.end())
arrows_draw(it, self->anm2->layers.begin(), self->anm2->layers.end(), self->anm2->layers, &isSwap, isReversed);
}
if (type == ANM2_NULL_ANIMATION)
{
auto it = std::find_if(self->anm2->nulls.begin(), self->anm2->nulls.end(),
[&](const auto& pair) { return &pair.second == null; });
if (it != self->anm2->nulls.end())
arrows_draw(it, self->anm2->nulls.begin(), self->anm2->nulls.end(), self->anm2->nulls, &isSwap, isReversed);
}
}
ImGui::BeginGroup();
ImGui::Image(iconTexture, IMGUI_ICON_SIZE);
ImGui::SameLine();
ImGui::BeginChild(STRING_IMGUI_TIMELINE_ELEMENT_NAME_LABEL, IMGUI_TIMELINE_ELEMENT_NAME_SIZE);
if (isSelected && isChangeable)
{
if (ImGui::InputText(STRING_IMGUI_TIMELINE_ANIMATION_LABEL, nameBuffer, ANM2_STRING_MAX, ImGuiInputTextFlags_EnterReturnsTrue))
{
strncpy(namePointer, nameBuffer, ANM2_STRING_MAX);
selectedElementIndex = -1;
}
}
else
{
if (ImGui::Selectable(nameVisible, isSelected))
{
selectedElementIndex = *index;
if (selectType && selectID)
{
*selectType = type;
*selectID = *id;
}
}
}
switch (type)
{
case ANM2_ROOT_ANIMATION:
_imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_ROOT);
break;
case ANM2_LAYER_ANIMATION:
_imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_LAYER);
break;
case ANM2_NULL_ANIMATION:
_imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_NULL);
break;
case ANM2_TRIGGERS:
_imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_TRIGGERS);
break;
default:
break;
}
ImGui::EndChild();
/* Visiblity */
if (isVisible)
{
ImTextureID visibilityIcon = *isVisible
? self->packed->textures[PACKED_TEXTURE_EYE_OPEN].handle
: self->packed->textures[PACKED_TEXTURE_EYE_CLOSED].handle;
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - IMGUI_ICON_BUTTON_SIZE.x - ImGui::GetStyle().FramePadding.x * 2);
if (ImGui::ImageButton(STRING_IMGUI_TIMELINE_VISIBLE, visibilityIcon, IMGUI_ICON_SIZE))
*isVisible = !*isVisible;
_imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_VISIBLE);
}
/* Spritesheet IDs */
if (spritesheetID)
{
char spritesheetIDName[ANM2_STRING_FORMATTED_MAX];
if (*spritesheetID == -1)
snprintf(spritesheetIDName, ANM2_STRING_FORMATTED_MAX, STRING_IMGUI_TIMELINE_SPRITESHEET_UNKNOWN);
else
snprintf(spritesheetIDName, ANM2_STRING_FORMATTED_MAX, STRING_IMGUI_TIMELINE_SPRITESHEET_FORMAT, *spritesheetID);
ImGui::Image(self->packed->textures[PACKED_TEXTURE_SPRITESHEET].handle, IMGUI_ICON_SIZE);
ImGui::SameLine();
ImGui::BeginChild(STRING_IMGUI_TIMELINE_ELEMENT_SPRITESHEET_ID_LABEL, IMGUI_TIMELINE_SPRITESHEET_ID_SIZE);
if (selectedSpritesheetIndex == *index)
{
if (ImGui::DragInt(STRING_IMGUI_TIMELINE_ELEMENT_SPRITESHEET_ID_LABEL, spritesheetID, 0, 1, self->anm2->spritesheets.size() - 1))
selectedSpritesheetIndex = -1;
}
else
{
if (ImGui::Selectable(spritesheetIDName))
selectedSpritesheetIndex = *index;
}
_imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_SPRITESHEET);
ImGui::EndChild();
}
/* ShowRect */
if (isShowRect)
{
ImTextureID rectIcon = *isShowRect
? self->packed->textures[PACKED_TEXTURE_RECT_HIDE].handle
: self->packed->textures[PACKED_TEXTURE_RECT_SHOW].handle;
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - IMGUI_ICON_BUTTON_SIZE.x - ImGui::GetStyle().FramePadding.x * 2);
if (ImGui::ImageButton(STRING_IMGUI_TIMELINE_RECT, rectIcon, IMGUI_ICON_SIZE))
*isShowRect = !*isShowRect;
_imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_RECT);
}
if (ImGui::IsMouseClicked(0) && !ImGui::IsAnyItemHovered() && ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
{
selectedElementIndex = -1;
selectedSpritesheetIndex = -1;
}
ImGui::PopID();
ImGui::EndGroup();
ImGui::EndChild();
*index = *index + 1;
}
void
imgui_init(SDL_Window* window, SDL_GLContext glContext)
{
@@ -11,31 +286,604 @@ imgui_init(SDL_Window* window, SDL_GLContext glContext)
ImGui_ImplSDL3_InitForOpenGL(window, glContext);
ImGui_ImplOpenGL3_Init(STRING_OPENGL_VERSION);
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
printf(STRING_INFO_IMGUI_INIT);
}
void
imgui_tick(State* state)
imgui_tick(Imgui* self)
{
static s32 selectedSpritesheetID = -1;
static s32 selectedEventID = -1;
static s32 selectedAnimationID = -1;
static s32 selectedTimelineElementID = -1;
static Anm2AnimationType selectedTimelineElementType = ANM2_NONE;
static bool isInterpolated = true;
static bool isVisible = true;
static f32 rotation = 0;
static s32 duration = 0;
static vec2 cropPosition = {0, 0};
static vec2 cropSize = {0, 0};
static vec2 pivot = {0, 0};
static vec2 position = {0, 0};
static vec2 xyScale = {0, 0};
static vec3 offset = {0.0f, 0.0f, 0.0f};
static vec4 tint = {0.0f, 0.0f, 0.0f, 1.0f};
ImVec2 previewWindowSize;
ImVec2 previewSize;
f32 previewAspect = 0.0f;
f32 previewWindowAspect = 0.0f;
ImGuiWindowFlags taskbarWindowFlags;
ImGuiWindowFlags dockspaceWindowFlags;
ImGuiDockNodeFlags dockNodeFlags;
ImGui_ImplSDL3_NewFrame();
ImGui_ImplOpenGL3_NewFrame();
ImGui::NewFrame();
ImGui::Begin("Hello, world!");
ImGui::Text("Color");
ImGui::ColorEdit3("Color", value_ptr(state->clearColor));
taskbarWindowFlags = 0 |
ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoResize |
ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoScrollbar |
ImGuiWindowFlags_NoSavedSettings;
dockspaceWindowFlags = 0 |
ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoResize |
ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoBringToFrontOnFocus |
ImGuiWindowFlags_NoNavFocus;
dockNodeFlags = 0 |
ImGuiDockNodeFlags_PassthruCentralNode;
ImGuiViewport* viewport = ImGui::GetMainViewport();
/* Taskbar */
ImGui::SetNextWindowPos(viewport->Pos);
ImGui::SetNextWindowSize(ImVec2(viewport->Size.x, IMGUI_TASKBAR_HEIGHT));
ImGui::Begin(STRING_IMGUI_TASKBAR, NULL, taskbarWindowFlags);
if (ImGui::Selectable(STRING_IMGUI_TASKBAR_FILE, false, 0, ImGui::CalcTextSize(STRING_IMGUI_TASKBAR_FILE)))
ImGui::OpenPopup(STRING_IMGUI_FILE_MENU);
if (ImGui::IsItemHovered() || ImGui::IsItemActive())
ImGui::SetNextWindowPos(ImVec2(ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y + ImGui::GetItemRectSize().y));
if (ImGui::BeginPopup(STRING_IMGUI_FILE_MENU))
{
if (ImGui::Selectable(STRING_IMGUI_FILE_NEW))
{
selectedAnimationID = -1;
selectedSpritesheetID = -1;
selectedEventID = -1;
anm2_new(self->anm2);
window_title_from_anm2_set(self->window, self->anm2);
}
if (ImGui::Selectable(STRING_IMGUI_FILE_OPEN))
{
selectedAnimationID = -1;
selectedEventID = -1;
selectedSpritesheetID = -1;
dialog_anm2_open(self->dialog);
window_title_from_anm2_set(self->window, self->anm2);
}
if (ImGui::Selectable(STRING_IMGUI_FILE_SAVE))
{
if (!strcmp(self->anm2->path, STRING_EMPTY) == 0)
anm2_serialize(self->anm2, self->anm2->path);
else
dialog_anm2_save(self->dialog);
}
if (ImGui::Selectable(STRING_IMGUI_FILE_SAVE_AS))
{
dialog_anm2_save(self->dialog);
window_title_from_anm2_set(self->window, self->anm2);
}
ImGui::EndPopup();
}
ImGui::End();
/* Dockspace */
ImGui::SetNextWindowPos(ImVec2(viewport->Pos.x, viewport->Pos.y + IMGUI_TASKBAR_HEIGHT));
ImGui::SetNextWindowSize(ImVec2(viewport->Size.x, viewport->Size.y - IMGUI_TASKBAR_HEIGHT));
ImGui::SetNextWindowViewport(viewport->ID);
ImGui::Begin(STRING_IMGUI_WINDOW, NULL, dockspaceWindowFlags);
ImGuiID dockspace_id = ImGui::GetID(STRING_IMGUI_DOCKSPACE);
ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockNodeFlags);
ImGui::End();
/* -- Properties -- */
ImGui::Begin(STRING_IMGUI_PROPERTIES);
/* FPS */
ImGui::AlignTextToFramePadding();
ImGui::Text(STRING_IMGUI_PROPERTIES_FPS);
ImGui::SameLine();
ImGui::SliderInt(STRING_IMGUI_PROPERTIES_FPS_LABEL, &self->anm2->fps, ANM2_FPS_MIN, ANM2_FPS_MAX);
_imgui_tooltip(STRING_IMGUI_TOOLTIP_PROPERTIES_FPS);
/* CreatedBy */
ImGui::AlignTextToFramePadding();
ImGui::Text(STRING_IMGUI_PROPERTIES_CREATED_BY);
ImGui::SameLine();
ImGui::InputText(STRING_IMGUI_PROPERTIES_CREATED_BY_LABEL, self->anm2->createdBy, ANM2_STRING_MAX);
_imgui_tooltip(STRING_IMGUI_TOOLTIP_PROPERTIES_CREATED_BY);
/* CreatedOn */
ImGui::Text(STRING_IMGUI_PROPERTIES_CREATED_ON, self->anm2->createdOn);
/* Version */
ImGui::Text(STRING_IMGUI_PROPERTIES_VERSION, self->anm2->version);
ImGui::End();
/* -- Animations -- */
ImGui::Begin(STRING_IMGUI_ANIMATIONS);
/* Iterate through all animations, can be selected and names can be edited */
for (auto & [id, animation] : self->anm2->animations)
{
char name[ANM2_STRING_FORMATTED_MAX];
char oldName[ANM2_STRING_MAX];
bool isSelected = selectedAnimationID == id;
static s32 defaultAnimationID = -1;
/* Distinguish default animation; if animation has the same name, only mark the first one as default */
if (strcmp(animation.name, self->anm2->defaultAnimation) == 0)
{
snprintf(name, ANM2_STRING_FORMATTED_MAX, STRING_IMGUI_ANIMATIONS_DEFAULT_ANIMATION_FORMAT, animation.name);
defaultAnimationID = id;
}
else
strncpy(name, animation.name, ANM2_STRING_FORMATTED_MAX - 1);
ImGui::PushID(id);
ImGui::Image(self->packed->textures[PACKED_TEXTURE_ANIMATION].handle, IMGUI_ICON_SIZE);
ImGui::SameLine();
if (isSelected)
{
if (ImGui::InputText(STRING_IMGUI_ANIMATIONS_ANIMATION_LABEL, animation.name, ANM2_STRING_MAX, ImGuiInputTextFlags_EnterReturnsTrue))
{
if (id == defaultAnimationID)
strncpy(self->anm2->defaultAnimation, animation.name, ANM2_STRING_MAX);
selectedAnimationID = -1;
}
}
else
{
if (ImGui::Selectable(name, isSelected))
selectedAnimationID = id;
}
_imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATIONS_SELECT);
ImGui::PopID();
}
if (ImGui::Button(STRING_IMGUI_ANIMATIONS_ADD))
{
s32 id;
bool isDefault = self->anm2->animations.size() == 0; /* first animation is default automatically */
id = anm2_animation_add(self->anm2);
selectedAnimationID = id;
if (isDefault)
strncpy(self->anm2->defaultAnimation, self->anm2->animations[id].name, ANM2_STRING_MAX);
}
_imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATIONS_ADD);
ImGui::SameLine();
if (selectedAnimationID != -1)
{
/* Remove */
if (ImGui::Button(STRING_IMGUI_ANIMATIONS_REMOVE))
{
anm2_animation_remove(self->anm2, selectedAnimationID);
selectedAnimationID = -1;
}
_imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATIONS_REMOVE);
ImGui::SameLine();
/* Duplicate */
if (ImGui::Button(STRING_IMGUI_ANIMATIONS_DUPLICATE))
{
s32 id = map_next_id_get(self->anm2->animations);
self->anm2->animations.insert({id, self->anm2->animations[selectedAnimationID]});
selectedAnimationID = id;
}
_imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATIONS_DUPLICATE);
if (ImGui::Button(STRING_IMGUI_ANIMATIONS_SET_AS_DEFAULT))
{
strncpy(self->anm2->defaultAnimation, self->anm2->animations[selectedAnimationID].name, ANM2_STRING_MAX);
selectedAnimationID = -1;
}
_imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATIONS_SET_AS_DEFAULT);
}
if (ImGui::IsMouseClicked(0) && !ImGui::IsAnyItemHovered() && ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
selectedAnimationID = -1;
ImGui::End();
/* -- Events -- */
ImGui::Begin(STRING_IMGUI_EVENTS);
/* Iterate through all events, can be selected and names can be edited */
for (auto & [id, event] : self->anm2->events)
{
char eventString[ANM2_STRING_FORMATTED_MAX];
bool isSelected;
snprintf(eventString, ANM2_STRING_FORMATTED_MAX, STRING_IMGUI_EVENT_FORMAT, (s32)id, event.name);
ImGui::PushID(id);
ImGui::Image(self->packed->textures[PACKED_TEXTURE_EVENT].handle, IMGUI_ICON_SIZE);
ImGui::SameLine();
isSelected = selectedEventID == id;
if (isSelected)
{
if (ImGui::InputText(STRING_IMGUI_EVENTS_EVENT_LABEL, event.name, ANM2_STRING_MAX, ImGuiInputTextFlags_EnterReturnsTrue))
selectedEventID = -1;
}
else
{
if (ImGui::Selectable(eventString, isSelected))
selectedEventID = id;
}
_imgui_tooltip(STRING_IMGUI_TOOLTIP_EVENTS_SELECT);
ImGui::PopID();
}
if (ImGui::Button(STRING_IMGUI_EVENTS_ADD))
{
s32 id = map_next_id_get(self->anm2->events);
self->anm2->events[id] = Anm2Event{};
selectedEventID = id;
}
_imgui_tooltip(STRING_IMGUI_TOOLTIP_EVENTS_ADD);
ImGui::SameLine();
if (selectedEventID != -1)
{
if (ImGui::Button(STRING_IMGUI_EVENTS_REMOVE))
{
self->anm2->events.erase(selectedEventID);
selectedEventID = -1;
}
_imgui_tooltip(STRING_IMGUI_TOOLTIP_EVENTS_REMOVE);
}
if (ImGui::IsMouseClicked(0) && !ImGui::IsAnyItemHovered() && ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
selectedEventID = -1;
ImGui::End();
/* -- Spritesheets -- */
ImGui::Begin(STRING_IMGUI_SPRITESHEETS);
for (auto [id, spritesheet] : self->anm2->spritesheets)
{
char spritesheetString[ANM2_STRING_FORMATTED_MAX];
bool isSelected = false;
snprintf(spritesheetString, ANM2_STRING_FORMATTED_MAX, STRING_IMGUI_SPRITESHEET_FORMAT, (s32)id, spritesheet.path);
ImGui::BeginChild(spritesheetString, IMGUI_SPRITESHEET_SIZE, true, ImGuiWindowFlags_None);
ImGui::PushID(id);
ImGui::Image(self->packed->textures[PACKED_TEXTURE_SPRITESHEET].handle, IMGUI_ICON_SIZE);
ImGui::SameLine();
isSelected = selectedSpritesheetID == id;
if (ImGui::Selectable(spritesheetString, isSelected))
selectedSpritesheetID = id;
ImGui::PopID();
ImGui::EndChild();
}
ImGui::Button(STRING_IMGUI_SPRITESHEETS_ADD);
_imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEETS_ADD);
ImGui::SameLine();
if (selectedSpritesheetID != -1)
{
if (ImGui::Button(STRING_IMGUI_SPRITESHEETS_REMOVE))
{
self->anm2->spritesheets.erase(selectedSpritesheetID);
selectedSpritesheetID = -1;
}
_imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEETS_REMOVE);
ImGui::SameLine();
ImGui::Button(STRING_IMGUI_SPRITESHEETS_RELOAD);
_imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEETS_RELOAD);
ImGui::SameLine();
ImGui::Button(STRING_IMGUI_SPRITESHEETS_REPLACE);
_imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEETS_REPLACE);
}
if (ImGui::IsMouseClicked(0) && !ImGui::IsAnyItemHovered() && ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
selectedSpritesheetID = -1;
ImGui::End();
/* -- Frame Properties -- */
ImGui::Begin(STRING_IMGUI_FRAME_PROPERTIES);
ImGui::DragFloat2(STRING_IMGUI_FRAME_PROPERTIES_POSITION, value_ptr(position), 1, 0, 0, "%.0f");
_imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_POSITION);
ImGui::DragFloat2(STRING_IMGUI_FRAME_PROPERTIES_CROP_POSITION, value_ptr(cropPosition), 1, 0, 0, "%.0f");
_imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_CROP_POSITION);
ImGui::DragFloat2(STRING_IMGUI_FRAME_PROPERTIES_CROP_SIZE, value_ptr(cropSize), 1, 0, 0, "%.0f");
_imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_CROP_SIZE);
ImGui::DragFloat2(STRING_IMGUI_FRAME_PROPERTIES_PIVOT, value_ptr(pivot), 1, 0, 0, "%.0f");
_imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_PIVOT);
ImGui::DragFloat2(STRING_IMGUI_FRAME_PROPERTIES_SCALE, value_ptr(xyScale), 1.0, 0, 0, "%.1f");
_imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_SCALE);
ImGui::DragFloat(STRING_IMGUI_FRAME_PROPERTIES_ROTATION, &rotation, 1, 0, 0, "%.1f");
_imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_ROTATION);
ImGui::DragInt(STRING_IMGUI_FRAME_PROPERTIES_DURATION, &duration, 1, 0, 255);
_imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_DURATION);
ImGui::ColorEdit4(STRING_IMGUI_FRAME_PROPERTIES_TINT, value_ptr(tint));
_imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_TINT);
ImGui::ColorEdit3(STRING_IMGUI_FRAME_PROPERTIES_COLOR_OFFSET, value_ptr(offset));
_imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_COLOR_OFFSET);
ImGui::Checkbox(STRING_IMGUI_FRAME_PROPERTIES_VISIBLE, &isVisible);
_imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_VISIBLE);
ImGui::SameLine();
ImGui::Checkbox(STRING_IMGUI_FRAME_PROPERTIES_INTERPOLATED, &isInterpolated);
_imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_INTERPOLATED);
ImGui::End();
/* -- Animation Preview -- */
ImGui::Begin(STRING_IMGUI_ANIMATION_PREVIEW);
/* Settings */
ImGui::BeginChild(STRING_IMGUI_ANIMATION_PREVIEW_SETTINGS, IMGUI_ANIMATION_PREVIEW_SETTINGS_SIZE, true);
/* Grid settings */
ImGui::BeginChild(STRING_IMGUI_ANIMATION_PREVIEW_GRID_SETTINGS, IMGUI_ANIMATION_PREVIEW_SETTINGS_GRID_SIZE, true);
/* Grid toggle */
ImGui::Checkbox(STRING_IMGUI_ANIMATION_PREVIEW_GRID, &self->preview->isGrid);
_imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_GRID);
ImGui::SameLine();
/* Grid Color */
ImGui::ColorEdit4(STRING_IMGUI_ANIMATION_PREVIEW_GRID_COLOR, value_ptr(self->preview->gridColor), ImGuiColorEditFlags_NoInputs);
_imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_GRID_COLOR);
/* Grid Size */
ImGui::InputInt2(STRING_IMGUI_ANIMATION_PREVIEW_GRID_SIZE, value_ptr(self->preview->gridSize));
self->preview->gridSize.x = CLAMP(self->preview->gridSize.x, PREVIEW_GRID_MIN, PREVIEW_GRID_MAX);
self->preview->gridSize.y = CLAMP(self->preview->gridSize.y, PREVIEW_GRID_MIN, PREVIEW_GRID_MAX);
_imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_GRID_SIZE);
ImGui::EndChild();
ImGui::SameLine();
/* Zoom settings */
ImGui::BeginChild(STRING_IMGUI_ANIMATION_PREVIEW_ZOOM_SETTINGS, IMGUI_ANIMATION_PREVIEW_SETTINGS_ZOOM_SIZE, true);
/* Zoom */
ImGui::DragFloat(STRING_IMGUI_ANIMATION_PREVIEW_ZOOM, &self->preview->zoom, 1, PREVIEW_ZOOM_MIN, PREVIEW_ZOOM_MAX, "%.0f");
_imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_ZOOM);
ImGui::EndChild();
ImGui::SameLine();
/* Background settings */
ImGui::BeginChild(STRING_IMGUI_ANIMATION_PREVIEW_BACKGROUND_SETTINGS, IMGUI_ANIMATION_PREVIEW_SETTINGS_BACKGROUND_SIZE, true);
/* Background color */
ImGui::ColorEdit4(STRING_IMGUI_ANIMATION_PREVIEW_BACKGROUND_COLOR, value_ptr(self->preview->color), ImGuiColorEditFlags_NoInputs);
_imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_BACKGROUND_COLOR);
ImGui::EndChild();
ImGui::SameLine();
ImGui::EndChild();
ImGui::Image(self->preview->texture, ImVec2(PREVIEW_SIZE.x, PREVIEW_SIZE.y));
ImGui::End();
/* -- Spritesheet Editor -- */
ImGui::Begin(STRING_IMGUI_SPRITESHEET_EDITOR);
ImGui::End();
/* -- Timeline -- */
ImGui::Begin(STRING_IMGUI_TIMELINE);
if (selectedAnimationID != -1)
{
s32 index = 0;
Anm2Animation* animation = &self->anm2->animations[selectedAnimationID];
ImGui::BeginChild(STRING_IMGUI_TIMELINE_ANIMATIONS, IMGUI_TIMELINE_ELEMENT_LIST_SIZE, true);
/* Root */
_imgui_timeline_element(self, &animation->rootAnimation, NULL, &index, ANM2_ROOT_ANIMATION, NULL, NULL);
/* reverse order */
for (auto it = animation->layerAnimations.rbegin(); it != animation->layerAnimations.rend(); it++)
{
s32 id = it->first;
Anm2LayerAnimation& layer = it->second;
_imgui_timeline_element(self, &layer, &id, &index, ANM2_LAYER_ANIMATION, &selectedTimelineElementType, &selectedTimelineElementID);
}
for (auto & [id, null] : animation->nullAnimations)
_imgui_timeline_element(self, &null, (s32*)&id, &index, ANM2_NULL_ANIMATION, &selectedTimelineElementType, &selectedTimelineElementID);
/* Triggers */
_imgui_timeline_element(self, &animation->triggers, NULL, &index, ANM2_TRIGGERS, NULL, NULL);
/* Element configuration */
if (ImGui::Button(STRING_IMGUI_TIMELINE_ELEMENT_ADD))
ImGui::OpenPopup(STRING_IMGUI_TIMELINE_ELEMENT_ADD_MENU);
_imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_ADD);
if (ImGui::BeginPopup(STRING_IMGUI_TIMELINE_ELEMENT_ADD_MENU))
{
if (ImGui::Selectable(STRING_IMGUI_TIMELINE_ELEMENT_ADD_MENU_LAYER))
anm2_layer_add(self->anm2);
if (ImGui::Selectable(STRING_IMGUI_TIMELINE_ELEMENT_ADD_MENU_NULL))
anm2_null_add(self->anm2);
ImGui::EndPopup();
}
ImGui::SameLine();
if
(
selectedTimelineElementID != -1 &&
((selectedTimelineElementType == ANM2_LAYER_ANIMATION) || (selectedTimelineElementType == ANM2_NULL_ANIMATION))
)
{
if (ImGui::Button(STRING_IMGUI_TIMELINE_ELEMENT_REMOVE))
{
switch (selectedTimelineElementType)
{
case ANM2_LAYER_ANIMATION:
anm2_layer_remove(self->anm2, selectedTimelineElementID);
break;
case ANM2_NULL_ANIMATION:
anm2_null_remove(self->anm2, selectedTimelineElementID);
break;
default:
break;
}
selectedTimelineElementID = -1;
selectedTimelineElementType = ANM2_NONE;
}
_imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_REMOVE);
}
else
{
selectedTimelineElementID = -1;
selectedTimelineElementType = ANM2_NONE;
}
ImGui::EndChild();
ImGui::SameLine();
/* Animation playback and frames */
static bool isPlaying = false;
if (isPlaying)
{
if (ImGui::Button(STRING_IMGUI_TIMELINE_PAUSE))
{
isPlaying = !isPlaying;
}
_imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_PLAY);
}
else
{
if (ImGui::Button(STRING_IMGUI_TIMELINE_PLAY))
{
isPlaying = !isPlaying;
}
_imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_PAUSE);
}
/*
ImGui::SameLine();
if (ImGui::Button(STRING_IMGUI_TIMELINE_ADD_FRAME))
{
}
_imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_FRAME_ADD);
ImGui::SameLine();
if (ImGui::Button(STRING_IMGUI_TIMELINE_REMOVE_FRAME))
{
}
*/
}
ImGui::End();
}
void
imgui_draw(void)
imgui_draw(Imgui* self)
{
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}
void
imgui_free(void)
imgui_free(Imgui* self)
{
ImGui_ImplSDL3_Shutdown();
ImGui_ImplOpenGL3_Shutdown();