it's kind of finished
This commit is contained in:
28
src/COMMON.h
28
src/COMMON.h
@@ -108,17 +108,35 @@ 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;
|
||||
}
|
||||
|
||||
/* Swaps elements in a map */
|
||||
/* If neither key exists, do nothing */
|
||||
/* If one key exists, change its ID */
|
||||
/* If both keys exist, swap */
|
||||
template<typename Map, typename Key>
|
||||
static inline void map_swap(Map& map, const Key& key1, const Key& key2)
|
||||
{
|
||||
if (key1 == key2)
|
||||
return;
|
||||
|
||||
auto it1 = map.find(key1);
|
||||
auto it2 = map.find(key2);
|
||||
if (it1 == map.end() || it2 == map.end())
|
||||
return;
|
||||
|
||||
using std::swap;
|
||||
swap(it1->second, it2->second);
|
||||
}
|
||||
if (it1 != map.end() && it2 != map.end())
|
||||
{
|
||||
using std::swap;
|
||||
swap(it1->second, it2->second);
|
||||
}
|
||||
else if (it1 != map.end())
|
||||
{
|
||||
map[key2] = std::move(it1->second);
|
||||
map.erase(it1);
|
||||
}
|
||||
else if (it2 != map.end())
|
||||
{
|
||||
map[key1] = std::move(it2->second);
|
||||
map.erase(it2);
|
||||
}
|
||||
};
|
||||
|
||||
#define DEFINE_ENUM_TO_STRING_FN(fn_name, arr, count) \
|
||||
static inline const char* fn_name(s32 index) { \
|
||||
|
@@ -62,13 +62,15 @@
|
||||
#define STRING_IMGUI_ANIMATIONS_REMOVE "Remove"
|
||||
#define STRING_IMGUI_ANIMATIONS_DUPLICATE "Duplicate"
|
||||
#define STRING_IMGUI_ANIMATIONS_SET_AS_DEFAULT "Set as Default"
|
||||
#define STRING_IMGUI_ANIMATIONS_DEFAULT_ANIMATION_FORMAT "%s (*)"
|
||||
#define STRING_IMGUI_ANIMATIONS_DEFAULT_ANIMATION_FORMAT "(*) %s "
|
||||
#define STRING_IMGUI_ANIMATIONS_DRAG_DROP "Animation Drag/Drop"
|
||||
|
||||
#define STRING_IMGUI_EVENTS "Events"
|
||||
#define STRING_IMGUI_EVENTS_EVENT_LABEL "##Event"
|
||||
#define STRING_IMGUI_EVENTS_ADD "Add"
|
||||
#define STRING_IMGUI_EVENTS_REMOVE "Remove"
|
||||
#define STRING_IMGUI_EVENT_FORMAT "#%i %s"
|
||||
#define STRING_IMGUI_EVENTS_DRAG_DROP "Event Drag/Drop"
|
||||
|
||||
#define STRING_IMGUI_SPRITESHEETS "Spritesheets"
|
||||
#define STRING_IMGUI_SPRITESHEETS_ADD "Add"
|
||||
@@ -76,6 +78,7 @@
|
||||
#define STRING_IMGUI_SPRITESHEETS_RELOAD "Reload"
|
||||
#define STRING_IMGUI_SPRITESHEETS_REPLACE "Replace"
|
||||
#define STRING_IMGUI_SPRITESHEET_FORMAT "#%i %s"
|
||||
#define STRING_IMGUI_SPRITESHEETS_DRAG_DROP "Spritesheet Drag/Drop"
|
||||
|
||||
#define STRING_IMGUI_FRAME_PROPERTIES "Frame Properties"
|
||||
#define STRING_IMGUI_FRAME_PROPERTIES_CROP_POSITION "Crop Position"
|
||||
@@ -116,12 +119,15 @@
|
||||
#define STRING_IMGUI_ANIMATION_PREVIEW_AXIS_COLOR "Color"
|
||||
#define STRING_IMGUI_ANIMATION_PREVIEW_ROOT_TRANSFORM "Root Transform"
|
||||
#define STRING_IMGUI_ANIMATION_PREVIEW_SHOW_PIVOT "Show Pivot"
|
||||
#define STRING_IMGUI_ANIMATION_PREVIEW_POSITION "##Position"
|
||||
#define STRING_IMGUI_ANIMATION_PREVIEW_POSITION_FORMAT "Position: {%5.0f, %5.0f}"
|
||||
|
||||
#define STRING_IMGUI_SPRITESHEET_EDITOR "Spritesheet Editor"
|
||||
#define STRING_IMGUI_SPRITESHEET_EDITOR_LABEL "##Animation Preview"
|
||||
#define STRING_IMGUI_SPRITESHEET_EDITOR_SETTINGS "##Animation Preview Settings"
|
||||
#define STRING_IMGUI_SPRITESHEET_EDITOR_GRID_SETTINGS "##Grid Settings"
|
||||
#define STRING_IMGUI_SPRITESHEET_EDITOR_GRID "Grid"
|
||||
#define STRING_IMGUI_SPRITESHEET_EDITOR_GRID_SNAP "Snap"
|
||||
#define STRING_IMGUI_SPRITESHEET_EDITOR_GRID_SIZE "Size"
|
||||
#define STRING_IMGUI_SPRITESHEET_EDITOR_GRID_OFFSET "Offset"
|
||||
#define STRING_IMGUI_SPRITESHEET_EDITOR_GRID_COLOR "Color"
|
||||
@@ -131,6 +137,8 @@
|
||||
#define STRING_IMGUI_SPRITESHEET_EDITOR_BACKGROUND_COLOR "Background Color"
|
||||
#define STRING_IMGUI_SPRITESHEET_EDITOR_CENTER_VIEW "Center View"
|
||||
#define STRING_IMGUI_SPRITESHEET_EDITOR_BORDER "Border"
|
||||
#define STRING_IMGUI_SPRITESHEET_EDITOR_POSITION "##Position"
|
||||
#define STRING_IMGUI_SPRITESHEET_EDITOR_POSITION_FORMAT "Position: {%5.0f, %5.0f}"
|
||||
|
||||
#define STRING_IMGUI_TIMELINE "Timeline"
|
||||
#define STRING_IMGUI_TIMELINE_HEADER "##Header"
|
||||
@@ -178,6 +186,8 @@
|
||||
#define STRING_IMGUI_TIMELINE_VIEWER "Viewer"
|
||||
#define STRING_IMGUI_TIMELINE_CHILD "Timeline"
|
||||
#define STRING_IMGUI_TIMELINE_MAIN "Main"
|
||||
#define STRING_IMGUI_TIMELINE_FRAME_DRAG_DROP "Frame Drag/Drop"
|
||||
#define STRING_IMGUI_TIMELINE_ITEM_DRAG_DROP "Item Drag/Drop"
|
||||
|
||||
#define STRING_IMGUI_TOOLS "Tools"
|
||||
#define STRING_IMGUI_TOOLS_PAN "##Pan"
|
||||
@@ -190,7 +200,7 @@
|
||||
#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_ANIMATIONS_SET_AS_DEFAULT "Sets the selected animation as the default.\nThe default animation is marked with \"(*)\"."
|
||||
#define STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_AXIS "Toggles the display of the X/Y axes on the animation preview."
|
||||
#define STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_AXIS_COLOR "Changes the color of the X/Y axes on the animation preview."
|
||||
#define STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_BACKGROUND_COLOR "Changes the background color of the animation preview."
|
||||
@@ -200,7 +210,7 @@
|
||||
#define STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_GRID_OFFSET "Changes the animation preview grid's offset, in pixels."
|
||||
#define STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_GRID_SIZE "Changes the animation preview grid's size, in pixels."
|
||||
#define STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_ZOOM "Changes the animation preview zoom level."
|
||||
#define STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_ROOT_TRANSFORM "Toggle the properties of the Root element of an animation being able to change the properties (such as position or scale) of all of the animation's elements."
|
||||
#define STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_ROOT_TRANSFORM "Toggle the properties of the Root element of an animation being able to change the properties (such as position or scale) of all of the animation's elements.\nNOTE: Scale/rotation currently not implemented. Matrix math is hard."
|
||||
#define STRING_IMGUI_TOOLTIP_ANIMATION_PREVIEW_SHOW_PIVOT "Toggle the pivots of layer animation elements being visible on the animation preview."
|
||||
#define STRING_IMGUI_TOOLTIP_EVENTS_ADD "Add a new event."
|
||||
#define STRING_IMGUI_TOOLTIP_EVENTS_REMOVE "Removes the selected event."
|
||||
@@ -251,16 +261,17 @@
|
||||
#define STRING_IMGUI_TOOLTIP_SPRITESHEET_EDITOR_BACKGROUND_COLOR "Changes the background color of the spritesheet editor."
|
||||
#define STRING_IMGUI_TOOLTIP_SPRITESHEET_EDITOR_CENTER_VIEW "Centers the spritesheet editor's pan."
|
||||
#define STRING_IMGUI_TOOLTIP_SPRITESHEET_EDITOR_GRID "Toggles grid visibility on the spritesheet editor."
|
||||
#define STRING_IMGUI_TOOLTIP_SPRITESHEET_EDITOR_GRID_SNAP "When using the crop tool, will snap points to the grid."
|
||||
#define STRING_IMGUI_TOOLTIP_SPRITESHEET_EDITOR_GRID_COLOR "Changes the spritesheet editor grid color."
|
||||
#define STRING_IMGUI_TOOLTIP_SPRITESHEET_EDITOR_GRID_OFFSET "Changes the spritesheet editor grid's offset, in pixels."
|
||||
#define STRING_IMGUI_TOOLTIP_SPRITESHEET_EDITOR_GRID_SIZE "Changes the spritesheet editor grid's size, in pixels."
|
||||
#define STRING_IMGUI_TOOLTIP_SPRITESHEET_EDITOR_ZOOM "Changes the spritesheet editor zoom level."
|
||||
#define STRING_IMGUI_TOOLTIP_SPRITESHEET_EDITOR_BORDER "Toggles a border appearing around the confines of the spritesheet."
|
||||
#define STRING_IMGUI_TOOLTIP_TOOLS_PAN "Use the pan tool.\nWill shift the view as the cursor is dragged."
|
||||
#define STRING_IMGUI_TOOLTIP_TOOLS_MOVE "Use the move tool.\nWill move selected elements as the cursor is dragged."
|
||||
#define STRING_IMGUI_TOOLTIP_TOOLS_ROTATE "Use the rotate tool.\nWill rotate selected elements as the cursor is dragged."
|
||||
#define STRING_IMGUI_TOOLTIP_TOOLS_SCALE "Use the scale tool.\nWill scale the selected elements as the cursor is dragged."
|
||||
#define STRING_IMGUI_TOOLTIP_TOOLS_CROP "Use the crop tool.\nWill set the crop of the selected elements as the cursor is dragged."
|
||||
#define STRING_IMGUI_TOOLTIP_TOOLS_MOVE "Use the move tool.\nWill move selected elements as the cursor is dragged.\n(Animation Preview only.)"
|
||||
#define STRING_IMGUI_TOOLTIP_TOOLS_ROTATE "Use the rotate tool.\nWill rotate selected elements as the cursor is dragged.\n(Animation Preview only.)"
|
||||
#define STRING_IMGUI_TOOLTIP_TOOLS_SCALE "Use the scale tool.\nWill scale the selected elements as the cursor is dragged.\n(Animation Preview only.)"
|
||||
#define STRING_IMGUI_TOOLTIP_TOOLS_CROP "Use the crop tool.\nWill set the crop of the selected elements as the cursor is dragged.\n(Spritesheet Editor only.)"
|
||||
|
||||
#define STRING_OPENGL_VERSION "#version 330"
|
||||
|
||||
|
476
src/anm2.cpp
476
src/anm2.cpp
@@ -37,7 +37,6 @@ 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);
|
||||
@@ -45,8 +44,6 @@ anm2_serialize(Anm2* self, const char* path)
|
||||
/* Increment anm2's version */
|
||||
self->version++;
|
||||
|
||||
/* Set the anm2's date to the system time */
|
||||
|
||||
/* AnimatedActor */
|
||||
animatedActorElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_ANIMATED_ACTOR]);
|
||||
document.InsertFirstChild(animatedActorElement);
|
||||
@@ -283,14 +280,14 @@ anm2_serialize(Anm2* self, const char* path)
|
||||
/* Triggers */
|
||||
triggersElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_TRIGGERS]);
|
||||
|
||||
for (auto & trigger : animation.triggers.items)
|
||||
for (auto & frame : animation.triggers.frames)
|
||||
{
|
||||
XMLElement* triggerElement;
|
||||
|
||||
/* Trigger */
|
||||
triggerElement = document.NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_TRIGGER]);
|
||||
triggerElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_EVENT_ID], trigger.eventID); /* EventID */
|
||||
triggerElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_AT_FRAME], trigger.atFrame); /* AtFrame */
|
||||
triggerElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_EVENT_ID], frame.eventID); /* EventID */
|
||||
triggerElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_AT_FRAME], frame.atFrame); /* AtFrame */
|
||||
triggersElement->InsertEndChild(triggerElement);
|
||||
}
|
||||
|
||||
@@ -321,35 +318,27 @@ anm2_serialize(Anm2* self, const char* path)
|
||||
bool
|
||||
anm2_deserialize(Anm2* self, Resources* resources, const char* path)
|
||||
{
|
||||
XMLDocument document;
|
||||
XMLError error;
|
||||
const XMLElement* element;
|
||||
const XMLElement* root;
|
||||
Anm2Spritesheet* lastSpritesheet = NULL;
|
||||
Anm2Layer* lastLayer = NULL;
|
||||
Anm2Null* lastNull = NULL;
|
||||
Anm2Event* lastEvent = NULL;
|
||||
Anm2Animation* lastAnimation = NULL;
|
||||
Anm2LayerAnimation* lastLayerAnimation = NULL;
|
||||
Anm2NullAnimation* lastNullAnimation = NULL;
|
||||
Anm2Frame* lastFrame = NULL;
|
||||
Anm2Trigger* lastTrigger = NULL;
|
||||
XMLDocument xmlDocument;
|
||||
XMLError xmlError;
|
||||
const XMLElement* xmlElement;
|
||||
const XMLElement* xmlRoot;
|
||||
Anm2Animation* animation = NULL;
|
||||
Anm2Layer* layer = NULL;
|
||||
Anm2Null* null = NULL;
|
||||
Anm2Item* item = NULL;
|
||||
Anm2Event* event = NULL;
|
||||
Anm2Frame* frame = NULL;
|
||||
Anm2Spritesheet* spritesheet = NULL;
|
||||
Anm2Element anm2Element = ANM2_ELEMENT_ANIMATED_ACTOR;
|
||||
Anm2Attribute anm2Attribute = ANM2_ATTRIBUTE_ID;
|
||||
Anm2AnimationType animationType = ANM2_ROOT_ANIMATION;
|
||||
Anm2Null tempNull;
|
||||
Anm2Layer tempLayer;
|
||||
Anm2Spritesheet tempSpritesheet;
|
||||
Anm2Event tempEvent;
|
||||
char lastSpritesheetPath[PATH_MAX];
|
||||
|
||||
*self = Anm2{};
|
||||
|
||||
error = document.LoadFile(path);
|
||||
xmlError = xmlDocument.LoadFile(path);
|
||||
|
||||
if (error != XML_SUCCESS)
|
||||
if (xmlError != XML_SUCCESS)
|
||||
{
|
||||
printf(STRING_ERROR_ANM2_READ, path, document.ErrorStr());
|
||||
printf(STRING_ERROR_ANM2_READ, path, xmlDocument.ErrorStr());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -357,297 +346,252 @@ anm2_deserialize(Anm2* self, Resources* resources, const char* path)
|
||||
strncpy(self->path, path, PATH_MAX - 1);
|
||||
working_directory_from_path_set(path);
|
||||
|
||||
root = document.FirstChildElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_ANIMATED_ACTOR]);
|
||||
element = root;
|
||||
xmlRoot = xmlDocument.FirstChildElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_ANIMATED_ACTOR]);
|
||||
xmlElement = xmlRoot;
|
||||
|
||||
while (element)
|
||||
while (xmlElement)
|
||||
{
|
||||
const XMLAttribute* attribute;
|
||||
const XMLElement* child;
|
||||
s32 id;
|
||||
|
||||
const XMLAttribute* xmlAttribute = NULL;
|
||||
const XMLElement* xmlChild = NULL;
|
||||
s32 id = 0;
|
||||
|
||||
/* Elements */
|
||||
anm2Element = anm2_element_from_string(element->Name());
|
||||
|
||||
anm2Element = anm2_element_from_string(xmlElement->Name());
|
||||
|
||||
switch (anm2Element)
|
||||
{
|
||||
case ANM2_ELEMENT_SPRITESHEET:
|
||||
lastSpritesheet = &tempSpritesheet;
|
||||
id = map_next_id_get(self->spritesheets);
|
||||
self->spritesheets[id] = Anm2Spritesheet{};
|
||||
spritesheet = &self->spritesheets[id];
|
||||
break;
|
||||
case ANM2_ELEMENT_LAYER:
|
||||
lastLayer = &tempLayer;
|
||||
id = map_next_id_get(self->layers);
|
||||
self->layers[id] = Anm2Layer{};
|
||||
layer = &self->layers[id];
|
||||
break;
|
||||
case ANM2_ELEMENT_NULL:
|
||||
lastNull = &tempNull;
|
||||
id = map_next_id_get(self->nulls);
|
||||
self->nulls[id] = Anm2Null{};
|
||||
null = &self->nulls[id];
|
||||
break;
|
||||
case ANM2_ELEMENT_EVENT:
|
||||
lastEvent = &tempEvent;
|
||||
id = map_next_id_get(self->events);
|
||||
self->events[id] = Anm2Event{};
|
||||
event = &self->events[id];
|
||||
break;
|
||||
case ANM2_ELEMENT_ANIMATION:
|
||||
id = map_next_id_get(self->animations);
|
||||
self->animations[id] = Anm2Animation{};
|
||||
lastAnimation = &self->animations[id];
|
||||
animation = &self->animations[id];
|
||||
break;
|
||||
case ANM2_ELEMENT_ROOT_ANIMATION:
|
||||
animationType = ANM2_ROOT_ANIMATION;
|
||||
item = &animation->rootAnimation;
|
||||
break;
|
||||
case ANM2_ELEMENT_LAYER_ANIMATION:
|
||||
animationType = ANM2_LAYER_ANIMATION;
|
||||
lastLayerAnimation = NULL;
|
||||
id = map_next_id_get(animation->layerAnimations);
|
||||
animation->layerAnimations[id] = Anm2Item{};
|
||||
item = &animation->layerAnimations[id];
|
||||
break;
|
||||
case ANM2_ELEMENT_NULL_ANIMATION:
|
||||
animationType = ANM2_NULL_ANIMATION;
|
||||
lastNullAnimation = NULL;
|
||||
id = map_next_id_get(animation->nullAnimations);
|
||||
animation->nullAnimations[id] = Anm2Item{};
|
||||
item = &animation->nullAnimations[id];
|
||||
break;
|
||||
case ANM2_ELEMENT_TRIGGERS:
|
||||
item = &animation->triggers;
|
||||
break;
|
||||
case ANM2_ELEMENT_FRAME:
|
||||
switch (animationType)
|
||||
{
|
||||
case ANM2_ROOT_ANIMATION:
|
||||
lastAnimation->rootAnimation.frames.push_back(Anm2Frame{});
|
||||
lastFrame = &lastAnimation->rootAnimation.frames.back();
|
||||
break;
|
||||
case ANM2_LAYER_ANIMATION:
|
||||
if (!lastLayerAnimation) break;
|
||||
lastLayerAnimation->frames.push_back(Anm2Frame{});
|
||||
lastFrame = &lastLayerAnimation->frames.back();
|
||||
break;
|
||||
case ANM2_NULL_ANIMATION:
|
||||
if (!lastNullAnimation) break;
|
||||
lastNullAnimation->frames.push_back(Anm2Frame{});
|
||||
lastFrame = &lastNullAnimation->frames.back();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ANM2_ELEMENT_TRIGGER:
|
||||
lastAnimation->triggers.items.push_back(Anm2Trigger{});
|
||||
lastTrigger = &lastAnimation->triggers.items.back();
|
||||
break;
|
||||
item->frames.push_back(Anm2Frame{});
|
||||
frame = &item->frames.back();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Attributes */
|
||||
attribute = element->FirstAttribute();
|
||||
xmlAttribute = xmlElement->FirstAttribute();
|
||||
|
||||
while (attribute)
|
||||
while (xmlAttribute)
|
||||
{
|
||||
anm2Attribute = anm2_attribute_from_string(attribute->Name());
|
||||
|
||||
anm2Attribute = anm2_attribute_from_string(xmlAttribute->Name());
|
||||
|
||||
switch (anm2Attribute)
|
||||
{
|
||||
case ANM2_ATTRIBUTE_CREATED_BY:
|
||||
strncpy(self->createdBy, attribute->Value(), ANM2_STRING_MAX - 1);
|
||||
strncpy(self->createdBy, xmlAttribute->Value(), ANM2_STRING_MAX - 1);
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_CREATED_ON:
|
||||
strncpy(self->createdOn, attribute->Value(), ANM2_STRING_MAX - 1);
|
||||
strncpy(self->createdOn, xmlAttribute->Value(), ANM2_STRING_MAX - 1);
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_VERSION:
|
||||
self->version = atoi(attribute->Value());
|
||||
self->version = atoi(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_FPS:
|
||||
self->fps = atoi(attribute->Value());
|
||||
self->fps = atoi(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_ID:
|
||||
id = atoi(attribute->Value());
|
||||
switch (anm2Element)
|
||||
{
|
||||
case ANM2_ELEMENT_SPRITESHEET:
|
||||
self->spritesheets[id] = tempSpritesheet;
|
||||
lastSpritesheet = &self->spritesheets[id];
|
||||
break;
|
||||
case ANM2_ELEMENT_LAYER:
|
||||
self->layers[id] = tempLayer;
|
||||
lastLayer = &self->layers[id];
|
||||
break;
|
||||
case ANM2_ELEMENT_NULL:
|
||||
self->nulls[id] = tempNull;
|
||||
lastNull = &self->nulls[id];
|
||||
break;
|
||||
case ANM2_ELEMENT_EVENT:
|
||||
self->events[id] = tempEvent;
|
||||
lastEvent = &self->events[id];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_LAYER_ID:
|
||||
map_swap(animation->layerAnimations, id, atoi(xmlAttribute->Value()));
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_NULL_ID:
|
||||
map_swap(animation->nullAnimations, id, atoi(xmlAttribute->Value()));
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_PATH:
|
||||
/* Make path lowercase */
|
||||
strncpy(lastSpritesheetPath, attribute->Value(), PATH_MAX - 1);
|
||||
strncpy(spritesheet->path, xmlAttribute->Value(), PATH_MAX - 1);
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_NAME:
|
||||
switch (anm2Element)
|
||||
{
|
||||
case ANM2_ELEMENT_LAYER:
|
||||
strncpy(lastLayer->name, attribute->Value(), ANM2_STRING_MAX - 1);
|
||||
strncpy(layer->name, xmlAttribute->Value(), ANM2_STRING_MAX - 1);
|
||||
break;
|
||||
case ANM2_ELEMENT_NULL:
|
||||
strncpy(lastNull->name, attribute->Value(), ANM2_STRING_MAX - 1);
|
||||
strncpy(null->name, xmlAttribute->Value(), ANM2_STRING_MAX - 1);
|
||||
break;
|
||||
case ANM2_ELEMENT_ANIMATION:
|
||||
strncpy(lastAnimation->name, attribute->Value(), ANM2_STRING_MAX - 1);
|
||||
strncpy(animation->name, xmlAttribute->Value(), ANM2_STRING_MAX - 1);
|
||||
break;
|
||||
case ANM2_ELEMENT_EVENT:
|
||||
strncpy(lastEvent->name, attribute->Value(), ANM2_STRING_MAX - 1);
|
||||
strncpy(event->name, xmlAttribute->Value(), ANM2_STRING_MAX - 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_SPRITESHEET_ID:
|
||||
lastLayer->spritesheetID = atoi(attribute->Value());
|
||||
layer->spritesheetID = atoi(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_SHOW_RECT:
|
||||
switch (anm2Element)
|
||||
{
|
||||
case ANM2_ELEMENT_NULL:
|
||||
lastNull->isShowRect = string_to_bool(attribute->Value());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
null->isShowRect = string_to_bool(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_DEFAULT_ANIMATION:
|
||||
strncpy(self->defaultAnimation, attribute->Value(), ANM2_STRING_MAX - 1);
|
||||
strncpy(self->defaultAnimation, xmlAttribute->Value(), ANM2_STRING_MAX - 1);
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_FRAME_NUM:
|
||||
lastAnimation->frameNum = atoi(attribute->Value());
|
||||
animation->frameNum = atoi(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_LOOP:
|
||||
lastAnimation->isLoop = string_to_bool(attribute->Value());
|
||||
animation->isLoop = string_to_bool(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_X_POSITION:
|
||||
lastFrame->position.x = atof(attribute->Value());
|
||||
frame->position.x = atof(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_Y_POSITION:
|
||||
lastFrame->position.y = atof(attribute->Value());
|
||||
frame->position.y = atof(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_X_PIVOT:
|
||||
lastFrame->pivot.x = atof(attribute->Value());
|
||||
frame->pivot.x = atof(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_Y_PIVOT:
|
||||
lastFrame->pivot.y = atof(attribute->Value());
|
||||
frame->pivot.y = atof(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_X_CROP:
|
||||
lastFrame->crop.x = atof(attribute->Value());
|
||||
frame->crop.x = atof(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_Y_CROP:
|
||||
lastFrame->crop.y = atof(attribute->Value());
|
||||
frame->crop.y = atof(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_WIDTH:
|
||||
lastFrame->size.x = atof(attribute->Value());
|
||||
frame->size.x = atof(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_HEIGHT:
|
||||
lastFrame->size.y = atof(attribute->Value());
|
||||
frame->size.y = atof(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_X_SCALE:
|
||||
lastFrame->scale.x = atof(attribute->Value());
|
||||
frame->scale.x = atof(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_Y_SCALE:
|
||||
lastFrame->scale.y = atof(attribute->Value());
|
||||
frame->scale.y = atof(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_DELAY:
|
||||
lastFrame->delay = atoi(attribute->Value());
|
||||
frame->delay = atoi(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_VISIBLE:
|
||||
switch (anm2Element)
|
||||
{
|
||||
case ANM2_ELEMENT_FRAME:
|
||||
lastFrame->isVisible = string_to_bool(attribute->Value());
|
||||
frame->isVisible = string_to_bool(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_LAYER_ANIMATION:
|
||||
lastLayerAnimation->isVisible = string_to_bool(attribute->Value());
|
||||
break;
|
||||
case ANM2_NULL_ANIMATION:
|
||||
lastNullAnimation->isVisible = string_to_bool(attribute->Value());
|
||||
case ANM2_ELEMENT_ROOT_ANIMATION:
|
||||
case ANM2_ELEMENT_LAYER_ANIMATION:
|
||||
case ANM2_ELEMENT_NULL_ANIMATION:
|
||||
item->isVisible = string_to_bool(xmlAttribute->Value());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_RED_TINT:
|
||||
lastFrame->tintRGBA.r = COLOR_INT_TO_FLOAT(atoi(attribute->Value()));
|
||||
frame->tintRGBA.r = COLOR_INT_TO_FLOAT(atoi(xmlAttribute->Value()));
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_GREEN_TINT:
|
||||
lastFrame->tintRGBA.g = COLOR_INT_TO_FLOAT(atoi(attribute->Value()));
|
||||
frame->tintRGBA.g = COLOR_INT_TO_FLOAT(atoi(xmlAttribute->Value()));
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_BLUE_TINT:
|
||||
lastFrame->tintRGBA.b = COLOR_INT_TO_FLOAT(atoi(attribute->Value()));
|
||||
frame->tintRGBA.b = COLOR_INT_TO_FLOAT(atoi(xmlAttribute->Value()));
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_ALPHA_TINT:
|
||||
lastFrame->tintRGBA.a = COLOR_INT_TO_FLOAT(atoi(attribute->Value()));
|
||||
frame->tintRGBA.a = COLOR_INT_TO_FLOAT(atoi(xmlAttribute->Value()));
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_RED_OFFSET:
|
||||
lastFrame->offsetRGB.r = COLOR_INT_TO_FLOAT(atoi(attribute->Value()));
|
||||
frame->offsetRGB.r = COLOR_INT_TO_FLOAT(atoi(xmlAttribute->Value()));
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_GREEN_OFFSET:
|
||||
lastFrame->offsetRGB.g = COLOR_INT_TO_FLOAT(atoi(attribute->Value()));
|
||||
frame->offsetRGB.g = COLOR_INT_TO_FLOAT(atoi(xmlAttribute->Value()));
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_BLUE_OFFSET:
|
||||
lastFrame->offsetRGB.b = COLOR_INT_TO_FLOAT(atoi(attribute->Value()));
|
||||
frame->offsetRGB.b = COLOR_INT_TO_FLOAT(atoi(xmlAttribute->Value()));
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_ROTATION:
|
||||
lastFrame->rotation = atof(attribute->Value());
|
||||
frame->rotation = atof(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_INTERPOLATED:
|
||||
lastFrame->isInterpolated = string_to_bool(attribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_LAYER_ID:
|
||||
id = atoi(attribute->Value());
|
||||
lastAnimation->layerAnimations[id] = Anm2LayerAnimation{};
|
||||
lastLayerAnimation = &lastAnimation->layerAnimations[id];
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_NULL_ID:
|
||||
id = atoi(attribute->Value());
|
||||
lastAnimation->nullAnimations[id] = Anm2NullAnimation{};
|
||||
lastNullAnimation = &lastAnimation->nullAnimations[id];
|
||||
frame->isInterpolated = string_to_bool(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_EVENT_ID:
|
||||
lastTrigger->eventID = atoi(attribute->Value());
|
||||
frame->eventID = atoi(xmlAttribute->Value());
|
||||
break;
|
||||
case ANM2_ATTRIBUTE_AT_FRAME:
|
||||
lastTrigger->atFrame = atoi(attribute->Value());
|
||||
frame->atFrame = atoi(xmlAttribute->Value());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
attribute = attribute->Next();
|
||||
xmlAttribute = xmlAttribute->Next();
|
||||
}
|
||||
|
||||
/* Load spritesheet textures */
|
||||
if (anm2Element == ANM2_ELEMENT_SPRITESHEET)
|
||||
{
|
||||
strncpy(lastSpritesheet->path, lastSpritesheetPath, PATH_MAX);
|
||||
anm2_spritesheet_texture_load(self, resources, lastSpritesheetPath , id);
|
||||
}
|
||||
anm2_spritesheet_texture_load(self, resources, spritesheet->path , id);
|
||||
|
||||
/* Iterate through children */
|
||||
child = element->FirstChildElement();
|
||||
xmlChild = xmlElement->FirstChildElement();
|
||||
|
||||
if (child)
|
||||
if (xmlChild)
|
||||
{
|
||||
element = child;
|
||||
xmlElement = xmlChild;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Iterate through siblings */
|
||||
while (element)
|
||||
while (xmlElement)
|
||||
{
|
||||
const XMLElement* next;
|
||||
const XMLElement* xmlNext;
|
||||
|
||||
next = element->NextSiblingElement();
|
||||
xmlNext = xmlElement->NextSiblingElement();
|
||||
|
||||
if (next)
|
||||
if (xmlNext)
|
||||
{
|
||||
element = next;
|
||||
xmlElement = xmlNext;
|
||||
break;
|
||||
}
|
||||
|
||||
/* If no siblings, return to parent. If no parent, end parsing */
|
||||
element = element->Parent() ? element->Parent()->ToElement() : NULL;
|
||||
xmlElement = xmlElement->Parent() ? xmlElement->Parent()->ToElement() : NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -665,7 +609,7 @@ anm2_layer_add(Anm2* self)
|
||||
self->layers[id] = Anm2Layer{};
|
||||
|
||||
for (auto & [animationID, animation] : self->animations)
|
||||
animation.layerAnimations[id] = Anm2LayerAnimation{};
|
||||
animation.layerAnimations[id] = Anm2Item{};
|
||||
}
|
||||
|
||||
/* Removes a layer from the anm2 given the index/id */
|
||||
@@ -674,8 +618,8 @@ anm2_layer_remove(Anm2* self, s32 id)
|
||||
{
|
||||
self->layers.erase(id);
|
||||
|
||||
for (auto& animationPair : self->animations)
|
||||
animationPair.second.layerAnimations.erase(id);
|
||||
for (auto & [animationID, animation] : self->animations)
|
||||
animation.layerAnimations.erase(id);
|
||||
}
|
||||
|
||||
/* Adds a new null to the anm2 */
|
||||
@@ -687,7 +631,7 @@ anm2_null_add(Anm2* self)
|
||||
self->nulls[id] = Anm2Null{};
|
||||
|
||||
for (auto & [animationID, animation] : self->animations)
|
||||
animation.nullAnimations[id] = Anm2NullAnimation{};
|
||||
animation.nullAnimations[id] = Anm2Item{};
|
||||
}
|
||||
|
||||
/* Removes a null from the anm2 given the index/id */
|
||||
@@ -696,8 +640,8 @@ anm2_null_remove(Anm2* self, s32 id)
|
||||
{
|
||||
self->nulls.erase(id);
|
||||
|
||||
for (auto& animationPair : self->animations)
|
||||
animationPair.second.nullAnimations.erase(id);
|
||||
for (auto & [animationID, animation] : self->animations)
|
||||
animation.nullAnimations.erase(id);
|
||||
}
|
||||
|
||||
/* Adds a new animation to the anm2, makes sure to keep the layeranimations/nullsanimation check */
|
||||
@@ -710,13 +654,13 @@ anm2_animation_add(Anm2* self)
|
||||
/* match layers */
|
||||
for (auto & [layerID, layer] : self->layers)
|
||||
{
|
||||
animation.layerAnimations[layerID] = Anm2LayerAnimation{};
|
||||
animation.layerAnimations[layerID] = Anm2Item{};
|
||||
}
|
||||
|
||||
/* match nulls */
|
||||
for (auto & [nullID, null] : self->nulls)
|
||||
{
|
||||
animation.nullAnimations[nullID] = Anm2NullAnimation{};
|
||||
animation.nullAnimations[nullID] = Anm2Item{};
|
||||
}
|
||||
|
||||
/* add a root frame */
|
||||
@@ -757,69 +701,104 @@ anm2_spritesheet_texture_load(Anm2* self, Resources* resources, const char* path
|
||||
resources->textures[id] = texture;
|
||||
}
|
||||
|
||||
Anm2Animation*
|
||||
anm2_animation_from_id(Anm2* self, s32 animationID)
|
||||
{
|
||||
auto it = self->animations.find(animationID);
|
||||
if (it == self->animations.end())
|
||||
return NULL;
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
/* Returns the item from a anm2 reference. */
|
||||
Anm2Item*
|
||||
anm2_item_from_reference(Anm2* self, Anm2Reference* reference, s32 animationID)
|
||||
{
|
||||
Anm2Animation* animation = anm2_animation_from_id(self, animationID);
|
||||
|
||||
if (!animation)
|
||||
return NULL;
|
||||
|
||||
switch (reference->type)
|
||||
{
|
||||
case ANM2_ROOT:
|
||||
return &animation->rootAnimation;
|
||||
case ANM2_LAYER:
|
||||
{
|
||||
auto it = animation->layerAnimations.find(reference->id);
|
||||
if (it == animation->layerAnimations.end())
|
||||
return NULL;
|
||||
return &it->second;
|
||||
}
|
||||
case ANM2_NULL:
|
||||
{
|
||||
auto it = animation->nullAnimations.find(reference->id);
|
||||
if (it == animation->nullAnimations.end())
|
||||
return NULL;
|
||||
return &it->second;
|
||||
}
|
||||
case ANM2_TRIGGERS:
|
||||
return &animation->triggers;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Gets the frame from the reference's properties */
|
||||
Anm2Frame*
|
||||
anm2_frame_from_reference(Anm2* self, Anm2Reference* reference, s32 animationID)
|
||||
{
|
||||
Anm2Item* item = anm2_item_from_reference(self, reference, animationID);
|
||||
|
||||
if (!item)
|
||||
return NULL;
|
||||
|
||||
if (reference->index < 0 || reference->index >= (s32)item->frames.size())
|
||||
return NULL;
|
||||
|
||||
return &item->frames[reference->index];
|
||||
}
|
||||
|
||||
/* Creates/fetches a frame from a given time. */
|
||||
/* Returns true/false if frame will be valid or not. */
|
||||
bool
|
||||
anm2_frame_from_time(Anm2* self, Anm2Animation* animation, Anm2Frame* frame, Anm2AnimationType type, s32 id, f32 time)
|
||||
void
|
||||
anm2_frame_from_time(Anm2* self, Anm2Frame* frame, Anm2Reference reference, s32 animationID, f32 time)
|
||||
{
|
||||
Anm2Animation* animation = anm2_animation_from_id(self, animationID);
|
||||
|
||||
/* Out of range */
|
||||
if (time < 0 || time > animation->frameNum)
|
||||
return false;
|
||||
return;
|
||||
|
||||
Anm2Item* item = anm2_item_from_reference(self, &reference, animationID);
|
||||
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
Anm2RootAnimation* rootAnimation;
|
||||
Anm2LayerAnimation* layerAnimation;
|
||||
Anm2NullAnimation* nullAnimation;
|
||||
Anm2Frame* nextFrame = NULL;
|
||||
std::vector<Anm2Frame>* frames = NULL;
|
||||
f32 delayCurrent = 0;
|
||||
f32 delayNext = 0;
|
||||
bool isTimeMatchedFrame = false;
|
||||
s32 delayCurrent = 0;
|
||||
s32 delayNext = 0;
|
||||
|
||||
switch (type)
|
||||
for (s32 i = 0; i < (s32)item->frames.size(); i++)
|
||||
{
|
||||
case ANM2_ROOT_ANIMATION:
|
||||
frames = &animation->rootAnimation.frames;
|
||||
break;
|
||||
case ANM2_LAYER_ANIMATION:
|
||||
if (id < 0 || id >= (s32)animation->layerAnimations.size())
|
||||
return false;
|
||||
frames = &animation->layerAnimations[id].frames;
|
||||
break;
|
||||
case ANM2_NULL_ANIMATION:
|
||||
if (id < 0 || id >= (s32)animation->nullAnimations.size())
|
||||
return false;
|
||||
frames = &animation->nullAnimations[id].frames;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
for (s32 i = 0; i < (s32)frames->size(); i++)
|
||||
{
|
||||
*frame = (*frames)[i];
|
||||
*frame = item->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)
|
||||
{
|
||||
if (i + 1 < (s32)frames->size())
|
||||
nextFrame = &(*frames)[i + 1];
|
||||
if (i + 1 < (s32)item->frames.size())
|
||||
nextFrame = &item->frames[i + 1];
|
||||
else
|
||||
nextFrame = NULL;
|
||||
|
||||
isTimeMatchedFrame = true;
|
||||
break;
|
||||
}
|
||||
|
||||
delayCurrent += frame->delay;
|
||||
}
|
||||
|
||||
/* No valid frame found */
|
||||
if (!isTimeMatchedFrame)
|
||||
return false;
|
||||
|
||||
/* interpolate only if there's a frame following */
|
||||
/* Interpolate only if there's a frame following */
|
||||
if (frame->isInterpolated && nextFrame)
|
||||
{
|
||||
f32 interpolationTime = (time - delayCurrent) / (delayNext - delayCurrent);
|
||||
@@ -830,6 +809,67 @@ anm2_frame_from_time(Anm2* self, Anm2Animation* animation, Anm2Frame* frame, Anm
|
||||
frame->offsetRGB = glm::mix(frame->offsetRGB, nextFrame->offsetRGB, interpolationTime);;
|
||||
frame->tintRGBA = glm::mix(frame->tintRGBA, nextFrame->tintRGBA, interpolationTime);;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
/* Will try adding a frame to the anm2 given the specified reference */
|
||||
Anm2Frame*
|
||||
anm2_frame_add(Anm2* self, Anm2Reference* reference, s32 animationID, s32 time)
|
||||
{
|
||||
Anm2Animation* animation = anm2_animation_from_id(self, animationID);
|
||||
Anm2Item* item = anm2_item_from_reference(self, reference, animationID);
|
||||
|
||||
if (!animation || !item)
|
||||
return NULL;
|
||||
|
||||
if (item)
|
||||
{
|
||||
Anm2Frame frame = Anm2Frame{};
|
||||
s32 index = -1;
|
||||
|
||||
if (reference->type == ANM2_TRIGGERS)
|
||||
{
|
||||
/* don't add redudant triggers (i.e. at same time) */
|
||||
for (auto & frameCheck : item->frames)
|
||||
{
|
||||
if (frameCheck.atFrame == time)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
frame.atFrame = time;
|
||||
index = item->frames.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
s32 delay = 0;
|
||||
s32 frameDelayCount = 0;
|
||||
|
||||
/* Add up all delay to see where this new frame might lie */
|
||||
for (auto & frameCheck : item->frames)
|
||||
frameDelayCount += frameCheck.delay;
|
||||
|
||||
/* If adding the smallest frame would be over the length, don't bother */
|
||||
if (frameDelayCount + ANM2_FRAME_DELAY_MIN > animation->frameNum)
|
||||
return NULL;
|
||||
|
||||
/* Will insert next to frame if frame exists */
|
||||
Anm2Frame* checkFrame = anm2_frame_from_reference(self, reference, animationID);
|
||||
|
||||
if (checkFrame)
|
||||
{
|
||||
/* Will shrink frame delay to fit */
|
||||
if (frameDelayCount + checkFrame->delay > animation->frameNum)
|
||||
frame.delay = animation->frameNum - frameDelayCount;
|
||||
|
||||
index = reference->index + 1;
|
||||
}
|
||||
else
|
||||
index = (s32)item->frames.size();
|
||||
}
|
||||
|
||||
item->frames.insert(item->frames.begin() + index, frame);
|
||||
|
||||
return &item->frames[index];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
66
src/anm2.h
66
src/anm2.h
@@ -14,6 +14,7 @@
|
||||
#define ANM2_FPS_MAX 120
|
||||
#define ANM2_FRAME_NUM_MIN 1
|
||||
#define ANM2_FRAME_NUM_MAX 1000000
|
||||
#define ANM2_FRAME_DELAY_MIN 1
|
||||
|
||||
/* Elements */
|
||||
#define ANM2_ELEMENT_LIST \
|
||||
@@ -108,14 +109,14 @@ static const char* ANM2_ATTRIBUTE_STRINGS[] = {
|
||||
|
||||
DEFINE_STRING_TO_ENUM_FN(anm2_attribute_from_string, Anm2Attribute, ANM2_ATTRIBUTE_STRINGS, ANM2_ATTRIBUTE_COUNT)
|
||||
|
||||
#define ANM2_ANIMATION_TYPE_COUNT (ANM2_ANIMATION_TRIGGERS + 1)
|
||||
enum Anm2AnimationType
|
||||
#define ANM2_COUNT (ANM2_TRIGGER + 1)
|
||||
enum Anm2Type
|
||||
{
|
||||
ANM2_NONE,
|
||||
ANM2_ROOT_ANIMATION,
|
||||
ANM2_LAYER_ANIMATION,
|
||||
ANM2_NULL_ANIMATION,
|
||||
ANM2_TRIGGER
|
||||
ANM2_ROOT,
|
||||
ANM2_LAYER,
|
||||
ANM2_NULL,
|
||||
ANM2_TRIGGERS
|
||||
};
|
||||
|
||||
struct Anm2Spritesheet
|
||||
@@ -140,18 +141,14 @@ struct Anm2Event
|
||||
char name[ANM2_STRING_MAX] = STRING_ANM2_NEW_EVENT;
|
||||
};
|
||||
|
||||
struct Anm2Trigger
|
||||
{
|
||||
s32 eventID = -1;
|
||||
s32 atFrame = -1;
|
||||
};
|
||||
|
||||
struct Anm2Frame
|
||||
{
|
||||
bool isInterpolated = false;
|
||||
bool isVisible = true;
|
||||
f32 rotation = 1.0f;
|
||||
s32 delay = 1;
|
||||
s32 delay = ANM2_FRAME_DELAY_MIN;
|
||||
s32 atFrame = -1;
|
||||
s32 eventID = -1;
|
||||
vec2 crop = {0.0f, 0.0f};
|
||||
vec2 pivot = {0.0f, 0.0f};
|
||||
vec2 position = {0.0f, 0.0f};
|
||||
@@ -161,39 +158,21 @@ struct Anm2Frame
|
||||
vec4 tintRGBA = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
};
|
||||
|
||||
struct Anm2LayerAnimation
|
||||
{
|
||||
bool isVisible = true;
|
||||
std::vector<Anm2Frame> frames;
|
||||
};
|
||||
|
||||
struct Anm2NullAnimation
|
||||
{
|
||||
bool isVisible = true;
|
||||
std::vector<Anm2Frame> frames;
|
||||
};
|
||||
|
||||
struct Anm2RootAnimation
|
||||
struct Anm2Item
|
||||
{
|
||||
bool isVisible = true;
|
||||
std::vector<Anm2Frame> frames;
|
||||
};
|
||||
|
||||
struct Anm2Triggers
|
||||
{
|
||||
bool isVisible = true;
|
||||
std::vector<Anm2Trigger> items;
|
||||
};
|
||||
|
||||
struct Anm2Animation
|
||||
{
|
||||
s32 frameNum = ANM2_FRAME_NUM_MIN;
|
||||
char name[ANM2_STRING_MAX] = STRING_ANM2_NEW_ANIMATION;
|
||||
bool isLoop = true;
|
||||
Anm2RootAnimation rootAnimation;
|
||||
std::map<s32, Anm2LayerAnimation> layerAnimations;
|
||||
std::map<s32, Anm2NullAnimation> nullAnimations;
|
||||
Anm2Triggers triggers;
|
||||
Anm2Item rootAnimation;
|
||||
std::map<s32, Anm2Item> layerAnimations;
|
||||
std::map<s32, Anm2Item> nullAnimations;
|
||||
Anm2Item triggers;
|
||||
};
|
||||
|
||||
struct Anm2
|
||||
@@ -211,6 +190,15 @@ struct Anm2
|
||||
std::map<s32, Anm2Animation> animations;
|
||||
};
|
||||
|
||||
struct Anm2Reference
|
||||
{
|
||||
Anm2Type type = ANM2_NONE;
|
||||
s32 id = -1;
|
||||
s32 index = -1;
|
||||
|
||||
auto operator<=>(const Anm2Reference&) const = default;
|
||||
};
|
||||
|
||||
void anm2_layer_add(Anm2* self);
|
||||
void anm2_layer_remove(Anm2* self, s32 id);
|
||||
void anm2_null_add(Anm2* self);
|
||||
@@ -222,4 +210,8 @@ void anm2_created_on_set(Anm2* self);
|
||||
s32 anm2_animation_add(Anm2* self);
|
||||
void anm2_animation_remove(Anm2* self, s32 id);
|
||||
void anm2_spritesheet_texture_load(Anm2* self, Resources* resources, const char* path, s32 id);
|
||||
bool anm2_frame_from_time(Anm2* self, Anm2Animation* animation, Anm2Frame* frame, Anm2AnimationType type, s32 id, f32 time);
|
||||
Anm2Animation* anm2_animation_from_id(Anm2* self, s32 animationID);
|
||||
Anm2Item* anm2_item_from_reference(Anm2* self, Anm2Reference* reference, s32 animationID);
|
||||
Anm2Frame* anm2_frame_from_reference(Anm2* self, Anm2Reference* reference, s32 animationID);
|
||||
Anm2Frame* anm2_frame_add(Anm2* self, Anm2Reference* reference, s32 animationID, s32 time);
|
||||
void anm2_frame_from_time(Anm2* self, Anm2Frame* frame, Anm2Reference reference, s32 animationID, f32 time);
|
@@ -19,9 +19,10 @@ _dialog_callback(void* userdata, const char* const* filelist, s32 filter)
|
||||
}
|
||||
|
||||
void
|
||||
dialog_init(Dialog* self, Anm2* anm2, Resources* resources, SDL_Window* window)
|
||||
dialog_init(Dialog* self, Anm2* anm2, Anm2Reference* reference, Resources* resources, SDL_Window* window)
|
||||
{
|
||||
self->anm2 = anm2;
|
||||
self->reference = reference;
|
||||
self->resources = resources;
|
||||
self->window = window;
|
||||
}
|
||||
@@ -76,6 +77,7 @@ dialog_tick(Dialog* self)
|
||||
switch (self->type)
|
||||
{
|
||||
case DIALOG_ANM2_OPEN:
|
||||
*self->reference = Anm2Reference{};
|
||||
resources_textures_free(self->resources);
|
||||
anm2_deserialize(self->anm2, self->resources, self->path);
|
||||
window_title_from_anm2_set(self->window, self->anm2);
|
||||
|
@@ -26,6 +26,7 @@ enum DialogType
|
||||
struct Dialog
|
||||
{
|
||||
Anm2* anm2 = NULL;
|
||||
Anm2Reference* reference = NULL;
|
||||
Resources* resources = NULL;
|
||||
SDL_Window* window = NULL;
|
||||
s32 replaceID = -1;
|
||||
@@ -34,7 +35,7 @@ struct Dialog
|
||||
bool isSelected = false;
|
||||
};
|
||||
|
||||
void dialog_init(Dialog* self, Anm2* anm2, Resources* resources, SDL_Window* window);
|
||||
void dialog_init(Dialog* self, Anm2* anm2, Anm2Reference* reference, Resources* resources, SDL_Window* window);
|
||||
void dialog_anm2_open(Dialog* self);
|
||||
void dialog_png_open(Dialog* self);
|
||||
void dialog_png_replace(Dialog* self);
|
||||
|
@@ -1,8 +1,8 @@
|
||||
#include "editor.h"
|
||||
|
||||
static void _editor_grid_set(Editor* self);
|
||||
static s32 _editor_grid_set(Editor* self);
|
||||
|
||||
static void
|
||||
static s32
|
||||
_editor_grid_set(Editor* self)
|
||||
{
|
||||
std::vector<f32> vertices;
|
||||
@@ -34,19 +34,32 @@ _editor_grid_set(Editor* self)
|
||||
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);
|
||||
|
||||
return (s32)vertices.size();
|
||||
}
|
||||
|
||||
void
|
||||
editor_init(Editor* self, Resources* resources, Settings* settings)
|
||||
editor_init
|
||||
(
|
||||
Editor* self,
|
||||
Anm2* anm2,
|
||||
Anm2Reference* reference,
|
||||
s32* animationID,
|
||||
s32* spritesheetID,
|
||||
Resources* resources,
|
||||
Settings* settings
|
||||
)
|
||||
{
|
||||
self->anm2 = anm2;
|
||||
self->reference = reference;
|
||||
self->animationID = animationID;
|
||||
self->spritesheetID = spritesheetID;
|
||||
self->resources = resources;
|
||||
self->settings = settings;
|
||||
|
||||
@@ -140,9 +153,9 @@ editor_draw(Editor* self)
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
if (self->spritesheetID > -1)
|
||||
if (*self->spritesheetID > -1)
|
||||
{
|
||||
Texture* texture = &self->resources->textures[self->spritesheetID];
|
||||
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);
|
||||
@@ -186,12 +199,16 @@ editor_draw(Editor* self)
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
if (self->isFrame)
|
||||
Anm2Frame* frame = (Anm2Frame*)anm2_frame_from_reference(self->anm2, self->reference, *self->animationID);
|
||||
|
||||
/* Draw the layer frame's crop and pivot */
|
||||
if (frame && self->reference->type == ANM2_LAYER)
|
||||
{
|
||||
/* Rect */
|
||||
glm::mat4 rectTransform = editorTransform;
|
||||
|
||||
glm::vec2 rectNDCPos = self->frame.crop / (EDITOR_SIZE / 2.0f);
|
||||
glm::vec2 rectNDCScale = self->frame.size / (EDITOR_SIZE * 0.5f);
|
||||
glm::vec2 rectNDCPos = frame->crop / (EDITOR_SIZE / 2.0f);
|
||||
glm::vec2 rectNDCScale = frame->size / (EDITOR_SIZE / 2.0f);
|
||||
|
||||
rectTransform = glm::translate(rectTransform, glm::vec3(rectNDCPos, 0.0f));
|
||||
rectTransform = glm::scale(rectTransform, glm::vec3(rectNDCScale, 1.0f));
|
||||
@@ -208,9 +225,10 @@ editor_draw(Editor* self)
|
||||
glBindVertexArray(0);
|
||||
glUseProgram(0);
|
||||
|
||||
/* Pivot */
|
||||
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);
|
||||
glm::vec2 pivotNDCPos = ((frame->crop + frame->pivot) - (EDITOR_PIVOT_SIZE / 2.0f)) / (EDITOR_SIZE / 2.0f);
|
||||
glm::vec2 pivotNDCScale = EDITOR_PIVOT_SIZE / (EDITOR_SIZE / 2.0f);
|
||||
|
||||
pivotTransform = glm::translate(pivotTransform, glm::vec3(pivotNDCPos, 0.0f));
|
||||
pivotTransform = glm::scale(pivotTransform, glm::vec3(pivotNDCScale, 1.0f));
|
||||
@@ -244,16 +262,21 @@ editor_draw(Editor* self)
|
||||
|
||||
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);
|
||||
static ivec2 previousGridSize = {-1, -1};
|
||||
static ivec2 previousGridOffset = {-1, -1};
|
||||
static s32 gridVertexCount = -1;
|
||||
ivec2 gridSize = ivec2(self->settings->editorGridSizeX, self->settings->editorGridSizeY);
|
||||
ivec2 gridOffset = ivec2(self->settings->editorGridOffsetX, self->settings->editorGridOffsetY);
|
||||
|
||||
if (previousGridSize != gridSize || previousGridOffset != gridOffset)
|
||||
{
|
||||
gridVertexCount = _editor_grid_set(self);
|
||||
previousGridSize = gridSize;
|
||||
previousGridOffset = gridOffset;
|
||||
}
|
||||
|
||||
glUseProgram(shaderLine);
|
||||
glBindVertexArray(self->gridVAO);
|
||||
|
||||
glUniformMatrix4fv(glGetUniformLocation(shaderLine, SHADER_UNIFORM_TRANSFORM), 1, GL_FALSE, (f32*)value_ptr(editorTransform));
|
||||
|
||||
glUniform4f
|
||||
@@ -262,7 +285,7 @@ editor_draw(Editor* self)
|
||||
self->settings->editorGridColorR, self->settings->editorGridColorG, self->settings->editorGridColorB, self->settings->editorGridColorA
|
||||
);
|
||||
|
||||
glDrawArrays(GL_LINES, 0, self->gridVertexCount);
|
||||
glDrawArrays(GL_LINES, 0, gridVertexCount);
|
||||
|
||||
glBindVertexArray(0);
|
||||
glUseProgram(0);
|
||||
@@ -275,8 +298,6 @@ 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
|
||||
|
24
src/editor.h
24
src/editor.h
@@ -13,12 +13,17 @@
|
||||
#define EDITOR_GRID_OFFSET_MAX 100
|
||||
|
||||
static const vec2 EDITOR_SIZE = {5000, 5000};
|
||||
static const vec2 EDITOR_PIVOT_SIZE = {4, 4};
|
||||
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
|
||||
{
|
||||
Anm2* anm2 = NULL;
|
||||
Anm2Reference* reference = NULL;
|
||||
s32* animationID = NULL;
|
||||
s32* spritesheetID = NULL;
|
||||
Resources* resources = NULL;
|
||||
Settings* settings = NULL;
|
||||
GLuint fbo;
|
||||
@@ -31,16 +36,19 @@ struct Editor
|
||||
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_init
|
||||
(
|
||||
Editor* self,
|
||||
Anm2* anm2,
|
||||
Anm2Reference* reference,
|
||||
s32* animationID,
|
||||
s32* spritesheetID,
|
||||
Resources* resources,
|
||||
Settings* settings
|
||||
);
|
||||
|
||||
void editor_draw(Editor* self);
|
||||
void editor_tick(Editor* self);
|
||||
void editor_free(Editor* self);
|
1467
src/imgui.cpp
1467
src/imgui.cpp
File diff suppressed because it is too large
Load Diff
52
src/imgui.h
52
src/imgui.h
@@ -7,6 +7,7 @@
|
||||
#include "window.h"
|
||||
#include "input.h"
|
||||
#include "settings.h"
|
||||
#include "tool.h"
|
||||
|
||||
#define IMGUI_IMPL_OPENGL_LOADER_CUSTOM
|
||||
#define IMGUI_ENABLE_DOCKING
|
||||
@@ -15,8 +16,6 @@
|
||||
#include <imgui/backends/imgui_impl_sdl3.h>
|
||||
#include <imgui/backends/imgui_impl_opengl3.h>
|
||||
|
||||
|
||||
#define IMGUI_TIMELINE_ELEMENT_WIDTH 300
|
||||
#define IMGUI_TIMELINE_ELEMENT_WIDTH 300
|
||||
|
||||
#define IMGUI_DRAG_SPEED 1.0
|
||||
@@ -32,15 +31,15 @@
|
||||
#define IMGUI_PICKER_LINE_COLOR IM_COL32(255, 255, 255, 255)
|
||||
#define IMGUI_TOOLS_WIDTH_INCREMENT -2
|
||||
|
||||
#define IMGUI_POSITION_STRING_MAX 0xFF
|
||||
|
||||
static const vec2 IMGUI_TASKBAR_MARGINS = {8, 4};
|
||||
static const vec2 IMGUI_SPRITESHEET_EDITOR_CROP_FORGIVENESS = {1, 1};
|
||||
|
||||
static const ImVec2 IMGUI_ANIMATION_PREVIEW_SETTINGS_SIZE = {1280, 105};
|
||||
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};
|
||||
|
||||
@@ -52,15 +51,13 @@ static const ImVec2 IMGUI_TIMELINE_VIEWER_SIZE = {0, 40};
|
||||
static const ImVec2 IMGUI_TIMELINE_ELEMENTS_TIMELINE_SIZE = {0, 40};
|
||||
static const ImVec2 IMGUI_TIMELINE_FRAME_INDICES_SIZE = {0, 40};
|
||||
static const ImVec2 IMGUI_TIMELINE_ELEMENT_SIZE = {300, 40};
|
||||
static const ImVec2 IMGUI_TIMELINE_SHIFT_ARROWS_SIZE = {64, 40};
|
||||
static const ImVec2 IMGUI_TIMELINE_ELEMENT_NAME_SIZE = {150, 20};
|
||||
static const ImVec2 IMGUI_TIMELINE_ELEMENT_SPRITESHEET_ID_SIZE = {60, 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_SMALL_SIZE = {8, 8};
|
||||
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_ICON_BUTTON_SIZE = {24, 24};
|
||||
static const ImVec2 IMGUI_DUMMY_SIZE = {1, 1};
|
||||
|
||||
static const ImVec4 IMGUI_TIMELINE_HEADER_COLOR = {0.04, 0.04, 0.04, 1.0f};
|
||||
@@ -89,15 +86,6 @@ static const ImVec4 IMGUI_TIMELINE_LAYER_ACTIVE_COLOR = {1.000, 0.618, 0.324, 0.
|
||||
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
|
||||
{
|
||||
@@ -105,36 +93,38 @@ struct Imgui
|
||||
Resources* resources = NULL;
|
||||
Input* input = NULL;
|
||||
Anm2* anm2 = NULL;
|
||||
Anm2Reference* reference = NULL;
|
||||
s32* animationID = NULL;
|
||||
s32* spritesheetID = NULL;
|
||||
Editor* editor = NULL;
|
||||
Preview* preview = NULL;
|
||||
Settings* settings = NULL;
|
||||
Tool* tool = NULL;
|
||||
SDL_Window* window = NULL;
|
||||
SDL_GLContext* glContext = NULL;
|
||||
Settings* settings = NULL;
|
||||
s32 animationID = -1;
|
||||
s32 timelineElementID = -1;
|
||||
s32 eventID = -1;
|
||||
s32 spritesheetID = -1;
|
||||
s32 timelineElementIndex = -1;
|
||||
Anm2AnimationType animationType = ANM2_NONE;
|
||||
ToolType tool = TOOL_PAN;
|
||||
void* frameVector = NULL;
|
||||
s32 frameIndex = -1;
|
||||
bool isSwap = false;
|
||||
Anm2Reference swapReference;
|
||||
};
|
||||
|
||||
void imgui_init
|
||||
void
|
||||
imgui_init
|
||||
(
|
||||
Imgui* self,
|
||||
Dialog* dialog,
|
||||
Resources* resources,
|
||||
Input* input,
|
||||
Anm2* anm2,
|
||||
Anm2Reference* reference,
|
||||
s32* animationID,
|
||||
s32* spritesheetID,
|
||||
Editor* editor,
|
||||
Preview* preview,
|
||||
Settings* settings,
|
||||
Tool* tool,
|
||||
SDL_Window* window,
|
||||
SDL_GLContext* glContext
|
||||
);
|
||||
|
||||
void imgui_tick(Imgui* self);
|
||||
void imgui_draw(Imgui* self);
|
||||
void imgui_free(Imgui* self);
|
||||
void imgui_free(Imgui* self);
|
@@ -29,6 +29,19 @@ _mouse_tick(Mouse* self)
|
||||
self->oldPosition = self->position;
|
||||
}
|
||||
|
||||
static void
|
||||
_keyboard_tick(Keyboard* self)
|
||||
{
|
||||
const bool* state;
|
||||
|
||||
memcpy(&self->previous, &self->current, sizeof(self->previous));
|
||||
memset(&self->current, '\0', sizeof(self->current));
|
||||
|
||||
state = SDL_GetKeyboardState(NULL);
|
||||
|
||||
memcpy(&self->current, state, KEY_COUNT);
|
||||
}
|
||||
|
||||
bool
|
||||
mouse_press(Mouse* self, MouseType type)
|
||||
{
|
||||
@@ -47,8 +60,27 @@ mouse_release(Mouse* self, MouseType type)
|
||||
return (!self->current[type] && self->previous[type]);
|
||||
}
|
||||
|
||||
bool
|
||||
key_press(Keyboard* self, KeyType type)
|
||||
{
|
||||
return (self->current[type] && !self->previous[type]);
|
||||
}
|
||||
|
||||
bool
|
||||
key_held(Keyboard* self, KeyType type)
|
||||
{
|
||||
return (self->current[type] && self->previous[type]);
|
||||
}
|
||||
|
||||
bool
|
||||
key_release(Keyboard* self, KeyType type)
|
||||
{
|
||||
return (!self->current[type] && self->previous[type]);
|
||||
}
|
||||
|
||||
void
|
||||
input_tick(Input* self)
|
||||
{
|
||||
_mouse_tick(&self->mouse);
|
||||
_keyboard_tick(&self->keyboard);
|
||||
}
|
||||
|
262
src/input.h
262
src/input.h
@@ -9,22 +9,267 @@ enum MouseType
|
||||
MOUSE_RIGHT
|
||||
};
|
||||
|
||||
#define KEY_COUNT (KEY_DELETE + 1)
|
||||
#define KEY_COUNT (255)
|
||||
enum KeyType
|
||||
{
|
||||
KEY_DELETE
|
||||
KEY_UNKNOWN = 0,
|
||||
KEY_UNKNOWN_TWO = 1,
|
||||
KEY_UNKNOWN_THREE = 2,
|
||||
KEY_UNKNOWN_FOUR = 3,
|
||||
KEY_A = 4,
|
||||
KEY_B = 5,
|
||||
KEY_C = 6,
|
||||
KEY_D = 7,
|
||||
KEY_E = 8,
|
||||
KEY_F = 9,
|
||||
KEY_G = 10,
|
||||
KEY_H = 11,
|
||||
KEY_I = 12,
|
||||
KEY_J = 13,
|
||||
KEY_K = 14,
|
||||
KEY_L = 15,
|
||||
KEY_M = 16,
|
||||
KEY_N = 17,
|
||||
KEY_O = 18,
|
||||
KEY_P = 19,
|
||||
KEY_Q = 20,
|
||||
KEY_R = 21,
|
||||
KEY_S = 22,
|
||||
KEY_T = 23,
|
||||
KEY_U = 24,
|
||||
KEY_V = 25,
|
||||
KEY_W = 26,
|
||||
KEY_X = 27,
|
||||
KEY_Y = 28,
|
||||
KEY_Z = 29,
|
||||
KEY_1 = 30,
|
||||
KEY_2 = 31,
|
||||
KEY_3 = 32,
|
||||
KEY_4 = 33,
|
||||
KEY_5 = 34,
|
||||
KEY_6 = 35,
|
||||
KEY_7 = 36,
|
||||
KEY_8 = 37,
|
||||
KEY_9 = 38,
|
||||
KEY_0 = 39,
|
||||
KEY_RETURN = 40,
|
||||
KEY_ESCAPE = 41,
|
||||
KEY_BACKSPACE = 42,
|
||||
KEY_TAB = 43,
|
||||
KEY_SPACE = 44,
|
||||
KEY_MINUS = 45,
|
||||
KEY_EQUALS = 46,
|
||||
KEY_LEFTBRACKET = 47,
|
||||
KEY_RIGHTBRACKET = 48,
|
||||
KEY_BACKSLASH = 49,
|
||||
KEY_NONUSHASH = 50,
|
||||
KEY_SEMICOLON = 51,
|
||||
KEY_APOSTROPHE = 52,
|
||||
KEY_GRAVE = 53,
|
||||
KEY_COMMA = 54,
|
||||
KEY_PERIOD = 55,
|
||||
KEY_SLASH = 56,
|
||||
KEY_CAPSLOCK = 57,
|
||||
KEY_F1 = 58,
|
||||
KEY_F2 = 59,
|
||||
KEY_F3 = 60,
|
||||
KEY_F4 = 61,
|
||||
KEY_F5 = 62,
|
||||
KEY_F6 = 63,
|
||||
KEY_F7 = 64,
|
||||
KEY_F8 = 65,
|
||||
KEY_F9 = 66,
|
||||
KEY_F10 = 67,
|
||||
KEY_F11 = 68,
|
||||
KEY_F12 = 69,
|
||||
KEY_PRINTSCREEN = 70,
|
||||
KEY_SCROLLLOCK = 71,
|
||||
KEY_PAUSE = 72,
|
||||
KEY_INSERT = 73,
|
||||
KEY_HOME = 74,
|
||||
KEY_PAGEUP = 75,
|
||||
KEY_DELETE = 76,
|
||||
KEY_END = 77,
|
||||
KEY_PAGEDOWN = 78,
|
||||
KEY_RIGHT = 79,
|
||||
KEY_LEFT = 80,
|
||||
KEY_DOWN = 81,
|
||||
KEY_UP = 82,
|
||||
KEY_NUMLOCKCLEAR = 83,
|
||||
KEY_KP_DIVIDE = 84,
|
||||
KEY_KP_MULTIPLY = 85,
|
||||
KEY_KP_MINUS = 86,
|
||||
KEY_KP_PLUS = 87,
|
||||
KEY_KP_ENTER = 88,
|
||||
KEY_KP_1 = 89,
|
||||
KEY_KP_2 = 90,
|
||||
KEY_KP_3 = 91,
|
||||
KEY_KP_4 = 92,
|
||||
KEY_KP_5 = 93,
|
||||
KEY_KP_6 = 94,
|
||||
KEY_KP_7 = 95,
|
||||
KEY_KP_8 = 96,
|
||||
KEY_KP_9 = 97,
|
||||
KEY_KP_0 = 98,
|
||||
KEY_KP_PERIOD = 99,
|
||||
KEY_NONUSBACKSLASH = 100,
|
||||
KEY_APPLICATION = 101,
|
||||
KEY_POWER = 102,
|
||||
KEY_KP_EQUALS = 103,
|
||||
KEY_F13 = 104,
|
||||
KEY_F14 = 105,
|
||||
KEY_F15 = 106,
|
||||
KEY_F16 = 107,
|
||||
KEY_F17 = 108,
|
||||
KEY_F18 = 109,
|
||||
KEY_F19 = 110,
|
||||
KEY_F20 = 111,
|
||||
KEY_F21 = 112,
|
||||
KEY_F22 = 113,
|
||||
KEY_F23 = 114,
|
||||
KEY_F24 = 115,
|
||||
KEY_EXECUTE = 116,
|
||||
KEY_HELP = 117,
|
||||
KEY_MENU = 118,
|
||||
KEY_SELECT = 119,
|
||||
KEY_STOP = 120,
|
||||
KEY_AGAIN = 121,
|
||||
KEY_UNDO = 122,
|
||||
KEY_CUT = 123,
|
||||
KEY_COPY = 124,
|
||||
KEY_PASTE = 125,
|
||||
KEY_FIND = 126,
|
||||
KEY_MUTE = 127,
|
||||
KEY_VOLUMEUP = 128,
|
||||
KEY_VOLUMEDOWN = 129,
|
||||
KEY_LOCKINGCAPSLOCK = 130,
|
||||
KEY_LOCKINGNUMLOCK = 131,
|
||||
KEY_LOCKINGSCROLLLOCK = 132,
|
||||
KEY_KP_COMMA = 133,
|
||||
KEY_KP_EQUALSAS400 = 134,
|
||||
KEY_INTERNATIONAL1 = 135,
|
||||
KEY_INTERNATIONAL2 = 136,
|
||||
KEY_INTERNATIONAL3 = 137,
|
||||
KEY_INTERNATIONAL4 = 138,
|
||||
KEY_INTERNATIONAL5 = 139,
|
||||
KEY_INTERNATIONAL6 = 140,
|
||||
KEY_INTERNATIONAL7 = 141,
|
||||
KEY_INTERNATIONAL8 = 142,
|
||||
KEY_INTERNATIONAL9 = 143,
|
||||
KEY_LANG1 = 144,
|
||||
KEY_LANG2 = 145,
|
||||
KEY_LANG3 = 146,
|
||||
KEY_LANG4 = 147,
|
||||
KEY_LANG5 = 148,
|
||||
KEY_LANG6 = 149,
|
||||
KEY_LANG7 = 150,
|
||||
KEY_LANG8 = 151,
|
||||
KEY_LANG9 = 152,
|
||||
KEY_ALTERASE = 153,
|
||||
KEY_SYSREQ = 154,
|
||||
KEY_CANCEL = 155,
|
||||
KEY_CLEAR = 156,
|
||||
KEY_PRIOR = 157,
|
||||
KEY_RETURN2 = 158,
|
||||
KEY_SEPARATOR = 159,
|
||||
KEY_OUT = 160,
|
||||
KEY_OPER = 161,
|
||||
KEY_CLEARAGAIN = 162,
|
||||
KEY_CRSEL = 163,
|
||||
KEY_EXSEL = 164,
|
||||
KEY_KP_00 = 176,
|
||||
KEY_KP_000 = 177,
|
||||
KEY_THOUSANDSSEPARATOR = 178,
|
||||
KEY_DECIMALSEPARATOR = 179,
|
||||
KEY_CURRENCYUNIT = 180,
|
||||
KEY_CURRENCYSUBUNIT = 181,
|
||||
KEY_KP_LEFTPAREN = 182,
|
||||
KEY_KP_RIGHTPAREN = 183,
|
||||
KEY_KP_LEFTBRACE = 184,
|
||||
KEY_KP_RIGHTBRACE = 185,
|
||||
KEY_KP_TAB = 186,
|
||||
KEY_KP_BACKSPACE = 187,
|
||||
KEY_KP_A = 188,
|
||||
KEY_KP_B = 189,
|
||||
KEY_KP_C = 190,
|
||||
KEY_KP_D = 191,
|
||||
KEY_KP_E = 192,
|
||||
KEY_KP_F = 193,
|
||||
KEY_KP_XOR = 194,
|
||||
KEY_KP_POWER = 195,
|
||||
KEY_KP_PERCENT = 196,
|
||||
KEY_KP_LESS = 197,
|
||||
KEY_KP_GREATER = 198,
|
||||
KEY_KP_AMPERSAND = 199,
|
||||
KEY_KP_DBLAMPERSAND = 200,
|
||||
KEY_KP_VERTICALBAR = 201,
|
||||
KEY_KP_DBLVERTICALBAR = 202,
|
||||
KEY_KP_COLON = 203,
|
||||
KEY_KP_HASH = 204,
|
||||
KEY_KP_SPACE = 205,
|
||||
KEY_KP_AT = 206,
|
||||
KEY_KP_EXCLAM = 207,
|
||||
KEY_KP_MEMSTORE = 208,
|
||||
KEY_KP_MEMRECALL = 209,
|
||||
KEY_KP_MEMCLEAR = 210,
|
||||
KEY_KP_MEMADD = 211,
|
||||
KEY_KP_MEMSUBTRACT = 212,
|
||||
KEY_KP_MEMMULTIPLY = 213,
|
||||
KEY_KP_MEMDIVIDE = 214,
|
||||
KEY_KP_PLUSMINUS = 215,
|
||||
KEY_KP_CLEAR = 216,
|
||||
KEY_KP_CLEARENTRY = 217,
|
||||
KEY_KP_BINARY = 218,
|
||||
KEY_KP_OCTAL = 219,
|
||||
KEY_KP_DECIMAL = 220,
|
||||
KEY_KP_HEXADECIMAL = 221,
|
||||
KEY_LCTRL = 224,
|
||||
KEY_LSHIFT = 225,
|
||||
KEY_LALT = 226,
|
||||
KEY_LGUI = 227,
|
||||
KEY_RCTRL = 228,
|
||||
KEY_RSHIFT = 229,
|
||||
KEY_RALT = 230,
|
||||
KEY_RGUI = 231
|
||||
};
|
||||
|
||||
#define INPUT_COUNT (INPUT_MOUSE_CLICK + 1)
|
||||
#define INPUT_COUNT (INPUT_ZOOM_OUT + 1)
|
||||
enum InputType
|
||||
{
|
||||
INPUT_MOUSE_CLICK
|
||||
INPUT_PAN,
|
||||
INPUT_MOVE,
|
||||
INPUT_SCALE,
|
||||
INPUT_CROP,
|
||||
INPUT_LEFT,
|
||||
INPUT_RIGHT,
|
||||
INPUT_UP,
|
||||
INPUT_DOWN,
|
||||
INPUT_ROTATE_LEFT,
|
||||
INPUT_ROTATE_RIGHT,
|
||||
INPUT_ZOOM_IN,
|
||||
INPUT_ZOOM_OUT
|
||||
};
|
||||
|
||||
static const KeyType INPUT_KEYS[INPUT_COUNT]
|
||||
{
|
||||
KEY_SPACE,
|
||||
KEY_T,
|
||||
KEY_S,
|
||||
KEY_C,
|
||||
KEY_LEFT,
|
||||
KEY_RIGHT,
|
||||
KEY_UP,
|
||||
KEY_DOWN,
|
||||
KEY_Q,
|
||||
KEY_W,
|
||||
KEY_1,
|
||||
KEY_2
|
||||
};
|
||||
|
||||
struct Keyboard
|
||||
{
|
||||
bool current[MOUSE_COUNT];
|
||||
bool previous[MOUSE_COUNT];
|
||||
bool current[KEY_COUNT];
|
||||
bool previous[KEY_COUNT];
|
||||
};
|
||||
|
||||
struct Mouse
|
||||
@@ -39,11 +284,14 @@ struct Mouse
|
||||
|
||||
struct Input
|
||||
{
|
||||
Keyboard keyboard;
|
||||
Mouse mouse;
|
||||
Keyboard keyboard;
|
||||
};
|
||||
|
||||
bool mouse_press(Mouse* self, MouseType type);
|
||||
bool mouse_held(Mouse* self, MouseType type);
|
||||
bool mouse_release(Mouse* self, MouseType type);
|
||||
bool key_press(Keyboard* self, KeyType type);
|
||||
bool key_held(Keyboard* self, KeyType type);
|
||||
bool key_release(Keyboard* self, KeyType type);
|
||||
void input_tick(Input* self);
|
107
src/preview.cpp
107
src/preview.cpp
@@ -1,7 +1,7 @@
|
||||
#include "preview.h"
|
||||
|
||||
static void _preview_axis_set(Preview* self);
|
||||
static void _preview_grid_set(Preview* self);
|
||||
static s32 _preview_grid_set(Preview* self);
|
||||
|
||||
static void
|
||||
_preview_axis_set(Preview* self)
|
||||
@@ -16,13 +16,14 @@ _preview_axis_set(Preview* self)
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
static void
|
||||
/* Sets and returns the grid's vertices */
|
||||
static s32
|
||||
_preview_grid_set(Preview* self)
|
||||
{
|
||||
std::vector<f32> vertices;
|
||||
|
||||
s32 verticalLineCount = PREVIEW_SIZE.x / MIN(self->settings->previewGridSizeX, PREVIEW_GRID_MIN);
|
||||
s32 horizontalLineCount = PREVIEW_SIZE.y / MIN(self->settings->previewGridSizeY, PREVIEW_GRID_MIN);
|
||||
s32 verticalLineCount = (s32)(PREVIEW_SIZE.x / MIN(self->settings->previewGridSizeX, PREVIEW_GRID_MIN));
|
||||
s32 horizontalLineCount = (s32)(PREVIEW_SIZE.y / MIN(self->settings->previewGridSizeY, PREVIEW_GRID_MIN));
|
||||
|
||||
/* Vertical */
|
||||
for (s32 i = 0; i <= verticalLineCount; i++)
|
||||
@@ -48,22 +49,23 @@ _preview_grid_set(Preview* self)
|
||||
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);
|
||||
|
||||
return (s32)vertices.size();
|
||||
}
|
||||
|
||||
void
|
||||
preview_init(Preview* self, Anm2* anm2, Resources* resources, Input* input, Settings* settings)
|
||||
preview_init(Preview* self, Anm2* anm2, Anm2Reference* reference, s32* animationID, Resources* resources, Settings* settings)
|
||||
{
|
||||
self->anm2 = anm2;
|
||||
self->reference = reference;
|
||||
self->animationID = animationID;
|
||||
self->resources = resources;
|
||||
self->input = input;
|
||||
self->settings = settings;
|
||||
|
||||
/* Framebuffer + texture */
|
||||
@@ -137,14 +139,11 @@ void
|
||||
preview_tick(Preview* self)
|
||||
{
|
||||
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);
|
||||
|
||||
Anm2Animation* animation = anm2_animation_from_id(self->anm2, *self->animationID);
|
||||
|
||||
if (self->animationID > -1)
|
||||
if (animation)
|
||||
{
|
||||
Anm2Animation* animation = &self->anm2->animations[self->animationID];
|
||||
|
||||
if (self->isPlaying)
|
||||
{
|
||||
self->time += (f32)self->anm2->fps / TICK_RATE;
|
||||
@@ -162,7 +161,7 @@ preview_draw(Preview* self)
|
||||
{
|
||||
GLuint shaderLine = self->resources->shaders[SHADER_LINE];
|
||||
GLuint shaderTexture = self->resources->shaders[SHADER_TEXTURE];
|
||||
|
||||
|
||||
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));
|
||||
@@ -183,12 +182,18 @@ preview_draw(Preview* self)
|
||||
/* Grid */
|
||||
if (self->settings->previewIsGrid)
|
||||
{
|
||||
if
|
||||
(
|
||||
(ivec2(self->settings->previewGridSizeX, self->settings->previewGridSizeY) != self->oldGridSize) ||
|
||||
(ivec2(self->settings->previewGridOffsetX, self->settings->previewGridOffsetY) != self->oldGridOffset)
|
||||
)
|
||||
_preview_grid_set(self);
|
||||
static ivec2 previousGridSize = {-1, -1};
|
||||
static ivec2 previousGridOffset = {-1, -1};
|
||||
static s32 gridVertexCount = -1;
|
||||
ivec2 gridSize = ivec2(self->settings->previewGridSizeX, self->settings->previewGridSizeY);
|
||||
ivec2 gridOffset = ivec2(self->settings->previewGridOffsetX, self->settings->previewGridOffsetY);
|
||||
|
||||
if (previousGridSize != gridSize || previousGridOffset != gridOffset)
|
||||
{
|
||||
gridVertexCount = _preview_grid_set(self);
|
||||
previousGridSize = gridSize;
|
||||
previousGridOffset = gridOffset;
|
||||
}
|
||||
|
||||
glUseProgram(shaderLine);
|
||||
glBindVertexArray(self->gridVAO);
|
||||
@@ -200,7 +205,7 @@ preview_draw(Preview* self)
|
||||
self->settings->previewGridColorR, self->settings->previewGridColorG, self->settings->previewGridColorB, self->settings->previewGridColorA
|
||||
);
|
||||
|
||||
glDrawArrays(GL_LINES, 0, self->gridVertexCount);
|
||||
glDrawArrays(GL_LINES, 0, gridVertexCount);
|
||||
|
||||
glBindVertexArray(0);
|
||||
glUseProgram(0);
|
||||
@@ -230,33 +235,32 @@ preview_draw(Preview* self)
|
||||
|
||||
glDrawArrays(GL_LINES, 2, 2);
|
||||
|
||||
|
||||
glBindVertexArray(0);
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
Anm2Animation* animation = anm2_animation_from_id(self->anm2, *self->animationID);
|
||||
|
||||
/* Animation */
|
||||
if (self->animationID > -1)
|
||||
if (animation)
|
||||
{
|
||||
Anm2Frame rootFrame = Anm2Frame{};
|
||||
Anm2Animation* animation = &self->anm2->animations[self->animationID];
|
||||
bool isRootFrame = anm2_frame_from_time(self->anm2, animation, &rootFrame, ANM2_ROOT_ANIMATION, 0, self->time);
|
||||
Anm2Frame rootFrame;
|
||||
anm2_frame_from_time(self->anm2, &rootFrame, Anm2Reference{ANM2_ROOT, 0, 0}, *self->animationID, self->time);
|
||||
|
||||
/* Layers (Reversed) */
|
||||
/* Layers */
|
||||
for (auto & [id, layerAnimation] : animation->layerAnimations)
|
||||
{
|
||||
if (!layerAnimation.isVisible || layerAnimation.frames.size() <= 0)
|
||||
continue;
|
||||
|
||||
Anm2Layer* layer = &self->anm2->layers[id];
|
||||
Anm2Frame frame = layerAnimation.frames[0];
|
||||
Anm2Frame frame;
|
||||
|
||||
anm2_frame_from_time(self->anm2, animation, &frame, ANM2_LAYER_ANIMATION, id, self->time);
|
||||
anm2_frame_from_time(self->anm2, &frame, Anm2Reference{ANM2_LAYER, id, 0}, *self->animationID, self->time);
|
||||
|
||||
if (!frame.isVisible)
|
||||
continue;
|
||||
|
||||
Texture* texture = &self->resources->textures[layer->spritesheetID];
|
||||
Texture* texture = &self->resources->textures[self->anm2->layers[id].spritesheetID];
|
||||
|
||||
if (texture->isInvalid)
|
||||
continue;
|
||||
@@ -264,7 +268,7 @@ preview_draw(Preview* self)
|
||||
glm::mat4 layerTransform = previewTransform;
|
||||
|
||||
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 scale = 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);
|
||||
@@ -276,7 +280,6 @@ preview_draw(Preview* self)
|
||||
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);
|
||||
|
||||
@@ -305,17 +308,13 @@ preview_draw(Preview* self)
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
/* Root */
|
||||
if
|
||||
(isRootFrame && animation->rootAnimation.isVisible && rootFrame.isVisible)
|
||||
if (animation->rootAnimation.isVisible && rootFrame.isVisible)
|
||||
{
|
||||
glm::mat4 rootTransform = previewTransform;
|
||||
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);
|
||||
glm::vec2 ndcPos = (rootFrame.position - (PREVIEW_TARGET_SIZE / 2.0f)) / (PREVIEW_SIZE / 2.0f);
|
||||
glm::vec2 ndcScale = PREVIEW_TARGET_SIZE / (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[] = ATLAS_UV_VERTICES(TEXTURE_TARGET);
|
||||
@@ -346,17 +345,15 @@ preview_draw(Preview* self)
|
||||
/* Pivots */
|
||||
if (self->settings->previewIsShowPivot)
|
||||
{
|
||||
for (auto it = animation->layerAnimations.rbegin(); it != animation->layerAnimations.rend(); it++)
|
||||
/* Layers (Reversed) */
|
||||
for (auto & [id, layerAnimation] : animation->layerAnimations)
|
||||
{
|
||||
s32 id = it->first;
|
||||
Anm2LayerAnimation layerAnimation = it->second;
|
||||
|
||||
if (!layerAnimation.isVisible || layerAnimation.frames.size() <= 0)
|
||||
continue;
|
||||
|
||||
Anm2Frame frame = layerAnimation.frames[0];
|
||||
Anm2Frame frame;
|
||||
|
||||
anm2_frame_from_time(self->anm2, animation, &frame, ANM2_LAYER_ANIMATION, id, self->time);
|
||||
anm2_frame_from_time(self->anm2, &frame, Anm2Reference{ANM2_LAYER, id, 0}, *self->animationID, self->time);
|
||||
|
||||
if (!frame.isVisible)
|
||||
continue;
|
||||
@@ -365,8 +362,8 @@ preview_draw(Preview* self)
|
||||
|
||||
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);
|
||||
glm::vec2 ndcPos = (position - (PREVIEW_PIVOT_SIZE / 2.0f)) / (PREVIEW_SIZE / 2.0f);
|
||||
glm::vec2 ndcScale = PREVIEW_PIVOT_SIZE / (PREVIEW_SIZE / 2.0f);
|
||||
|
||||
pivotTransform = glm::translate(pivotTransform, glm::vec3(ndcPos, 0.0f));
|
||||
pivotTransform = glm::scale(pivotTransform, glm::vec3(ndcScale, 1.0f));
|
||||
@@ -403,21 +400,19 @@ preview_draw(Preview* self)
|
||||
if (!nullAnimation.isVisible || nullAnimation.frames.size() <= 0)
|
||||
continue;
|
||||
|
||||
Anm2Frame frame = nullAnimation.frames[0];
|
||||
Anm2Frame frame;
|
||||
|
||||
anm2_frame_from_time(self->anm2, animation, &frame, ANM2_NULL_ANIMATION, id, self->time);
|
||||
anm2_frame_from_time(self->anm2, &frame, Anm2Reference{ANM2_NULL, id, 0}, *self->animationID, self->time);
|
||||
|
||||
if (!frame.isVisible)
|
||||
continue;
|
||||
|
||||
Anm2Null* null = NULL;
|
||||
|
||||
null = &self->anm2->nulls[id];
|
||||
Anm2Null* 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 size = null->isShowRect ? PREVIEW_POINT_SIZE : PREVIEW_TARGET_SIZE;
|
||||
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);
|
||||
@@ -477,8 +472,6 @@ preview_draw(Preview* self)
|
||||
}
|
||||
}
|
||||
|
||||
glUseProgram(0);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
|
@@ -15,6 +15,9 @@ static const vec2 PREVIEW_CENTER = {0, 0};
|
||||
#define PREVIEW_GRID_MAX 1000
|
||||
#define PREVIEW_GRID_OFFSET_MIN 0
|
||||
#define PREVIEW_GRID_OFFSET_MAX 100
|
||||
#define PREVIEW_MOVE_STEP 1
|
||||
#define PREVIEW_ROTATE_STEP 1
|
||||
#define PREVIEW_SCALE_STEP 1
|
||||
|
||||
static const f32 PREVIEW_AXIS_VERTICES[] =
|
||||
{
|
||||
@@ -26,16 +29,20 @@ static const f32 PREVIEW_AXIS_VERTICES[] =
|
||||
|
||||
static const vec2 PREVIEW_NULL_RECT_SIZE = {100, 100};
|
||||
static const vec2 PREVIEW_POINT_SIZE = {2, 2};
|
||||
static const vec2 PREVIEW_PIVOT_SIZE = {4, 4};
|
||||
static const vec4 PREVIEW_ROOT_TINT = COLOR_GREEN;
|
||||
static const vec4 PREVIEW_NULL_TINT = COLOR_BLUE;
|
||||
static const vec4 PREVIEW_PIVOT_TINT = COLOR_RED;
|
||||
static const vec2 PREVIEW_TARGET_SIZE = {16, 16};
|
||||
|
||||
struct Preview
|
||||
{
|
||||
Anm2* anm2 = NULL;
|
||||
Anm2Reference* reference = NULL;
|
||||
Input* input = NULL;
|
||||
Resources* resources = NULL;
|
||||
Settings* settings = NULL;
|
||||
s32* animationID = NULL;
|
||||
GLuint axisVAO;
|
||||
GLuint axisVBO;
|
||||
GLuint fbo;
|
||||
@@ -50,14 +57,9 @@ struct Preview
|
||||
GLuint textureVBO;
|
||||
bool isPlaying = false;
|
||||
f32 time = 0;
|
||||
ivec2 oldGridOffset = {-1, -1};
|
||||
ivec2 oldGridSize = {-1, -1};
|
||||
ivec2 viewport = PREVIEW_SIZE;
|
||||
s32 animationID = -1;
|
||||
s32 gridVertexCount = -1;
|
||||
};
|
||||
|
||||
void preview_init(Preview* self, Anm2* anm2, Resources* resources, Input* input, Settings* settings);
|
||||
void preview_init(Preview* self, Anm2* anm2, Anm2Reference* reference, s32* animationID, Resources* resources, Settings* settings);
|
||||
void preview_draw(Preview* self);
|
||||
void preview_tick(Preview* self);
|
||||
void preview_free(Preview* self);
|
||||
|
@@ -52,6 +52,7 @@ enum SettingsItem
|
||||
SETTINGS_PREVIEW_BACKGROUND_COLOR_B,
|
||||
SETTINGS_PREVIEW_BACKGROUND_COLOR_A,
|
||||
SETTINGS_EDITOR_IS_GRID,
|
||||
SETTINGS_EDITOR_IS_GRID_SNAP,
|
||||
SETTINGS_EDITOR_IS_BORDER,
|
||||
SETTINGS_EDITOR_PAN_X,
|
||||
SETTINGS_EDITOR_PAN_Y,
|
||||
@@ -98,6 +99,7 @@ struct Settings
|
||||
f32 previewBackgroundColorB = 0.286f;
|
||||
f32 previewBackgroundColorA = 1.0f;
|
||||
bool editorIsGrid = true;
|
||||
bool editorIsGridSnap = true;
|
||||
bool editorIsBorder = true;
|
||||
f32 editorPanX = 0.0f;
|
||||
f32 editorPanY = 0.0f;
|
||||
@@ -144,6 +146,7 @@ static const SettingsEntry SETTINGS_ENTRIES[SETTINGS_COUNT] =
|
||||
{"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)},
|
||||
{"editorIsGridSnap=", "editorIsGridSnap=%i", SETTINGS_TYPE_BOOL, offsetof(Settings, editorIsGridSnap)},
|
||||
{"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)},
|
||||
|
@@ -34,6 +34,7 @@ _tick(State* state)
|
||||
input_tick(&state->input);
|
||||
editor_tick(&state->editor);
|
||||
preview_tick(&state->preview);
|
||||
tool_tick(&state->tool);
|
||||
dialog_tick(&state->dialog);
|
||||
imgui_tick(&state->imgui);
|
||||
}
|
||||
@@ -104,10 +105,29 @@ init(State* state)
|
||||
printf(STRING_INFO_GLEW_INIT);
|
||||
|
||||
resources_init(&state->resources);
|
||||
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);
|
||||
dialog_init(&state->dialog, &state->anm2, &state->reference, &state->resources, state->window);
|
||||
tool_init(&state->tool, &state->input);
|
||||
|
||||
preview_init
|
||||
(
|
||||
&state->preview,
|
||||
&state->anm2,
|
||||
&state->reference,
|
||||
&state->animationID,
|
||||
&state->resources,
|
||||
&state->settings
|
||||
);
|
||||
|
||||
editor_init
|
||||
(
|
||||
&state->editor,
|
||||
&state->anm2,
|
||||
&state->reference,
|
||||
&state->animationID,
|
||||
&state->spritesheetID,
|
||||
&state->resources,
|
||||
&state->settings
|
||||
);
|
||||
|
||||
imgui_init
|
||||
(
|
||||
@@ -116,10 +136,14 @@ init(State* state)
|
||||
&state->resources,
|
||||
&state->input,
|
||||
&state->anm2,
|
||||
&state->reference,
|
||||
&state->animationID,
|
||||
&state->spritesheetID,
|
||||
&state->editor,
|
||||
&state->preview,
|
||||
&state->settings,
|
||||
state->window,
|
||||
&state->tool,
|
||||
state->window,
|
||||
&state->glContext
|
||||
);
|
||||
|
||||
@@ -144,10 +168,11 @@ loop(State* state)
|
||||
SDL_Delay(TICK_DELAY - (state->tick - state->lastTick));
|
||||
|
||||
_tick(state);
|
||||
_draw(state);
|
||||
|
||||
state->lastTick = state->tick;
|
||||
}
|
||||
|
||||
_draw(state);
|
||||
}
|
||||
|
||||
void
|
||||
|
10
src/state.h
10
src/state.h
@@ -18,14 +18,18 @@ struct State
|
||||
Editor editor;
|
||||
Preview preview;
|
||||
Anm2 anm2;
|
||||
Anm2Reference reference;
|
||||
Resources resources;
|
||||
Settings settings;
|
||||
Tool tool;
|
||||
bool isArgument = false;
|
||||
bool isRunning = true;
|
||||
char argument[PATH_MAX] = STRING_EMPTY;
|
||||
char startPath[PATH_MAX] = STRING_EMPTY;
|
||||
bool isArgument = false;
|
||||
u64 tick = 0;
|
||||
s32 animationID = -1;
|
||||
s32 spritesheetID = -1;
|
||||
u64 lastTick = 0;
|
||||
bool isRunning = true;
|
||||
u64 tick = 0;
|
||||
};
|
||||
|
||||
void init(State* state);
|
||||
|
33
src/tool.cpp
Normal file
33
src/tool.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#include "tool.h"
|
||||
|
||||
void
|
||||
tool_init(Tool* self, Input* input)
|
||||
{
|
||||
self->input = input;
|
||||
}
|
||||
|
||||
void
|
||||
tool_tick(Tool* self)
|
||||
{
|
||||
if (!self->isEnabled) return;
|
||||
|
||||
/* Input handling */
|
||||
if (key_press(&self->input->keyboard, INPUT_KEYS[INPUT_PAN]))
|
||||
self->type = TOOL_PAN;
|
||||
|
||||
if (key_press(&self->input->keyboard, INPUT_KEYS[INPUT_MOVE]))
|
||||
self->type = TOOL_MOVE;
|
||||
|
||||
if (key_press(&self->input->keyboard, INPUT_KEYS[INPUT_SCALE]))
|
||||
self->type = TOOL_SCALE;
|
||||
|
||||
if (key_press(&self->input->keyboard, INPUT_KEYS[INPUT_CROP]))
|
||||
self->type = TOOL_CROP;
|
||||
|
||||
if
|
||||
(
|
||||
key_press(&self->input->keyboard, INPUT_KEYS[INPUT_ROTATE_LEFT]) ||
|
||||
key_press(&self->input->keyboard, INPUT_KEYS[INPUT_ROTATE_RIGHT])
|
||||
)
|
||||
self->type = TOOL_ROTATE;
|
||||
}
|
23
src/tool.h
Normal file
23
src/tool.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "input.h"
|
||||
|
||||
#define TOOL_COUNT (TOOL_CROP + 1)
|
||||
enum ToolType
|
||||
{
|
||||
TOOL_PAN,
|
||||
TOOL_MOVE,
|
||||
TOOL_ROTATE,
|
||||
TOOL_SCALE,
|
||||
TOOL_CROP
|
||||
};
|
||||
|
||||
struct Tool
|
||||
{
|
||||
Input* input = NULL;
|
||||
ToolType type = TOOL_PAN;
|
||||
bool isEnabled = false;
|
||||
};
|
||||
|
||||
void tool_init(Tool* self, Input* input);
|
||||
void tool_tick(Tool* self);
|
Reference in New Issue
Block a user