forming the skeleton

This commit is contained in:
2025-06-21 21:36:32 -04:00
parent 3bedd81d96
commit ea2e7e918c
22 changed files with 921 additions and 309 deletions

View File

@ -6,6 +6,7 @@
#include <GL/gl.h>
#include <glm/glm/glm.hpp>
#include <glm/glm/gtc/type_ptr.hpp>
#include <glm/glm/gtc/matrix_transform.hpp>
#include <limits.h>
#include <math.h>
#include <stdbool.h>
@ -16,9 +17,10 @@
#include <tinyxml2.h>
#include <algorithm>
#include <filesystem>
#include <map>
#include <ranges>
#include <vector>
#include <map>
#include "STRINGS.h"
@ -48,6 +50,14 @@ static inline const char* enum_to_string(const char* arr[], s32 count, s32 index
static inline s32 string_to_enum(const char* str, const char* const* arr, s32 n) { for (s32 i=0; i<n; ++i) if (!strcmp(str, arr[i])) return i; return -1; }
static inline bool string_to_bool(const char* str) { if (strcmp(str, "true") == 0) return true; return false; }
static inline void working_directory_from_path_set(const char* path)
{
std::filesystem::path filePath = path;
std::filesystem::path dir = filePath.parent_path();
if (!dir.empty())
std::filesystem::current_path(dir);
};
template<typename T>
static inline s32 map_next_id_get(const std::map<s32, T>& map) {
s32 id = 0; for (const auto& [key, _] : map) if (key != id) break; else ++id; return id;

View File

@ -2,7 +2,8 @@
#include "COMMON.h"
struct PackedData
/* TextureData */
struct TextureData
{
const u8* data;
u32 length;
@ -266,25 +267,25 @@ static const unsigned char texture_arrow_down[] = {
};
static const unsigned int texture_arrow_down_len = 153;
#define PACKED_TEXTURE_COUNT (PACKED_TEXTURE_ARROW_DOWN + 1)
enum PackedTextureType
#define TEXTURE_COUNT (TEXTURE_ARROW_DOWN + 1)
enum TextureType
{
PACKED_TEXTURE_EYE_OPEN,
PACKED_TEXTURE_EYE_CLOSED,
PACKED_TEXTURE_ANIMATION,
PACKED_TEXTURE_EVENT,
PACKED_TEXTURE_LAYER,
PACKED_TEXTURE_NULL,
PACKED_TEXTURE_ROOT,
PACKED_TEXTURE_SPRITESHEET,
PACKED_TEXTURE_TRIGGER,
PACKED_TEXTURE_RECT_SHOW,
PACKED_TEXTURE_RECT_HIDE,
PACKED_TEXTURE_ARROW_UP,
PACKED_TEXTURE_ARROW_DOWN
TEXTURE_EYE_OPEN,
TEXTURE_EYE_CLOSED,
TEXTURE_ANIMATION,
TEXTURE_EVENT,
TEXTURE_LAYER,
TEXTURE_NULL,
TEXTURE_ROOT,
TEXTURE_SPRITESHEET,
TEXTURE_TRIGGER,
TEXTURE_RECT_SHOW,
TEXTURE_RECT_HIDE,
TEXTURE_ARROW_UP,
TEXTURE_ARROW_DOWN
};
static const PackedData PACKED_TEXTURE_DATA[PACKED_TEXTURE_COUNT] =
static const TextureData TEXTURE_DATA[TEXTURE_COUNT] =
{
{texture_eye_open, texture_eye_open_len},
{texture_eye_closed, texture_eye_closed_len},
@ -300,3 +301,45 @@ static const PackedData PACKED_TEXTURE_DATA[PACKED_TEXTURE_COUNT] =
{texture_arrow_up, texture_arrow_up_len},
{texture_arrow_down, texture_arrow_down_len},
};
/* Shaders */
struct ShaderData
{
const char* vertex;
const char* fragment;
};
#define SHADER_COUNT (SHADER + 1)
enum ShaderType
{
SHADER
};
static const char SHADER_VERTEX[] =
"#version 330 core\n" \
"layout (location = 0)\n" \
"in vec2 i_position;\n" \
"uniform mat4 u_transform;\n" \
"\n" \
"void main()\n" \
"{\n" \
" vec4 pos = vec4(i_position, 0.0, 1.0);\n" \
" gl_Position = u_transform * pos;\n" \
"}\n";
static const char SHADER_FRAGMENT[] = "#version 330 core\n" \
"out vec4 FragColor;\n" \
"uniform vec4 u_color;\n" \
"\n" \
"void main()\n" \
"{\n" \
" FragColor = u_color;\n" \
"}\n";
static const char SHADER_UNIFORM_COLOR[] = "u_color";
static const char SHADER_UNIFORM_TRANSFORM[] = "u_transform";
static const ShaderData SHADER_DATA[SHADER_COUNT] =
{
{SHADER_VERTEX, SHADER_FRAGMENT}
};

View File

@ -97,15 +97,20 @@
#define STRING_IMGUI_FRAME_PROPERTIES_COLOR_OFFSET "Color Offset"
#define STRING_IMGUI_ANIMATION_PREVIEW "Animation Preview"
#define STRING_IMGUI_ANIMATION_PREVIEW_LABEL "##Animation Preview"
#define STRING_IMGUI_ANIMATION_PREVIEW_SETTINGS "##Animation Preview Settings"
#define STRING_IMGUI_ANIMATION_PREVIEW_GRID_SETTINGS "##Grid Settings"
#define STRING_IMGUI_ANIMATION_PREVIEW_GRID "Grid"
#define STRING_IMGUI_ANIMATION_PREVIEW_GRID_SIZE "##Grid Size"
#define STRING_IMGUI_ANIMATION_PREVIEW_GRID_COLOR "Color"
#define STRING_IMGUI_ANIMATION_PREVIEW_ZOOM_SETTINGS "##Zoom Settings"
#define STRING_IMGUI_ANIMATION_PREVIEW_VIEW_SETTINGS "##View Settings"
#define STRING_IMGUI_ANIMATION_PREVIEW_ZOOM "Zoom"
#define STRING_IMGUI_ANIMATION_PREVIEW_BACKGROUND_SETTINGS "##Background Settings"
#define STRING_IMGUI_ANIMATION_PREVIEW_BACKGROUND_COLOR "Background Color"
#define STRING_IMGUI_ANIMATION_PREVIEW_HELPER_SETTINGS "##Helper Settings"
#define STRING_IMGUI_ANIMATION_PREVIEW_CENTER_VIEW "Center View"
#define STRING_IMGUI_ANIMATION_PREVIEW_AXIS "Axes"
#define STRING_IMGUI_ANIMATION_PREVIEW_AXIS_COLOR "Color"
#define STRING_IMGUI_SPRITESHEET_EDITOR "Spritesheet Editor"
@ -124,98 +129,75 @@
#define STRING_IMGUI_TIMELINE_ANIMATIONS "Animations"
#define STRING_IMGUI_TIMELINE_PLAY "|> Play"
#define STRING_IMGUI_TIMELINE_PAUSE "|| Pause"
#define STRING_IMGUI_TIMELINE_ADD_FRAME "+ Add Frame"
#define STRING_IMGUI_TIMELINE_REMOVE_FRAME "- Remove Frame"
#define STRING_IMGUI_TIMELINE_FRAME_ADD "Add Frame"
#define STRING_IMGUI_TIMELINE_FRAME_REMOVE "Remove Frame"
#define STRING_IMGUI_TIMELINE_FIT_ANIMATION_LENGTH "= Fit Animation Length"
#define STRING_IMGUI_TIMELINE_ANIMATION LENGTH "Animation Length:"
#define STRING_IMGUI_TIMELINE_VISIBLE "Visible"
#define STRING_IMGUI_TIMELINE_LAYER "Layer"
#define STRING_IMGUI_TIMELINE_NULL "Null"
#define STRING_IMGUI_TIMELINE_RECT "Rect"
#define STRING_IMGUI_TIMELINE_FRAME_INDICES "Frame Indices"
#define STRING_IMGUI_TIMELINE_ANIMATION_LENGTH "Animation Length"
#define STRING_IMGUI_TIMELINE_ELEMENT_TIMELINE "Element Timeline"
#define STRING_IMGUI_TIMELINE_ELEMENTS "Elements"
#define STRING_IMGUI_TIMELINE_ELEMENT_ADD "Add"
#define STRING_IMGUI_TIMELINE_ELEMENT_ADD "Add Element"
#define STRING_IMGUI_TIMELINE_ELEMENT_ADD_MENU "Element Add Menu"
#define STRING_IMGUI_TIMELINE_ELEMENT_ADD_MENU_LAYER "Add Layer..."
#define STRING_IMGUI_TIMELINE_ELEMENT_ADD_MENU_NULL "Add Null..."
#define STRING_IMGUI_TIMELINE_ELEMENT_REMOVE "Remove"
#define STRING_IMGUI_TIMELINE_ELEMENT_REMOVE "Remove Element"
#define STRING_IMGUI_TOOLTIP_ANIMATIONS_SELECT "Select the animation to edit.\nYou can also click the name to edit it."
#define STRING_IMGUI_TOOLTIP_ANIMATIONS_ADD "Add a new animation."
#define STRING_IMGUI_TOOLTIP_ANIMATIONS_REMOVE "Removes the selected animation."
#define STRING_IMGUI_TOOLTIP_ANIMATIONS_DUPLICATE "Duplicates the selected animation."
#define STRING_IMGUI_TOOLTIP_ANIMATIONS_REMOVE "Removes the selected animation."
#define STRING_IMGUI_TOOLTIP_ANIMATIONS_SELECT "Select the animation to edit.\nYou can also click the name to edit it."
#define STRING_IMGUI_TOOLTIP_ANIMATIONS_SET_AS_DEFAULT "Sets the selected animation as the default.\nDefault animations are marked with \"(*)\"."
#define STRING_IMGUI_TOOLTIP_EVENTS_SELECT "Set the event for the trigger, or rename it."
#define STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_AXIS "Toggles the display of the X/Y axes."
#define STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_AXIS_COLOR "Changes the color of the X/Y axes."
#define STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_BACKGROUND_COLOR "Changes the background color of the animation preview."
#define STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_CENTER_VIEW "Centers the preview's pan."
#define STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_GRID "Toggles grid visibility on the animation preview."
#define STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_GRID_SIZE "Changes the grid's size, in pixels."
#define STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_GRID_COLOR "Changes the animation preview grid color."
#define STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_ZOOM "Changes the animation preview zoom level."
#define STRING_IMGUI_TOOLTIP_EVENTS_ADD "Add a new event."
#define STRING_IMGUI_TOOLTIP_EVENTS_REMOVE "Removes the selected event."
#define STRING_IMGUI_TOOLTIP_SPRITESHEETS_ADD "Opens the file dialog to load in a new sprite."
#define STRING_IMGUI_TOOLTIP_SPRITESHEETS_REMOVE "Removes the selected spritesheet."
#define STRING_IMGUI_TOOLTIP_SPRITESHEETS_RELOAD "Reloads the selected spritesheet."
#define STRING_IMGUI_TOOLTIP_SPRITESHEETS_REPLACE "Replaces the selected spritesheet; opens up the file dialog."
#define STRING_IMGUI_TOOLTIP_PROPERTIES_FPS "Change the FPS of the animation."
#define STRING_IMGUI_TOOLTIP_PROPERTIES_CREATED_BY "Change the author of the animation."
#define STRING_IMGUI_TOOLTIP_PROPERTIES_CREATED_ON_NOW "Set the date of creation to the current system time."
#define STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_POSITION "Change the position of the frame."
#define STRING_IMGUI_TOOLTIP_EVENTS_SELECT "Set the event for the trigger, or rename it."
#define STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_COLOR_OFFSET "Change the color offset of the frame."
#define STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_CROP_POSITION "Change the crop position of the frame."
#define STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_CROP_SIZE "Change the crop size of the frame."
#define STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_PIVOT "Change the pivot of the frame."
#define STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_SCALE "Change the scale of the frame."
#define STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_ROTATION "Change the rotation of the frame."
#define STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_DURATION "Change the duration of the frame."
#define STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_TINT "Change the tint of the frame."
#define STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_COLOR_OFFSET "Change the color offset of the frame."
#define STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_VISIBLE "Toggles the visibility of the frame."
#define STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_INTERPOLATED "Toggles the interpolation of the frame.\nBetween keyframes, will transform the values in the in-betweens to be smooth."
#define STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_PIVOT "Change the pivot of the frame."
#define STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_POSITION "Change the position of the frame."
#define STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_ROTATION "Change the rotation of the frame."
#define STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_SCALE "Change the scale of the frame."
#define STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_TINT "Change the tint of the frame."
#define STRING_IMGUI_TOOLTIP_FRAME_PROPERTIES_VISIBLE "Toggles the visibility of the frame."
#define STRING_IMGUI_TOOLTIP_PROPERTIES_CREATED_BY "Change the author of the animation."
#define STRING_IMGUI_TOOLTIP_PROPERTIES_CREATED_ON_NOW "Set the date of creation to the current system time."
#define STRING_IMGUI_TOOLTIP_PROPERTIES_FPS "Change the FPS of the animation."
#define STRING_IMGUI_TOOLTIP_SPRITESHEETS_ADD "Opens the file dialog to load in a new spritesheet."
#define STRING_IMGUI_TOOLTIP_SPRITESHEETS_RELOAD "Reloads the selected spritesheet."
#define STRING_IMGUI_TOOLTIP_SPRITESHEETS_REMOVE "Removes the selected spritesheet."
#define STRING_IMGUI_TOOLTIP_SPRITESHEETS_REPLACE "Replaces the selected spritesheet; opens up the file dialog."
#define STRING_IMGUI_TOOLTIP_SPRITESHEETS_SELECT "Select the spritesheet element."
#define STRING_IMGUI_TOOLTIP_TIMELINE_ANIMATION_LENGTH "Changes the current animation's length."
#define STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_ADD "Add a layer or null timeline element."
#define STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_NAME "Click to rename the element."
#define STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_SPRITESHEET "Click to change the spritesheet the layer is using."
#define STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_REMOVE "Remove a timeline element."
#define STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_SHIFT_UP "Shift this timeline element above.\nElements with higher indices will display further behind."
#define STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_SHIFT_DOWN "Shift this timeline element below.\nElements with lower indices will display further in front."
#define STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_VISIBLE "Toggle visibility for this element."
#define STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_RECT "Toggle visibility for a rectangle around the null."
#define STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_ROOT "This is the Root element."
#define STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_LAYER "This is a Layer element.\nThese are the main graphical animation elements.\nClick to rename."
#define STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_NAME "Click to rename the element."
#define STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_NULL "This is a Null element.\nThese are invisible elements where a game engine may have access to them for additional effects.\nClick to rename."
#define STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_RECT "Toggle visibility for a rectangle around the null."
#define STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_REMOVE "Remove a timeline element."
#define STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_ROOT "This is the Root element."
#define STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_SHIFT_DOWN "Shift this timeline element below.\nElements with lower indices will display further in front."
#define STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_SHIFT_UP "Shift this timeline element above.\nElements with higher indices will display further behind."
#define STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_SPRITESHEET "Click to change the spritesheet the layer is using."
#define STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_TRIGGERS "This is the animation's Triggers.\nTriggers are special activations; each is bound to an Event."
#define STRING_IMGUI_TOOLTIP_TIMELINE_PLAY "Plays the animation."
#define STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_VISIBLE "Toggle visibility for this element."
#define STRING_IMGUI_TOOLTIP_TIMELINE_FRAME_ADD "Add a frame to the current selected element."
#define STRING_IMGUI_TOOLTIP_TIMELINE_FRAME_REMOVE "Removes the selected frame from the current selected element."
#define STRING_IMGUI_TOOLTIP_TIMELINE_PAUSE "Pauses the animation."
#define STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_GRID "Toggles grid visibility on the animation preview."
#define STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_GRID_COLOR "Changes the animation preview grid color."
#define STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_GRID_SIZE "Changes the animation preview grid size (number of rows/columns)."
#define STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_ZOOM "Changes the animation preview zoom level."
#define STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_BACKGROUND_COLOR "Changes the background color of the animation preview."
#define STRING_IMGUI_TOOLTIP_TIMELINE_PLAY "Plays the animation."
#define STRING_OPENGL_VERSION "#version 330"
#define SHADER_VERTEX "#version 330 core\n" \
"in vec2 l_position;\n" \
"in vec2 l_uv;\n" \
"\n" \
"uniform mat3 u_view;\n" \
"uniform mat3 u_projection;\n" \
"uniform mat3 u_model;\n" \
"\n" \
"out vec2 o_uv;\n" \
"\n" \
"void main()\n" \
"{\n" \
" gl_Position = vec4(u_projection * u_view * u_model * vec3(l_position, 1.0), 1.0);\n" \
" o_uv = l_uv;\n" \
"}"
#define SHADER_FRAGMENT "#version 330 core\n" \
"uniform vec4 u_tint;\n" \
"uniform vec4 u_color_offset;\n" \
"uniform sampler2D u_texture;\n" \
"\n" \
"in vec2 i_uv;\n" \
"\n" \
"out vec4 FragColor;\n" \
"\n" \
"void main()\n" \
"{\n" \
" FragColor = texture(u_texture, i_uv) * u_tint;\n" \
" FragColor.rgb += u_color_offset.rgb;\n" \
"\n" \
" if (FragColor.a == 0.0) discard;\n" \
"}\n"
#define STRING_OPENGL_VERSION "#version 330"

View File

@ -37,6 +37,7 @@ anm2_serialize(Anm2* self, const char* path)
if (!self || !path)
return false;
/* Update creation date on first version */
if (self->version == 0)
anm2_created_on_set(self);
@ -308,6 +309,8 @@ anm2_serialize(Anm2* self, const char* path)
return false;
}
working_directory_from_path_set(path);
printf(STRING_INFO_ANM2_WRITE, path);
strncpy(self->path, path, PATH_MAX - 1);
@ -316,7 +319,7 @@ anm2_serialize(Anm2* self, const char* path)
/* Loads the .anm2 file and deserializes it into the struct equivalent */
bool
anm2_deserialize(Anm2* self, const char* path)
anm2_deserialize(Anm2* self, Resources* resources, const char* path)
{
XMLDocument document;
XMLError error;
@ -349,6 +352,7 @@ anm2_deserialize(Anm2* self, const char* path)
return false;
}
resources_loaded_textures_free(resources);
strncpy(self->path, path, PATH_MAX - 1);
root = document.FirstChildElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_ANIMATED_ACTOR]);
@ -422,7 +426,6 @@ anm2_deserialize(Anm2* self, const char* path)
break;
}
/* Attributes */
attribute = element->FirstAttribute();
@ -469,7 +472,8 @@ anm2_deserialize(Anm2* self, const char* path)
}
break;
case ANM2_ATTRIBUTE_PATH:
strncpy(lastSpritesheet->path, attribute->Value(), ANM2_STRING_MAX - 1);
strncpy(lastSpritesheet->path, attribute->Value(), PATH_MAX - 1);
anm2_spritesheet_texture_load(self, resources, attribute->Value(), id);
break;
case ANM2_ATTRIBUTE_NAME:
switch (anm2Element)
@ -638,6 +642,8 @@ anm2_deserialize(Anm2* self, const char* path)
}
}
working_directory_from_path_set(path);
printf(STRING_INFO_ANM2_READ, path);
return true;
@ -719,4 +725,17 @@ anm2_new(Anm2* self)
{
*self = Anm2{};
anm2_created_on_set(self);
}
void
anm2_spritesheet_texture_load(Anm2* self, Resources* resources, const char* path, s32 id)
{
Texture texture;
/* free texture if it exists */
if (resources->loadedTextures.find(id) != resources->loadedTextures.end())
texture_free(&resources->loadedTextures[id]);
texture_from_path_init(&texture, path);
resources->loadedTextures[id] = texture;
}

