diff --git a/src/COMMON.h b/src/COMMON.h index b25688e..a784c62 100644 --- a/src/COMMON.h +++ b/src/COMMON.h @@ -55,6 +55,42 @@ using namespace glm; // fuck you #define SECOND 1000.0f #define TICK_RATE (SECOND / TICK_DELAY) +#define UV_VERTICES(uvMin, uvMax) \ +{ \ + 0, 0, uvMin.x, uvMin.y, \ + 1, 0, uvMax.x, uvMin.y, \ + 1, 1, uvMax.x, uvMax.y, \ + 0, 1, uvMin.x, uvMax.y, \ +} + +static const f32 GL_VERTICES[] = +{ + 0, 0, + 1, 0, + 1, 1, + 0, 1 +}; + +static const f32 GL_UV_VERTICES[] = +{ + 0, 0, 0.0f, 0.0f, + 1, 0, 1.0f, 0.0f, + 1, 1, 1.0f, 1.0f, + 0, 1, 0.0f, 1.0f +}; +#define IMVEC2_VEC2(value) ImVec2(value.x, value.y) +#define VEC2_IMVEC2(value) glm::vec2(value.x, value.y) + +static const GLuint GL_TEXTURE_INDICES[] = {0, 1, 2, 2, 3, 0}; + +static const vec4 COLOR_RED = {1.0f, 0.0f, 0.0f, 1.0f}; +static const vec4 COLOR_GREEN = {0.0f, 1.0f, 0.0f, 1.0f}; +static const vec4 COLOR_BLUE = {0.0f, 0.0f, 1.0f, 1.0f}; +static const vec4 COLOR_OPAQUE = {1.0f, 1.0f, 1.0f, 1.0f}; +static const vec4 COLOR_TRANSPARENT = {0.0f, 0.0f, 0.0f, 1.0f}; +static const vec3 COLOR_OFFSET_NONE = {0.0f, 0.0f, 0.0f}; + + static inline const char* enum_to_string(const char* arr[], s32 count, s32 index) { return (index >= 0 && index < count) ? arr[index] : "undefined"; } static inline s32 string_to_enum(const char* str, const char* const* arr, s32 n) { for (s32 i=0; ipath, path, PATH_MAX - 1); working_directory_from_path_set(path); @@ -746,21 +746,15 @@ anm2_spritesheet_texture_load(Anm2* self, Resources* resources, const char* path { Texture texture; - /* free texture if it exists, and if it's not texture error */ - if - ( - resources->loadedTextures.find(id) != resources->loadedTextures.end() && - resources->loadedTextures[id].handle != resources->textures[TEXTURE_ERROR].handle - ) - texture_free(&resources->loadedTextures[id]); + if (resources->textures.find(id) != resources->textures.end() && resources->textures[id].id != resources->textures[TEXTURE_ERROR].id) + texture_free(&resources->textures[id]); if (texture_from_path_init(&texture, path)) - resources->loadedTextures[id] = texture; + resources->textures[id] = texture; else - { - resources->loadedTextures[id] = resources->textures[TEXTURE_ERROR]; - resources->loadedTextures[id].isInvalid = true; - } + texture.isInvalid = true; + + resources->textures[id] = texture; } /* Creates/fetches a frame from a given time. */ @@ -775,12 +769,11 @@ anm2_frame_from_time(Anm2* self, Anm2Animation* animation, Anm2Frame* frame, Anm Anm2RootAnimation* rootAnimation; Anm2LayerAnimation* layerAnimation; Anm2NullAnimation* nullAnimation; - Anm2Frame* baseFrame = NULL; Anm2Frame* nextFrame = NULL; std::vector* frames = NULL; f32 delayCurrent = 0; f32 delayNext = 0; - bool isBaseFrame = false; + bool isTimeMatchedFrame = false; switch (type) { @@ -803,19 +796,19 @@ anm2_frame_from_time(Anm2* self, Anm2Animation* animation, Anm2Frame* frame, Anm for (s32 i = 0; i < (s32)frames->size(); i++) { - Anm2Frame* frame = &(*frames)[i]; + *frame = (*frames)[i]; delayNext += frame->delay; + /* If a frame is within the time constraints, it's a time matched frame, break */ + /* Otherwise, the last found frame parsed will be used. */ if (time >= delayCurrent && time < delayNext) { - baseFrame = frame; - if (i + 1 < (s32)frames->size()) nextFrame = &(*frames)[i + 1]; else nextFrame = NULL; - isBaseFrame = true; + isTimeMatchedFrame = true; break; } @@ -823,21 +816,19 @@ anm2_frame_from_time(Anm2* self, Anm2Animation* animation, Anm2Frame* frame, Anm } /* No valid frame found */ - if (!isBaseFrame) + if (!isTimeMatchedFrame) return false; - *frame = *baseFrame; - /* interpolate only if there's a frame following */ if (frame->isInterpolated && nextFrame) { f32 interpolationTime = (time - delayCurrent) / (delayNext - delayCurrent); - frame->rotation = glm::mix(baseFrame->rotation, nextFrame->rotation, interpolationTime);; - frame->position = glm::mix(baseFrame->position, nextFrame->position, interpolationTime);; - frame->scale = glm::mix(baseFrame->scale, nextFrame->scale, interpolationTime);; - frame->offsetRGB = glm::mix(baseFrame->offsetRGB, nextFrame->offsetRGB, interpolationTime);; - frame->tintRGBA = glm::mix(baseFrame->tintRGBA, nextFrame->tintRGBA, interpolationTime);; + frame->rotation = glm::mix(frame->rotation, nextFrame->rotation, interpolationTime);; + frame->position = glm::mix(frame->position, nextFrame->position, interpolationTime);; + frame->scale = glm::mix(frame->scale, nextFrame->scale, interpolationTime);; + frame->offsetRGB = glm::mix(frame->offsetRGB, nextFrame->offsetRGB, interpolationTime);; + frame->tintRGBA = glm::mix(frame->tintRGBA, nextFrame->tintRGBA, interpolationTime);; } return true; diff --git a/src/dialog.cpp b/src/dialog.cpp index d062abc..bb85de2 100644 --- a/src/dialog.cpp +++ b/src/dialog.cpp @@ -76,7 +76,7 @@ dialog_tick(Dialog* self) switch (self->type) { case DIALOG_ANM2_OPEN: - resources_loaded_textures_free(self->resources); + resources_textures_free(self->resources); anm2_deserialize(self->anm2, self->resources, self->path); window_title_from_anm2_set(self->window, self->anm2); break; @@ -85,7 +85,7 @@ dialog_tick(Dialog* self) window_title_from_anm2_set(self->window, self->anm2); break; case DIALOG_PNG_OPEN: - id = map_next_id_get(self->resources->loadedTextures); + id = map_next_id_get(self->resources->textures); self->anm2->spritesheets[id] = Anm2Spritesheet{}; strncpy(self->anm2->spritesheets[id].path, relativePath, PATH_MAX); anm2_spritesheet_texture_load(self->anm2, self->resources, relativePath, id); diff --git a/src/editor.cpp b/src/editor.cpp new file mode 100644 index 0000000..353329c --- /dev/null +++ b/src/editor.cpp @@ -0,0 +1,288 @@ +#include "editor.h" + +static void _editor_grid_set(Editor* self); + +static void +_editor_grid_set(Editor* self) +{ + std::vector vertices; + + s32 verticalLineCount = (s32)(EDITOR_SIZE.x / MIN(self->settings->editorGridSizeX, EDITOR_GRID_MIN)); + s32 horizontalLineCount = (s32)(EDITOR_SIZE.y / MIN(self->settings->editorGridSizeY, EDITOR_GRID_MIN)); + + /* Vertical */ + for (s32 i = 0; i <= verticalLineCount; i++) + { + s32 x = i * self->settings->editorGridSizeX - self->settings->editorGridOffsetX; + f32 normX = (2.0f * x) / EDITOR_SIZE.x - 1.0f; + + vertices.push_back(normX); + vertices.push_back(-1.0f); + vertices.push_back(normX); + vertices.push_back(1.0f); + } + + /* Horizontal */ + for (s32 i = 0; i <= horizontalLineCount; i++) + { + s32 y = i * self->settings->editorGridSizeY - self->settings->editorGridOffsetY; + f32 normY = (2.0f * y) / EDITOR_SIZE.y - 1.0f; + + vertices.push_back(-1.0f); + vertices.push_back(normY); + vertices.push_back(1.0f); + vertices.push_back(normY); + } + + self->gridVertexCount = (s32)vertices.size(); + + glBindVertexArray(self->gridVAO); + glBindBuffer(GL_ARRAY_BUFFER, self->gridVBO); + glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(f32), vertices.data(), GL_DYNAMIC_DRAW); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(f32), (void*)0); +} + +void +editor_init(Editor* self, Resources* resources, Settings* settings) +{ + self->resources = resources; + self->settings = settings; + + /* Framebuffer + texture */ + glGenFramebuffers(1, &self->fbo); + + glBindFramebuffer(GL_FRAMEBUFFER, self->fbo); + + glGenTextures(1, &self->texture); + glBindTexture(GL_TEXTURE_2D, self->texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (s32)EDITOR_SIZE.x, (s32)EDITOR_SIZE.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->texture, 0); + + glGenRenderbuffers(1, &self->rbo); + glBindRenderbuffer(GL_RENDERBUFFER, self->rbo); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, (s32)EDITOR_SIZE.x, (s32)EDITOR_SIZE.y); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, self->rbo); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + /* Grid */ + glGenVertexArrays(1, &self->gridVAO); + glGenBuffers(1, &self->gridVBO); + + /* Border */ + glGenVertexArrays(1, &self->borderVAO); + glGenBuffers(1, &self->borderVBO); + + glBindVertexArray(self->borderVAO); + + glBindBuffer(GL_ARRAY_BUFFER, self->borderVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(GL_VERTICES), GL_VERTICES, GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(f32), (void*)0); + + /* Viewing texture */ + glGenVertexArrays(1, &self->textureVAO); + glGenBuffers(1, &self->textureVBO); + glGenBuffers(1, &self->textureEBO); + + glBindVertexArray(self->textureVAO); + + glBindBuffer(GL_ARRAY_BUFFER, self->textureVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(f32) * 4 * 4, NULL, GL_DYNAMIC_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self->textureEBO); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GL_TEXTURE_INDICES), GL_TEXTURE_INDICES, GL_STATIC_DRAW); + + /* Position */ + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(f32), (void*)0); + + /* UV */ + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(f32), (void*)(2 * sizeof(f32))); + + glBindVertexArray(0); + + _editor_grid_set(self); +} + +void +editor_draw(Editor* self) +{ + GLuint shaderLine = self->resources->shaders[SHADER_LINE]; + GLuint shaderLineDotted = self->resources->shaders[SHADER_LINE_DOTTED]; + GLuint shaderTexture = self->resources->shaders[SHADER_TEXTURE]; + f32 zoomFactor = self->settings->editorZoom / 100.0f; + + /* Convert pan to pixels */ + glm::vec2 ndcPan = glm::vec2(-self->settings->editorPanX / (EDITOR_SIZE.x / 2.0f), -self->settings->editorPanY / (EDITOR_SIZE.y / 2.0f)); + + /* Transformation matrix */ + glm::mat4 editorTransform = glm::translate(glm::mat4(1.0f), glm::vec3(ndcPan, 0.0f)); + editorTransform = glm::scale(editorTransform, glm::vec3(zoomFactor, zoomFactor, 1.0f)); + + glBindFramebuffer(GL_FRAMEBUFFER, self->fbo); + glViewport(0, 0, EDITOR_SIZE.x, EDITOR_SIZE.y); + + glClearColor + ( + self->settings->editorBackgroundColorR, + self->settings->editorBackgroundColorG, + self->settings->editorBackgroundColorB, + self->settings->editorBackgroundColorA + ); + + glClear(GL_COLOR_BUFFER_BIT); + + if (self->spritesheetID > -1) + { + Texture* texture = &self->resources->textures[self->spritesheetID]; + + glm::mat4 spritesheetTransform = editorTransform; + glm::vec2 ndcScale = glm::vec2(texture->size.x, texture->size.y) / (EDITOR_SIZE * 0.5f); + + spritesheetTransform = glm::scale(spritesheetTransform, glm::vec3(ndcScale, 1.0f)); + + glUseProgram(shaderTexture); + + glBindVertexArray(self->textureVAO); + + glBindBuffer(GL_ARRAY_BUFFER, self->textureVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(GL_UV_VERTICES), GL_UV_VERTICES, GL_DYNAMIC_DRAW); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture->id); + + glUniform1i(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TEXTURE), 0); + glUniform4fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TINT), 1, value_ptr(COLOR_OPAQUE)); + glUniform3fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_COLOR_OFFSET), 1, value_ptr(COLOR_OFFSET_NONE)); + glUniformMatrix4fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, value_ptr(spritesheetTransform)); + + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + + glBindTexture(GL_TEXTURE_2D, 0); + + glBindVertexArray(0); + glUseProgram(0); + + if (self->settings->editorIsBorder) + { + glUseProgram(shaderLineDotted); + + glBindVertexArray(self->borderVAO); + + glUniformMatrix4fv(glGetUniformLocation(shaderLine, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, glm::value_ptr(spritesheetTransform)); + glUniform4fv(glGetUniformLocation(shaderLine, SHADER_UNIFORM_COLOR), 1, glm::value_ptr(EDITOR_BORDER_TINT)); + + glDrawArrays(GL_LINE_LOOP, 0, 4); + + glBindVertexArray(0); + glUseProgram(0); + } + + if (self->isFrame) + { + glm::mat4 rectTransform = editorTransform; + + glm::vec2 rectNDCPos = self->frame.crop / (EDITOR_SIZE / 2.0f); + glm::vec2 rectNDCScale = self->frame.size / (EDITOR_SIZE * 0.5f); + + rectTransform = glm::translate(rectTransform, glm::vec3(rectNDCPos, 0.0f)); + rectTransform = glm::scale(rectTransform, glm::vec3(rectNDCScale, 1.0f)); + + glUseProgram(shaderLineDotted); + + glBindVertexArray(self->borderVAO); + + glUniformMatrix4fv(glGetUniformLocation(shaderLine, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, glm::value_ptr(rectTransform)); + glUniform4fv(glGetUniformLocation(shaderLine, SHADER_UNIFORM_COLOR), 1, glm::value_ptr(EDITOR_FRAME_TINT)); + + glDrawArrays(GL_LINE_LOOP, 0, 4); + + glBindVertexArray(0); + glUseProgram(0); + + glm::mat4 pivotTransform = editorTransform; + glm::vec2 pivotNDCPos = self->frame.pivot / (EDITOR_SIZE / 2.0f); + glm::vec2 pivotNDCScale = ATLAS_SIZES[TEXTURE_PIVOT] / (EDITOR_SIZE * 0.5f); + + pivotTransform = glm::translate(pivotTransform, glm::vec3(pivotNDCPos, 0.0f)); + pivotTransform = glm::scale(pivotTransform, glm::vec3(pivotNDCScale, 1.0f)); + + glUseProgram(shaderTexture); + + glBindVertexArray(self->textureVAO); + + glBindBuffer(GL_ARRAY_BUFFER, self->textureVBO); + + f32 vertices[] = ATLAS_UV_VERTICES(TEXTURE_PIVOT); + + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, self->resources->atlas.id); + + glUniform1i(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TEXTURE), 0); + glUniform4fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TINT), 1, value_ptr(EDITOR_FRAME_TINT)); + glUniform3fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_COLOR_OFFSET), 1, value_ptr(COLOR_OFFSET_NONE)); + glUniformMatrix4fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, value_ptr(pivotTransform)); + + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindTexture(GL_TEXTURE_2D, 0); + glUseProgram(0); + } + } + + if (self->settings->editorIsGrid) + { + if + ( + (ivec2(self->settings->editorGridSizeX, self->settings->editorGridSizeY) != self->oldGridSize) || + (ivec2(self->settings->editorGridOffsetX, self->settings->editorGridOffsetY) != self->oldGridOffset) + ) + _editor_grid_set(self); + + glUseProgram(shaderLine); + glBindVertexArray(self->gridVAO); + + glUniformMatrix4fv(glGetUniformLocation(shaderLine, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, (f32*)value_ptr(editorTransform)); + + glUniform4f + ( + glGetUniformLocation(shaderLine, SHADER_UNIFORM_COLOR), + self->settings->editorGridColorR, self->settings->editorGridColorG, self->settings->editorGridColorB, self->settings->editorGridColorA + ); + + glDrawArrays(GL_LINES, 0, self->gridVertexCount); + + glBindVertexArray(0); + glUseProgram(0); + } + + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +void +editor_tick(Editor* self) +{ + self->settings->editorZoom = CLAMP(self->settings->editorZoom, EDITOR_ZOOM_MIN, EDITOR_ZOOM_MAX); + self->oldGridSize = glm::vec2(self->settings->editorGridSizeX, self->settings->editorGridSizeY); + self->oldGridOffset = glm::vec2(self->settings->editorGridOffsetX, self->settings->editorGridOffsetY); +} + +void +editor_free(Editor* self) +{ + glDeleteTextures(1, &self->texture); + glDeleteFramebuffers(1, &self->fbo); + glDeleteRenderbuffers(1, &self->rbo); +} \ No newline at end of file diff --git a/src/editor.h b/src/editor.h new file mode 100644 index 0000000..fe86b4c --- /dev/null +++ b/src/editor.h @@ -0,0 +1,46 @@ +#pragma once + +#include "anm2.h" +#include "resources.h" +#include "settings.h" + +#define EDITOR_ZOOM_MIN 1 +#define EDITOR_ZOOM_MAX 1000 +#define EDITOR_ZOOM_STEP 25 +#define EDITOR_GRID_MIN 1 +#define EDITOR_GRID_MAX 1000 +#define EDITOR_GRID_OFFSET_MIN 0 +#define EDITOR_GRID_OFFSET_MAX 100 + +static const vec2 EDITOR_SIZE = {5000, 5000}; +static const vec4 EDITOR_TEXTURE_TINT = COLOR_OPAQUE; +static const vec4 EDITOR_BORDER_TINT = COLOR_OPAQUE; +static const vec4 EDITOR_FRAME_TINT = COLOR_RED; + +struct Editor +{ + Resources* resources = NULL; + Settings* settings = NULL; + GLuint fbo; + GLuint rbo; + GLuint gridVAO; + GLuint gridVBO; + GLuint texture; + GLuint textureEBO; + GLuint textureVAO; + GLuint textureVBO; + GLuint borderVAO; + GLuint borderVBO; + s32 gridVertexCount = -1; + s32 spritesheetID = -1; + s32 oldSpritesheetID = -1; + ivec2 oldGridSize = {-1, -1}; + ivec2 oldGridOffset = {-1, -1}; + Anm2Frame frame; + bool isFrame = false; +}; + +void editor_init(Editor* self, Resources* resources, Settings* settings); +void editor_draw(Editor* self); +void editor_tick(Editor* self); +void editor_free(Editor* self); \ No newline at end of file diff --git a/src/imgui.cpp b/src/imgui.cpp index 391f074..95c1579 100644 --- a/src/imgui.cpp +++ b/src/imgui.cpp @@ -31,7 +31,10 @@ _imgui_timeline_element_frames(Imgui* self, void* element, s32* id, s32* index, Anm2RootAnimation* rootAnimation = NULL; Anm2Triggers* triggers = NULL; ImVec2 cursorPos = ImGui::GetCursorPos(); - + ImVec4 frameColor; + ImVec4 hoveredColor; + ImVec4 activeColor; + void* frames = NULL; switch (type) @@ -39,18 +42,30 @@ _imgui_timeline_element_frames(Imgui* self, void* element, s32* id, s32* index, case ANM2_ROOT_ANIMATION: rootAnimation = (Anm2RootAnimation*)element; frames = &rootAnimation->frames; + frameColor = IMGUI_TIMELINE_ROOT_FRAME_COLOR; + hoveredColor = IMGUI_TIMELINE_ROOT_HIGHLIGHT_COLOR; + activeColor = IMGUI_TIMELINE_ROOT_ACTIVE_COLOR; break; case ANM2_LAYER_ANIMATION: layerAnimation = (Anm2LayerAnimation*)element; frames = &layerAnimation->frames; + frameColor = IMGUI_TIMELINE_LAYER_FRAME_COLOR; + hoveredColor = IMGUI_TIMELINE_LAYER_HIGHLIGHT_COLOR; + activeColor = IMGUI_TIMELINE_LAYER_ACTIVE_COLOR; break; case ANM2_NULL_ANIMATION: nullAnimation = (Anm2NullAnimation*)element; frames = &nullAnimation->frames; + frameColor = IMGUI_TIMELINE_NULL_FRAME_COLOR; + hoveredColor = IMGUI_TIMELINE_NULL_HIGHLIGHT_COLOR; + activeColor = IMGUI_TIMELINE_NULL_ACTIVE_COLOR; break; case ANM2_TRIGGER: triggers = (Anm2Triggers*)element; frames = &triggers->items; + frameColor = IMGUI_TIMELINE_TRIGGERS_FRAME_COLOR; + hoveredColor = IMGUI_TIMELINE_TRIGGERS_HIGHLIGHT_COLOR; + activeColor = IMGUI_TIMELINE_TRIGGERS_ACTIVE_COLOR; break; default: break; @@ -83,7 +98,7 @@ _imgui_timeline_element_frames(Imgui* self, void* element, s32* id, s32* index, ImGui::GetWindowDrawList()->AddRectFilled(bgMin, bgMax, bgColor); } - ImGui::Image(self->resources->textures[TEXTURE_FRAME_ALTERNATE].handle, IMGUI_TIMELINE_FRAME_SIZE); + ImGui::Image(self->resources->atlas.id, IMGUI_TIMELINE_FRAME_SIZE, IMVEC2_ATLAS_UV_GET(TEXTURE_FRAME_ALT)); ImGui::SameLine(); ImGui::PopID(); @@ -101,29 +116,29 @@ _imgui_timeline_element_frames(Imgui* self, void* element, s32* id, s32* index, triggerPos.x = framePos.x + (IMGUI_TIMELINE_FRAME_SIZE.x * trigger.atFrame); ImGui::SetCursorPos(triggerPos); - + + ImVec4 buttonColor = self->frameIndex == i && self->frameVector == elementTriggers ? activeColor : frameColor; + ImGui::PushStyleColor(ImGuiCol_Button, buttonColor); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, hoveredColor); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, activeColor); ImGui::PushStyleColor(ImGuiCol_Border, IMGUI_FRAME_BORDER_COLOR); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, IMGUI_FRAME_BORDER); - - ImVec4 buttonColor = self->frameIndex == i && self->frameVector == elementTriggers ? - ImGui::GetStyle().Colors[ImGuiCol_ButtonHovered] : ImGui::GetStyle().Colors[ImGuiCol_Button]; - ImGui::PushStyleColor(ImGuiCol_Button, buttonColor); - + ImGui::PushID(i); if (ImGui::Button(STRING_IMGUI_TIMELINE_TRIGGER_LABEL, IMGUI_TIMELINE_FRAME_SIZE)) { self->frameIndex = i; self->frameVector = elementTriggers; self->animationType = type; + self->timelineElementIndex = *index; } ImGui::PopStyleVar(); - ImGui::PopStyleColor(); - ImGui::PopStyleColor(); + ImGui::PopStyleColor(4); ImGui::SetCursorPos(ImVec2(triggerPos.x + 1.0f, (triggerPos.y + (IMGUI_TIMELINE_FRAME_SIZE.y / 2)) - IMGUI_ICON_SMALL_SIZE.y / 2)); - ImGui::Image(self->resources->textures[TEXTURE_TRIGGER_FRAME_ICON].handle, IMGUI_ICON_SMALL_SIZE); + ImGui::Image(self->resources->atlas.id, IMGUI_ICON_SMALL_SIZE, IMVEC2_ATLAS_UV_GET(TEXTURE_TRIGGER)); ImGui::PopID(); } @@ -134,22 +149,20 @@ _imgui_timeline_element_frames(Imgui* self, void* element, s32* id, s32* index, for (auto [i, frame] : std::views::enumerate(*elementFrames)) { - Texture* texture = frame.isInterpolated ? - &self->resources->textures[TEXTURE_INTERPOLATED_FRAME_ICON] : - &self->resources->textures[TEXTURE_UNINTERPOLATED_FRAME_ICON]; + TextureType textureType = frame.isInterpolated ? TEXTURE_CIRCLE : TEXTURE_SQUARE; f32 frameWidth = IMGUI_TIMELINE_FRAME_SIZE.x * frame.delay; ImVec2 frameSize = ImVec2(frameWidth, IMGUI_TIMELINE_FRAME_SIZE.y); ImGui::SetCursorPos(framePos); - + + ImVec4 buttonColor = self->frameIndex == i && self->frameVector == elementFrames ? activeColor : frameColor; + ImGui::PushStyleColor(ImGuiCol_Button, buttonColor); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, hoveredColor); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, activeColor); ImGui::PushStyleColor(ImGuiCol_Border, IMGUI_FRAME_BORDER_COLOR); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, IMGUI_FRAME_BORDER); - ImVec4 buttonColor = self->frameIndex == i && self->frameVector == elementFrames ? - ImGui::GetStyle().Colors[ImGuiCol_ButtonHovered] : ImGui::GetStyle().Colors[ImGuiCol_Button]; - ImGui::PushStyleColor(ImGuiCol_Button, buttonColor); - ImGui::PushID(i); if (ImGui::Button(STRING_IMGUI_TIMELINE_FRAME_LABEL, frameSize)) @@ -157,15 +170,18 @@ _imgui_timeline_element_frames(Imgui* self, void* element, s32* id, s32* index, self->frameIndex = i; self->frameVector = elementFrames; self->animationType = type; + self->timelineElementIndex = *index; + + if (type == ANM2_LAYER_ANIMATION) + self->spritesheetID = self->anm2->layers[*id].spritesheetID; } ImGui::PopStyleVar(); - ImGui::PopStyleColor(); - ImGui::PopStyleColor(); + ImGui::PopStyleColor(4); ImGui::SetCursorPos(ImVec2(framePos.x + 1.0f, (framePos.y + (frameSize.y / 2)) - IMGUI_ICON_SMALL_SIZE.y / 2)); - ImGui::Image(texture->handle, IMGUI_ICON_SMALL_SIZE); + ImGui::Image(self->resources->atlas.id, IMGUI_ICON_SMALL_SIZE, IMVEC2_ATLAS_UV_GET(textureType)); ImGui::PopID(); @@ -203,7 +219,7 @@ _imgui_timeline_element(Imgui* self, void* element, s32* id, s32* index, Anm2Ani void* frames = NULL; ImVec2 framePos; ImVec2 frameFinishPos; - ImTextureID iconTexture = -1; + TextureType textureType = TEXTURE_ERROR; bool isSelected = *index == self->timelineElementIndex; bool isArrows = false; bool* isShowRect = NULL; @@ -214,44 +230,49 @@ _imgui_timeline_element(Imgui* self, void* element, s32* id, s32* index, Anm2Ani s32* spritesheetID = NULL; bool isChangeable = type != ANM2_ROOT_ANIMATION && type != ANM2_TRIGGER; f32 cursorPosY = ImGui::GetCursorPosY(); + ImVec4 color; switch (type) { case ANM2_ROOT_ANIMATION: rootAnimation = (Anm2RootAnimation*)element; - iconTexture = self->resources->textures[TEXTURE_ROOT].handle; + textureType = TEXTURE_ROOT; strncpy(nameVisible, STRING_IMGUI_TIMELINE_ROOT, ANM2_STRING_FORMATTED_MAX); isVisible = &rootAnimation->isVisible; frames = &rootAnimation->frames; + color = IMGUI_TIMELINE_ROOT_COLOR; break; case ANM2_LAYER_ANIMATION: layerAnimation = (Anm2LayerAnimation*)element; layer = &self->anm2->layers[*id]; - iconTexture = self->resources->textures[TEXTURE_LAYER].handle; + textureType = TEXTURE_LAYER; 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); frames = &layerAnimation->frames; + color = IMGUI_TIMELINE_LAYER_COLOR; break; case ANM2_NULL_ANIMATION: nullAnimation = (Anm2NullAnimation*)element; null = &self->anm2->nulls[*id]; - iconTexture = self->resources->textures[TEXTURE_NULL].handle; + textureType = TEXTURE_NULL; 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); frames = &nullAnimation->frames; + color = IMGUI_TIMELINE_NULL_COLOR; break; case ANM2_TRIGGER: triggers = (Anm2Triggers*)element; - iconTexture = self->resources->textures[TEXTURE_TRIGGER].handle; + textureType = TEXTURE_TRIGGER; strncpy(nameVisible, STRING_IMGUI_TIMELINE_TRIGGERS, ANM2_STRING_FORMATTED_MAX); isVisible = &triggers->isVisible; frames = &triggers->items; + color = IMGUI_TIMELINE_TRIGGERS_COLOR; break; default: break; @@ -259,8 +280,10 @@ _imgui_timeline_element(Imgui* self, void* element, s32* id, s32* index, Anm2Ani ImGui::PushID(*index); + ImGui::PushStyleColor(ImGuiCol_ChildBg, color); ImGui::BeginChild(nameVisible, IMGUI_TIMELINE_ELEMENT_SIZE, true, ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoScrollbar); - + ImGui::PopStyleColor(); + /* Shift arrows */ if (isChangeable) { @@ -283,7 +306,11 @@ _imgui_timeline_element(Imgui* self, void* element, s32* id, s32* index, Anm2Ani if (canMoveUp) { auto target = isReversed ? std::next(it) : std::prev(it); - if (target != map.end() && ImGui::ImageButton(STRING_IMGUI_TIMELINE_ELEMENT_SHIFT_ABOVE, self->resources->textures[TEXTURE_ARROW_UP].handle, IMGUI_ICON_SIZE)) + if + ( + target != map.end() && + ImGui::ImageButton(STRING_IMGUI_TIMELINE_ELEMENT_UP, self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[TEXTURE_UP]), IMVEC2_ATLAS_UV_GET(TEXTURE_UP)) + ) { map_swap(map, it->first, target->first); @@ -311,7 +338,11 @@ _imgui_timeline_element(Imgui* self, void* element, s32* id, s32* index, Anm2Ani ImGui::SameLine(); auto target = isReversed ? std::prev(it) : std::next(it); - if (target != map.end() && ImGui::ImageButton(STRING_IMGUI_TIMELINE_ELEMENT_SHIFT_BELOW, self->resources->textures[TEXTURE_ARROW_DOWN].handle, IMGUI_ICON_SIZE)) + if + ( + target != map.end() && + ImGui::ImageButton(STRING_IMGUI_TIMELINE_ELEMENT_DOWN, self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[TEXTURE_DOWN]), IMVEC2_ATLAS_UV_GET(TEXTURE_DOWN)) + ) { map_swap(map, it->first, target->first); @@ -360,7 +391,7 @@ _imgui_timeline_element(Imgui* self, void* element, s32* id, s32* index, Anm2Ani } } - ImGui::Image(iconTexture, IMGUI_ICON_SIZE); + ImGui::Image(self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[textureType]), IMVEC2_ATLAS_UV_GET(textureType)); ImGui::SameLine(); @@ -378,6 +409,9 @@ _imgui_timeline_element(Imgui* self, void* element, s32* id, s32* index, Anm2Ani self->frameVector = frames; self->animationType = type; self->timelineElementIndex = *index; + + if (type == ANM2_LAYER_ANIMATION) + self->spritesheetID = *spritesheetID; } } @@ -401,20 +435,18 @@ _imgui_timeline_element(Imgui* self, void* element, s32* id, s32* index, Anm2Ani ImGui::EndChild(); - /* Visiblity */ + /* IsVisible */ if (isVisible) { ImVec2 cursorPos; - ImTextureID visibilityIcon = *isVisible - ? self->resources->textures[TEXTURE_EYE_OPEN].handle - : self->resources->textures[TEXTURE_EYE_CLOSED].handle; + TextureType visibleTextureType = *isVisible ? TEXTURE_VISIBLE : TEXTURE_INVISIBLE; ImGui::SameLine(); cursorPos = ImGui::GetCursorPos(); ImGui::SetCursorPosX(cursorPos.x + ImGui::GetContentRegionAvail().x - IMGUI_ICON_BUTTON_SIZE.x - ImGui::GetStyle().FramePadding.x * 2); - if (ImGui::ImageButton(STRING_IMGUI_TIMELINE_VISIBLE, visibilityIcon, IMGUI_ICON_SIZE)) + if (ImGui::ImageButton(STRING_IMGUI_TIMELINE_VISIBLE, self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[visibleTextureType]), IMVEC2_ATLAS_UV_GET(visibleTextureType))) *isVisible = !*isVisible; _imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_VISIBLE); @@ -433,7 +465,7 @@ _imgui_timeline_element(Imgui* self, void* element, s32* id, s32* index, Anm2Ani ImGui::BeginChild(STRING_IMGUI_TIMELINE_ELEMENT_SPRITESHEET_ID_LABEL, IMGUI_TIMELINE_ELEMENT_SPRITESHEET_ID_SIZE); - ImGui::Image(self->resources->textures[TEXTURE_SPRITESHEET].handle, IMGUI_ICON_SIZE); + ImGui::Image(self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[TEXTURE_SPRITESHEET]), IMVEC2_ATLAS_UV_GET(TEXTURE_SPRITESHEET)); ImGui::SameLine(); if (selectedSpritesheetIndex == *index) @@ -454,13 +486,11 @@ _imgui_timeline_element(Imgui* self, void* element, s32* id, s32* index, Anm2Ani /* ShowRect */ if (isShowRect) { - ImTextureID rectIcon = *isShowRect - ? self->resources->textures[TEXTURE_RECT_SHOW].handle - : self->resources->textures[TEXTURE_RECT_HIDE].handle; + TextureType rectTextureType = *isShowRect ? TEXTURE_RECT : TEXTURE_RECT_HIDE; ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - ((IMGUI_ICON_BUTTON_SIZE.x - ImGui::GetStyle().FramePadding.x * 2) * 4)); - if (ImGui::ImageButton(STRING_IMGUI_TIMELINE_RECT, rectIcon, IMGUI_ICON_SIZE)) + if (ImGui::ImageButton(STRING_IMGUI_TIMELINE_RECT, self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[rectTextureType]), IMVEC2_ATLAS_UV_GET(rectTextureType))) *isShowRect = !*isShowRect; _imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_RECT); @@ -506,23 +536,22 @@ _imgui_timeline(Imgui* self) s32 idDefault = 0; const char* buttonText = self->preview->isPlaying ? STRING_IMGUI_TIMELINE_PAUSE : STRING_IMGUI_TIMELINE_PLAY; const char* buttonTooltipText = self->preview->isPlaying ? STRING_IMGUI_TOOLTIP_TIMELINE_PAUSE : STRING_IMGUI_TOOLTIP_TIMELINE_PLAY; - - ImVec2 timelineSize = {0, ImGui::GetContentRegionAvail().y - IMGUI_TIMELINE_OFFSET_Y}; - - /* Generally, things need to be dranw out of apparent order for correct scrolling to work. */ + ImVec2 region = ImGui::GetContentRegionAvail(); + ImVec2 windowSize; - /* Main timeline child */ + ImVec2 timelineSize = {region.x, region.y - IMGUI_TIMELINE_OFFSET_Y}; + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); ImGui::BeginChild(STRING_IMGUI_TIMELINE_CHILD, timelineSize, true); - + windowSize = ImGui::GetWindowSize(); + cursorPos = ImGui::GetCursorPos(); drawList = ImGui::GetWindowDrawList(); - /* Element frames */ ImGui::SetCursorPos(ImVec2(cursorPos.x + IMGUI_TIMELINE_ELEMENT_SIZE.x, cursorPos.y + IMGUI_TIMELINE_VIEWER_SIZE.y)); - ImGui::BeginChild(STRING_IMGUI_TIMELINE_ELEMENT_FRAMES, IMGUI_TIMELINE_ELEMENT_FRAMES_SIZE, true); + ImGui::BeginChild(STRING_IMGUI_TIMELINE_ELEMENT_FRAMES, {0, 0}, false, ImGuiWindowFlags_HorizontalScrollbar); ImGui::PopStyleVar(); ImGui::PopStyleVar(); elementScrollX = ImGui::GetScrollX(); @@ -547,22 +576,26 @@ _imgui_timeline(Imgui* self) ImGui::SetCursorPos(cursorPos); - /* Element bar */ - ImGui::BeginChild(STRING_IMGUI_TIMELINE_ELEMENTS, IMGUI_TIMELINE_ELEMENT_SIZE, true); - ImGui::Text(STRING_IMGUI_TIMELINE_ELEMENTS); - + ImGui::PushStyleColor(ImGuiCol_ChildBg, IMGUI_TIMELINE_HEADER_COLOR); + ImGui::BeginChild(STRING_IMGUI_TIMELINE_HEADER, IMGUI_TIMELINE_ELEMENT_SIZE, true); ImGui::EndChild(); + ImGui::PopStyleColor(); - /* Viewer */ if (animation->frameNum > 0) { bool isMouseInElementsRegion = false; + + ImVec2 cursorScreenPos = ImGui::GetCursorScreenPos(); + ImVec2 clipRectMin = {cursorScreenPos.x + IMGUI_TIMELINE_ELEMENT_SIZE.x, 0}; + ImVec2 clipRectMax = {cursorScreenPos.x + timelineSize.x + IMGUI_TIMELINE_FRAME_SIZE.x, cursorScreenPos.y + timelineSize.y}; ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); - - ImGui::SameLine(); - ImGui::BeginChild(STRING_IMGUI_TIMELINE_FRAME_INDICES, frameIndicesSize, true); + ImGui::SameLine(); + + ImGui::PushClipRect(clipRectMin, clipRectMax, true); + + ImGui::BeginChild(STRING_IMGUI_TIMELINE_FRAME_INDICES, {0, IMGUI_TIMELINE_FRAME_SIZE.y}); ImGui::SetScrollX(elementScrollX); ImVec2 elementsRectMin = ImGui::GetWindowPos(); @@ -624,7 +657,7 @@ _imgui_timeline(Imgui* self) drawList->AddRectFilled(bgMin, bgMax, bgColor); } - ImGui::Image(self->resources->textures[TEXTURE_FRAME].handle, IMGUI_TIMELINE_FRAME_SIZE); + ImGui::Image(self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[TEXTURE_FRAME]), IMVEC2_ATLAS_UV_GET(TEXTURE_FRAME)); ImGui::SameLine(); } @@ -636,21 +669,24 @@ _imgui_timeline(Imgui* self) lineStart = ImVec2(pickerPos.x + frameSize.x / 2.0f, pickerPos.y + frameSize.y); lineEnd = ImVec2(lineStart.x, lineStart.y + timelineSize.y - IMGUI_TIMELINE_FRAME_SIZE.y); - ImGui::GetWindowDrawList()->AddImage( - self->resources->textures[TEXTURE_PICKER].handle, + ImGui::GetWindowDrawList()->AddImage + ( + self->resources->atlas.id, pickerPos, - ImVec2(pickerPos.x + frameSize.x, pickerPos.y + frameSize.y) + ImVec2(pickerPos.x + frameSize.x, pickerPos.y + frameSize.y), + IMVEC2_ATLAS_UV_GET(TEXTURE_PICKER) ); - ImGui::GetForegroundDrawList()->AddRectFilled( + drawList->AddRectFilled( ImVec2(lineStart.x - IMGUI_PICKER_LINE_SIZE, lineStart.y), ImVec2(lineStart.x + IMGUI_PICKER_LINE_SIZE, lineEnd.y), IMGUI_PICKER_LINE_COLOR ); - + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); ImGui::EndChild(); + ImGui::PopClipRect(); ImGui::PopStyleVar(); ImGui::PopStyleVar(); } @@ -660,7 +696,6 @@ _imgui_timeline(Imgui* self) ImGui::Dummy(frameIndicesSize); } - /* Element list */ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); ImGui::BeginChild(STRING_IMGUI_TIMELINE_ELEMENT_LIST, IMGUI_TIMELINE_ELEMENT_LIST_SIZE, true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse); @@ -685,6 +720,7 @@ _imgui_timeline(Imgui* self) ImGui::EndChild(); + ImGui::EndChild(); /* Buttons */ @@ -959,6 +995,72 @@ _imgui_taskbar(Imgui* self) ImGui::End(); } +/* Tools */ +static void +_imgui_tools(Imgui* self) +{ + ImGui::Begin(STRING_IMGUI_TOOLS); + + ImVec2 availableSize = ImGui::GetContentRegionAvail(); + f32 availableWidth = availableSize.x; + + s32 buttonsPerRow = availableWidth / TEXTURE_SIZE.x + IMGUI_TOOLS_WIDTH_INCREMENT; + buttonsPerRow = MIN(buttonsPerRow, 1); + + for (s32 i = 0; i < TOOL_COUNT; i++) + { + const char* string = NULL; + const char* tooltip = NULL; + TextureType textureType; + + if (i > 0 && i % buttonsPerRow != 0) + ImGui::SameLine(); + + ImVec4 buttonColor = self->tool == (ToolType)i ? ImGui::GetStyle().Colors[ImGuiCol_ButtonHovered] : ImGui::GetStyle().Colors[ImGuiCol_Button]; + ImGui::PushStyleColor(ImGuiCol_Button, buttonColor); + + switch (i) + { + case TOOL_PAN: + string = STRING_IMGUI_TOOLS_PAN; + tooltip = STRING_IMGUI_TOOLTIP_TOOLS_PAN; + textureType = TEXTURE_PAN; + break; + case TOOL_MOVE: + string = STRING_IMGUI_TOOLS_MOVE; + tooltip = STRING_IMGUI_TOOLTIP_TOOLS_MOVE; + textureType = TEXTURE_MOVE; + break; + case TOOL_ROTATE: + string = STRING_IMGUI_TOOLS_ROTATE; + tooltip = STRING_IMGUI_TOOLTIP_TOOLS_ROTATE; + textureType = TEXTURE_ROTATE; + break; + case TOOL_SCALE: + string = STRING_IMGUI_TOOLS_SCALE; + tooltip = STRING_IMGUI_TOOLTIP_TOOLS_SCALE; + textureType = TEXTURE_SCALE; + break; + case TOOL_CROP: + string = STRING_IMGUI_TOOLS_CROP; + tooltip = STRING_IMGUI_TOOLTIP_TOOLS_CROP; + textureType = TEXTURE_CROP; + break; + default: + break; + } + + if (ImGui::ImageButton(string, self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[textureType]), IMVEC2_ATLAS_UV_GET(textureType))) + self->tool = (ToolType)i; + + _imgui_tooltip(tooltip); + + ImGui::PopStyleColor(); + } + + ImGui::End(); +} + /* Animations */ static void _imgui_animations(Imgui* self) @@ -980,15 +1082,14 @@ _imgui_animations(Imgui* self) ImGui::PushID(id); - ImGui::Image(self->resources->textures[TEXTURE_ANIMATION].handle, IMGUI_ICON_SIZE); + ImGui::Image(self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[TEXTURE_ANIMATION]), IMVEC2_ATLAS_UV_GET(TEXTURE_ANIMATION)); ImGui::SameLine(); if (isSelected) { if (ImGui::InputText(STRING_IMGUI_ANIMATIONS_ANIMATION_LABEL, animation.name, ANM2_STRING_MAX, ImGuiInputTextFlags_EnterReturnsTrue)) { - strncpy(self->anm2->defaultAnimation, animation.name, ANM2_STRING_MAX); - + strncpy(self->anm2->defaultAnimation, animation.name, ANM2_STRING_MAX); self->animationID = -1; } } @@ -1004,7 +1105,6 @@ _imgui_animations(Imgui* self) self->preview->time = 0.0f; } } - _imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATIONS_SELECT); ImGui::PopID(); @@ -1081,7 +1181,7 @@ _imgui_events(Imgui* self) ImGui::PushID(id); - ImGui::Image(self->resources->textures[TEXTURE_EVENT].handle, IMGUI_ICON_SIZE); + ImGui::Image(self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[TEXTURE_EVENT]), IMVEC2_ATLAS_UV_GET(TEXTURE_EVENT)); ImGui::SameLine(); isSelected = self->eventID == id; @@ -1139,8 +1239,9 @@ _imgui_spritesheets(Imgui* self) ImVec2 spritesheetPreviewSize = IMGUI_SPRITESHEET_PREVIEW_SIZE; char spritesheetString[ANM2_STRING_FORMATTED_MAX]; bool isSelected = false; + Texture* texture = &self->resources->textures[id]; - f32 spritesheetAspect = (f32)self->resources->loadedTextures[id].size.x / self->resources->loadedTextures[id].size.y; + f32 spritesheetAspect = (f32)self->resources->textures[id].size.x / self->resources->textures[id].size.y; if ((IMGUI_SPRITESHEET_PREVIEW_SIZE.x / IMGUI_SPRITESHEET_PREVIEW_SIZE.y) > spritesheetAspect) spritesheetPreviewSize.x = IMGUI_SPRITESHEET_PREVIEW_SIZE.y * spritesheetAspect; @@ -1153,16 +1254,18 @@ _imgui_spritesheets(Imgui* self) ImGui::PushID(id); - ImGui::Image(self->resources->textures[TEXTURE_SPRITESHEET].handle, IMGUI_ICON_SIZE); + ImGui::Image(self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[TEXTURE_SPRITESHEET]), IMVEC2_ATLAS_UV_GET(TEXTURE_SPRITESHEET)); ImGui::SameLine(); isSelected = self->spritesheetID == id; if (ImGui::Selectable(spritesheetString, isSelected)) self->spritesheetID = id; - _imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEETS_SELECT); - - ImGui::Image(self->resources->loadedTextures[id].handle, spritesheetPreviewSize); + + if (texture->isInvalid) + ImGui::Image(self->resources->atlas.id, IMVEC2_VEC2(ATLAS_SIZES[TEXTURE_ERROR]), IMVEC2_ATLAS_UV_GET(TEXTURE_ERROR)); + else + ImGui::Image(texture->id, spritesheetPreviewSize); ImGui::PopID(); @@ -1180,7 +1283,7 @@ _imgui_spritesheets(Imgui* self) { if (self->spritesheetID > -1) { - self->resources->loadedTextures.erase(self->spritesheetID); + self->resources->textures.erase(self->spritesheetID); self->anm2->spritesheets.erase(self->spritesheetID); self->spritesheetID = -1; } @@ -1219,32 +1322,33 @@ _imgui_spritesheets(Imgui* self) static void _imgui_animation_preview(Imgui* self) { - static bool isHoverPreview = false; + static bool isPreviewHover = false; static bool isPreviewCenter = false; - + vec2 previewPos; + ImGui::Begin(STRING_IMGUI_ANIMATION_PREVIEW, NULL, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse); /* Grid settings */ ImGui::BeginChild(STRING_IMGUI_ANIMATION_PREVIEW_GRID_SETTINGS, IMGUI_ANIMATION_PREVIEW_SETTINGS_CHILD_SIZE, true); /* Grid toggle */ - ImGui::Checkbox(STRING_IMGUI_ANIMATION_PREVIEW_GRID, &self->settings->isGrid); + ImGui::Checkbox(STRING_IMGUI_ANIMATION_PREVIEW_GRID, &self->settings->previewIsGrid); _imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_GRID); ImGui::SameLine(); /* Grid Color */ - ImGui::ColorEdit4(STRING_IMGUI_ANIMATION_PREVIEW_GRID_COLOR, (f32*)&self->settings->gridColorR, ImGuiColorEditFlags_NoInputs); + ImGui::ColorEdit4(STRING_IMGUI_ANIMATION_PREVIEW_GRID_COLOR, (f32*)&self->settings->previewGridColorR, ImGuiColorEditFlags_NoInputs); _imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_GRID_COLOR); /* Grid Size */ - ImGui::InputInt2(STRING_IMGUI_ANIMATION_PREVIEW_GRID_SIZE, (s32*)&self->settings->gridSizeX); - self->settings->gridSizeX = CLAMP(self->settings->gridSizeX, PREVIEW_GRID_MIN, PREVIEW_GRID_MAX); - self->settings->gridSizeY = CLAMP(self->settings->gridSizeY, PREVIEW_GRID_MIN, PREVIEW_GRID_MAX); + ImGui::InputInt2(STRING_IMGUI_ANIMATION_PREVIEW_GRID_SIZE, (s32*)&self->settings->previewGridSizeX); + self->settings->previewGridSizeX = CLAMP(self->settings->previewGridSizeX, PREVIEW_GRID_MIN, PREVIEW_GRID_MAX); + self->settings->previewGridSizeY = CLAMP(self->settings->previewGridSizeY, PREVIEW_GRID_MIN, PREVIEW_GRID_MAX); _imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_GRID_SIZE); /* Grid Offset */ - ImGui::InputInt2(STRING_IMGUI_ANIMATION_PREVIEW_GRID_OFFSET, (s32*)&self->settings->gridOffsetX); + ImGui::InputInt2(STRING_IMGUI_ANIMATION_PREVIEW_GRID_OFFSET, (s32*)&self->settings->previewGridOffsetX); _imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_GRID_OFFSET); ImGui::EndChild(); @@ -1255,21 +1359,21 @@ _imgui_animation_preview(Imgui* self) ImGui::BeginChild(STRING_IMGUI_ANIMATION_PREVIEW_HELPER_SETTINGS, IMGUI_ANIMATION_PREVIEW_SETTINGS_CHILD_SIZE, true); /* Axis toggle */ - ImGui::Checkbox(STRING_IMGUI_ANIMATION_PREVIEW_AXIS, &self->settings->isAxis); + ImGui::Checkbox(STRING_IMGUI_ANIMATION_PREVIEW_AXIS, &self->settings->previewIsAxis); _imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_AXIS); ImGui::SameLine(); /* Axis colors */ - ImGui::ColorEdit4(STRING_IMGUI_ANIMATION_PREVIEW_AXIS_COLOR, (f32*)&self->settings->axisColorR, ImGuiColorEditFlags_NoInputs); + ImGui::ColorEdit4(STRING_IMGUI_ANIMATION_PREVIEW_AXIS_COLOR, (f32*)&self->settings->previewAxisColorR, ImGuiColorEditFlags_NoInputs); _imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_AXIS_COLOR); /* Root transform */ - ImGui::Checkbox(STRING_IMGUI_ANIMATION_PREVIEW_ROOT_TRANSFORM, &self->settings->isRootTransform); + ImGui::Checkbox(STRING_IMGUI_ANIMATION_PREVIEW_ROOT_TRANSFORM, &self->settings->previewIsRootTransform); _imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_ROOT_TRANSFORM); /* Show pivot */ - ImGui::Checkbox(STRING_IMGUI_ANIMATION_PREVIEW_SHOW_PIVOT, &self->settings->isShowPivot); + ImGui::Checkbox(STRING_IMGUI_ANIMATION_PREVIEW_SHOW_PIVOT, &self->settings->previewIsShowPivot); _imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_SHOW_PIVOT); ImGui::EndChild(); @@ -1280,7 +1384,7 @@ _imgui_animation_preview(Imgui* self) ImGui::BeginChild(STRING_IMGUI_ANIMATION_PREVIEW_VIEW_SETTINGS, IMGUI_ANIMATION_PREVIEW_SETTINGS_CHILD_SIZE, true); /* Zoom */ - ImGui::DragFloat(STRING_IMGUI_ANIMATION_PREVIEW_ZOOM, &self->settings->zoom, 1, PREVIEW_ZOOM_MIN, PREVIEW_ZOOM_MAX, "%.0f"); + ImGui::DragFloat(STRING_IMGUI_ANIMATION_PREVIEW_ZOOM, &self->settings->previewZoom, 1, PREVIEW_ZOOM_MIN, PREVIEW_ZOOM_MAX, "%.0f"); _imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_ZOOM); /* Center view */ @@ -1296,42 +1400,93 @@ _imgui_animation_preview(Imgui* self) ImGui::BeginChild(STRING_IMGUI_ANIMATION_PREVIEW_BACKGROUND_SETTINGS, IMGUI_ANIMATION_PREVIEW_SETTINGS_CHILD_SIZE, true); /* Background color */ - ImGui::ColorEdit4(STRING_IMGUI_ANIMATION_PREVIEW_BACKGROUND_COLOR, (f32*)&self->settings->backgroundColorR, ImGuiColorEditFlags_NoInputs); + ImGui::ColorEdit4(STRING_IMGUI_ANIMATION_PREVIEW_BACKGROUND_COLOR, (f32*)&self->settings->previewBackgroundColorR, ImGuiColorEditFlags_NoInputs); _imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_BACKGROUND_COLOR); ImGui::EndChild(); - /* Elements drawn out of order in order to get the size of the preview before how it visually appears */ - ImGui::Image(self->preview->texture, ImVec2(PREVIEW_SIZE.x, PREVIEW_SIZE.y)); + /* Animation preview texture */ + previewPos = VEC2_IMVEC2(ImGui::GetCursorPos()); + ImGui::Image(self->preview->texture, IMVEC2_VEC2(PREVIEW_SIZE)); /* Panning */ if (ImGui::IsItemHovered()) { - SDL_SetCursor(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_MOVE)); - isHoverPreview = true; - - if (mouse_held(&self->input->mouse, MOUSE_LEFT)) + Anm2Frame* frame = NULL; + + if (self->frameIndex > - 1 && self->animationType != ANM2_TRIGGER) { - self->settings->panX += self->input->mouse.delta.x; - self->settings->panY -= self->input->mouse.delta.y; + std::vector* frames = (std::vector*)self->frameVector; + frame = &(*frames)[self->frameIndex]; } - self->settings->zoom = self->settings->zoom == PREVIEW_ZOOM_MIN ? 0 : self->settings->zoom; + switch (self->tool) + { + case TOOL_PAN: + SDL_SetCursor(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_POINTER)); + + if (mouse_held(&self->input->mouse, MOUSE_LEFT)) + { + self->settings->previewPanX -= self->input->mouse.delta.x; + self->settings->previewPanY -= self->input->mouse.delta.y; + } + break; + case TOOL_MOVE: + SDL_SetCursor(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_MOVE)); + if (mouse_held(&self->input->mouse, MOUSE_LEFT) && frame) + { + vec2 mousePos = VEC2_IMVEC2(ImGui::GetMousePos()); + vec2 windowPos = VEC2_IMVEC2(ImGui::GetWindowPos()); + + mousePos -= (windowPos + previewPos); + mousePos -= (PREVIEW_SIZE / 2.0f); + mousePos.x += self->settings->previewPanX; + mousePos.y += self->settings->previewPanY; + mousePos.x /= (self->settings->previewZoom / 100.0f); + mousePos.y /= (self->settings->previewZoom / 100.0f); + + frame->position = VEC2_IMVEC2(mousePos); + } + break; + case TOOL_ROTATE: + SDL_SetCursor(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_CROSSHAIR)); + if (mouse_held(&self->input->mouse, MOUSE_LEFT) && frame) + frame->rotation += (s32)self->input->mouse.delta.x; + break; + case TOOL_SCALE: + SDL_SetCursor(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NE_RESIZE)); + if (mouse_held(&self->input->mouse, MOUSE_LEFT) && frame) + { + frame->scale.x += (s32)self->input->mouse.delta.x; + frame->scale.y += (s32)self->input->mouse.delta.y; + } + break; + case TOOL_CROP: + SDL_SetCursor(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_CROSSHAIR)); + break; + default: + break; + }; + + isPreviewHover = true; + + /* Used to not be annoying when at lowest zoom */ + self->settings->previewZoom = self->settings->previewZoom == EDITOR_ZOOM_MIN ? 0 : self->settings->previewZoom; if (self->input->mouse.wheelDeltaY > 0) - self->settings->zoom += PREVIEW_ZOOM_STEP; + self->settings->previewZoom += PREVIEW_ZOOM_STEP; if (self->input->mouse.wheelDeltaY < 0) - self->settings->zoom -= PREVIEW_ZOOM_STEP; + self->settings->previewZoom -= PREVIEW_ZOOM_STEP; - self->settings->zoom = CLAMP(self->settings->zoom, PREVIEW_ZOOM_MIN, PREVIEW_ZOOM_MAX); + self->settings->previewZoom = CLAMP(self->settings->previewZoom, PREVIEW_ZOOM_MIN, PREVIEW_ZOOM_MAX); } else { - if (isHoverPreview) + if (isPreviewHover) { SDL_SetCursor(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_DEFAULT)); - isHoverPreview = false; + isPreviewHover = false; } } @@ -1340,10 +1495,8 @@ _imgui_animation_preview(Imgui* self) ImVec2 previewWindowRectSize = ImGui::GetCurrentWindow()->ClipRect.GetSize(); /* Based on the preview's crop in its window, adjust the pan */ - self->settings->panX = PREVIEW_CENTER.x + ((previewWindowRectSize.x - PREVIEW_SIZE.x) / 2.0f); - self->settings->panY = PREVIEW_CENTER.y - ((previewWindowRectSize.y - PREVIEW_SIZE.y) / 2.0f); - - self->settings->panY += (IMGUI_ANIMATION_PREVIEW_SETTINGS_SIZE.y / 2.0f); + self->settings->previewPanX = -(previewWindowRectSize.x - PREVIEW_SIZE.x) / 2.0f; + self->settings->previewPanY = -((previewWindowRectSize.y - PREVIEW_SIZE.y) / 2.0f);// + (IMGUI_ANIMATION_PREVIEW_SETTINGS_SIZE.y / 2.0f); isPreviewCenter = false; } @@ -1355,8 +1508,111 @@ _imgui_animation_preview(Imgui* self) static void _imgui_spritesheet_editor(Imgui* self) { - ImGui::Begin(STRING_IMGUI_SPRITESHEET_EDITOR); + static bool isEditorHover = false; + static bool isEditorCenter = false; + + ImGui::Begin(STRING_IMGUI_SPRITESHEET_EDITOR, NULL, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse); + /* Grid settings */ + ImGui::BeginChild(STRING_IMGUI_SPRITESHEET_EDITOR_GRID_SETTINGS, IMGUI_SPRITESHEET_EDITOR_SETTINGS_CHILD_SIZE, true); + + /* Grid toggle */ + ImGui::Checkbox(STRING_IMGUI_SPRITESHEET_EDITOR_GRID, &self->settings->editorIsGrid); + _imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEET_EDITOR_GRID); + + ImGui::SameLine(); + + /* Grid Color */ + ImGui::ColorEdit4(STRING_IMGUI_SPRITESHEET_EDITOR_GRID_COLOR, (f32*)&self->settings->editorGridColorR, ImGuiColorEditFlags_NoInputs); + _imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEET_EDITOR_GRID_COLOR); + + /* Grid Size */ + ImGui::InputInt2(STRING_IMGUI_SPRITESHEET_EDITOR_GRID_SIZE, (s32*)&self->settings->editorGridSizeX); + self->settings->editorGridSizeX = CLAMP(self->settings->editorGridSizeX, PREVIEW_GRID_MIN, PREVIEW_GRID_MAX); + self->settings->editorGridSizeY = CLAMP(self->settings->editorGridSizeY, PREVIEW_GRID_MIN, PREVIEW_GRID_MAX); + _imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEET_EDITOR_GRID_SIZE); + + /* Grid Offset */ + ImGui::InputInt2(STRING_IMGUI_SPRITESHEET_EDITOR_GRID_OFFSET, (s32*)&self->settings->editorGridOffsetX); + _imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEET_EDITOR_GRID_OFFSET); + + ImGui::EndChild(); + + ImGui::SameLine(); + + /* View settings */ + ImGui::BeginChild(STRING_IMGUI_SPRITESHEET_EDITOR_VIEW_SETTINGS, IMGUI_SPRITESHEET_EDITOR_SETTINGS_CHILD_SIZE, true); + + /* Zoom */ + ImGui::DragFloat(STRING_IMGUI_SPRITESHEET_EDITOR_ZOOM, &self->settings->editorZoom, 1, PREVIEW_ZOOM_MIN, PREVIEW_ZOOM_MAX, "%.0f"); + _imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEET_EDITOR_ZOOM); + + /* Center view */ + if (ImGui::Button(STRING_IMGUI_SPRITESHEET_EDITOR_CENTER_VIEW)) + isEditorCenter = true; + _imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEET_EDITOR_CENTER_VIEW); + + ImGui::EndChild(); + + ImGui::SameLine(); + + /* Background settings */ + ImGui::BeginChild(STRING_IMGUI_SPRITESHEET_EDITOR_BACKGROUND_SETTINGS, IMGUI_SPRITESHEET_EDITOR_SETTINGS_CHILD_SIZE, true); + + /* Background color */ + ImGui::ColorEdit4(STRING_IMGUI_SPRITESHEET_EDITOR_BACKGROUND_COLOR, (f32*)&self->settings->editorBackgroundColorR, ImGuiColorEditFlags_NoInputs); + _imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEET_EDITOR_BACKGROUND_COLOR); + + /* Border */ + ImGui::Checkbox(STRING_IMGUI_SPRITESHEET_EDITOR_BORDER, &self->settings->editorIsBorder); + _imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEET_EDITOR_BORDER); + + ImGui::EndChild(); + + ImGui::Image(self->editor->texture, IMVEC2_VEC2(EDITOR_SIZE)); + + self->editor->spritesheetID = self->spritesheetID; + + /* Panning + zoom */ + if (ImGui::IsItemHovered()) + { + SDL_SetCursor(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_MOVE)); + isEditorHover = true; + + if (mouse_held(&self->input->mouse, MOUSE_LEFT)) + { + self->settings->editorPanX -= self->input->mouse.delta.x; + self->settings->editorPanY -= self->input->mouse.delta.y; + } + + /* Used to not be annoying when at lowest zoom */ + self->settings->editorZoom = self->settings->editorZoom == EDITOR_ZOOM_MIN ? 0 : self->settings->editorZoom; + + if (self->input->mouse.wheelDeltaY > 0) + self->settings->editorZoom += EDITOR_ZOOM_STEP; + + if (self->input->mouse.wheelDeltaY < 0) + self->settings->editorZoom -= EDITOR_ZOOM_STEP; + + self->settings->editorZoom = CLAMP(self->settings->editorZoom, EDITOR_ZOOM_MIN, EDITOR_ZOOM_MAX); + } + else + { + if (isEditorHover) + { + SDL_SetCursor(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_DEFAULT)); + isEditorHover = false; + } + } + + if (isEditorCenter) + { + self->settings->editorPanX = EDITOR_SIZE.x / 2.0f; + self->settings->editorPanY = EDITOR_SIZE.y / 2.0f; + + isEditorCenter = false; + } + ImGui::End(); } @@ -1431,9 +1687,22 @@ _imgui_frame_properties(Imgui* self) /* Visible */ ImGui::Checkbox(STRING_IMGUI_FRAME_PROPERTIES_VISIBLE, &frame->isVisible); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_VISIBLE); - + + /* Flip X */ + if (ImGui::Button(STRING_IMGUI_FRAME_PROPERTIES_FLIP_X)) + frame->scale.x = -frame->scale.x; + _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_FLIP_X); + + ImGui::SameLine(); + + /* Flip Y */ + if (ImGui::Button(STRING_IMGUI_FRAME_PROPERTIES_FLIP_Y)) + frame->scale.y = -frame->scale.y; + _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_FLIP_Y); + ImGui::SameLine(); + /* Interpolation */ ImGui::Checkbox(STRING_IMGUI_FRAME_PROPERTIES_INTERPOLATED, &frame->isInterpolated); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_INTERPOLATED); break; @@ -1478,13 +1747,26 @@ _imgui_frame_properties(Imgui* self) /* Color Offset */ ImGui::ColorEdit3(STRING_IMGUI_FRAME_PROPERTIES_COLOR_OFFSET, value_ptr(frame->offsetRGB)); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_COLOR_OFFSET); - + + /* Flip X */ + if (ImGui::Button(STRING_IMGUI_FRAME_PROPERTIES_FLIP_X)) + frame->scale.x = -frame->scale.x; + _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_FLIP_X); + + ImGui::SameLine(); + + /* Flip Y */ + if (ImGui::Button(STRING_IMGUI_FRAME_PROPERTIES_FLIP_Y)) + frame->scale.y = -frame->scale.y; + _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_FLIP_Y); + /* Visible */ ImGui::Checkbox(STRING_IMGUI_FRAME_PROPERTIES_VISIBLE, &frame->isVisible); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_VISIBLE); ImGui::SameLine(); + /* Interpolation */ ImGui::Checkbox(STRING_IMGUI_FRAME_PROPERTIES_INTERPOLATED, &frame->isInterpolated); _imgui_tooltip(STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_INTERPOLATED); break; @@ -1533,6 +1815,7 @@ imgui_init Resources* resources, Input* input, Anm2* anm2, + Editor* editor, Preview* preview, Settings* settings, SDL_Window* window, @@ -1545,6 +1828,7 @@ imgui_init self->resources = resources; self->input = input; self->anm2 = anm2; + self->editor = editor; self->preview = preview; self->settings = settings; self->window = window; @@ -1559,8 +1843,8 @@ imgui_init ImGuiIO& io = ImGui::GetIO(); io.IniFilename = NULL; io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; + io.ConfigWindowsMoveFromTitleBarOnly = true; - /* load ini manually */ ImGui::LoadIniSettingsFromDisk(PATH_SETTINGS); printf(STRING_INFO_IMGUI_INIT); @@ -1588,6 +1872,7 @@ _imgui_dock(Imgui* self) ImGui::DockSpace(ImGui::GetID(STRING_IMGUI_DOCKSPACE), ImVec2(0.0f, 0.0f), ImGuiDockNodeFlags_PassthruCentralNode); + _imgui_tools(self); _imgui_animations(self); _imgui_events(self); _imgui_spritesheets(self); @@ -1610,6 +1895,15 @@ imgui_tick(Imgui* self) _imgui_dock(self); self->preview->animationID = self->animationID; + + if (self->frameIndex > -1 && self->animationType == ANM2_LAYER_ANIMATION) + { + std::vector* framesVector = (std::vector*)self->frameVector; + self->editor->frame = (*framesVector)[self->frameIndex]; + self->editor->isFrame = true; + } + else + self->editor->isFrame = false; } void diff --git a/src/imgui.h b/src/imgui.h index 1869753..f0645b8 100644 --- a/src/imgui.h +++ b/src/imgui.h @@ -2,6 +2,7 @@ #include "dialog.h" #include "resources.h" +#include "editor.h" #include "preview.h" #include "window.h" #include "input.h" @@ -14,6 +15,10 @@ #include #include + +#define IMGUI_TIMELINE_ELEMENT_WIDTH 300 +#define IMGUI_TIMELINE_ELEMENT_WIDTH 300 + #define IMGUI_DRAG_SPEED 1.0 #define IMGUI_TASKBAR_HEIGHT 32 #define IMGUI_TIMELINE_OFFSET_Y 24 @@ -25,16 +30,20 @@ #define IMGUI_PICKER_LINE_SIZE 1.0f #define IMGUI_FRAME_BORDER 2.0f #define IMGUI_PICKER_LINE_COLOR IM_COL32(255, 255, 255, 255) +#define IMGUI_TOOLS_WIDTH_INCREMENT -2 static const vec2 IMGUI_TASKBAR_MARGINS = {8, 4}; static const ImVec2 IMGUI_ANIMATION_PREVIEW_SETTINGS_SIZE = {1280, 105}; -static const ImVec2 IMGUI_ANIMATION_PREVIEW_SETTINGS_CHILD_SIZE = {175, 85}; +static const ImVec2 IMGUI_ANIMATION_PREVIEW_SETTINGS_CHILD_SIZE = {200, 85}; static const ImVec2 IMGUI_ANIMATION_PREVIEW_POSITION = {8, 135}; static const ImVec2 IMGUI_TIMELINE_ELEMENT_NAME_SIZE = {95, 20}; static const ImVec2 IMGUI_TIMELINE_ELEMENT_SPRITESHEET_ID_SIZE = {45, 20}; +static const ImVec2 IMGUI_SPRITESHEET_EDITOR_SETTINGS_CHILD_SIZE = {200, 85}; +static const ImVec2 IMGUI_SPRITESHEET_EDITOR_SETTINGS_SIZE = {1280, 105}; + static const ImVec2 IMGUI_TIMELINE_ELEMENT_LIST_SIZE = {300, 0}; static const ImVec2 IMGUI_TIMELINE_FRAMES_SIZE = {0, 0}; static const ImVec2 IMGUI_TIMELINE_ELEMENT_FRAMES_SIZE = {0, 0}; @@ -54,13 +63,41 @@ static const ImVec2 IMGUI_ICON_BUTTON_SIZE = {24, 24}; static const ImVec2 IMGUI_IMAGE_TARGET_SIZE = {125, 125}; static const ImVec2 IMGUI_DUMMY_SIZE = {1, 1}; +static const ImVec4 IMGUI_TIMELINE_HEADER_COLOR = {0.04, 0.04, 0.04, 1.0f}; static const ImVec4 IMGUI_FRAME_BORDER_COLOR = {1.0f, 1.0f, 1.0f, 0.5f}; static const ImVec4 IMGUI_FRAME_OVERLAY_COLOR = {0.0f, 0.0f, 0.0f, 0.25f}; static const ImVec4 IMGUI_FRAME_INDICES_OVERLAY_COLOR = {0.113, 0.184, 0.286, 1.0f}; static const ImVec4 IMGUI_FRAME_INDICES_COLOR = {0.113, 0.184, 0.286, 0.5f}; +static const ImVec4 IMGUI_TIMELINE_ROOT_COLOR = {0.010, 0.049, 0.078, 1.0f}; +static const ImVec4 IMGUI_TIMELINE_LAYER_COLOR = {0.098, 0.039, 0.020, 1.0f}; +static const ImVec4 IMGUI_TIMELINE_NULL_COLOR = {0.020, 0.049, 0.000, 1.0f}; +static const ImVec4 IMGUI_TIMELINE_TRIGGERS_COLOR = {0.078, 0.020, 0.029, 1.0f}; -#define IMGUI_TIMELINE_SHIFT_ARROWS_WIDTH (IMGUI_TIMELINE_SHIFT_ARROWS_SIZE.x * 1.35) +static const ImVec4 IMGUI_TIMELINE_ROOT_FRAME_COLOR = {0.020, 0.294, 0.569, 0.5}; +static const ImVec4 IMGUI_TIMELINE_LAYER_FRAME_COLOR = {0.529, 0.157, 0.000, 0.5}; +static const ImVec4 IMGUI_TIMELINE_NULL_FRAME_COLOR = {0.137, 0.353, 0.000, 0.5}; +static const ImVec4 IMGUI_TIMELINE_TRIGGERS_FRAME_COLOR = {0.529, 0.118, 0.196, 0.5}; + +static const ImVec4 IMGUI_TIMELINE_ROOT_HIGHLIGHT_COLOR = {0.314, 0.588, 0.843, 0.75}; +static const ImVec4 IMGUI_TIMELINE_LAYER_HIGHLIGHT_COLOR = {0.882, 0.412, 0.216, 0.75}; +static const ImVec4 IMGUI_TIMELINE_NULL_HIGHLIGHT_COLOR = {0.431, 0.647, 0.294, 0.75}; +static const ImVec4 IMGUI_TIMELINE_TRIGGERS_HIGHLIGHT_COLOR = {0.804, 0.412, 0.490, 0.75}; + +static const ImVec4 IMGUI_TIMELINE_ROOT_ACTIVE_COLOR = {0.471, 0.882, 1.000, 0.75}; +static const ImVec4 IMGUI_TIMELINE_LAYER_ACTIVE_COLOR = {1.000, 0.618, 0.324, 0.75}; +static const ImVec4 IMGUI_TIMELINE_NULL_ACTIVE_COLOR = {0.646, 0.971, 0.441, 0.75}; +static const ImVec4 IMGUI_TIMELINE_TRIGGERS_ACTIVE_COLOR = {1.000, 0.618, 0.735, 0.75}; + +#define TOOL_COUNT (TOOL_CROP + 1) +enum ToolType +{ + TOOL_PAN, + TOOL_MOVE, + TOOL_ROTATE, + TOOL_SCALE, + TOOL_CROP +}; struct Imgui { @@ -68,6 +105,7 @@ struct Imgui Resources* resources = NULL; Input* input = NULL; Anm2* anm2 = NULL; + Editor* editor = NULL; Preview* preview = NULL; SDL_Window* window = NULL; SDL_GLContext* glContext = NULL; @@ -78,6 +116,7 @@ struct Imgui s32 spritesheetID = -1; s32 timelineElementIndex = -1; Anm2AnimationType animationType = ANM2_NONE; + ToolType tool = TOOL_PAN; void* frameVector = NULL; s32 frameIndex = -1; }; @@ -89,6 +128,7 @@ void imgui_init Resources* resources, Input* input, Anm2* anm2, + Editor* editor, Preview* preview, Settings* settings, SDL_Window* window, diff --git a/src/preview.cpp b/src/preview.cpp index bdb0278..6a61207 100644 --- a/src/preview.cpp +++ b/src/preview.cpp @@ -21,13 +21,13 @@ _preview_grid_set(Preview* self) { std::vector vertices; - s32 verticalLineCount = PREVIEW_SIZE.x / MIN(self->settings->gridSizeX, PREVIEW_GRID_MIN); - s32 horizontalLineCount = PREVIEW_SIZE.y / MIN(self->settings->gridSizeY, PREVIEW_GRID_MIN); + s32 verticalLineCount = PREVIEW_SIZE.x / MIN(self->settings->previewGridSizeX, PREVIEW_GRID_MIN); + s32 horizontalLineCount = PREVIEW_SIZE.y / MIN(self->settings->previewGridSizeY, PREVIEW_GRID_MIN); /* Vertical */ for (s32 i = 0; i <= verticalLineCount; i++) { - s32 x = i * self->settings->gridSizeX - self->settings->gridOffsetX; + s32 x = i * self->settings->previewGridSizeX - self->settings->previewGridOffsetX; f32 normX = (2.0f * x) / PREVIEW_SIZE.x - 1.0f; vertices.push_back(normX); @@ -39,7 +39,7 @@ _preview_grid_set(Preview* self) /* Horizontal */ for (s32 i = 0; i <= horizontalLineCount; i++) { - s32 y = i * self->settings->gridSizeY - self->settings->gridOffsetY; + s32 y = i * self->settings->previewGridSizeY - self->settings->previewGridOffsetY; f32 normY = (2.0f * y) / PREVIEW_SIZE.y - 1.0f; vertices.push_back(-1.0f); @@ -66,13 +66,14 @@ preview_init(Preview* self, Anm2* anm2, Resources* resources, Input* input, Sett self->input = input; self->settings = settings; + /* Framebuffer + texture */ glGenFramebuffers(1, &self->fbo); glBindFramebuffer(GL_FRAMEBUFFER, self->fbo); glGenTextures(1, &self->texture); glBindTexture(GL_TEXTURE_2D, self->texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, PREVIEW_SIZE.x, PREVIEW_SIZE.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (s32)PREVIEW_SIZE.x, (s32)PREVIEW_SIZE.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -80,17 +81,32 @@ preview_init(Preview* self, Anm2* anm2, Resources* resources, Input* input, Sett glGenRenderbuffers(1, &self->rbo); glBindRenderbuffer(GL_RENDERBUFFER, self->rbo); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, PREVIEW_SIZE.x, PREVIEW_SIZE.y); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, (s32)PREVIEW_SIZE.x, (s32)PREVIEW_SIZE.y); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, self->rbo); glBindFramebuffer(GL_FRAMEBUFFER, 0); + /* Axis */ glGenVertexArrays(1, &self->axisVAO); glGenBuffers(1, &self->axisVBO); + /* Grid */ glGenVertexArrays(1, &self->gridVAO); glGenBuffers(1, &self->gridVBO); + /* Rect */ + glGenVertexArrays(1, &self->rectVAO); + glGenBuffers(1, &self->rectVBO); + + glBindVertexArray(self->rectVAO); + + glBindBuffer(GL_ARRAY_BUFFER, self->rectVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(GL_VERTICES), GL_VERTICES, GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(f32), (void*)0); + + /* Texture */ glGenVertexArrays(1, &self->textureVAO); glGenBuffers(1, &self->textureVBO); glGenBuffers(1, &self->textureEBO); @@ -101,7 +117,7 @@ preview_init(Preview* self, Anm2* anm2, Resources* resources, Input* input, Sett glBufferData(GL_ARRAY_BUFFER, sizeof(f32) * 4 * 4, NULL, GL_DYNAMIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self->textureEBO); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(PREVIEW_TEXTURE_INDICES), PREVIEW_TEXTURE_INDICES, GL_STATIC_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GL_TEXTURE_INDICES), GL_TEXTURE_INDICES, GL_STATIC_DRAW); /* Position */ glEnableVertexAttribArray(0); @@ -120,9 +136,10 @@ preview_init(Preview* self, Anm2* anm2, Resources* resources, Input* input, Sett void preview_tick(Preview* self) { - self->settings->zoom = CLAMP(self->settings->zoom, PREVIEW_ZOOM_MIN, PREVIEW_ZOOM_MAX); - self->oldGridSize = glm::vec2(self->settings->gridSizeX, self->settings->gridSizeY); - self->oldGridOffset = glm::vec2(self->settings->gridOffsetX, self->settings->gridOffsetY); + self->settings->previewZoom = CLAMP(self->settings->previewZoom, PREVIEW_ZOOM_MIN, PREVIEW_ZOOM_MAX); + + self->oldGridSize = glm::vec2(self->settings->previewGridSizeX, self->settings->previewGridSizeY); + self->oldGridOffset = glm::vec2(self->settings->previewGridOffsetX, self->settings->previewGridOffsetY); if (self->animationID > -1) { @@ -146,81 +163,79 @@ preview_draw(Preview* self) GLuint shaderLine = self->resources->shaders[SHADER_LINE]; GLuint shaderTexture = self->resources->shaders[SHADER_TEXTURE]; - f32 zoomFactor = self->settings->zoom / 100.0f; - - /* Convert pan to pixels */ - glm::vec2 ndcPan = glm::vec2( - self->settings->panX / (PREVIEW_SIZE.x / 2.0f), - -self->settings->panY / (PREVIEW_SIZE.y / 2.0f) - ); - - /* Transformation matrix */ + f32 zoomFactor = self->settings->previewZoom / 100.0f; + glm::vec2 ndcPan = glm::vec2(-self->settings->previewPanX / (PREVIEW_SIZE.x / 2.0f), -self->settings->previewPanY / (PREVIEW_SIZE.y / 2.0f)); glm::mat4 previewTransform = glm::translate(glm::mat4(1.0f), glm::vec3(ndcPan, 0.0f)); previewTransform = glm::scale(previewTransform, glm::vec3(zoomFactor, zoomFactor, 1.0f)); glBindFramebuffer(GL_FRAMEBUFFER, self->fbo); - glViewport(0, 0, PREVIEW_SIZE.x, PREVIEW_SIZE.y); + glViewport(0, 0, (s32)PREVIEW_SIZE.x, (s32)PREVIEW_SIZE.y); glClearColor ( - self->settings->backgroundColorR, - self->settings->backgroundColorG, - self->settings->backgroundColorB, - self->settings->backgroundColorA + self->settings->previewBackgroundColorR, + self->settings->previewBackgroundColorG, + self->settings->previewBackgroundColorB, + self->settings->previewBackgroundColorA ); glClear(GL_COLOR_BUFFER_BIT); - glUseProgram(shaderLine); - glUniformMatrix4fv(glGetUniformLocation(shaderLine, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, (f32*)value_ptr(previewTransform)); - - if (self->settings->isGrid) + /* Grid */ + if (self->settings->previewIsGrid) { if ( - (ivec2(self->settings->gridSizeX, self->settings->gridSizeY) != self->oldGridSize) || - (ivec2(self->settings->gridOffsetX, self->settings->gridOffsetY) != self->oldGridOffset) + (ivec2(self->settings->previewGridSizeX, self->settings->previewGridSizeY) != self->oldGridSize) || + (ivec2(self->settings->previewGridOffsetX, self->settings->previewGridOffsetY) != self->oldGridOffset) ) _preview_grid_set(self); + glUseProgram(shaderLine); glBindVertexArray(self->gridVAO); + glUniformMatrix4fv(glGetUniformLocation(shaderLine, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, (f32*)value_ptr(previewTransform)); glUniform4f ( glGetUniformLocation(shaderLine, SHADER_UNIFORM_COLOR), - self->settings->gridColorR, self->settings->gridColorG, self->settings->gridColorB, self->settings->gridColorA + self->settings->previewGridColorR, self->settings->previewGridColorG, self->settings->previewGridColorB, self->settings->previewGridColorA ); glDrawArrays(GL_LINES, 0, self->gridVertexCount); glBindVertexArray(0); + glUseProgram(0); } - if (self->settings->isAxis) + /* Axes */ + if (self->settings->previewIsAxis) { + glUseProgram(shaderLine); glBindVertexArray(self->axisVAO); - /* Axes */ + glUniformMatrix4fv(glGetUniformLocation(shaderLine, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, (f32*)value_ptr(previewTransform)); + glUniform4f ( glGetUniformLocation(shaderLine, SHADER_UNIFORM_COLOR), - self->settings->axisColorR, self->settings->axisColorG, self->settings->axisColorB, self->settings->axisColorA + self->settings->previewAxisColorR, self->settings->previewAxisColorG, self->settings->previewAxisColorB, self->settings->previewAxisColorA ); + glDrawArrays(GL_LINES, 0, 2); + glUniform4f ( glGetUniformLocation(shaderLine, SHADER_UNIFORM_COLOR), - self->settings->axisColorR, self->settings->axisColorG, self->settings->axisColorB, self->settings->axisColorA + self->settings->previewAxisColorR, self->settings->previewAxisColorG, self->settings->previewAxisColorB, self->settings->previewAxisColorA ); + glDrawArrays(GL_LINES, 2, 2); - + glBindVertexArray(0); + glUseProgram(0); } - glUseProgram(0); - - glUseProgram(shaderTexture); - + /* Animation */ if (self->animationID > -1) { Anm2Frame rootFrame = Anm2Frame{}; @@ -230,63 +245,53 @@ preview_draw(Preview* self) /* Layers (Reversed) */ for (auto & [id, layerAnimation] : animation->layerAnimations) { - Anm2Layer* layer = &self->anm2->layers[id]; - Anm2Frame frame; - - Texture* texture = &self->resources->loadedTextures[layer->spritesheetID]; - - if (texture->isInvalid) - continue; - if (!layerAnimation.isVisible || layerAnimation.frames.size() <= 0) continue; - if (!anm2_frame_from_time(self->anm2, animation, &frame, ANM2_LAYER_ANIMATION, id, self->time)) - continue; + Anm2Layer* layer = &self->anm2->layers[id]; + Anm2Frame frame = layerAnimation.frames[0]; + + anm2_frame_from_time(self->anm2, animation, &frame, ANM2_LAYER_ANIMATION, id, self->time); if (!frame.isVisible) continue; + Texture* texture = &self->resources->textures[layer->spritesheetID]; + + if (texture->isInvalid) + continue; + glm::mat4 layerTransform = previewTransform; - glm::vec2 previewSize = glm::vec2(PREVIEW_SIZE); - glm::vec2 scale = self->settings->isRootTransform ? - (frame.scale / 100.0f) * (rootFrame.scale / 100.0f) : - (frame.scale / 100.0f); - - glm::vec2 position = self->settings->isRootTransform ? - (frame.position + rootFrame.position) : - frame.position; - - glm::vec2 scaledSize = frame.size * scale; - glm::vec2 scaledPivot = frame.pivot * scale; - - glm::vec2 ndcPos = position / (previewSize / 2.0f); - glm::vec2 ndcPivotOffset = scaledPivot / (previewSize * 0.5f); - glm::vec2 ndcScale = scaledSize / (previewSize * 0.5f); + glm::vec2 position = self->settings->previewIsRootTransform ? (frame.position + rootFrame.position) : frame.position; + glm::vec2 scale = self->settings->previewIsRootTransform ? (frame.scale / 100.0f) * (rootFrame.scale / 100.0f) : (frame.scale / 100.0f); + glm::vec2 ndcPos = position / (PREVIEW_SIZE / 2.0f); + glm::vec2 ndcPivotOffset = (frame.pivot * scale) / (PREVIEW_SIZE / 2.0f); + glm::vec2 ndcScale = (frame.size * scale) / (PREVIEW_SIZE / 2.0f); + f32 rotation = frame.rotation; layerTransform = glm::translate(layerTransform, glm::vec3(ndcPos - ndcPivotOffset, 0.0f)); layerTransform = glm::translate(layerTransform, glm::vec3(ndcPivotOffset, 0.0f)); - layerTransform = glm::rotate(layerTransform, glm::radians(frame.rotation), glm::vec3(0, 0, 1)); + layerTransform = glm::rotate(layerTransform, glm::radians(rotation), glm::vec3(0, 0, 1)); layerTransform = glm::translate(layerTransform, glm::vec3(-ndcPivotOffset, 0.0f)); layerTransform = glm::scale(layerTransform, glm::vec3(ndcScale, 1.0f)); - + + glm::vec2 uvMin = frame.crop / glm::vec2(texture->size); glm::vec2 uvMax = (frame.crop + frame.size) / glm::vec2(texture->size); - f32 vertices[] = { - 0, 0, uvMin.x, uvMin.y, - 1, 0, uvMax.x, uvMin.y, - 1, 1, uvMax.x, uvMax.y, - 0, 1, uvMin.x, uvMax.y - }; + f32 vertices[] = UV_VERTICES(uvMin, uvMax); + + glUseProgram(shaderTexture); glBindVertexArray(self->textureVAO); glBindBuffer(GL_ARRAY_BUFFER, self->textureVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW); + glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, texture->handle); + glBindTexture(GL_TEXTURE_2D, texture->id); + glUniform1i(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TEXTURE), 0); glUniform4fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TINT), 1, (f32*)value_ptr(frame.tintRGBA)); glUniform3fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_COLOR_OFFSET), 1, (f32*)value_ptr(frame.offsetRGB)); @@ -294,7 +299,10 @@ preview_draw(Preview* self) glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); glBindTexture(GL_TEXTURE_2D, 0); + glUseProgram(0); } /* Root */ @@ -302,151 +310,170 @@ preview_draw(Preview* self) (isRootFrame && animation->rootAnimation.isVisible && rootFrame.isVisible) { glm::mat4 rootTransform = previewTransform; - glm::vec2 previewSize = {(f32)PREVIEW_SIZE.x, (f32)PREVIEW_SIZE.y}; - glm::vec2 ndcPos = (rootFrame.position - (PREVIEW_TARGET_SIZE / 2.0f)) / (previewSize / 2.0f); - glm::vec2 ndcScale = PREVIEW_TARGET_SIZE / (previewSize * 0.5f); + glm::vec2 ndcPos = (rootFrame.position - (ATLAS_SIZES[TEXTURE_TARGET] / 2.0f)) / (PREVIEW_SIZE / 2.0f); + glm::vec2 ndcScale = ATLAS_SIZES[TEXTURE_TARGET] / (PREVIEW_SIZE / 2.0f); + glm::vec2 ndcPivot = (-ATLAS_SIZES[TEXTURE_TARGET] / 2.0f) / (PREVIEW_SIZE / 2.0f); rootTransform = glm::translate(rootTransform, glm::vec3(ndcPos, 0.0f)); + rootTransform = glm::rotate(rootTransform, glm::radians(rootFrame.rotation), glm::vec3(0, 0, 1)); rootTransform = glm::scale(rootTransform, glm::vec3(ndcScale, 1.0f)); - f32 vertices[] = - { - 0, 0, 0.0f, 0.0f, - 1, 0, 1.0f, 0.0f, - 1, 1, 1.0f, 1.0f, - 0, 1, 0.0f, 1.0f - }; - + f32 vertices[] = ATLAS_UV_VERTICES(TEXTURE_TARGET); + + glUseProgram(shaderTexture); + glBindVertexArray(self->textureVAO); glBindBuffer(GL_ARRAY_BUFFER, self->textureVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW); + glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, self->resources->textures[TEXTURE_TARGET].handle); + glBindTexture(GL_TEXTURE_2D, self->resources->atlas.id); + glUniform1i(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TEXTURE), 0); glUniform4fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TINT), 1, value_ptr(PREVIEW_ROOT_TINT)); - glUniform3fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_COLOR_OFFSET), 1, value_ptr(PREVIEW_ROOT_COLOR_OFFSET)); + glUniform3fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_COLOR_OFFSET), 1, value_ptr(COLOR_OFFSET_NONE)); glUniformMatrix4fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, value_ptr(rootTransform)); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); glBindTexture(GL_TEXTURE_2D, 0); + glUseProgram(0); } /* Pivots */ - if (self->settings->isShowPivot) + if (self->settings->previewIsShowPivot) { for (auto it = animation->layerAnimations.rbegin(); it != animation->layerAnimations.rend(); it++) { s32 id = it->first; Anm2LayerAnimation layerAnimation = it->second; - Anm2Layer* layer = &self->anm2->layers[id]; - Anm2Frame frame; - - Texture* texture = &self->resources->loadedTextures[layer->spritesheetID]; - if (!layerAnimation.isVisible || layerAnimation.frames.size() <= 0) continue; + + Anm2Frame frame = layerAnimation.frames[0]; - if (!anm2_frame_from_time(self->anm2, animation, &frame, ANM2_LAYER_ANIMATION, id, self->time)) - continue; + anm2_frame_from_time(self->anm2, animation, &frame, ANM2_LAYER_ANIMATION, id, self->time); if (!frame.isVisible) continue; - - glm::vec2 scale = self->settings->isRootTransform ? - (frame.scale / 100.0f) * (rootFrame.scale / 100.0f) : - (frame.scale / 100.0f); - - glm::vec2 position = self->settings->isRootTransform ? - (frame.position + rootFrame.position) : - frame.position; - glm::mat4 pivotTransform = previewTransform; - glm::vec2 previewSize = {(f32)PREVIEW_SIZE.x, (f32)PREVIEW_SIZE.y}; - glm::vec2 scaledSize = PREVIEW_PIVOT_SIZE * scale; - glm::vec2 ndcPos = (position - (PREVIEW_PIVOT_SIZE / 2.0f)) / (previewSize / 2.0f); - glm::vec2 ndcScale = scaledSize / (previewSize * 0.5f); + + glm::vec2 position = self->settings->previewIsRootTransform ? (frame.position + rootFrame.position) : frame.position; + + glm::vec2 ndcPos = (position - (ATLAS_SIZES[TEXTURE_PIVOT] / 2.0f)) / (PREVIEW_SIZE / 2.0f); + glm::vec2 ndcScale = ATLAS_SIZES[TEXTURE_PIVOT] / (PREVIEW_SIZE / 2.0f); pivotTransform = glm::translate(pivotTransform, glm::vec3(ndcPos, 0.0f)); pivotTransform = glm::scale(pivotTransform, glm::vec3(ndcScale, 1.0f)); - f32 vertices[] = - { - 0, 0, 0.0f, 0.0f, - 1, 0, 1.0f, 0.0f, - 1, 1, 1.0f, 1.0f, - 0, 1, 0.0f, 1.0f - }; - + f32 vertices[] = ATLAS_UV_VERTICES(TEXTURE_PIVOT); + + glUseProgram(shaderTexture); + glBindVertexArray(self->textureVAO); glBindBuffer(GL_ARRAY_BUFFER, self->textureVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW); + glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, self->resources->textures[TEXTURE_PIVOT].handle); + glBindTexture(GL_TEXTURE_2D, self->resources->atlas.id); + glUniform1i(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TEXTURE), 0); glUniform4fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TINT), 1, value_ptr(PREVIEW_PIVOT_TINT)); - glUniform3fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_COLOR_OFFSET), 1, value_ptr(PREVIEW_PIVOT_COLOR_OFFSET)); + glUniform3fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_COLOR_OFFSET), 1, value_ptr(COLOR_OFFSET_NONE)); glUniformMatrix4fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, value_ptr(pivotTransform)); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); glBindTexture(GL_TEXTURE_2D, 0); + glUseProgram(0); } } /* Nulls */ for (auto & [id, nullAnimation] : animation->nullAnimations) { - Anm2Frame frame; - if (!nullAnimation.isVisible || nullAnimation.frames.size() <= 0) continue; - if (!anm2_frame_from_time(self->anm2, animation, &frame, ANM2_NULL_ANIMATION, id, self->time)) - continue; + Anm2Frame frame = nullAnimation.frames[0]; + + anm2_frame_from_time(self->anm2, animation, &frame, ANM2_NULL_ANIMATION, id, self->time); if (!frame.isVisible) continue; - glm::mat4 nullTransform = previewTransform; - glm::vec2 previewSize = {(f32)PREVIEW_SIZE.x, (f32)PREVIEW_SIZE.y}; - - glm::vec2 pos = self->settings->isRootTransform ? - frame.position + (rootFrame.position) - (PREVIEW_TARGET_SIZE / 2.0f): - frame.position - (PREVIEW_TARGET_SIZE / 2.0f); + Anm2Null* null = NULL; - glm::vec2 ndcPos = pos / (previewSize / 2.0f); - glm::vec2 ndcScale = PREVIEW_TARGET_SIZE / (previewSize * 0.5f); + null = &self->anm2->nulls[id]; + + glm::mat4 nullTransform = previewTransform; + + TextureType textureType = null->isShowRect ? TEXTURE_SQUARE : TEXTURE_TARGET; + glm::vec2 size = null->isShowRect ? PREVIEW_POINT_SIZE : ATLAS_SIZES[TEXTURE_TARGET]; + glm::vec2 pos = self->settings->previewIsRootTransform ? frame.position + (rootFrame.position) - (size / 2.0f) : frame.position - (size / 2.0f); + + glm::vec2 ndcPos = pos / (PREVIEW_SIZE / 2.0f); + glm::vec2 ndcScale = size / (PREVIEW_SIZE / 2.0f); nullTransform = glm::translate(nullTransform, glm::vec3(ndcPos, 0.0f)); nullTransform = glm::scale(nullTransform, glm::vec3(ndcScale, 1.0f)); - f32 vertices[] = - { - 0, 0, 0.0f, 0.0f, - 1, 0, 1.0f, 0.0f, - 1, 1, 1.0f, 1.0f, - 0, 1, 0.0f, 1.0f - }; + f32 vertices[] = ATLAS_UV_VERTICES(textureType); + + glUseProgram(shaderTexture); glBindVertexArray(self->textureVAO); glBindBuffer(GL_ARRAY_BUFFER, self->textureVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW); + glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, self->resources->textures[TEXTURE_TARGET].handle); + glBindTexture(GL_TEXTURE_2D, self->resources->atlas.id); + glUniform1i(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TEXTURE), 0); glUniform4fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TINT), 1, value_ptr(PREVIEW_NULL_TINT)); - glUniform3fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_COLOR_OFFSET), 1, value_ptr(PREVIEW_NULL_COLOR_OFFSET)); + glUniform3fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_COLOR_OFFSET), 1, value_ptr(COLOR_OFFSET_NONE)); glUniformMatrix4fv(glGetUniformLocation(shaderTexture, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, value_ptr(nullTransform)); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glBindTexture(GL_TEXTURE_2D, 0); + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glUseProgram(0); + + if (null->isShowRect) + { + glm::mat4 rectTransform = previewTransform; + + glm::vec2 rectPos = pos - (PREVIEW_NULL_RECT_SIZE / 2.0f); + glm::vec2 rectNDCPos = rectPos / (PREVIEW_SIZE / 2.0f); + glm::vec2 rectNDCScale = PREVIEW_NULL_RECT_SIZE / (PREVIEW_SIZE / 2.0f); + + rectTransform = glm::translate(rectTransform, glm::vec3(rectNDCPos, 0.0f)); + rectTransform = glm::scale(rectTransform, glm::vec3(rectNDCScale, 1.0f)); + + glUseProgram(shaderLine); + + glBindVertexArray(self->rectVAO); + + glUniformMatrix4fv(glGetUniformLocation(shaderLine, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, glm::value_ptr(rectTransform)); + + glUniform4fv(glGetUniformLocation(shaderLine, SHADER_UNIFORM_COLOR), 1, glm::value_ptr(PREVIEW_NULL_TINT)); + + glDrawArrays(GL_LINE_LOOP, 0, 4); + + glBindVertexArray(0); + glUseProgram(0); + } } } @@ -461,6 +488,4 @@ preview_free(Preview* self) glDeleteTextures(1, &self->texture); glDeleteFramebuffers(1, &self->fbo); glDeleteRenderbuffers(1, &self->rbo); - - memset(self, '\0', sizeof(Preview)); } \ No newline at end of file diff --git a/src/preview.h b/src/preview.h index 6f0c3fb..4f57dff 100644 --- a/src/preview.h +++ b/src/preview.h @@ -5,17 +5,16 @@ #include "input.h" #include "settings.h" -static const ivec2 PREVIEW_SIZE = {2000, 2000}; -static const ivec2 PREVIEW_CENTER = {0, 0}; +static const vec2 PREVIEW_SIZE = {5000, 5000}; +static const vec2 PREVIEW_CENTER = {0, 0}; -#define PREVIEW_ZOOM_MIN 1.0f -#define PREVIEW_ZOOM_MAX 800.0f +#define PREVIEW_ZOOM_MIN 1 +#define PREVIEW_ZOOM_MAX 1000 +#define PREVIEW_ZOOM_STEP 25 #define PREVIEW_GRID_MIN 1 -#define PREVIEW_GRID_MAX 50 +#define PREVIEW_GRID_MAX 1000 #define PREVIEW_GRID_OFFSET_MIN 0 #define PREVIEW_GRID_OFFSET_MAX 100 -#define PREVIEW_ZOOM_STEP 50 -#define PREVIEW static const f32 PREVIEW_AXIS_VERTICES[] = { @@ -25,16 +24,11 @@ static const f32 PREVIEW_AXIS_VERTICES[] = 0.0f, 1.0f }; -static const GLuint PREVIEW_TEXTURE_INDICES[] = {0, 1, 2, 2, 3, 0}; - -static const vec2 PREVIEW_PIVOT_SIZE = {6, 6}; -static const vec2 PREVIEW_TARGET_SIZE = {16, 16}; -static const vec4 PREVIEW_ROOT_TINT = {0.0f, 1.0f, 0.0f, 1.0f}; -static const vec3 PREVIEW_ROOT_COLOR_OFFSET = {0.0f, 0.0f, 0.0f}; -static const vec4 PREVIEW_NULL_TINT = {0.0f, 0.0f, 1.0f, 1.0f}; -static const vec3 PREVIEW_NULL_COLOR_OFFSET = {0.0f, 0.0f, 0.0f}; -static const vec4 PREVIEW_PIVOT_TINT = {1.0f, 1.0f, 1.0f, 1.0f}; -static const vec3 PREVIEW_PIVOT_COLOR_OFFSET = {0.0f, 0.0f, 0.0f}; +static const vec2 PREVIEW_NULL_RECT_SIZE = {100, 100}; +static const vec2 PREVIEW_POINT_SIZE = {2, 2}; +static const vec4 PREVIEW_ROOT_TINT = COLOR_GREEN; +static const vec4 PREVIEW_NULL_TINT = COLOR_BLUE; +static const vec4 PREVIEW_PIVOT_TINT = COLOR_RED; struct Preview { @@ -49,6 +43,8 @@ struct Preview GLuint gridVBO; GLuint rbo; GLuint texture; + GLuint rectVAO; + GLuint rectVBO; GLuint textureEBO; GLuint textureVAO; GLuint textureVBO; @@ -59,7 +55,6 @@ struct Preview ivec2 viewport = PREVIEW_SIZE; s32 animationID = -1; s32 gridVertexCount = -1; - }; void preview_init(Preview* self, Anm2* anm2, Resources* resources, Input* input, Settings* settings); diff --git a/src/resources.cpp b/src/resources.cpp index 930d9cd..766e4ef 100644 --- a/src/resources.cpp +++ b/src/resources.cpp @@ -4,9 +4,7 @@ void resources_init(Resources* self) { - /* Textures */ - for (s32 i = 0; i < TEXTURE_COUNT; i++) - texture_from_data_init(&self->textures[i], (u8*)TEXTURE_DATA[i].data, TEXTURE_DATA[i].length); + texture_from_data_init(&self->atlas, (u8*)TEXTURE_ATLAS, TEXTURE_ATLAS_LENGTH); for (s32 i = 0; i < SHADER_COUNT; i++) shader_init(&self->shaders[i], SHADER_DATA[i].vertex, SHADER_DATA[i].fragment); @@ -16,19 +14,18 @@ resources_init(Resources* self) void resources_free(Resources* self) { - for (s32 i = 0; i < TEXTURE_COUNT; i++) - texture_free(&self->textures[i]); + resources_textures_free(self); for (s32 i = 0; i < SHADER_COUNT; i++) shader_free(&self->shaders[i]); - - resources_loaded_textures_free(self); + + texture_free(&self->atlas); } /* Frees loaded textures */ void -resources_loaded_textures_free(Resources* self) +resources_textures_free(Resources* self) { - for (auto & [id, texture] : self->loadedTextures) + for (auto & [id, texture] : self->textures) texture_free(&self->textures[id]); } \ No newline at end of file diff --git a/src/resources.h b/src/resources.h index fcc402b..ed46fbc 100644 --- a/src/resources.h +++ b/src/resources.h @@ -6,11 +6,11 @@ struct Resources { - Texture textures[TEXTURE_COUNT]; GLuint shaders[SHADER_COUNT]; - std::map loadedTextures; + Texture atlas; + std::map textures; }; void resources_init(Resources* self); void resources_free(Resources* self); -void resources_loaded_textures_free(Resources* self); +void resources_textures_free(Resources* self); diff --git a/src/settings.cpp b/src/settings.cpp index 2ee60f8..c82eb3c 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -14,7 +14,6 @@ _settings_setting_load(Settings* self, char* line) char* value = line + strlen(SETTINGS_ENTRIES[i].value); void* target = (u8*)self + SETTINGS_ENTRIES[i].offset; - switch (SETTINGS_ENTRIES[i].type) { case SETTINGS_TYPE_INT: diff --git a/src/settings.h b/src/settings.h index 45077e8..2fe8e23 100644 --- a/src/settings.h +++ b/src/settings.h @@ -23,92 +23,143 @@ struct SettingsEntry s32 offset; }; -#define SETTINGS_COUNT (SETTINGS_BACKGROUND_COLOR_A + 1) +#define SETTINGS_COUNT (SETTINGS_EDITOR_BACKGROUND_COLOR_A + 1) enum SettingsItem { SETTINGS_WINDOW_W, SETTINGS_WINDOW_H, - SETTINGS_IS_AXIS, - SETTINGS_IS_GRID, - SETTINGS_IS_ROOT_TRANSFORM, - SETTINGS_IS_SHOW_PIVOT, - SETTINGS_PAN_X, - SETTINGS_PAN_Y, - SETTINGS_ZOOM, - SETTINGS_GRID_SIZE_X, - SETTINGS_GRID_SIZE_Y, - SETTINGS_GRID_OFFSET_X, - SETTINGS_GRID_OFFSET_Y, - SETTINGS_GRID_COLOR_R, - SETTINGS_GRID_COLOR_G, - SETTINGS_GRID_COLOR_B, - SETTINGS_GRID_COLOR_A, - SETTINGS_AXIS_COLOR_R, - SETTINGS_AXIS_COLOR_G, - SETTINGS_AXIS_COLOR_B, - SETTINGS_AXIS_COLOR_A, - SETTINGS_BACKGROUND_COLOR_R, - SETTINGS_BACKGROUND_COLOR_G, - SETTINGS_BACKGROUND_COLOR_B, - SETTINGS_BACKGROUND_COLOR_A + SETTINGS_PREVIEW_IS_AXIS, + SETTINGS_PREVIEW_IS_GRID, + SETTINGS_PREVIEW_IS_ROOT_TRANSFORM, + SETTINGS_PREVIEW_IS_SHOW_PIVOT, + SETTINGS_PREVIEW_PAN_X, + SETTINGS_PREVIEW_PAN_Y, + SETTINGS_PREVIEW_ZOOM, + SETTINGS_PREVIEW_GRID_SIZE_X, + SETTINGS_PREVIEW_GRID_SIZE_Y, + SETTINGS_PREVIEW_GRID_OFFSET_X, + SETTINGS_PREVIEW_GRID_OFFSET_Y, + SETTINGS_PREVIEW_GRID_COLOR_R, + SETTINGS_PREVIEW_GRID_COLOR_G, + SETTINGS_PREVIEW_GRID_COLOR_B, + SETTINGS_PREVIEW_GRID_COLOR_A, + SETTINGS_PREVIEW_AXIS_COLOR_R, + SETTINGS_PREVIEW_AXIS_COLOR_G, + SETTINGS_PREVIEW_AXIS_COLOR_B, + SETTINGS_PREVIEW_AXIS_COLOR_A, + SETTINGS_PREVIEW_BACKGROUND_COLOR_R, + SETTINGS_PREVIEW_BACKGROUND_COLOR_G, + SETTINGS_PREVIEW_BACKGROUND_COLOR_B, + SETTINGS_PREVIEW_BACKGROUND_COLOR_A, + SETTINGS_EDITOR_IS_GRID, + SETTINGS_EDITOR_IS_BORDER, + SETTINGS_EDITOR_PAN_X, + SETTINGS_EDITOR_PAN_Y, + SETTINGS_EDITOR_ZOOM, + SETTINGS_EDITOR_GRID_SIZE_X, + SETTINGS_EDITOR_GRID_SIZE_Y, + SETTINGS_EDITOR_GRID_OFFSET_X, + SETTINGS_EDITOR_GRID_OFFSET_Y, + SETTINGS_EDITOR_GRID_COLOR_R, + SETTINGS_EDITOR_GRID_COLOR_G, + SETTINGS_EDITOR_GRID_COLOR_B, + SETTINGS_EDITOR_GRID_COLOR_A, + SETTINGS_EDITOR_BACKGROUND_COLOR_R, + SETTINGS_EDITOR_BACKGROUND_COLOR_G, + SETTINGS_EDITOR_BACKGROUND_COLOR_B, + SETTINGS_EDITOR_BACKGROUND_COLOR_A }; struct Settings { s32 windowW = 1920; s32 windowH = 1080; - bool isAxis = true; - bool isGrid = true; - bool isRootTransform = false; - bool isShowPivot = false; - f32 panX = 0.0f; - f32 panY = 0.0f; - f32 zoom = 200.0f; - s32 gridSizeX = 10; - s32 gridSizeY = 10; - s32 gridOffsetX = 10; - s32 gridOffsetY = 10; - f32 gridColorR = 1.0f; - f32 gridColorG = 1.0f; - f32 gridColorB = 1.0f; - f32 gridColorA = 0.125f; - f32 axisColorR = 1.0f; - f32 axisColorG = 1.0f; - f32 axisColorB = 1.0f; - f32 axisColorA = 0.5f; - f32 backgroundColorR = 0.113f; - f32 backgroundColorG = 0.184f; - f32 backgroundColorB = 0.286f; - f32 backgroundColorA = 1.0f; + bool previewIsAxis = true; + bool previewIsGrid = true; + bool previewIsRootTransform = false; + bool previewIsShowPivot = false; + f32 previewPanX = 0.0f; + f32 previewPanY = 0.0f; + f32 previewZoom = 200.0f; + s32 previewGridSizeX = 32; + s32 previewGridSizeY = 32; + s32 previewGridOffsetX = 0; + s32 previewGridOffsetY = 0; + f32 previewGridColorR = 1.0f; + f32 previewGridColorG = 1.0f; + f32 previewGridColorB = 1.0f; + f32 previewGridColorA = 0.125f; + f32 previewAxisColorR = 1.0f; + f32 previewAxisColorG = 1.0f; + f32 previewAxisColorB = 1.0f; + f32 previewAxisColorA = 0.5f; + f32 previewBackgroundColorR = 0.113f; + f32 previewBackgroundColorG = 0.184f; + f32 previewBackgroundColorB = 0.286f; + f32 previewBackgroundColorA = 1.0f; + bool editorIsGrid = true; + bool editorIsBorder = true; + f32 editorPanX = 0.0f; + f32 editorPanY = 0.0f; + f32 editorZoom = 200.0f; + s32 editorGridSizeX = 32; + s32 editorGridSizeY = 32; + s32 editorGridOffsetX = 32; + s32 editorGridOffsetY = 32; + f32 editorGridColorR = 1.0f; + f32 editorGridColorG = 1.0f; + f32 editorGridColorB = 1.0f; + f32 editorGridColorA = 0.125f; + f32 editorBackgroundColorR = 0.113f; + f32 editorBackgroundColorG = 0.184f; + f32 editorBackgroundColorB = 0.286f; + f32 editorBackgroundColorA = 1.0f; }; static const SettingsEntry SETTINGS_ENTRIES[SETTINGS_COUNT] = { {"windowW=", "windowW=%i", SETTINGS_TYPE_INT, offsetof(Settings, windowW)}, {"windowH=", "windowH=%i", SETTINGS_TYPE_INT, offsetof(Settings, windowH)}, - {"isAxis=", "isAxis=%i", SETTINGS_TYPE_BOOL, offsetof(Settings, isAxis)}, - {"isGrid=", "isGrid=%i", SETTINGS_TYPE_BOOL, offsetof(Settings, isGrid)}, - {"isRootTransform=", "isRootTransform=%i", SETTINGS_TYPE_BOOL, offsetof(Settings, isRootTransform)}, - {"isShowPivot=", "isShowPivot=%i", SETTINGS_TYPE_BOOL, offsetof(Settings, isShowPivot)}, - {"panX=", "panX=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, panX)}, - {"panY=", "panY=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, panY)}, - {"zoom=", "zoom=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, zoom)}, - {"gridSizeX=", "gridSizeX=%i", SETTINGS_TYPE_INT, offsetof(Settings, gridSizeX)}, - {"gridSizeY=", "gridSizeY=%i", SETTINGS_TYPE_INT, offsetof(Settings, gridSizeY)}, - {"gridOffsetX=", "gridOffsetX=%i", SETTINGS_TYPE_INT, offsetof(Settings, gridOffsetX)}, - {"gridOffsetY=", "gridOffsetY=%i", SETTINGS_TYPE_INT, offsetof(Settings, gridOffsetY)}, - {"gridColorR=", "gridColorR=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, gridColorR)}, - {"gridColorG=", "gridColorG=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, gridColorG)}, - {"gridColorB=", "gridColorB=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, gridColorB)}, - {"gridColorA=", "gridColorA=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, gridColorA)}, - {"axisColorR=", "axisColorR=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, axisColorR)}, - {"axisColorG=", "axisColorG=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, axisColorG)}, - {"axisColorB=", "axisColorB=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, axisColorB)}, - {"axisColorA=", "axisColorA=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, axisColorA)}, - {"backgroundColorR=", "backgroundColorR=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, backgroundColorR)}, - {"backgroundColorG=", "backgroundColorG=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, backgroundColorG)}, - {"backgroundColorB=", "backgroundColorB=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, backgroundColorB)}, - {"backgroundColorA=", "backgroundColorA=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, backgroundColorA)} + {"previewIsAxis=", "previewIsAxis=%i", SETTINGS_TYPE_BOOL, offsetof(Settings, previewIsAxis)}, + {"previewIsGrid=", "previewIsGrid=%i", SETTINGS_TYPE_BOOL, offsetof(Settings, previewIsGrid)}, + {"previewIsRootTransform=", "previewIsRootTransform=%i", SETTINGS_TYPE_BOOL, offsetof(Settings, previewIsRootTransform)}, + {"previewIsShowPivot=", "previewIsShowPivot=%i", SETTINGS_TYPE_BOOL, offsetof(Settings, previewIsShowPivot)}, + {"previewPanX=", "previewPanX=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewPanX)}, + {"previewPanY=", "previewPanY=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewPanY)}, + {"previewZoom=", "previewZoom=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewZoom)}, + {"previewGridSizeX=", "previewGridSizeX=%i", SETTINGS_TYPE_INT, offsetof(Settings, previewGridSizeX)}, + {"previewGridSizeY=", "previewGridSizeY=%i", SETTINGS_TYPE_INT, offsetof(Settings, previewGridSizeY)}, + {"previewGridOffsetX=", "previewGridOffsetX=%i", SETTINGS_TYPE_INT, offsetof(Settings, previewGridOffsetX)}, + {"previewGridOffsetY=", "previewGridOffsetY=%i", SETTINGS_TYPE_INT, offsetof(Settings, previewGridOffsetY)}, + {"previewGridColorR=", "previewGridColorR=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewGridColorR)}, + {"previewGridColorG=", "previewGridColorG=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewGridColorG)}, + {"previewGridColorB=", "previewGridColorB=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewGridColorB)}, + {"previewGridColorA=", "previewGridColorA=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewGridColorA)}, + {"previewAxisColorR=", "previewAxisColorR=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewAxisColorR)}, + {"previewAxisColorG=", "previewAxisColorG=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewAxisColorG)}, + {"previewAxisColorB=", "previewAxisColorB=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewAxisColorB)}, + {"previewAxisColorA=", "previewAxisColorA=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewAxisColorA)}, + {"previewBackgroundColorR=", "previewBackgroundColorR=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewBackgroundColorR)}, + {"previewBackgroundColorG=", "previewBackgroundColorG=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewBackgroundColorG)}, + {"previewBackgroundColorB=", "previewBackgroundColorB=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewBackgroundColorB)}, + {"previewBackgroundColorA=", "previewBackgroundColorA=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, previewBackgroundColorA)}, + {"editorIsGrid=", "editorIsGrid=%i", SETTINGS_TYPE_BOOL, offsetof(Settings, editorIsGrid)}, + {"editorIsBorder=", "editorIsBorder=%i", SETTINGS_TYPE_BOOL, offsetof(Settings, editorIsBorder)}, + {"editorPanX=", "editorPanX=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorPanX)}, + {"editorPanY=", "editorPanY=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorPanY)}, + {"editorZoom=", "editorZoom=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorZoom)}, + {"editorGridSizeX=", "editorGridSizeX=%i", SETTINGS_TYPE_INT, offsetof(Settings, editorGridSizeX)}, + {"editorGridSizeY=", "editorGridSizeY=%i", SETTINGS_TYPE_INT, offsetof(Settings, editorGridSizeY)}, + {"editorGridOffsetX=", "editorGridOffsetX=%i", SETTINGS_TYPE_INT, offsetof(Settings, editorGridOffsetX)}, + {"editorGridOffsetY=", "editorGridOffsetY=%i", SETTINGS_TYPE_INT, offsetof(Settings, editorGridOffsetY)}, + {"editorGridColorR=", "editorGridColorR=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorGridColorR)}, + {"editorGridColorG=", "editorGridColorG=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorGridColorG)}, + {"editorGridColorB=", "editorGridColorB=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorGridColorB)}, + {"editorGridColorA=", "editorGridColorA=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorGridColorA)}, + {"editorBackgroundColorR=", "editorBackgroundColorR=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorBackgroundColorR)}, + {"editorBackgroundColorG=", "editorBackgroundColorG=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorBackgroundColorG)}, + {"editorBackgroundColorB=", "editorBackgroundColorB=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorBackgroundColorB)}, + {"editorBackgroundColorA=", "editorBackgroundColorA=%f", SETTINGS_TYPE_FLOAT, offsetof(Settings, editorBackgroundColorA)} }; void settings_save(Settings* self); diff --git a/src/state.cpp b/src/state.cpp index 64cd593..f36c702 100644 --- a/src/state.cpp +++ b/src/state.cpp @@ -32,6 +32,7 @@ _tick(State* state) SDL_GetWindowSize(state->window, &state->settings.windowW, &state->settings.windowH); input_tick(&state->input); + editor_tick(&state->editor); preview_tick(&state->preview); dialog_tick(&state->dialog); imgui_tick(&state->imgui); @@ -40,6 +41,7 @@ _tick(State* state) static void _draw(State* state) { + editor_draw(&state->editor); preview_draw(&state->preview); imgui_draw(&state->imgui); @@ -97,6 +99,7 @@ init(State* state) glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_DEPTH_TEST); + glLineWidth(LINE_WIDTH); printf(STRING_INFO_GLEW_INIT); @@ -104,7 +107,8 @@ init(State* state) dialog_init(&state->dialog, &state->anm2, &state->resources, state->window); preview_init(&state->preview, &state->anm2, &state->resources, &state->input, &state->settings); - + editor_init(&state->editor, &state->resources, &state->settings); + imgui_init ( &state->imgui, @@ -112,6 +116,7 @@ init(State* state) &state->resources, &state->input, &state->anm2, + &state->editor, &state->preview, &state->settings, state->window, @@ -154,6 +159,7 @@ quit(State* state) imgui_free(&state->imgui); settings_save(&state->settings); preview_free(&state->preview); + editor_free(&state->editor); resources_free(&state->resources); SDL_GL_DestroyContext(state->glContext); diff --git a/src/state.h b/src/state.h index 4c380e0..f075365 100644 --- a/src/state.h +++ b/src/state.h @@ -5,6 +5,7 @@ #define WINDOW_WIDTH 1920 #define WINDOW_HEIGHT 1080 #define WINDOW_FLAGS SDL_WINDOW_RESIZABLE +#define LINE_WIDTH 2.0f struct State { @@ -14,6 +15,7 @@ struct State Imgui imgui; Input input; Dialog dialog; + Editor editor; Preview preview; Anm2 anm2; Resources resources; diff --git a/src/texture.cpp b/src/texture.cpp index 7f436ef..4e3aee5 100644 --- a/src/texture.cpp +++ b/src/texture.cpp @@ -9,9 +9,9 @@ void texture_gl_set(Texture* self, void* data) { - glGenTextures(1, &self->handle); + glGenTextures(1, &self->id); - glBindTexture(GL_TEXTURE_2D, self->handle); + glBindTexture(GL_TEXTURE_2D, self->id); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, self->size.x, self->size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); @@ -20,7 +20,7 @@ texture_gl_set(Texture* self, void* data) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glBindTexture(GL_TEXTURE_2D, 0); /* unbinds */ + glBindTexture(GL_TEXTURE_2D, 0); } bool @@ -61,6 +61,6 @@ texture_from_data_init(Texture* self, const u8* data, u32 length) void texture_free(Texture* self) { - glDeleteTextures(1, &self->handle); + glDeleteTextures(1, &self->id); memset(self, '\0', sizeof(Texture)); } \ No newline at end of file diff --git a/src/texture.h b/src/texture.h index 1341322..2602d1d 100644 --- a/src/texture.h +++ b/src/texture.h @@ -4,7 +4,7 @@ struct Texture { - GLuint handle = 0; + GLuint id = 0; ivec2 size = {0, 0}; s32 channels = -1; bool isInvalid = false;