it's kind of finished
This commit is contained in:
		
							
								
								
									
										30
									
								
								src/COMMON.h
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								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)
 | 
			
		||||
{
 | 
			
		||||
    auto it1 = map.find(key1);
 | 
			
		||||
    auto it2 = map.find(key2);
 | 
			
		||||
    if (it1 == map.end() || it2 == map.end())
 | 
			
		||||
    if (key1 == key2)
 | 
			
		||||
        return;
 | 
			
		||||
    
 | 
			
		||||
    using std::swap;
 | 
			
		||||
    swap(it1->second, it2->second);
 | 
			
		||||
}
 | 
			
		||||
    auto it1 = map.find(key1);
 | 
			
		||||
    auto it2 = map.find(key2);
 | 
			
		||||
 | 
			
		||||
    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"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										474
									
								
								src/anm2.cpp
									
									
									
									
									
								
							
							
						
						
									
										474
									
								
								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);
 | 
			
		||||
							
								
								
									
										1415
									
								
								src/imgui.cpp
									
									
									
									
									
								
							
							
						
						
									
										1415
									
								
								src/imgui.cpp
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										50
									
								
								src/imgui.h
									
									
									
									
									
								
							
							
						
						
									
										50
									
								
								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,32 +93,34 @@ 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
 | 
			
		||||
);
 | 
			
		||||
 
 | 
			
		||||
@@ -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 */
 | 
			
		||||
@@ -138,13 +140,10 @@ 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;
 | 
			
		||||
@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Animation */
 | 
			
		||||
    if (self->animationID > -1)
 | 
			
		||||
    {
 | 
			
		||||
        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);
 | 
			
		||||
    Anm2Animation* animation = anm2_animation_from_id(self->anm2, *self->animationID);
 | 
			
		||||
    
 | 
			
		||||
        /* Layers (Reversed) */
 | 
			
		||||
    /* Animation */
 | 
			
		||||
    if (animation)
 | 
			
		||||
    {
 | 
			
		||||
        Anm2Frame rootFrame;
 | 
			
		||||
        anm2_frame_from_time(self->anm2, &rootFrame, Anm2Reference{ANM2_ROOT, 0, 0}, *self->animationID, self->time);
 | 
			
		||||
 | 
			
		||||
        /* 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);
 | 
			
		||||
	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->resources, &state->input, &state->settings);
 | 
			
		||||
	editor_init(&state->editor, &state->resources, &state->settings);
 | 
			
		||||
	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,9 +136,13 @@ init(State* state)
 | 
			
		||||
		&state->resources,
 | 
			
		||||
		&state->input,
 | 
			
		||||
		&state->anm2,
 | 
			
		||||
		&state->reference,
 | 
			
		||||
		&state->animationID,
 | 
			
		||||
		&state->spritesheetID,
 | 
			
		||||
		&state->editor,
 | 
			
		||||
		&state->preview,
 | 
			
		||||
		&state->settings,
 | 
			
		||||
		&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