View File

@ -1,12 +1,14 @@
#pragma once
#include "COMMON.h"
#include "resources.h"
#define ANM2_SCALE_CONVERT(x) ((f32)x / 100.0f)
#define ANM2_TINT_CONVERT(x) ((f32)x / 255.0f)
#define ANM2_STRING_MAX 0xFF
#define ANM2_STRING_FORMATTED_MAX 0xFFF
#define ANM2_PATH_FORMATTED_MAX PATH_MAX + 0xFF
#define ANM2_BUFFER_MAX 0xFFFFF
#define ANM2_FPS_MIN 0
#define ANM2_FPS_DEFAULT 30
@ -117,7 +119,7 @@ enum Anm2AnimationType
struct Anm2Spritesheet
{
char path[ANM2_STRING_MAX] = STRING_EMPTY;
char path[PATH_MAX] = STRING_EMPTY;
};
struct Anm2Layer
@ -213,8 +215,9 @@ void anm2_layer_remove(Anm2* self, s32 id);
void anm2_null_add(Anm2* self);
void anm2_null_remove(Anm2* self, s32 id);
bool anm2_serialize(Anm2* self, const char* path);
bool anm2_deserialize(Anm2* self, const char* path);
bool anm2_deserialize(Anm2* self, Resources* resources, const char* path);
void anm2_new(Anm2* self);
void anm2_created_on_set(Anm2* self);
s32 anm2_animation_add(Anm2* self);
void anm2_animation_remove(Anm2* self, s32 id);
void anm2_animation_remove(Anm2* self, s32 id);
void anm2_spritesheet_texture_load(Anm2* self, Resources* resources, const char* path, s32 id);

View File

@ -19,11 +19,18 @@ _dialog_callback(void* userdata, const char* const* filelist, s32 filter)
}
void
dialog_init(Dialog* self, Anm2* anm2, Resources* resources)
{
self->anm2 = anm2;
self->resources = resources;
}
/* Opens file dialog for user to pick anm2 files */
void
dialog_anm2_open(Dialog* self)
{
SDL_ShowOpenFileDialog(_dialog_callback, self, NULL, ANM2_DIALOG_FILE_FILTER, 1, NULL, false);
SDL_ShowOpenFileDialog(_dialog_callback, self, NULL, DIALOG_FILE_FILTER_ANM2, 1, NULL, false);
self->type = DIALOG_ANM2_OPEN;
}
@ -31,22 +38,60 @@ dialog_anm2_open(Dialog* self)
void
dialog_anm2_save(Dialog* self)
{
SDL_ShowSaveFileDialog(_dialog_callback, self, NULL, ANM2_DIALOG_FILE_FILTER, 1, NULL);
SDL_ShowSaveFileDialog(_dialog_callback, self, NULL, DIALOG_FILE_FILTER_ANM2, 1, NULL);
self->type = DIALOG_ANM2_SAVE;
}
/* Opens file dialog for user to pick png files for spritesheets */
void
dialog_png_open(Dialog* self)
{
SDL_ShowOpenFileDialog(_dialog_callback, self, NULL, DIALOG_FILE_FILTER_PNG, 1, NULL, false);
self->type = DIALOG_PNG_OPEN;
}
/* Opens file dialog for user to pick png file to replace selected one */
void
dialog_png_replace(Dialog* self)
{
SDL_ShowOpenFileDialog(_dialog_callback, self, NULL, DIALOG_FILE_FILTER_PNG, 1, NULL, false);
self->type = DIALOG_PNG_REPLACE;
}
void
dialog_tick(Dialog* self)
{
if (self->isSelected)
{
Texture texture;
s32 id;
char relativePath[PATH_MAX];
/* Get the relative path */
std::filesystem::path baseDirectory = std::filesystem::current_path();
std::filesystem::path relativePathString = std::filesystem::relative(self->path, baseDirectory);
strncpy(relativePath, relativePathString.c_str(), PATH_MAX - 1);
switch (self->type)
{
case DIALOG_ANM2_OPEN:
anm2_deserialize(self->anm2, self->path);
anm2_deserialize(self->anm2, self->resources, relativePath);
resources_loaded_textures_free(self->resources);
break;
case DIALOG_ANM2_SAVE:
anm2_serialize(self->anm2, self->path);
anm2_serialize(self->anm2, relativePath);
break;
case DIALOG_PNG_OPEN:
id = map_next_id_get(self->resources->loadedTextures);
self->anm2->spritesheets[id] = Anm2Spritesheet{};
strncpy(self->anm2->spritesheets[id].path, relativePath, PATH_MAX);
anm2_spritesheet_texture_load(self->anm2, self->resources, relativePath, id);
break;
case DIALOG_PNG_REPLACE:
strncpy(self->anm2->spritesheets[self->replaceID].path, relativePath, PATH_MAX);
anm2_spritesheet_texture_load(self->anm2, self->resources, relativePath, self->replaceID);
self->replaceID = -1;
break;
default:
break;

View File

@ -1,26 +1,40 @@
#pragma once
#include "anm2.h"
#include "resources.h"
static const SDL_DialogFileFilter ANM2_DIALOG_FILE_FILTER[] =
static const SDL_DialogFileFilter DIALOG_FILE_FILTER_ANM2[] =
{
{"Anm2", "anm2;xml"}
};
static const SDL_DialogFileFilter DIALOG_FILE_FILTER_PNG[] =
{
{"png", "png"}
};
enum DialogType
{
DIALOG_NONE,
DIALOG_ANM2_OPEN,
DIALOG_ANM2_SAVE
DIALOG_ANM2_SAVE,
DIALOG_PNG_OPEN,
DIALOG_PNG_REPLACE
};
struct Dialog
{
Anm2* anm2 = NULL;
enum DialogType type = DIALOG_ANM2_OPEN;
Resources* resources = NULL;
s32 replaceID = -1;
enum DialogType type = DIALOG_NONE;
char path[PATH_MAX] = "";
bool isSelected = false;
};
void dialog_init(Dialog* self, Anm2* anm2, Resources* resources);
void dialog_anm2_open(Dialog* self);
void dialog_png_open(Dialog* self);
void dialog_png_replace(Dialog* self);
void dialog_anm2_save(Dialog* self);
void dialog_tick(Dialog* self);

View File

@ -1,7 +1,19 @@
#include "imgui.h"
static void _imgui_tooltip(const char* tooltip);
static void _imgui_timeline_element(Imgui* self, void* element, s32* id, s32* index, Anm2AnimationType type, Anm2AnimationType* selectType, s32* selectID);
static void
_imgui_timeline_element
(
Imgui* self,
Anm2Animation* animation,
void* element,
s32* id,
s32* index,
Anm2AnimationType type,
Anm2AnimationType* selectType,
s32* selectID
);
/* Makes a tooltip! */
static void _imgui_tooltip(const char* tooltip)
@ -12,17 +24,32 @@ static void _imgui_tooltip(const char* tooltip)
/* Displays each element of the timeline of a selected animation */
static void
_imgui_timeline_element(Imgui* self, void* element, s32* id, s32* index, Anm2AnimationType type, Anm2AnimationType* selectType, s32* selectID)
_imgui_timeline_element
(
Imgui* self,
Anm2Animation* animation,
void* element,
s32* id,
s32* index,
Anm2AnimationType type,
Anm2AnimationType* selectType,
s32* selectID
)
{
static s32 selectedElementIndex = -1;
static s32 selectedSpritesheetIndex = -1;
void* frames = NULL;
Anm2Layer* layer = NULL;
Anm2LayerAnimation* layerAnimation = NULL;
Anm2Null* null = NULL;
Anm2NullAnimation* nullAnimation = NULL;
Anm2RootAnimation* rootAnimation = NULL;
Anm2Triggers* triggers = NULL;
ImVec2 frameListSize = {IMGUI_TIMELINE_FRAME_SIZE.x * animation->frameNum, IMGUI_TIMELINE_ELEMENTS_TIMELINE_SIZE.y};
ImTextureID iconTexture = -1;
ImGuiWindowFlags windowFlags = 0 |
ImGuiWindowFlags_NoScrollbar |
ImGuiWindowFlags_NoScrollWithMouse;
bool isArrows = false;
bool* isShowRect = NULL;
@ -38,33 +65,37 @@ _imgui_timeline_element(Imgui* self, void* element, s32* id, s32* index, Anm2Ani
{
case ANM2_ROOT_ANIMATION:
rootAnimation = (Anm2RootAnimation*)element;
iconTexture = self->packed->textures[PACKED_TEXTURE_ROOT].handle;
iconTexture = self->resources->textures[TEXTURE_ROOT].handle;
strncpy(nameVisible, STRING_IMGUI_TIMELINE_ROOT, ANM2_STRING_FORMATTED_MAX);
isVisible = &rootAnimation->isVisible;
frames = &rootAnimation->frames;
break;
case ANM2_LAYER_ANIMATION:
layerAnimation = (Anm2LayerAnimation*)element;
layer = &self->anm2->layers[*id];
iconTexture = self->packed->textures[PACKED_TEXTURE_LAYER].handle;
iconTexture = self->resources->textures[TEXTURE_LAYER].handle;
isVisible = &layerAnimation->isVisible;
spritesheetID = &layer->spritesheetID;
namePointer = layer->name;
frames = &layerAnimation->frames;
snprintf(nameBuffer, ANM2_STRING_MAX, "%s", namePointer);
snprintf(nameVisible, ANM2_STRING_FORMATTED_MAX, STRING_IMGUI_TIMELINE_ELEMENT_FORMAT, *id, namePointer);
break;
case ANM2_NULL_ANIMATION:
nullAnimation = (Anm2NullAnimation*)element;
null = &self->anm2->nulls[*id];
iconTexture = self->packed->textures[PACKED_TEXTURE_NULL].handle;
iconTexture = self->resources->textures[TEXTURE_NULL].handle;
isVisible = &nullAnimation->isVisible;
isShowRect = &null->isShowRect;
namePointer = null->name;
frames = &nullAnimation->frames;
snprintf(nameBuffer, ANM2_STRING_MAX, "%s", namePointer);
snprintf(nameVisible, ANM2_STRING_FORMATTED_MAX, STRING_IMGUI_TIMELINE_ELEMENT_FORMAT, *id, namePointer);
break;
case ANM2_TRIGGERS:
triggers = (Anm2Triggers*)element;
iconTexture = self->packed->textures[PACKED_TEXTURE_TRIGGER].handle;
frames = &triggers->items;
iconTexture = self->resources->textures[TEXTURE_TRIGGER].handle;
strncpy(nameVisible, STRING_IMGUI_TIMELINE_TRIGGERS, ANM2_STRING_FORMATTED_MAX);
isVisible = &triggers->isVisible;
break;
@ -72,7 +103,7 @@ _imgui_timeline_element(Imgui* self, void* element, s32* id, s32* index, Anm2Ani
break;
}
ImGui::BeginChild(nameVisible, IMGUI_TIMELINE_ELEMENT_SIZE, true, ImGuiWindowFlags_NoScrollbar);
ImGui::BeginChild(nameVisible, IMGUI_TIMELINE_ELEMENT_SIZE, true, windowFlags);
ImGui::PushID(*index);
@ -95,7 +126,7 @@ _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->packed->textures[PACKED_TEXTURE_ARROW_UP].handle, IMGUI_ICON_SIZE))
if (target != map.end() && ImGui::ImageButton(STRING_IMGUI_TIMELINE_ELEMENT_SHIFT_ABOVE, self->resources->textures[TEXTURE_ARROW_UP].handle, IMGUI_ICON_SIZE))
{
map_swap(map, it->first, target->first);
*didSwap = true;
@ -107,11 +138,14 @@ _imgui_timeline_element(Imgui* self, void* element, s32* id, s32* index, Anm2Ani
if (canMoveDown)
{
if (!canMoveUp)
ImGui::Dummy(IMGUI_ICON_BUTTON_SIZE);
ImGui::SameLine();
auto target = isReversed ? std::prev(it) : std::next(it);
if (target != map.end() && ImGui::ImageButton(STRING_IMGUI_TIMELINE_ELEMENT_SHIFT_BELOW, self->packed->textures[PACKED_TEXTURE_ARROW_DOWN].handle, IMGUI_ICON_SIZE))
if (target != map.end() && ImGui::ImageButton(STRING_IMGUI_TIMELINE_ELEMENT_SHIFT_BELOW, self->resources->textures[TEXTURE_ARROW_DOWN].handle, IMGUI_ICON_SIZE))
{
map_swap(map, it->first, target->first);
*didSwap = true;
@ -176,7 +210,7 @@ _imgui_timeline_element(Imgui* self, void* element, s32* id, s32* index, Anm2Ani
}
}
switch (type)
{
case ANM2_ROOT_ANIMATION:
@ -200,18 +234,22 @@ _imgui_timeline_element(Imgui* self, void* element, s32* id, s32* index, Anm2Ani
/* Visiblity */
if (isVisible)
{
ImVec2 cursorPos;
ImTextureID visibilityIcon = *isVisible
? self->packed->textures[PACKED_TEXTURE_EYE_OPEN].handle
: self->packed->textures[PACKED_TEXTURE_EYE_CLOSED].handle;
? self->resources->textures[TEXTURE_EYE_OPEN].handle
: self->resources->textures[TEXTURE_EYE_CLOSED].handle;
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - IMGUI_ICON_BUTTON_SIZE.x - ImGui::GetStyle().FramePadding.x * 2);
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))
*isVisible = !*isVisible;
_imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_VISIBLE);
ImGui::SetCursorPos(cursorPos);
}
/* Spritesheet IDs */
@ -224,14 +262,14 @@ _imgui_timeline_element(Imgui* self, void* element, s32* id, s32* index, Anm2Ani
else
snprintf(spritesheetIDName, ANM2_STRING_FORMATTED_MAX, STRING_IMGUI_TIMELINE_SPRITESHEET_FORMAT, *spritesheetID);
ImGui::Image(self->packed->textures[PACKED_TEXTURE_SPRITESHEET].handle, IMGUI_ICON_SIZE);
ImGui::Image(self->resources->textures[TEXTURE_SPRITESHEET].handle, IMGUI_ICON_SIZE);
ImGui::SameLine();
ImGui::BeginChild(STRING_IMGUI_TIMELINE_ELEMENT_SPRITESHEET_ID_LABEL, IMGUI_TIMELINE_SPRITESHEET_ID_SIZE);
if (selectedSpritesheetIndex == *index)
{
if (ImGui::DragInt(STRING_IMGUI_TIMELINE_ELEMENT_SPRITESHEET_ID_LABEL, spritesheetID, 0, 1, self->anm2->spritesheets.size() - 1))
if (ImGui::InputInt(STRING_IMGUI_TIMELINE_ELEMENT_SPRITESHEET_ID_LABEL, spritesheetID, 0, 0, ImGuiInputTextFlags_None))
selectedSpritesheetIndex = -1;
}
else
@ -249,10 +287,10 @@ _imgui_timeline_element(Imgui* self, void* element, s32* id, s32* index, Anm2Ani
if (isShowRect)
{
ImTextureID rectIcon = *isShowRect
? self->packed->textures[PACKED_TEXTURE_RECT_HIDE].handle
: self->packed->textures[PACKED_TEXTURE_RECT_SHOW].handle;
? self->resources->textures[TEXTURE_RECT_HIDE].handle
: self->resources->textures[TEXTURE_RECT_SHOW].handle;
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - IMGUI_ICON_BUTTON_SIZE.x - ImGui::GetStyle().FramePadding.x * 2);
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))
*isShowRect = !*isShowRect;
@ -265,25 +303,69 @@ _imgui_timeline_element(Imgui* self, void* element, s32* id, s32* index, Anm2Ani
selectedElementIndex = -1;
selectedSpritesheetIndex = -1;
}
ImGui::PopID();
ImGui::EndGroup();
ImGui::PopID();
ImGui::EndChild();
if (animation->frameNum > 0)
{
ImGui::SameLine();
ImGui::PushID(*index);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
ImGui::BeginChild(STRING_IMGUI_TIMELINE_ELEMENT_TIMELINE, frameListSize, true);
for (s32 i = 0; i < animation->frameNum; i++)
{
ImGui::PushID(i);
if (ImGui::Button(" ", IMGUI_TIMELINE_FRAME_SIZE))
{
}
ImGui::SameLine(0.0f, 0.0f);
ImGui::PopID();
}
ImGui::EndChild();
ImGui::PopStyleVar();
ImGui::PopID();
}
*index = *index + 1;
}
void
imgui_init(SDL_Window* window, SDL_GLContext glContext)
imgui_init
(
Imgui* self,
Dialog* dialog,
Resources* resources,
Input* input,
Anm2* anm2,
Preview* preview,
SDL_Window* window,
SDL_GLContext* glContext
)
{
IMGUI_CHECKVERSION();
self->dialog = dialog;
self->resources = resources;
self->input = input;
self->anm2 = anm2;
self->preview = preview;
self->window = window;
self->glContext = glContext;
ImGui::CreateContext();
ImGui::StyleColorsDark();
ImGui_ImplSDL3_InitForOpenGL(window, glContext);
ImGui_ImplSDL3_InitForOpenGL(self->window, *self->glContext);
ImGui_ImplOpenGL3_Init(STRING_OPENGL_VERSION);
ImGuiIO& io = ImGui::GetIO();
@ -302,6 +384,10 @@ imgui_tick(Imgui* self)
static Anm2AnimationType selectedTimelineElementType = ANM2_NONE;
static bool isInterpolated = true;
static bool isVisible = true;
static bool isHoverPreview = false;
static ImRect previewWindowRect;
static ImVec2 settingsCursorPos;
static bool isFirstTick = true;
static f32 rotation = 0;
static s32 duration = 0;
@ -313,27 +399,15 @@ imgui_tick(Imgui* self)
static vec3 offset = {0.0f, 0.0f, 0.0f};
static vec4 tint = {0.0f, 0.0f, 0.0f, 1.0f};
ImVec2 previewWindowSize;
ImVec2 previewSize;
f32 previewAspect = 0.0f;
f32 previewWindowAspect = 0.0f;
ImGuiWindowFlags taskbarWindowFlags;
ImGuiWindowFlags dockspaceWindowFlags;
ImGuiDockNodeFlags dockNodeFlags;
ImGui_ImplSDL3_NewFrame();
ImGui_ImplOpenGL3_NewFrame();
ImGui::NewFrame();
taskbarWindowFlags = 0 |
ImGuiWindowFlags taskbarWindowFlags = 0 |
ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoResize |
ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoScrollbar |
ImGuiWindowFlags_NoScrollWithMouse |
ImGuiWindowFlags_NoSavedSettings;
dockspaceWindowFlags = 0 |
ImGuiWindowFlags dockspaceWindowFlags = 0 |
ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoResize |
@ -341,9 +415,23 @@ imgui_tick(Imgui* self)
ImGuiWindowFlags_NoBringToFrontOnFocus |
ImGuiWindowFlags_NoNavFocus;
dockNodeFlags = 0 |
ImGuiWindowFlags childWindowFlags = 0 |
ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoResize |
ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoBringToFrontOnFocus |
ImGuiWindowFlags_NoNavFocus |
ImGuiWindowFlags_NoScrollbar |
ImGuiWindowFlags_NoScrollWithMouse;
ImGuiDockNodeFlags dockNodeFlags = 0 |
ImGuiDockNodeFlags_PassthruCentralNode;
ImGui_ImplSDL3_NewFrame();
ImGui_ImplOpenGL3_NewFrame();
ImGui::NewFrame();
ImGuiViewport* viewport = ImGui::GetMainViewport();
/* Taskbar */
@ -457,7 +545,7 @@ imgui_tick(Imgui* self)
ImGui::PushID(id);
ImGui::Image(self->packed->textures[PACKED_TEXTURE_ANIMATION].handle, IMGUI_ICON_SIZE);
ImGui::Image(self->resources->textures[TEXTURE_ANIMATION].handle, IMGUI_ICON_SIZE);
ImGui::SameLine();
if (isSelected)
@ -545,7 +633,7 @@ imgui_tick(Imgui* self)
ImGui::PushID(id);
ImGui::Image(self->packed->textures[PACKED_TEXTURE_EVENT].handle, IMGUI_ICON_SIZE);
ImGui::Image(self->resources->textures[TEXTURE_EVENT].handle, IMGUI_ICON_SIZE);
ImGui::SameLine();
isSelected = selectedEventID == id;
@ -596,46 +684,70 @@ imgui_tick(Imgui* self)
for (auto [id, spritesheet] : self->anm2->spritesheets)
{
ImVec2 spritesheetPreviewSize = IMGUI_SPRITESHEET_PREVIEW_SIZE;
char spritesheetString[ANM2_STRING_FORMATTED_MAX];
bool isSelected = false;
snprintf(spritesheetString, ANM2_STRING_FORMATTED_MAX, STRING_IMGUI_SPRITESHEET_FORMAT, (s32)id, spritesheet.path);
f32 spritesheetAspect = (f32)self->resources->loadedTextures[id].size.x / self->resources->loadedTextures[id].size.y;
if ((IMGUI_SPRITESHEET_PREVIEW_SIZE.x / IMGUI_SPRITESHEET_PREVIEW_SIZE.y) > spritesheetAspect)
spritesheetPreviewSize.x = IMGUI_SPRITESHEET_PREVIEW_SIZE.y * spritesheetAspect;
else
spritesheetPreviewSize.y = IMGUI_SPRITESHEET_PREVIEW_SIZE.x / spritesheetAspect;
snprintf(spritesheetString, ANM2_PATH_FORMATTED_MAX, STRING_IMGUI_SPRITESHEET_FORMAT, (s32)id, spritesheet.path);
ImGui::BeginChild(spritesheetString, IMGUI_SPRITESHEET_SIZE, true, ImGuiWindowFlags_None);
ImGui::PushID(id);
ImGui::Image(self->packed->textures[PACKED_TEXTURE_SPRITESHEET].handle, IMGUI_ICON_SIZE);
ImGui::Image(self->resources->textures[TEXTURE_SPRITESHEET].handle, IMGUI_ICON_SIZE);
ImGui::SameLine();
isSelected = selectedSpritesheetID == id;
if (ImGui::Selectable(spritesheetString, isSelected))
selectedSpritesheetID = id;
_imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEETS_SELECT);
ImGui::Image(self->resources->loadedTextures[id].handle, spritesheetPreviewSize);
ImGui::PopID();
ImGui::EndChild();
}
ImGui::Button(STRING_IMGUI_SPRITESHEETS_ADD);
if (ImGui::Button(STRING_IMGUI_SPRITESHEETS_ADD))
dialog_png_open(self->dialog);
_imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEETS_ADD);
ImGui::SameLine();
if (selectedSpritesheetID != -1)
{
/* Remove */
if (ImGui::Button(STRING_IMGUI_SPRITESHEETS_REMOVE))
{
self->resources->loadedTextures.erase(selectedSpritesheetID);
self->anm2->spritesheets.erase(selectedSpritesheetID);
selectedSpritesheetID = -1;
}
_imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEETS_REMOVE);
ImGui::SameLine();
ImGui::Button(STRING_IMGUI_SPRITESHEETS_RELOAD);
/* Reload */
if (ImGui::Button(STRING_IMGUI_SPRITESHEETS_RELOAD))
anm2_spritesheet_texture_load(self->anm2, self->resources, self->anm2->spritesheets[selectedSpritesheetID].path, selectedSpritesheetID);
_imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEETS_RELOAD);
ImGui::SameLine();
ImGui::Button(STRING_IMGUI_SPRITESHEETS_REPLACE);
/* Replace */
if (ImGui::Button(STRING_IMGUI_SPRITESHEETS_REPLACE))
{
self->dialog->replaceID = selectedSpritesheetID;
dialog_png_replace(self->dialog);
}
_imgui_tooltip(STRING_IMGUI_TOOLTIP_SPRITESHEETS_REPLACE);
}
@ -686,14 +798,58 @@ imgui_tick(Imgui* self)
ImGui::End();
/* -- Animation Preview -- */
ImGui::Begin(STRING_IMGUI_ANIMATION_PREVIEW);
/* elements drawn out of order in order to get the size of the preview before how it visually appears */
settingsCursorPos = ImGui::GetCursorPos();
ImGui::SetCursorPos(IMGUI_ANIMATION_PREVIEW_POSITION);
ImGui::BeginChild(STRING_IMGUI_ANIMATION_PREVIEW_LABEL, ImVec2(0, 0), true, childWindowFlags);
previewWindowRect = ImGui::GetCurrentWindow()->ClipRect;
ImGui::Image(self->preview->texture, ImVec2(PREVIEW_SIZE.x, PREVIEW_SIZE.y));
/* Panning */
if (ImGui::IsItemHovered())
{
SDL_SetCursor(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_MOVE));
isHoverPreview = true;
if (mouse_held(&self->input->mouse, MOUSE_LEFT))
{
self->preview->pan.x += self->input->mouse.delta.x;
self->preview->pan.y -= self->input->mouse.delta.y;
}
self->preview->zoom = self->preview->zoom == PREVIEW_ZOOM_MIN ? 0 : self->preview->zoom;
if (self->input->mouse.wheelDeltaY > 0)
self->preview->zoom += PREVIEW_ZOOM_STEP;
if (self->input->mouse.wheelDeltaY < 0)
self->preview->zoom -= PREVIEW_ZOOM_STEP;
self->preview->zoom = CLAMP(self->preview->zoom, PREVIEW_ZOOM_MIN, PREVIEW_ZOOM_MAX);
}
else
{
if (isHoverPreview)
{
SDL_SetCursor(SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_DEFAULT));
isHoverPreview = false;
}
}
ImGui::EndChild();
ImGui::SetCursorPos(settingsCursorPos);
/* Settings */
ImGui::BeginChild(STRING_IMGUI_ANIMATION_PREVIEW_SETTINGS, IMGUI_ANIMATION_PREVIEW_SETTINGS_SIZE, true);
ImGui::BeginChild(STRING_IMGUI_ANIMATION_PREVIEW_SETTINGS, IMGUI_ANIMATION_PREVIEW_SETTINGS_SIZE, true, childWindowFlags);
/* Grid settings */
ImGui::BeginChild(STRING_IMGUI_ANIMATION_PREVIEW_GRID_SETTINGS, IMGUI_ANIMATION_PREVIEW_SETTINGS_GRID_SIZE, true);
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->preview->isGrid);
@ -715,32 +871,60 @@ imgui_tick(Imgui* self)
ImGui::SameLine();
/* Zoom settings */
ImGui::BeginChild(STRING_IMGUI_ANIMATION_PREVIEW_ZOOM_SETTINGS, IMGUI_ANIMATION_PREVIEW_SETTINGS_ZOOM_SIZE, true);
/* Helper settings */
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->preview->isAxis);
_imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_AXIS);
ImGui::SameLine();
/* Axis colors*/
ImGui::ColorEdit4(STRING_IMGUI_ANIMATION_PREVIEW_AXIS_COLOR, value_ptr(self->preview->axisColor), ImGuiColorEditFlags_NoInputs);
_imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_AXIS_COLOR);
ImGui::EndChild();
ImGui::SameLine();
/* View settings */
ImGui::BeginChild(STRING_IMGUI_ANIMATION_PREVIEW_VIEW_SETTINGS, IMGUI_ANIMATION_PREVIEW_SETTINGS_CHILD_SIZE, true);
/* Zoom */
ImGui::DragFloat(STRING_IMGUI_ANIMATION_PREVIEW_ZOOM, &self->preview->zoom, 1, PREVIEW_ZOOM_MIN, PREVIEW_ZOOM_MAX, "%.0f");
_imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_ZOOM);
/* Center view */
if (ImGui::Button(STRING_IMGUI_ANIMATION_PREVIEW_CENTER_VIEW) || isFirstTick)
{
ImVec2 previewWindowSize = previewWindowRect.GetSize();
previewWindowSize.x = MAX(previewWindowSize.x, PREVIEW_SIZE.x);
previewWindowSize.y = MAX(previewWindowSize.y, PREVIEW_SIZE.y);
/* Based on the preview's crop in its window, adjust the preview */
self->preview->pan.x = PREVIEW_CENTER.x + ((previewWindowSize.x - PREVIEW_SIZE.x) / 2);
self->preview->pan.y = PREVIEW_CENTER.y - ((previewWindowSize.y - PREVIEW_SIZE.y) / 2);
}
_imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_CENTER_VIEW);
ImGui::EndChild();
ImGui::SameLine();
/* Background settings */
ImGui::BeginChild(STRING_IMGUI_ANIMATION_PREVIEW_BACKGROUND_SETTINGS, IMGUI_ANIMATION_PREVIEW_SETTINGS_BACKGROUND_SIZE, true);
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, value_ptr(self->preview->color), ImGuiColorEditFlags_NoInputs);
ImGui::ColorEdit4(STRING_IMGUI_ANIMATION_PREVIEW_BACKGROUND_COLOR, value_ptr(self->preview->backgroundColor), ImGuiColorEditFlags_NoInputs);
_imgui_tooltip(STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_BACKGROUND_COLOR);
ImGui::EndChild();
ImGui::SameLine();
ImGui::EndChild();
ImGui::Image(self->preview->texture, ImVec2(PREVIEW_SIZE.x, PREVIEW_SIZE.y));
ImGui::End();
/* -- Spritesheet Editor -- */
@ -755,12 +939,31 @@ imgui_tick(Imgui* self)
if (selectedAnimationID != -1)
{
s32 index = 0;
ImVec2 timelineSize = IMGUI_TIMELINE_SIZE;
Anm2Animation* animation = &self->anm2->animations[selectedAnimationID];
ImGui::BeginChild(STRING_IMGUI_TIMELINE_ANIMATIONS, IMGUI_TIMELINE_ELEMENT_LIST_SIZE, true);
ImVec2 frameIndicesSize =
{IMGUI_TIMELINE_FRAME_SIZE.x * animation->frameNum, IMGUI_TIMELINE_FRAME_INDICES_SIZE.y};
timelineSize.y = ImGui::GetContentRegionAvail().y - IMGUI_TIMELINE_OFFSET_Y;
ImGui::BeginChild(STRING_IMGUI_TIMELINE_ANIMATIONS, timelineSize, true);
/* Element top bar */
ImGui::BeginChild(STRING_IMGUI_TIMELINE_ELEMENTS, IMGUI_TIMELINE_ELEMENTS_BAR_SIZE, true);
ImGui::Text(STRING_IMGUI_TIMELINE_ELEMENTS);
ImGui::EndChild();
/* Frame indicies */
if (animation->frameNum > 0)
{
ImGui::SameLine();
ImGui::BeginChild(STRING_IMGUI_TIMELINE_FRAME_INDICES, frameIndicesSize, true);
ImGui::EndChild();
}
/* Root */
_imgui_timeline_element(self, &animation->rootAnimation, NULL, &index, ANM2_ROOT_ANIMATION, NULL, NULL);
_imgui_timeline_element(self, animation, &animation->rootAnimation, NULL, &index, ANM2_ROOT_ANIMATION, NULL, NULL);
/* reverse order */
for (auto it = animation->layerAnimations.rbegin(); it != animation->layerAnimations.rend(); it++)
@ -768,21 +971,23 @@ imgui_tick(Imgui* self)
s32 id = it->first;
Anm2LayerAnimation& layer = it->second;
_imgui_timeline_element(self, &layer, &id, &index, ANM2_LAYER_ANIMATION, &selectedTimelineElementType, &selectedTimelineElementID);
_imgui_timeline_element(self, animation, &layer, &id, &index, ANM2_LAYER_ANIMATION, &selectedTimelineElementType, &selectedTimelineElementID);
}
for (auto & [id, null] : animation->nullAnimations)
_imgui_timeline_element(self, &null, (s32*)&id, &index, ANM2_NULL_ANIMATION, &selectedTimelineElementType, &selectedTimelineElementID);
_imgui_timeline_element(self, animation, &null, (s32*)&id, &index, ANM2_NULL_ANIMATION, &selectedTimelineElementType, &selectedTimelineElementID);
/* Triggers */
_imgui_timeline_element(self, &animation->triggers, NULL, &index, ANM2_TRIGGERS, NULL, NULL);
_imgui_timeline_element(self, animation, &animation->triggers, NULL, &index, ANM2_TRIGGERS, NULL, NULL);
ImGui::EndChild();
/* Element configuration */
if (ImGui::Button(STRING_IMGUI_TIMELINE_ELEMENT_ADD))
ImGui::OpenPopup(STRING_IMGUI_TIMELINE_ELEMENT_ADD_MENU);
_imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_ADD);
if (ImGui::BeginPopup(STRING_IMGUI_TIMELINE_ELEMENT_ADD_MENU))
{
if (ImGui::Selectable(STRING_IMGUI_TIMELINE_ELEMENT_ADD_MENU_LAYER))
@ -798,41 +1003,29 @@ imgui_tick(Imgui* self)
if
(
selectedTimelineElementID != -1 &&
((selectedTimelineElementType == ANM2_LAYER_ANIMATION) || (selectedTimelineElementType == ANM2_NULL_ANIMATION))
ImGui::Button(STRING_IMGUI_TIMELINE_ELEMENT_REMOVE) &&
selectedTimelineElementID != -1
)
{
if (ImGui::Button(STRING_IMGUI_TIMELINE_ELEMENT_REMOVE))
switch (selectedTimelineElementType)
{
switch (selectedTimelineElementType)
{
case ANM2_LAYER_ANIMATION:
anm2_layer_remove(self->anm2, selectedTimelineElementID);
break;
case ANM2_NULL_ANIMATION:
anm2_null_remove(self->anm2, selectedTimelineElementID);
break;
default:
break;
}
selectedTimelineElementID = -1;
selectedTimelineElementType = ANM2_NONE;
case ANM2_LAYER_ANIMATION:
anm2_layer_remove(self->anm2, selectedTimelineElementID);
break;
case ANM2_NULL_ANIMATION:
anm2_null_remove(self->anm2, selectedTimelineElementID);
break;
default:
break;
}
_imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_REMOVE);
}
else
{
selectedTimelineElementID = -1;
selectedTimelineElementType = ANM2_NONE;
}
ImGui::EndChild();
_imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_ELEMENT_REMOVE);
ImGui::SameLine();
/* Animation playback and frames */
static bool isPlaying = false;
if (isPlaying)
@ -853,10 +1046,9 @@ imgui_tick(Imgui* self)
_imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_PAUSE);
}
/*
ImGui::SameLine();
if (ImGui::Button(STRING_IMGUI_TIMELINE_ADD_FRAME))
if (ImGui::Button(STRING_IMGUI_TIMELINE_FRAME_ADD))
{
}
@ -864,15 +1056,24 @@ imgui_tick(Imgui* self)
ImGui::SameLine();
if (ImGui::Button(STRING_IMGUI_TIMELINE_REMOVE_FRAME))
if (ImGui::Button(STRING_IMGUI_TIMELINE_FRAME_REMOVE))
{
}
*/
_imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_FRAME_REMOVE);
ImGui::SameLine();
ImGui::PushItemWidth(IMGUI_TIMELINE_ANIMATION_LENGTH_WIDTH);
ImGui::InputInt(STRING_IMGUI_TIMELINE_ANIMATION_LENGTH, &animation->frameNum);
ImGui::PopItemWidth();
_imgui_tooltip(STRING_IMGUI_TOOLTIP_TIMELINE_ANIMATION_LENGTH);
}
ImGui::End();
if (isFirstTick)
isFirstTick = false;
}
void

View File

@ -1,9 +1,10 @@
#pragma once
#include "dialog.h"
#include "packed.h"
#include "resources.h"
#include "preview.h"
#include "window.h"
#include "input.h"
#define IMGUI_IMPL_OPENGL_LOADER_CUSTOM
#define IMGUI_ENABLE_DOCKING
@ -14,23 +15,32 @@
#define IMGUI_DRAG_SPEED 1.0
#define IMGUI_TASKBAR_HEIGHT 32
#define IMGUI_TIMELINE_OFFSET_Y 32
#define IMGUI_TIMELINE_ANIMATION_LENGTH_WIDTH 200
static const vec2 IMGUI_TASKBAR_MARGINS = {8, 4};
static const ImVec2 IMGUI_ANIMATION_PREVIEW_SETTINGS_SIZE = {1280, 64};
static const ImVec2 IMGUI_ANIMATION_PREVIEW_SETTINGS_GRID_SIZE = {150, 64};
static const ImVec2 IMGUI_ANIMATION_PREVIEW_SETTINGS_ZOOM_SIZE = {150, 64};
static const ImVec2 IMGUI_ANIMATION_PREVIEW_SETTINGS_BACKGROUND_SIZE = {150, 64};
static const ImVec2 IMGUI_ANIMATION_PREVIEW_SETTINGS_SIZE = {1280, 80};
static const ImVec2 IMGUI_ANIMATION_PREVIEW_SETTINGS_CHILD_SIZE = {150, 64};
static const ImVec2 IMGUI_ANIMATION_PREVIEW_POSITION = {8, 110};
static const ImVec2 IMGUI_TIMELINE_ELEMENT_LIST_SIZE = {260, 0};
static const ImVec2 IMGUI_TIMELINE_ELEMENT_SIZE = {230, 64};
static const ImVec2 IMGUI_TIMELINE_SPRITESHEET_ID_SIZE = {50, 20};
static const ImVec2 IMGUI_TIMELINE_SHIFT_ARROWS_SIZE = {24, 48};
static const ImVec2 IMGUI_TIMELINE_ELEMENT_NAME_SIZE = {125, 20};
static const ImVec2 IMGUI_TIMELINE_FRAME_SIZE = {20, 40};
static const ImVec2 IMGUI_TIMELINE_SIZE = {0, 0};
static const ImVec2 IMGUI_TIMELINE_ELEMENTS_BAR_SIZE = {300, 32};
static const ImVec2 IMGUI_TIMELINE_ELEMENTS_TIMELINE_SIZE = {0, 40};
static const ImVec2 IMGUI_TIMELINE_FRAME_INDICES_SIZE = {0, 32};
static const ImVec2 IMGUI_TIMELINE_ELEMENT_LIST_SIZE = {300, 0};
static const ImVec2 IMGUI_TIMELINE_ELEMENT_SIZE = {300, 40};
static const ImVec2 IMGUI_TIMELINE_SPRITESHEET_ID_SIZE = {40, 20};
static const ImVec2 IMGUI_TIMELINE_SHIFT_ARROWS_SIZE = {64, 40};
static const ImVec2 IMGUI_TIMELINE_ELEMENT_NAME_SIZE = {85, 20};
static const ImVec2 IMGUI_SPRITESHEET_SIZE = {0, 150};
static const ImVec2 IMGUI_SPRITESHEET_PREVIEW_SIZE = {100, 100};
static const ImVec2 IMGUI_ICON_SIZE = {16, 16};
static const ImVec2 IMGUI_ICON_BUTTON_SIZE = {22, 22};
static const ImVec2 IMGUI_ICON_DUMMY_SIZE = {20, 16};
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};
#define IMGUI_TIMELINE_SHIFT_ARROWS_WIDTH (IMGUI_TIMELINE_SHIFT_ARROWS_SIZE.x * 1.35)
@ -38,13 +48,26 @@ static const ImVec2 IMGUI_DUMMY_SIZE = {1, 1};
struct Imgui
{
Dialog* dialog = NULL;
Packed* packed = NULL;
Resources* resources = NULL;
Input* input = NULL;
Anm2* anm2 = NULL;
Preview* preview = NULL;
SDL_Window* window = NULL;
SDL_GLContext* glContext = NULL;
};
void imgui_init(SDL_Window* window, SDL_GLContext glContext);
void imgui_init
(
Imgui* self,
Dialog* dialog,
Resources* resources,
Input* input,
Anm2* anm2,
Preview* preview,
SDL_Window* window,
SDL_GLContext* glContext
);
void imgui_tick(Imgui* self);
void imgui_draw(Imgui* self);
void imgui_free(Imgui* self);

54
src/input.cpp Normal file
View File

@ -0,0 +1,54 @@
#include "input.h"
static void _mouse_tick(Mouse* self);
static void
_mouse_tick(Mouse* self)
{
s32 state;
SDL_Event event;
memcpy(&self->previous, &self->current, sizeof(bool) * MOUSE_COUNT);
memset(&self->current, '\0', sizeof(bool) * MOUSE_COUNT);
state = SDL_GetMouseState(NULL, NULL);
if (state & SDL_BUTTON_LMASK != 0)
{
self->current[MOUSE_LEFT] = true;
}
if (state & SDL_BUTTON_RMASK != 0)
{
self->current[MOUSE_RIGHT] = true;
}
SDL_GetMouseState(&self->position.x, &self->position.y);
self->delta = self->position - self->oldPosition;
self->oldPosition = self->position;
}
bool
mouse_press(Mouse* self, MouseType type)
{
return (self->current[type] && !self->previous[type]);
}
bool
mouse_held(Mouse* self, MouseType type)
{
return (self->current[type] && self->previous[type]);
}
bool
mouse_release(Mouse* self, MouseType type)
{
return (!self->current[type] && self->previous[type]);
}
void
input_tick(Input* self)
{
_mouse_tick(&self->mouse);
}

35
src/input.h Normal file
View File

@ -0,0 +1,35 @@
#pragma once
#include "COMMON.h"
#define MOUSE_COUNT (MOUSE_RIGHT + 1)
enum MouseType
{
MOUSE_LEFT,
MOUSE_RIGHT
};
enum InputType
{
INPUT_MOUSE_CLICK
};
struct Mouse
{
bool current[MOUSE_COUNT];
bool previous[MOUSE_COUNT];
vec2 position = {-1, -1};
vec2 oldPosition = {-1, -1};
vec2 delta = {-1, -1};
s32 wheelDeltaY = 0;
};
struct Input
{
Mouse mouse;
};
bool mouse_press(Mouse* self, MouseType type);
bool mouse_held(Mouse* self, MouseType type);
bool mouse_release(Mouse* self, MouseType type);
void input_tick(Input* self);

View File

@ -1,17 +0,0 @@
#include "packed.h"
/* Loads in packed data */
void
packed_init(Packed* self)
{
for (s32 i = 0; i < PACKED_TEXTURE_COUNT; i++)
texture_from_data_init(&self->textures[i], (u8*)PACKED_TEXTURE_DATA[i].data, PACKED_TEXTURE_DATA[i].length);
}
/* Frees packed data */
void
packed_free(Packed* self)
{
for (s32 i = 0; i < PACKED_TEXTURE_COUNT; i++)
texture_free(&self->textures[i]);
}

View File

@ -1,12 +0,0 @@
#pragma once
#include "PACKED.h"
#include "texture.h"
struct Packed
{
Texture textures[PACKED_TEXTURE_COUNT];
};
void packed_init(Packed* self);
void packed_free(Packed* self);

View File

@ -1,10 +1,69 @@
#include "preview.h"
static void _preview_axis_set(Preview* self);
static void _preview_grid_set(Preview* self);
/* Initializes the preview */
void
preview_init(Preview* self)
static void
_preview_axis_set(Preview* self)
{
glBindVertexArray(self->axisVAO);
glBindBuffer(GL_ARRAY_BUFFER, self->axisVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(PREVIEW_AXIS_VERTICES), PREVIEW_AXIS_VERTICES, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
glBindVertexArray(0);
}
static void
_preview_grid_set(Preview* self)
{
std::vector<f32> vertices;
s32 verticalLineCount = PREVIEW_SIZE.x / self->gridSize.x;
s32 horizontalLineCount = PREVIEW_SIZE.y / self->gridSize.y;
/* Vertical */
for (s32 i = 0; i <= verticalLineCount; i++)
{
s32 x = i * self->gridSize.x;
f32 normX = (2.0f * x) / PREVIEW_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->gridSize.y;
f32 normY = (2.0f * y) / PREVIEW_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(float), vertices.data(), GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(f32), (void*)0);
}
void
preview_init(Preview* self, Resources* resources, Input* input)
{
self->resources = resources;
self->input = input;
glGenFramebuffers(1, &self->fbo);
glBindFramebuffer(GL_FRAMEBUFFER, self->fbo);
@ -23,18 +82,98 @@ preview_init(Preview* self)
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, self->rbo);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glGenVertexArrays(1, &self->axisVAO);
glGenBuffers(1, &self->axisVBO);
glGenVertexArrays(1, &self->gridVAO);
glGenBuffers(1, &self->gridVBO);
_preview_axis_set(self);
_preview_grid_set(self);
}
void
preview_tick(Preview* self)
{
self->zoom = CLAMP(self->zoom, PREVIEW_ZOOM_MIN, PREVIEW_ZOOM_MAX);
self->oldGridSize = self->gridSize;
}
void
preview_draw(Preview* self)
{
GLuint shader = self->resources->shaders[SHADER];
float zoomFactor = self->zoom / 100.0f;
/* Convert pan to pixels */
glm::vec2 ndcPan = glm::vec2(
self->pan.x / (PREVIEW_SIZE.x / 2.0f),
-self->pan.y / (PREVIEW_SIZE.y / 2.0f)
);
/* Transformation matrix */
glm::mat4 transform = glm::translate(glm::mat4(1.0f), glm::vec3(ndcPan, 0.0f));
transform = glm::scale(transform, glm::vec3(zoomFactor, zoomFactor, 1.0f));
glBindFramebuffer(GL_FRAMEBUFFER, self->fbo);
glViewport(0, 0, PREVIEW_SIZE.x, PREVIEW_SIZE.y);
glClearColor(self->color.r, self->color.g, self->color.b, self->color.a);
glClearColor
(
self->backgroundColor.r,
self->backgroundColor.g,
self->backgroundColor.b,
self->backgroundColor.a
);
glClear(GL_COLOR_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, 0); // unbind
glUseProgram(shader);
glUniformMatrix4fv(glGetUniformLocation(shader, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, (f32*)value_ptr(transform));
if (self->isGrid)
{
if (self->gridSize != self->oldGridSize)
_preview_grid_set(self);
glBindVertexArray(self->gridVAO);
glUniform4f
(
glGetUniformLocation(shader, SHADER_UNIFORM_COLOR),
self->gridColor.r, self->gridColor.g, self->gridColor.b, self->gridColor.a
);
glDrawArrays(GL_LINES, 0, self->gridVertexCount);
glBindVertexArray(0);
}
if (self->isAxis)
{
glBindVertexArray(self->axisVAO);
/* Axes */
glUniform4f
(
glGetUniformLocation(shader, SHADER_UNIFORM_COLOR),
self->axisColor.r, self->axisColor.g, self->axisColor.b, self->axisColor.a
);
glDrawArrays(GL_LINES, 0, 2);
glUniform4f
(
glGetUniformLocation(shader, SHADER_UNIFORM_COLOR),
self->axisColor.r, self->axisColor.g, self->axisColor.b, self->axisColor.a
);
glDrawArrays(GL_LINES, 2, 2);
glBindVertexArray(0);
}
glUseProgram(0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void

View File

@ -1,26 +1,50 @@
#pragma once
#include "texture.h"
#include "resources.h"
#include "input.h"
static const ivec2 PREVIEW_SIZE = {1280, 720};
static const ivec2 PREVIEW_SIZE = {960, 720};
static const ivec2 PREVIEW_CENTER = {0, 0};
#define PREVIEW_ZOOM_MIN 0
#define PREVIEW_ZOOM_MIN 1
#define PREVIEW_ZOOM_MAX 400
#define PREVIEW_GRID_MIN 0
#define PREVIEW_GRID_MAX 20
#define PREVIEW_GRID_MIN 1
#define PREVIEW_GRID_MAX 50
#define PREVIEW_ZOOM_STEP 10
static const f32 PREVIEW_AXIS_VERTICES[] =
{
-1.0f, 0.0f,
1.0f, 0.0f,
0.0f, -1.0f,
0.0f, 1.0f
};
struct Preview
{
GLuint texture;
GLuint fbo;
GLuint rbo;
bool isGrid;
GLuint gridVAO;
GLuint gridVBO;
GLuint axisVAO;
GLuint axisVBO;
Input* input;
Resources* resources;
bool isGrid = false;
bool isAxis = true;
ivec2 viewport = PREVIEW_SIZE;
f32 zoom = 100;
vec2 pan = PREVIEW_CENTER;
ivec2 gridSize = {10, 10};
vec4 color = {0.69, 0.69, 0.69, 1.0f};
vec4 gridColor = {0.35, 0.35, 0.35, 1.0f};
ivec2 oldGridSize = {-1, -1};
s32 gridVertexCount = -1;
vec4 backgroundColor = {0.113, 0.184, 0.286, 1.0f};
vec4 gridColor = {1.0, 1.0, 1.0, 0.125f};
vec4 axisColor = {1.0, 1.0, 1.0, 0.5f};
};
void preview_init(Preview* self);
void preview_init(Preview* self, Resources* resources, Input* input);
void preview_draw(Preview* self);
void preview_tick(Preview* self);
void preview_free(Preview* self);

33
src/resources.cpp Normal file
View File

@ -0,0 +1,33 @@
#include "resources.h"
/* Loads in resources */
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);
for (s32 i = 0; i < SHADER_COUNT; i++)
shader_init(&self->shaders[i], SHADER_DATA[i].vertex, SHADER_DATA[i].fragment);
}
/* Frees resources*/
void
resources_free(Resources* self)
{
for (s32 i = 0; i < TEXTURE_COUNT; i++)
texture_free(&self->textures[i]);
for (s32 i = 0; i < SHADER_COUNT; i++)
shader_free(&self->shaders[i]);
resources_loaded_textures_free(self);
}
void
resources_loaded_textures_free(Resources* self)
{
for (auto & [id, texture] : self->loadedTextures)
texture_free(&self->textures[id]);
}

16
src/resources.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include "RESOURCES.h"
#include "texture.h"
#include "shader.h"
struct Resources
{
Texture textures[TEXTURE_COUNT];
GLuint shaders[SHADER_COUNT];
std::map<s32, Texture> loadedTextures;
};
void resources_init(Resources* self);
void resources_free(Resources* self);
void resources_loaded_textures_free(Resources* self);

View File

@ -1,24 +1,24 @@
#include "shader.h"
static bool _shader_compile(GLuint handle, const char* text);
static bool _shader_compile(GLuint* self, const char* text);
static bool
_shader_compile(GLuint handle, const char* text)
_shader_compile(GLuint* self, const char* text)
{
char compileLog[SHADER_BUFFER_MAX];
s32 isCompile;
const GLchar* source = text;
glShaderSource(handle, 1, &source, NULL);
glShaderSource(*self, 1, &source, NULL);
glCompileShader(handle);
glGetShaderiv(handle, GL_COMPILE_STATUS, &isCompile);
glCompileShader(*self);
glGetShaderiv(*self, GL_COMPILE_STATUS, &isCompile);
if (!isCompile)
{
glGetShaderInfoLog(handle, SHADER_BUFFER_MAX, NULL, compileLog);
printf(STRING_ERROR_SHADER_INIT, handle, compileLog);
glGetShaderInfoLog(*self, SHADER_BUFFER_MAX, NULL, compileLog);
printf(STRING_ERROR_SHADER_INIT, *self, compileLog);
return false;
}
@ -26,47 +26,39 @@ _shader_compile(GLuint handle, const char* text)
}
bool
shader_init(Shader* self, const char* vertex, const char* fragment)
shader_init(GLuint* self, const char* vertex, const char* fragment)
{
GLuint vertexHandle;
GLuint fragmentHandle;
bool isSuccess;
memset(self, '\0', sizeof(Shader));
vertexHandle = glCreateShader(GL_VERTEX_SHADER);
fragmentHandle = glCreateShader(GL_FRAGMENT_SHADER);
if
(
!_shader_compile(vertexHandle, vertex) ||
!_shader_compile(fragmentHandle, fragment)
!_shader_compile(&vertexHandle, vertex) ||
!_shader_compile(&fragmentHandle, fragment)
)
return false;
self->handle = glCreateProgram();
*self = glCreateProgram();
glAttachShader(self->handle, vertexHandle);
glAttachShader(self->handle, fragmentHandle);
glAttachShader(*self, vertexHandle);
glAttachShader(*self, fragmentHandle);
glLinkProgram(self->handle);
glLinkProgram(*self);
glDeleteShader(vertexHandle);
glDeleteShader(fragmentHandle);
printf(STRING_INFO_SHADER_INIT, self->handle);
printf(STRING_INFO_SHADER_INIT, *self);
return true;
}
void
shader_use(Shader* self)
shader_free(GLuint* self)
{
glUseProgram(self->handle);
}
void
shader_free(Shader* self)
{
glDeleteProgram(self->handle);
}
glDeleteProgram(*self);
}

View File

@ -4,11 +4,5 @@
#define SHADER_BUFFER_MAX 2048
struct Shader
{
GLuint handle = 0;
};
bool shader_init(Shader* self, const char* vertex, const char* fragment);
void shader_free(Shader* self);
void shader_use(Shader* self);
bool shader_init(GLuint* self, const char* vertex, const char* fragment);
void shader_free(GLuint* self);

View File

@ -7,15 +7,30 @@ static void
_tick(State* state)
{
SDL_Event event;
SDL_MouseWheelEvent* mouseWheelEvent;
state->input.mouse.wheelDeltaY = 0;
while(SDL_PollEvent(&event))
{
ImGui_ImplSDL3_ProcessEvent(&event);
ImGui_ImplSDL3_ProcessEvent(&event);
if (event.type == SDL_EVENT_QUIT)
state->isRunning = false;
switch (event.type)
{
case SDL_EVENT_QUIT:
state->isRunning = false;
break;
case SDL_EVENT_MOUSE_WHEEL:
mouseWheelEvent = &event.wheel;
state->input.mouse.wheelDeltaY = mouseWheelEvent->y;
break;
default:
break;
}
}
input_tick(&state->input);
preview_tick(&state->preview);
dialog_tick(&state->dialog);
imgui_tick(&state->imgui);
}
@ -32,8 +47,6 @@ _draw(State* state)
void
init(State* state)
{
Shader shader;
printf(STRING_INFO_INIT);
if (!SDL_Init(SDL_INIT_VIDEO))
@ -64,31 +77,34 @@ init(State* state)
glewInit();
preview_init(&state->preview);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
printf(STRING_INFO_GLEW_INIT);
packed_init(&state->packed);
resources_init(&state->resources);
dialog_init(&state->dialog, &state->anm2, &state->resources);
preview_init(&state->preview, &state->resources, &state->input);
if (state->isArgument)
anm2_deserialize(&state->anm2, state->argument);
anm2_deserialize(&state->anm2, &state->resources, state->argument);
else
anm2_new(&state->anm2);
window_title_from_anm2_set(state->window, &state->anm2);
state->imgui =
{
imgui_init
(
&state->imgui,
&state->dialog,
&state->packed,
&state->anm2,
&state->resources,
&state->input,
&state->anm2,
&state->preview,
state->window
};
imgui_init(state->window, state->glContext);
state->dialog.anm2 = &state->anm2;
state->window,
&state->glContext
);
}
void
@ -104,7 +120,6 @@ loop(State* state)
SDL_Delay(TICK_DELAY - (state->tick - state->lastTick));
_tick(state);
_draw(state);
state->lastTick = state->tick;
@ -116,13 +131,11 @@ quit(State* state)
{
imgui_free(&state->imgui);
preview_free(&state->preview);
packed_free(&state->packed);
resources_free(&state->resources);
SDL_GL_DestroyContext(state->glContext);
SDL_Quit();
printf(STRING_INFO_SDL_QUIT);
printf(STRING_INFO_QUIT);
}

View File

@ -14,10 +14,11 @@ struct State
SDL_Renderer* renderer;
SDL_GLContext glContext;
Imgui imgui;
Input input;
Dialog dialog;
Preview preview;
Anm2 anm2;
Packed packed;
Resources resources;
char argument[PATH_MAX] = STRING_EMPTY;
bool isArgument = false;
u64 tick = 0;

View File

@ -63,4 +63,4 @@ texture_free(Texture* self)
{
glDeleteTextures(1, &self->handle);
memset(self, '\0', sizeof(Texture));
}
}