Redid layer system, added layer/null windows, more quality of life, polish
This commit is contained in:
22
src/COMMON.h
22
src/COMMON.h
@@ -233,8 +233,10 @@ static inline s32 map_next_id_get(const std::map<s32, T>& map)
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static inline T* map_find(std::map<s32, T>& map, s32 id)
|
template <typename Map>
|
||||||
|
static inline auto map_find(Map& map, typename Map::key_type id)
|
||||||
|
-> typename Map::mapped_type*
|
||||||
{
|
{
|
||||||
if (auto it = map.find(id); it != map.end())
|
if (auto it = map.find(id); it != map.end())
|
||||||
return &it->second;
|
return &it->second;
|
||||||
@@ -289,6 +291,22 @@ static inline void map_insert_shift(std::map<int, T>& map, s32 index, const T& v
|
|||||||
map[insertIndex] = value;
|
map[insertIndex] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void vector_value_erase(std::vector<T>& v, const T& value)
|
||||||
|
{
|
||||||
|
v.erase(std::remove(v.begin(), v.end(), value), v.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void vector_value_swap(std::vector<T>& v, const T& a, const T& b)
|
||||||
|
{
|
||||||
|
for (auto& element : v)
|
||||||
|
{
|
||||||
|
if (element == a) element = b;
|
||||||
|
else if (element == b) element = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline mat4 quad_model_get(vec2 size = {}, vec2 position = {}, vec2 pivot = {}, vec2 scale = vec2(1.0f), f32 rotation = {})
|
static inline mat4 quad_model_get(vec2 size = {}, vec2 position = {}, vec2 pivot = {}, vec2 scale = vec2(1.0f), f32 rotation = {})
|
||||||
{
|
{
|
||||||
vec2 scaleAbsolute = glm::abs(scale);
|
vec2 scaleAbsolute = glm::abs(scale);
|
||||||
|
150
src/anm2.cpp
150
src/anm2.cpp
@@ -64,7 +64,7 @@ void anm2_frame_serialize(Anm2Frame* frame, Anm2Type type, XMLDocument* document
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void anm2_animation_serialize(Anm2* self, Anm2Animation* animation, XMLDocument* document = nullptr, XMLElement* addElement = nullptr, std::string* string = nullptr)
|
void anm2_animation_serialize(Anm2Animation* animation, XMLDocument* document = nullptr, XMLElement* addElement = nullptr, std::string* string = nullptr)
|
||||||
{
|
{
|
||||||
XMLDocument localDocument;
|
XMLDocument localDocument;
|
||||||
XMLDocument* useDocument = document ? document : &localDocument;
|
XMLDocument* useDocument = document ? document : &localDocument;
|
||||||
@@ -86,7 +86,7 @@ void anm2_animation_serialize(Anm2* self, Anm2Animation* animation, XMLDocument*
|
|||||||
// LayerAnimations
|
// LayerAnimations
|
||||||
XMLElement* layersElement = useDocument->NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_LAYER_ANIMATIONS]);
|
XMLElement* layersElement = useDocument->NewElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_LAYER_ANIMATIONS]);
|
||||||
|
|
||||||
for (auto& [i, id] : self->layerMap)
|
for (auto& id : animation->layerOrder)
|
||||||
{
|
{
|
||||||
// LayerAnimation
|
// LayerAnimation
|
||||||
Anm2Item& layerAnimation = animation->layerAnimations[id];
|
Anm2Item& layerAnimation = animation->layerAnimations[id];
|
||||||
@@ -231,7 +231,7 @@ bool anm2_serialize(Anm2* self, const std::string& path)
|
|||||||
animationsElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_DEFAULT_ANIMATION], self->animations[self->defaultAnimationID].name.c_str()); // DefaultAnimation
|
animationsElement->SetAttribute(ANM2_ATTRIBUTE_STRINGS[ANM2_ATTRIBUTE_DEFAULT_ANIMATION], self->animations[self->defaultAnimationID].name.c_str()); // DefaultAnimation
|
||||||
|
|
||||||
for (auto& [id, animation] : self->animations)
|
for (auto& [id, animation] : self->animations)
|
||||||
anm2_animation_serialize(self, &animation, &document, animationsElement);
|
anm2_animation_serialize(&animation, &document, animationsElement);
|
||||||
|
|
||||||
animatedActorElement->InsertEndChild(animationsElement);
|
animatedActorElement->InsertEndChild(animationsElement);
|
||||||
|
|
||||||
@@ -248,7 +248,7 @@ bool anm2_serialize(Anm2* self, const std::string& path)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _anm2_frame_deserialize(Anm2* self, Anm2Frame* frame, const XMLElement* element)
|
static void _anm2_frame_deserialize(Anm2Frame* frame, const XMLElement* element)
|
||||||
{
|
{
|
||||||
for (const XMLAttribute* attribute = element->FirstAttribute(); attribute; attribute = attribute->Next())
|
for (const XMLAttribute* attribute = element->FirstAttribute(); attribute; attribute = attribute->Next())
|
||||||
{
|
{
|
||||||
@@ -276,18 +276,13 @@ static void _anm2_frame_deserialize(Anm2* self, Anm2Frame* frame, const XMLEleme
|
|||||||
case ANM2_ATTRIBUTE_INTERPOLATED: frame->isInterpolated = string_to_bool(attribute->Value()); break; // Interpolated
|
case ANM2_ATTRIBUTE_INTERPOLATED: frame->isInterpolated = string_to_bool(attribute->Value()); break; // Interpolated
|
||||||
case ANM2_ATTRIBUTE_AT_FRAME: frame->atFrame = std::atoi(attribute->Value()); break; // AtFrame
|
case ANM2_ATTRIBUTE_AT_FRAME: frame->atFrame = std::atoi(attribute->Value()); break; // AtFrame
|
||||||
case ANM2_ATTRIBUTE_DELAY: frame->delay = std::atoi(attribute->Value()); break; // Delay
|
case ANM2_ATTRIBUTE_DELAY: frame->delay = std::atoi(attribute->Value()); break; // Delay
|
||||||
case ANM2_ATTRIBUTE_EVENT_ID: // EventID
|
case ANM2_ATTRIBUTE_EVENT_ID: frame->eventID = std::atoi(attribute->Value()); break; // EventID
|
||||||
{
|
|
||||||
s32 eventID = std::atoi(attribute->Value());
|
|
||||||
frame->eventID = map_find(self->events, eventID) ? eventID : ID_NONE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _anm2_animation_deserialize(Anm2* self, Anm2Animation* animation, const XMLElement* element)
|
static void _anm2_animation_deserialize(Anm2Animation* animation, const XMLElement* element)
|
||||||
{
|
{
|
||||||
auto frames_deserialize = [&](const XMLElement* itemElement, Anm2Item* item)
|
auto frames_deserialize = [&](const XMLElement* itemElement, Anm2Item* item)
|
||||||
{
|
{
|
||||||
@@ -297,7 +292,7 @@ static void _anm2_animation_deserialize(Anm2* self, Anm2Animation* animation, co
|
|||||||
const XMLElement* frame = itemElement->FirstChildElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_FRAME]);
|
const XMLElement* frame = itemElement->FirstChildElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_FRAME]);
|
||||||
frame; frame = frame->NextSiblingElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_FRAME])
|
frame; frame = frame->NextSiblingElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_FRAME])
|
||||||
)
|
)
|
||||||
_anm2_frame_deserialize(self, &item->frames.emplace_back(Anm2Frame()), frame);
|
_anm2_frame_deserialize(&item->frames.emplace_back(Anm2Frame()), frame);
|
||||||
};
|
};
|
||||||
|
|
||||||
s32 id{};
|
s32 id{};
|
||||||
@@ -320,8 +315,6 @@ static void _anm2_animation_deserialize(Anm2* self, Anm2Animation* animation, co
|
|||||||
// LayerAnimations
|
// LayerAnimations
|
||||||
if (const XMLElement* layerAnimations = element->FirstChildElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_LAYER_ANIMATIONS]))
|
if (const XMLElement* layerAnimations = element->FirstChildElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_LAYER_ANIMATIONS]))
|
||||||
{
|
{
|
||||||
s32 layerMapIndex = 0;
|
|
||||||
|
|
||||||
// LayerAnimation
|
// LayerAnimation
|
||||||
for
|
for
|
||||||
(
|
(
|
||||||
@@ -331,7 +324,6 @@ static void _anm2_animation_deserialize(Anm2* self, Anm2Animation* animation, co
|
|||||||
{
|
{
|
||||||
Anm2Item layerAnimationItem;
|
Anm2Item layerAnimationItem;
|
||||||
|
|
||||||
|
|
||||||
for (const XMLAttribute* attribute = layerAnimation->FirstAttribute(); attribute; attribute = attribute->Next())
|
for (const XMLAttribute* attribute = layerAnimation->FirstAttribute(); attribute; attribute = attribute->Next())
|
||||||
{
|
{
|
||||||
switch (ANM2_ATTRIBUTE_STRING_TO_ENUM(attribute->Name()))
|
switch (ANM2_ATTRIBUTE_STRING_TO_ENUM(attribute->Name()))
|
||||||
@@ -344,9 +336,7 @@ static void _anm2_animation_deserialize(Anm2* self, Anm2Animation* animation, co
|
|||||||
|
|
||||||
frames_deserialize(layerAnimation, &layerAnimationItem);
|
frames_deserialize(layerAnimation, &layerAnimationItem);
|
||||||
animation->layerAnimations[id] = layerAnimationItem;
|
animation->layerAnimations[id] = layerAnimationItem;
|
||||||
|
animation->layerOrder.push_back(id);
|
||||||
self->layerMap[id] = layerMapIndex;
|
|
||||||
layerMapIndex++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -386,7 +376,7 @@ static void _anm2_animation_deserialize(Anm2* self, Anm2Animation* animation, co
|
|||||||
const XMLElement* trigger = triggers->FirstChildElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_TRIGGER]);
|
const XMLElement* trigger = triggers->FirstChildElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_TRIGGER]);
|
||||||
trigger; trigger = trigger->NextSiblingElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_TRIGGER])
|
trigger; trigger = trigger->NextSiblingElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_TRIGGER])
|
||||||
)
|
)
|
||||||
_anm2_frame_deserialize(self, &animation->triggers.frames.emplace_back(Anm2Frame()), trigger);
|
_anm2_frame_deserialize(&animation->triggers.frames.emplace_back(Anm2Frame()), trigger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -568,7 +558,7 @@ bool anm2_deserialize(Anm2* self, const std::string& path, bool isTextures)
|
|||||||
const XMLElement* animation = animations->FirstChildElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_ANIMATION]);
|
const XMLElement* animation = animations->FirstChildElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_ANIMATION]);
|
||||||
animation; animation = animation->NextSiblingElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_ANIMATION])
|
animation; animation = animation->NextSiblingElement(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_ANIMATION])
|
||||||
)
|
)
|
||||||
_anm2_animation_deserialize(self, &self->animations[map_next_id_get(self->animations)], animation);
|
_anm2_animation_deserialize(&self->animations[map_next_id_get(self->animations)], animation);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& [id, animation] : self->animations)
|
for (auto& [id, animation] : self->animations)
|
||||||
@@ -584,99 +574,68 @@ bool anm2_deserialize(Anm2* self, const std::string& path, bool isTextures)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void anm2_layer_add(Anm2* self)
|
void anm2_animation_layer_animation_add(Anm2Animation* animation, s32 id)
|
||||||
|
{
|
||||||
|
animation->layerAnimations[id] = Anm2Item{};
|
||||||
|
animation->layerOrder.push_back(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void anm2_animation_layer_animation_remove(Anm2Animation* animation, s32 id)
|
||||||
|
{
|
||||||
|
animation->layerAnimations.erase(id);
|
||||||
|
vector_value_erase(animation->layerOrder, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void anm2_animation_null_animation_add(Anm2Animation* animation, s32 id)
|
||||||
|
{
|
||||||
|
animation->nullAnimations[id] = Anm2Item{};
|
||||||
|
}
|
||||||
|
|
||||||
|
void anm2_animation_null_animation_remove(Anm2Animation* animation, s32 id)
|
||||||
|
{
|
||||||
|
animation->nullAnimations.erase(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 anm2_layer_add(Anm2* self)
|
||||||
{
|
{
|
||||||
s32 id = map_next_id_get(self->layers);
|
s32 id = map_next_id_get(self->layers);
|
||||||
|
|
||||||
self->layers[id] = Anm2Layer{};
|
self->layers[id] = Anm2Layer{};
|
||||||
self->layerMap[self->layers.size() - 1] = id;
|
return id;
|
||||||
|
|
||||||
for (auto& [_, animation] : self->animations)
|
|
||||||
animation.layerAnimations[id] = Anm2Item{};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void anm2_layer_remove(Anm2* self, s32 id)
|
void anm2_layer_remove(Anm2* self, s32 id)
|
||||||
{
|
{
|
||||||
if (!self->layers.contains(id)) return;
|
|
||||||
|
|
||||||
self->layers.erase(id);
|
self->layers.erase(id);
|
||||||
|
|
||||||
for (auto it = self->layerMap.begin(); it != self->layerMap.end(); ++it)
|
|
||||||
{
|
|
||||||
if (it->second == id)
|
|
||||||
{
|
|
||||||
self->layerMap.erase(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<s32, s32> newLayerMap;
|
|
||||||
s32 newIndex = 0;
|
|
||||||
|
|
||||||
for (const auto& [_, layerID] : self->layerMap)
|
|
||||||
newLayerMap[newIndex++] = layerID;
|
|
||||||
|
|
||||||
self->layerMap = std::move(newLayerMap);
|
|
||||||
|
|
||||||
for (auto& [_, animation] : self->animations)
|
for (auto& [_, animation] : self->animations)
|
||||||
animation.layerAnimations.erase(id);
|
anm2_animation_layer_animation_remove(&animation, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void anm2_null_add(Anm2* self)
|
s32 anm2_null_add(Anm2* self)
|
||||||
{
|
{
|
||||||
s32 id = map_next_id_get(self->nulls);
|
s32 id = map_next_id_get(self->nulls);
|
||||||
|
|
||||||
self->nulls[id] = Anm2Null{};
|
self->nulls[id] = Anm2Null{};
|
||||||
|
return id;
|
||||||
for (auto& [_, animation] : self->animations)
|
|
||||||
animation.nullAnimations[id] = Anm2Item{};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void anm2_null_remove(Anm2* self, s32 id)
|
void anm2_null_remove(Anm2* self, s32 id)
|
||||||
{
|
{
|
||||||
if (!self->nulls.contains(id))
|
if (!self->nulls.contains(id)) return;
|
||||||
return;
|
|
||||||
|
|
||||||
self->nulls.erase(id);
|
self->nulls.erase(id);
|
||||||
|
|
||||||
std::map<s32, Anm2Null> newNulls;
|
for (auto& [_, animation] : self->animations)
|
||||||
s32 newID = 0;
|
anm2_animation_null_animation_remove(&animation, id);
|
||||||
|
|
||||||
for (const auto& [_, null] : self->nulls)
|
|
||||||
newNulls[newID++] = null;
|
|
||||||
|
|
||||||
self->nulls = std::move(newNulls);
|
|
||||||
|
|
||||||
for (auto& [_, animation] : self->animations)
|
|
||||||
{
|
|
||||||
if (animation.nullAnimations.contains(id))
|
|
||||||
animation.nullAnimations.erase(id);
|
|
||||||
|
|
||||||
std::map<s32, Anm2Item> newNullAnims;
|
|
||||||
s32 newAnimID = 0;
|
|
||||||
for (const auto& [_, nullAnim] : animation.nullAnimations)
|
|
||||||
newNullAnims[newAnimID++] = nullAnim;
|
|
||||||
|
|
||||||
animation.nullAnimations = std::move(newNullAnims);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 anm2_animation_add(Anm2* self, bool isAddRootFrame, Anm2Animation* animation, s32 id)
|
s32 anm2_animation_add(Anm2* self, Anm2Animation* animation, s32 id)
|
||||||
{
|
{
|
||||||
s32 addID = map_next_id_get(self->animations);
|
s32 addID = map_next_id_get(self->animations);
|
||||||
|
|
||||||
Anm2Animation localAnimation;
|
Anm2Animation localAnimation;
|
||||||
Anm2Animation* addAnimation = animation ? animation : &localAnimation;
|
Anm2Animation* addAnimation = animation ? animation : &localAnimation;
|
||||||
|
|
||||||
for (auto& [layerID, layer] : self->layers)
|
if (!animation) addAnimation->rootAnimation.frames.push_back(Anm2Frame{});
|
||||||
if (!map_find(addAnimation->layerAnimations, layerID))
|
|
||||||
addAnimation->layerAnimations[layerID] = Anm2Item{};
|
|
||||||
for (auto& [nullID, null] : self->nulls)
|
|
||||||
if (!map_find(addAnimation->nullAnimations, nullID))
|
|
||||||
addAnimation->nullAnimations[nullID] = Anm2Item{};
|
|
||||||
|
|
||||||
if (isAddRootFrame)
|
|
||||||
addAnimation->rootAnimation.frames.push_back(Anm2Frame{});
|
|
||||||
|
|
||||||
if (id != ID_NONE)
|
if (id != ID_NONE)
|
||||||
{
|
{
|
||||||
@@ -685,6 +644,7 @@ s32 anm2_animation_add(Anm2* self, bool isAddRootFrame, Anm2Animation* animation
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
self->animations[addID] = *addAnimation;
|
self->animations[addID] = *addAnimation;
|
||||||
|
|
||||||
return addID;
|
return addID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1153,7 +1113,7 @@ void anm2_spritesheet_texture_pixels_download(Anm2* self)
|
|||||||
|
|
||||||
if (texture.id != GL_ID_NONE && !texture.isInvalid)
|
if (texture.id != GL_ID_NONE && !texture.isInvalid)
|
||||||
{
|
{
|
||||||
size_t bufferSize = (size_t)texture.size.x * (size_t)texture.size.y * (size_t)texture.channels;
|
size_t bufferSize = (size_t)texture.size.x * (size_t)texture.size.y * TEXTURE_CHANNELS;
|
||||||
spritesheet.pixels.resize(bufferSize);
|
spritesheet.pixels.resize(bufferSize);
|
||||||
glBindTexture(GL_TEXTURE_2D, texture.id);
|
glBindTexture(GL_TEXTURE_2D, texture.id);
|
||||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, spritesheet.pixels.data());
|
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, spritesheet.pixels.data());
|
||||||
@@ -1212,7 +1172,7 @@ vec4 anm2_animation_rect_get(Anm2* self, Anm2Reference* reference, bool isRootTr
|
|||||||
return {minX, minY, maxX - minX, maxY - minY};
|
return {minX, minY, maxX - minX, maxY - minY};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool anm2_animation_deserialize_from_xml(Anm2* self, Anm2Animation* animation, const std::string& xml)
|
bool anm2_animation_deserialize_from_xml(Anm2Animation* animation, const std::string& xml)
|
||||||
{
|
{
|
||||||
XMLDocument document;
|
XMLDocument document;
|
||||||
|
|
||||||
@@ -1225,14 +1185,15 @@ bool anm2_animation_deserialize_from_xml(Anm2* self, Anm2Animation* animation, c
|
|||||||
if (document.Parse(xml.c_str()) != XML_SUCCESS) return animation_deserialize_error();
|
if (document.Parse(xml.c_str()) != XML_SUCCESS) return animation_deserialize_error();
|
||||||
|
|
||||||
const XMLElement* element = document.RootElement();
|
const XMLElement* element = document.RootElement();
|
||||||
if (element && std::string(element->Name()) != std::string(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_ANIMATION]))
|
if (!element) return animation_deserialize_error();
|
||||||
|
if (std::string(element->Name()) != std::string(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_ANIMATION]))
|
||||||
return animation_deserialize_error();
|
return animation_deserialize_error();
|
||||||
|
|
||||||
_anm2_animation_deserialize(self, animation, element);
|
_anm2_animation_deserialize(animation, element);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool anm2_frame_deserialize_from_xml(Anm2* self, Anm2Frame* frame, const std::string& xml)
|
bool anm2_frame_deserialize_from_xml(Anm2Frame* frame, const std::string& xml)
|
||||||
{
|
{
|
||||||
XMLDocument document;
|
XMLDocument document;
|
||||||
|
|
||||||
@@ -1245,16 +1206,15 @@ bool anm2_frame_deserialize_from_xml(Anm2* self, Anm2Frame* frame, const std::st
|
|||||||
if (document.Parse(xml.c_str()) != XML_SUCCESS) return frame_deserialize_error();
|
if (document.Parse(xml.c_str()) != XML_SUCCESS) return frame_deserialize_error();
|
||||||
|
|
||||||
const XMLElement* element = document.RootElement();
|
const XMLElement* element = document.RootElement();
|
||||||
|
if (!element) return frame_deserialize_error();
|
||||||
|
|
||||||
if
|
if
|
||||||
(
|
(
|
||||||
element &&
|
std::string(element->Name()) != std::string(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_FRAME]) &&
|
||||||
(
|
std::string(element->Name()) != std::string(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_TRIGGER])
|
||||||
std::string(element->Name()) == std::string(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_FRAME]) ||
|
|
||||||
std::string(element->Name()) == std::string(ANM2_ELEMENT_STRINGS[ANM2_ELEMENT_TRIGGER])
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
return frame_deserialize_error();
|
return frame_deserialize_error();
|
||||||
|
|
||||||
_anm2_frame_deserialize(self, frame, element);
|
_anm2_frame_deserialize(frame, element);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
67
src/anm2.h
67
src/anm2.h
@@ -142,7 +142,7 @@ struct Anm2Spritesheet
|
|||||||
struct Anm2Layer
|
struct Anm2Layer
|
||||||
{
|
{
|
||||||
std::string name = "New Layer";
|
std::string name = "New Layer";
|
||||||
s32 spritesheetID = ID_NONE;
|
s32 spritesheetID{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Anm2Null
|
struct Anm2Null
|
||||||
@@ -199,9 +199,9 @@ struct Anm2Animation
|
|||||||
s32 frameNum = ANM2_FRAME_NUM_MIN;
|
s32 frameNum = ANM2_FRAME_NUM_MIN;
|
||||||
std::string name = "New Animation";
|
std::string name = "New Animation";
|
||||||
bool isLoop = true;
|
bool isLoop = true;
|
||||||
bool isShowUnused = true;
|
|
||||||
Anm2Item rootAnimation;
|
Anm2Item rootAnimation;
|
||||||
std::map<s32, Anm2Item> layerAnimations;
|
std::unordered_map<s32, Anm2Item> layerAnimations;
|
||||||
|
std::vector<s32> layerOrder;
|
||||||
std::map<s32, Anm2Item> nullAnimations;
|
std::map<s32, Anm2Item> nullAnimations;
|
||||||
Anm2Item triggers;
|
Anm2Item triggers;
|
||||||
};
|
};
|
||||||
@@ -216,7 +216,6 @@ struct Anm2
|
|||||||
std::map<s32, Anm2Null> nulls;
|
std::map<s32, Anm2Null> nulls;
|
||||||
std::map<s32, Anm2Event> events;
|
std::map<s32, Anm2Event> events;
|
||||||
std::map<s32, Anm2Animation> animations;
|
std::map<s32, Anm2Animation> animations;
|
||||||
std::map<s32, s32> layerMap; // index, id
|
|
||||||
s32 defaultAnimationID = ID_NONE;
|
s32 defaultAnimationID = ID_NONE;
|
||||||
s32 fps = ANM2_FPS_DEFAULT;
|
s32 fps = ANM2_FPS_DEFAULT;
|
||||||
s32 version{};
|
s32 version{};
|
||||||
@@ -253,38 +252,42 @@ enum OnionskinDrawOrder
|
|||||||
ONIONSKIN_ABOVE
|
ONIONSKIN_ABOVE
|
||||||
};
|
};
|
||||||
|
|
||||||
void anm2_layer_add(Anm2* self);
|
|
||||||
void anm2_layer_remove(Anm2* self, s32 id);
|
|
||||||
void anm2_null_add(Anm2* self);
|
|
||||||
void anm2_null_remove(Anm2* self, s32 id);
|
|
||||||
bool anm2_serialize(Anm2* self, const std::string& path);
|
|
||||||
bool anm2_deserialize(Anm2* self, const std::string& path, bool isTextures = true);
|
|
||||||
void anm2_new(Anm2* self);
|
|
||||||
void anm2_free(Anm2* self);
|
|
||||||
void anm2_created_on_set(Anm2* self);
|
|
||||||
s32 anm2_animation_add(Anm2* self, bool isAddRootFrame = true, Anm2Animation* animation = nullptr, s32 id = ID_NONE);
|
|
||||||
void anm2_animation_remove(Anm2* self, s32 id);
|
|
||||||
Anm2Animation* anm2_animation_from_reference(Anm2* self, Anm2Reference* reference);
|
Anm2Animation* anm2_animation_from_reference(Anm2* self, Anm2Reference* reference);
|
||||||
Anm2Item* anm2_item_from_reference(Anm2* self, Anm2Reference* reference);
|
|
||||||
Anm2Frame* anm2_frame_from_reference(Anm2* self, Anm2Reference* reference);
|
|
||||||
s32 anm2_frame_index_from_time(Anm2* self, Anm2Reference reference, f32 time);
|
|
||||||
Anm2Frame* anm2_frame_add(Anm2* self, Anm2Frame* frame, Anm2Reference* reference);
|
Anm2Frame* anm2_frame_add(Anm2* self, Anm2Frame* frame, Anm2Reference* reference);
|
||||||
void anm2_frame_remove(Anm2* self, Anm2Reference* reference);
|
Anm2Frame* anm2_frame_from_reference(Anm2* self, Anm2Reference* reference);
|
||||||
void anm2_frame_from_time(Anm2* self, Anm2Frame* frame, Anm2Reference reference, f32 time);
|
Anm2Item* anm2_item_from_reference(Anm2* self, Anm2Reference* reference);
|
||||||
void anm2_reference_clear(Anm2Reference* self);
|
bool anm2_animation_deserialize_from_xml(Anm2Animation* animation, const std::string& xml);
|
||||||
void anm2_reference_item_clear(Anm2Reference* self);
|
bool anm2_deserialize(Anm2* self, const std::string& path, bool isTextures = true);
|
||||||
void anm2_reference_frame_clear(Anm2Reference* self);
|
bool anm2_frame_deserialize_from_xml(Anm2Frame* frame, const std::string& xml);
|
||||||
|
bool anm2_serialize(Anm2* self, const std::string& path);
|
||||||
|
s32 anm2_animation_add(Anm2* self, Anm2Animation* animation = nullptr, s32 id = ID_NONE);
|
||||||
s32 anm2_animation_length_get(Anm2Animation* self);
|
s32 anm2_animation_length_get(Anm2Animation* self);
|
||||||
|
s32 anm2_frame_index_from_time(Anm2* self, Anm2Reference reference, f32 time);
|
||||||
|
s32 anm2_layer_add(Anm2* self);
|
||||||
|
s32 anm2_null_add(Anm2* self);
|
||||||
|
vec4 anm2_animation_rect_get(Anm2* anm2, Anm2Reference* reference, bool isRootTransform);
|
||||||
|
void anm2_animation_layer_animation_add(Anm2Animation* animation, s32 id);
|
||||||
|
void anm2_animation_layer_animation_remove(Anm2Animation* animation, s32 id);
|
||||||
void anm2_animation_length_set(Anm2Animation* self);
|
void anm2_animation_length_set(Anm2Animation* self);
|
||||||
void anm2_animation_merge(Anm2* self, s32 animationID, const std::vector<s32>& mergeIDs, Anm2MergeType type);
|
void anm2_animation_merge(Anm2* self, s32 animationID, const std::vector<s32>& mergeIDs, Anm2MergeType type);
|
||||||
|
void anm2_animation_null_animation_add(Anm2Animation* animation, s32 id);
|
||||||
|
void anm2_animation_null_animation_remove(Anm2Animation* animation, s32 id);
|
||||||
|
void anm2_animation_remove(Anm2* self, s32 id);
|
||||||
|
void anm2_animation_serialize(Anm2Animation* animation, XMLDocument* document, XMLElement* addElement, std::string* string);
|
||||||
|
void anm2_created_on_set(Anm2* self);
|
||||||
void anm2_frame_bake(Anm2* self, Anm2Reference* reference, s32 interval, bool isRoundScale, bool isRoundRotation);
|
void anm2_frame_bake(Anm2* self, Anm2Reference* reference, s32 interval, bool isRoundScale, bool isRoundRotation);
|
||||||
void anm2_item_frame_set(Anm2* self, Anm2Reference* reference, const Anm2FrameChange& change, Anm2ChangeType type, s32 start, s32 count);
|
void anm2_frame_from_time(Anm2* self, Anm2Frame* frame, Anm2Reference reference, f32 time);
|
||||||
void anm2_scale(Anm2* self, f32 scale);
|
void anm2_frame_remove(Anm2* self, Anm2Reference* reference);
|
||||||
void anm2_generate_from_grid(Anm2* self, Anm2Reference* reference, vec2 startPosition, vec2 size, vec2 pivot, s32 columns, s32 count, s32 delay);
|
|
||||||
void anm2_spritesheet_texture_pixels_upload(Anm2* self);
|
|
||||||
void anm2_spritesheet_texture_pixels_download(Anm2* self);
|
|
||||||
vec4 anm2_animation_rect_get(Anm2* anm2, Anm2Reference* reference, bool isRootTransform);
|
|
||||||
void anm2_frame_serialize(Anm2Frame* frame, Anm2Type type, XMLDocument* document, XMLElement* addElement, std::string* string);
|
void anm2_frame_serialize(Anm2Frame* frame, Anm2Type type, XMLDocument* document, XMLElement* addElement, std::string* string);
|
||||||
void anm2_animation_serialize(Anm2* self, Anm2Animation* animation, XMLDocument* document, XMLElement* addElement, std::string* string);
|
void anm2_free(Anm2* self);
|
||||||
bool anm2_frame_deserialize_from_xml(Anm2* self, Anm2Frame* frame, const std::string& xml);
|
void anm2_generate_from_grid(Anm2* self, Anm2Reference* reference, vec2 startPosition, vec2 size, vec2 pivot, s32 columns, s32 count, s32 delay);
|
||||||
bool anm2_animation_deserialize_from_xml(Anm2* self, Anm2Animation* frame, const std::string& xml);
|
void anm2_item_frame_set(Anm2* self, Anm2Reference* reference, const Anm2FrameChange& change, Anm2ChangeType type, s32 start, s32 count);
|
||||||
|
void anm2_layer_remove(Anm2* self, s32 id);
|
||||||
|
void anm2_new(Anm2* self);
|
||||||
|
void anm2_null_remove(Anm2* self, s32 id);
|
||||||
|
void anm2_reference_clear(Anm2Reference* self);
|
||||||
|
void anm2_reference_frame_clear(Anm2Reference* self);
|
||||||
|
void anm2_reference_item_clear(Anm2Reference* self);
|
||||||
|
void anm2_scale(Anm2* self, f32 scale);
|
||||||
|
void anm2_spritesheet_texture_pixels_download(Anm2* self);
|
||||||
|
void anm2_spritesheet_texture_pixels_upload(Anm2* self);
|
@@ -197,6 +197,7 @@ void canvas_rect_draw(Canvas* self, const GLuint& shader, const mat4& transform,
|
|||||||
glUseProgram(0);
|
glUseProgram(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void canvas_axes_draw(Canvas* self, GLuint& shader, mat4& transform, vec4& color)
|
void canvas_axes_draw(Canvas* self, GLuint& shader, mat4& transform, vec4& color)
|
||||||
{
|
{
|
||||||
vec4 originNDC = transform * vec4(0.0f, 0.0f, 0.0f, 1.0f);
|
vec4 originNDC = transform * vec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
@@ -28,7 +28,7 @@ void clipboard_copy(Clipboard* self)
|
|||||||
if (!id) break;
|
if (!id) break;
|
||||||
Anm2Animation* animation = map_find(self->anm2->animations, *id);
|
Anm2Animation* animation = map_find(self->anm2->animations, *id);
|
||||||
if (!animation) break;
|
if (!animation) break;
|
||||||
anm2_animation_serialize(self->anm2, animation, nullptr, nullptr, &clipboardText);
|
anm2_animation_serialize(animation, nullptr, nullptr, &clipboardText);
|
||||||
clipboard_text_set();
|
clipboard_text_set();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -63,7 +63,7 @@ void clipboard_cut(Clipboard* self)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void clipboard_paste(Clipboard* self)
|
bool clipboard_paste(Clipboard* self)
|
||||||
{
|
{
|
||||||
auto clipboard_string = [&]()
|
auto clipboard_string = [&]()
|
||||||
{
|
{
|
||||||
@@ -80,8 +80,9 @@ void clipboard_paste(Clipboard* self)
|
|||||||
Anm2Reference* reference = std::get_if<Anm2Reference>(&self->location);
|
Anm2Reference* reference = std::get_if<Anm2Reference>(&self->location);
|
||||||
if (!reference) break;
|
if (!reference) break;
|
||||||
Anm2Frame frame;
|
Anm2Frame frame;
|
||||||
if (anm2_frame_deserialize_from_xml(self->anm2, &frame, clipboard_string()))
|
if (anm2_frame_deserialize_from_xml(&frame, clipboard_string()))
|
||||||
anm2_frame_add(self->anm2, &frame, reference);
|
anm2_frame_add(self->anm2, &frame, reference);
|
||||||
|
else return false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CLIPBOARD_ANIMATION:
|
case CLIPBOARD_ANIMATION:
|
||||||
@@ -89,13 +90,16 @@ void clipboard_paste(Clipboard* self)
|
|||||||
s32* id = std::get_if<s32>(&self->location);
|
s32* id = std::get_if<s32>(&self->location);
|
||||||
if (!id) break;
|
if (!id) break;
|
||||||
Anm2Animation animation;
|
Anm2Animation animation;
|
||||||
if (anm2_animation_deserialize_from_xml(self->anm2, &animation, clipboard_string()))
|
if (anm2_animation_deserialize_from_xml(&animation, clipboard_string()))
|
||||||
anm2_animation_add(self->anm2, false, &animation, *id);
|
anm2_animation_add(self->anm2, &animation, *id);
|
||||||
|
else return false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clipboard_init(Clipboard* self, Anm2* anm2)
|
void clipboard_init(Clipboard* self, Anm2* anm2)
|
||||||
|
@@ -23,5 +23,5 @@ struct Clipboard
|
|||||||
bool clipboard_is_value(void);
|
bool clipboard_is_value(void);
|
||||||
void clipboard_copy(Clipboard* self);
|
void clipboard_copy(Clipboard* self);
|
||||||
void clipboard_cut(Clipboard* self);
|
void clipboard_cut(Clipboard* self);
|
||||||
void clipboard_paste(Clipboard* self);
|
bool clipboard_paste(Clipboard* self);
|
||||||
void clipboard_init(Clipboard* self, Anm2* anm2);
|
void clipboard_init(Clipboard* self, Anm2* anm2);
|
363
src/imgui.cpp
363
src/imgui.cpp
@@ -62,6 +62,8 @@ static void _imgui_spritesheet_add(Imgui* self, const std::string& path)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
imgui_snapshot(self, IMGUI_ACTION_ADD_SPRITESHEET);
|
||||||
|
|
||||||
std::filesystem::path workingPath = std::filesystem::current_path();
|
std::filesystem::path workingPath = std::filesystem::current_path();
|
||||||
std::string spritesheetPath = path;
|
std::string spritesheetPath = path;
|
||||||
std::string anm2WorkingPath = working_directory_from_file_set(self->anm2->path);
|
std::string anm2WorkingPath = working_directory_from_file_set(self->anm2->path);
|
||||||
@@ -79,6 +81,16 @@ static bool _imgui_is_window_hovered(void)
|
|||||||
return ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem);
|
return ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool _imgui_is_window_hovered_and_click(void)
|
||||||
|
{
|
||||||
|
return _imgui_is_window_hovered() && ImGui::IsMouseClicked(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _imgui_is_window_hovered_and_click_no_anm2_path(Imgui* self)
|
||||||
|
{
|
||||||
|
return _imgui_is_window_hovered_and_click() && self->anm2->path.empty();
|
||||||
|
}
|
||||||
|
|
||||||
static bool _imgui_is_no_click_on_item(void)
|
static bool _imgui_is_no_click_on_item(void)
|
||||||
{
|
{
|
||||||
return ImGui::IsMouseClicked(0) && !ImGui::IsAnyItemHovered();
|
return ImGui::IsMouseClicked(0) && !ImGui::IsAnyItemHovered();
|
||||||
@@ -141,7 +153,7 @@ static void _imgui_item_pre(const ImguiItem& self, ImguiItemType type)
|
|||||||
case IMGUI_WINDOW:
|
case IMGUI_WINDOW:
|
||||||
case IMGUI_DOCKSPACE:
|
case IMGUI_DOCKSPACE:
|
||||||
case IMGUI_CHILD:
|
case IMGUI_CHILD:
|
||||||
case IMGUI_OPTION_POPUP:
|
case IMGUI_CONFIRM_POPUP:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ImGui::BeginDisabled(self.isDisabled);
|
ImGui::BeginDisabled(self.isDisabled);
|
||||||
@@ -264,7 +276,7 @@ static void _imgui_item_post(const ImguiItem& self, Imgui* imgui, ImguiItemType
|
|||||||
case IMGUI_WINDOW:
|
case IMGUI_WINDOW:
|
||||||
case IMGUI_DOCKSPACE:
|
case IMGUI_DOCKSPACE:
|
||||||
case IMGUI_CHILD:
|
case IMGUI_CHILD:
|
||||||
case IMGUI_OPTION_POPUP:
|
case IMGUI_CONFIRM_POPUP:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();
|
||||||
@@ -569,7 +581,7 @@ IMGUI_ITEM_ATLAS_FUNCTION(_imgui_atlas_selectable, _imgui_selectable(self, imgui
|
|||||||
IMGUI_ITEM_ATLAS_VALUE_FUNCTION(_imgui_atlas_selectable_input_int, s32, _imgui_selectable_input_int(self, imgui, value));
|
IMGUI_ITEM_ATLAS_VALUE_FUNCTION(_imgui_atlas_selectable_input_int, s32, _imgui_selectable_input_int(self, imgui, value));
|
||||||
IMGUI_ITEM_ATLAS_VALUE_FUNCTION(_imgui_atlas_selectable_input_text, std::string, _imgui_selectable_input_text(self, imgui, value));
|
IMGUI_ITEM_ATLAS_VALUE_FUNCTION(_imgui_atlas_selectable_input_text, std::string, _imgui_selectable_input_text(self, imgui, value));
|
||||||
|
|
||||||
static bool _imgui_option_popup(ImguiItem self, Imgui* imgui, ImguiPopupState* state = nullptr)
|
static bool _imgui_confirm_popup(ImguiItem self, Imgui* imgui, ImguiPopupState* state = nullptr, bool isOnlyConfirm = false)
|
||||||
{
|
{
|
||||||
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
|
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
|
||||||
|
|
||||||
@@ -582,20 +594,23 @@ static bool _imgui_option_popup(ImguiItem self, Imgui* imgui, ImguiPopupState* s
|
|||||||
ImGui::Text(self.text_get());
|
ImGui::Text(self.text_get());
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
if (_imgui_button(IMGUI_POPUP_OK, imgui))
|
if (_imgui_button(IMGUI_POPUP_OK.copy({.rowCount = isOnlyConfirm ? 1 : IMGUI_CONFIRM_POPUP_ROW_COUNT}), imgui))
|
||||||
{
|
{
|
||||||
imgui_close_current_popup(imgui);
|
imgui_close_current_popup(imgui);
|
||||||
imgui_end_popup(imgui);
|
imgui_end_popup(imgui);
|
||||||
if (state) *state = IMGUI_POPUP_STATE_CONFIRM;
|
if (state) *state = isOnlyConfirm ? IMGUI_POPUP_STATE_CANCEL : IMGUI_POPUP_STATE_CONFIRM;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
if (_imgui_button(IMGUI_POPUP_CANCEL, imgui))
|
if (!isOnlyConfirm)
|
||||||
{
|
{
|
||||||
imgui_close_current_popup(imgui);
|
if (_imgui_button(IMGUI_POPUP_CANCEL, imgui))
|
||||||
if (state) *state = IMGUI_POPUP_STATE_CANCEL;
|
{
|
||||||
|
imgui_close_current_popup(imgui);
|
||||||
|
if (state) *state = IMGUI_POPUP_STATE_CANCEL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
imgui_end_popup(imgui);
|
imgui_end_popup(imgui);
|
||||||
@@ -604,6 +619,13 @@ static bool _imgui_option_popup(ImguiItem self, Imgui* imgui, ImguiPopupState* s
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _imgui_no_anm2_path_check(Imgui* self)
|
||||||
|
{
|
||||||
|
if (_imgui_is_window_hovered_and_click_no_anm2_path(self) && !imgui_is_any_popup_open())
|
||||||
|
imgui_open_popup(IMGUI_NO_ANM2_PATH_CONFIRMATION.label);
|
||||||
|
_imgui_confirm_popup(IMGUI_NO_ANM2_PATH_CONFIRMATION, self, nullptr, true);
|
||||||
|
}
|
||||||
|
|
||||||
static void _imgui_context_menu(Imgui* self)
|
static void _imgui_context_menu(Imgui* self)
|
||||||
{
|
{
|
||||||
if (!self->isContextualActionsEnabled) return;
|
if (!self->isContextualActionsEnabled) return;
|
||||||
@@ -650,6 +672,7 @@ static void _imgui_timeline(Imgui* self)
|
|||||||
static s32& itemID = self->reference->itemID;
|
static s32& itemID = self->reference->itemID;
|
||||||
|
|
||||||
IMGUI_BEGIN_OR_RETURN(IMGUI_TIMELINE, self);
|
IMGUI_BEGIN_OR_RETURN(IMGUI_TIMELINE, self);
|
||||||
|
_imgui_no_anm2_path_check(self);
|
||||||
|
|
||||||
Anm2Animation* animation = anm2_animation_from_reference(self->anm2, self->reference);
|
Anm2Animation* animation = anm2_animation_from_reference(self->anm2, self->reference);
|
||||||
|
|
||||||
@@ -704,12 +727,7 @@ static void _imgui_timeline(Imgui* self)
|
|||||||
localMousePos = ImVec2(mousePos.x - itemMin.x + scroll.x, mousePos.y - itemMin.y);
|
localMousePos = ImVec2(mousePos.x - itemMin.x + scroll.x, mousePos.y - itemMin.y);
|
||||||
frameTime = (s32)(localMousePos.x / frameSize.x);
|
frameTime = (s32)(localMousePos.x / frameSize.x);
|
||||||
|
|
||||||
if (ImGui::IsMouseDown(0) && _imgui_is_window_hovered())
|
if (ImGui::IsMouseDown(0) && _imgui_is_window_hovered()) isPlayheadDrag = true;
|
||||||
{
|
|
||||||
if (!isPlayheadDrag)
|
|
||||||
imgui_snapshot(self, IMGUI_ACTION_MOVE_PLAYHEAD);
|
|
||||||
isPlayheadDrag = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isPlayheadDrag)
|
if (isPlayheadDrag)
|
||||||
{
|
{
|
||||||
@@ -790,12 +808,12 @@ static void _imgui_timeline(Imgui* self)
|
|||||||
std::function<void(Anm2Reference, s32&)> timeline_item_child = [&](Anm2Reference reference, s32& index)
|
std::function<void(Anm2Reference, s32&)> timeline_item_child = [&](Anm2Reference reference, s32& index)
|
||||||
{
|
{
|
||||||
Anm2Item* item = anm2_item_from_reference(self->anm2, &reference);
|
Anm2Item* item = anm2_item_from_reference(self->anm2, &reference);
|
||||||
|
Anm2Type& type = reference.itemType;
|
||||||
if (!item) return;
|
if (!item) return;
|
||||||
|
if (!self->settings->timelineIsShowUnused && item->frames.empty() && (type == ANM2_LAYER || type == ANM2_NULL)) return;
|
||||||
|
|
||||||
ImVec2 buttonSize = ImVec2(ATLAS_SIZE_NORMAL) + (defaultFramePadding * ImVec2(2, 2));
|
ImVec2 buttonSize = ImVec2(ATLAS_SIZE_NORMAL) + (defaultFramePadding * ImVec2(2, 2));
|
||||||
|
|
||||||
Anm2Type& type = reference.itemType;
|
|
||||||
Anm2Layer* layer = nullptr;
|
Anm2Layer* layer = nullptr;
|
||||||
Anm2Null* null = nullptr;
|
Anm2Null* null = nullptr;
|
||||||
s32 buttonCount = type == ANM2_NULL ? 2 : 1;
|
s32 buttonCount = type == ANM2_NULL ? 2 : 1;
|
||||||
@@ -824,13 +842,13 @@ static void _imgui_timeline(Imgui* self)
|
|||||||
layer = &self->anm2->layers[reference.itemID];
|
layer = &self->anm2->layers[reference.itemID];
|
||||||
if
|
if
|
||||||
(
|
(
|
||||||
_imgui_atlas_selectable_input_text(IMGUI_TIMELINE_ITEM_SELECTABLES[type]->copy
|
_imgui_atlas_selectable(IMGUI_TIMELINE_ITEM_SELECTABLES[type]->copy
|
||||||
({
|
({
|
||||||
.isSelected = isSelected,
|
.isSelected = isSelected,
|
||||||
.label = std::format(IMGUI_TIMELINE_ITEM_CHILD_FORMAT, reference.itemID, layer->name),
|
.label = std::format(IMGUI_TIMELINE_ITEM_CHILD_FORMAT, reference.itemID, layer->name)
|
||||||
.id = index
|
|
||||||
}),
|
}),
|
||||||
self, layer->name)
|
self
|
||||||
|
)
|
||||||
)
|
)
|
||||||
*self->reference = reference;
|
*self->reference = reference;
|
||||||
break;
|
break;
|
||||||
@@ -838,13 +856,12 @@ static void _imgui_timeline(Imgui* self)
|
|||||||
null = &self->anm2->nulls[reference.itemID];
|
null = &self->anm2->nulls[reference.itemID];
|
||||||
if
|
if
|
||||||
(
|
(
|
||||||
_imgui_atlas_selectable_input_text(IMGUI_TIMELINE_ITEM_SELECTABLES[type]->copy
|
_imgui_atlas_selectable(IMGUI_TIMELINE_ITEM_SELECTABLES[type]->copy
|
||||||
({
|
({
|
||||||
.isSelected = isSelected,
|
.isSelected = isSelected,
|
||||||
.label = std::format(IMGUI_TIMELINE_ITEM_CHILD_FORMAT, reference.itemID, null->name),
|
.label = std::format(IMGUI_TIMELINE_ITEM_CHILD_FORMAT, reference.itemID, null->name)
|
||||||
.id = index
|
|
||||||
}),
|
}),
|
||||||
self, null->name)
|
self)
|
||||||
)
|
)
|
||||||
*self->reference = reference;
|
*self->reference = reference;
|
||||||
break;
|
break;
|
||||||
@@ -878,13 +895,6 @@ static void _imgui_timeline(Imgui* self)
|
|||||||
ImGui::EndDragDropTarget();
|
ImGui::EndDragDropTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == ANM2_LAYER)
|
|
||||||
{
|
|
||||||
ImGui::SameLine();
|
|
||||||
_imgui_atlas_selectable_input_int(IMGUI_TIMELINE_SPRITESHEET_ID.copy
|
|
||||||
({.label = std::format(IMGUI_SPRITESHEET_ID_FORMAT, layer->spritesheetID), .id = index}), self, layer->spritesheetID);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::SetCursorScreenPos({childPos.x + childSize.x - buttonAreaWidth, childPos.y + defaultWindowPadding.y});
|
ImGui::SetCursorScreenPos({childPos.x + childSize.x - buttonAreaWidth, childPos.y + defaultWindowPadding.y});
|
||||||
|
|
||||||
if (type == ANM2_NULL)
|
if (type == ANM2_NULL)
|
||||||
@@ -916,7 +926,7 @@ static void _imgui_timeline(Imgui* self)
|
|||||||
|
|
||||||
timeline_item_child({animationID, ANM2_ROOT}, index);
|
timeline_item_child({animationID, ANM2_ROOT}, index);
|
||||||
|
|
||||||
for (auto& [i, id] : std::ranges::reverse_view(self->anm2->layerMap))
|
for (auto& id : std::ranges::reverse_view(animation->layerOrder))
|
||||||
timeline_item_child({animationID, ANM2_LAYER, id}, index);
|
timeline_item_child({animationID, ANM2_LAYER, id}, index);
|
||||||
|
|
||||||
for (auto & [id, null] : animation->nullAnimations)
|
for (auto & [id, null] : animation->nullAnimations)
|
||||||
@@ -933,28 +943,12 @@ static void _imgui_timeline(Imgui* self)
|
|||||||
switch (swapItemReference.itemType)
|
switch (swapItemReference.itemType)
|
||||||
{
|
{
|
||||||
case ANM2_LAYER:
|
case ANM2_LAYER:
|
||||||
{
|
vector_value_swap(animation->layerOrder, self->reference->itemID, swapItemReference.itemID);
|
||||||
s32 indexA = INDEX_NONE;
|
|
||||||
s32 indexB = INDEX_NONE;
|
|
||||||
|
|
||||||
for (const auto& [index, id] : self->anm2->layerMap)
|
|
||||||
{
|
|
||||||
if (id == self->reference->itemID)
|
|
||||||
indexA = index;
|
|
||||||
else if (id == swapItemReference.itemID)
|
|
||||||
indexB = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((indexA != INDEX_NONE) && (indexB != INDEX_NONE))
|
|
||||||
std::swap(self->anm2->layerMap[indexA], self->anm2->layerMap[indexB]);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case ANM2_NULL:
|
case ANM2_NULL:
|
||||||
map_swap(self->anm2->nulls, self->reference->itemID, swapItemReference.itemID);
|
|
||||||
map_swap(animation->nullAnimations, self->reference->itemID, swapItemReference.itemID);
|
map_swap(animation->nullAnimations, self->reference->itemID, swapItemReference.itemID);
|
||||||
break;
|
break;
|
||||||
default:
|
default: break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self->reference->itemID = swapItemReference.itemID;
|
self->reference->itemID = swapItemReference.itemID;
|
||||||
@@ -966,7 +960,9 @@ static void _imgui_timeline(Imgui* self)
|
|||||||
std::function<void(Anm2Reference, s32&)> timeline_item_frames = [&](Anm2Reference reference, s32& index)
|
std::function<void(Anm2Reference, s32&)> timeline_item_frames = [&](Anm2Reference reference, s32& index)
|
||||||
{
|
{
|
||||||
Anm2Item* item = anm2_item_from_reference(self->anm2, &reference);
|
Anm2Item* item = anm2_item_from_reference(self->anm2, &reference);
|
||||||
|
if (!item) return;
|
||||||
Anm2Type& type = reference.itemType;
|
Anm2Type& type = reference.itemType;
|
||||||
|
if (!self->settings->timelineIsShowUnused && item->frames.empty() && (type == ANM2_LAYER || type == ANM2_NULL)) return;
|
||||||
|
|
||||||
ImGui::PushID(index);
|
ImGui::PushID(index);
|
||||||
|
|
||||||
@@ -1150,7 +1146,7 @@ static void _imgui_timeline(Imgui* self)
|
|||||||
|
|
||||||
timeline_item_frames(Anm2Reference(animationID, ANM2_ROOT), index);
|
timeline_item_frames(Anm2Reference(animationID, ANM2_ROOT), index);
|
||||||
|
|
||||||
for (auto& [i, id] : std::ranges::reverse_view(self->anm2->layerMap))
|
for (auto& id : std::ranges::reverse_view(animation->layerOrder))
|
||||||
timeline_item_frames(Anm2Reference(animationID, ANM2_LAYER, id), index);
|
timeline_item_frames(Anm2Reference(animationID, ANM2_LAYER, id), index);
|
||||||
|
|
||||||
for (auto & [id, null] : animation->nullAnimations)
|
for (auto & [id, null] : animation->nullAnimations)
|
||||||
@@ -1171,7 +1167,15 @@ static void _imgui_timeline(Imgui* self)
|
|||||||
timeline_frames_child();
|
timeline_frames_child();
|
||||||
ImGui::SetCursorPos(ImVec2());
|
ImGui::SetCursorPos(ImVec2());
|
||||||
|
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, defaultItemSpacing);
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, defaultWindowPadding);
|
||||||
|
|
||||||
_imgui_begin_child(IMGUI_TIMELINE_ITEM_CHILD, self);
|
_imgui_begin_child(IMGUI_TIMELINE_ITEM_CHILD, self);
|
||||||
|
|
||||||
|
const ImguiItem& unusedItem = self->settings->timelineIsShowUnused ? IMGUI_TIMELINE_SHOW_UNUSED : IMGUI_TIMELINE_HIDE_UNUSED;
|
||||||
|
if (_imgui_atlas_button(unusedItem, self)) self->settings->timelineIsShowUnused = !self->settings->timelineIsShowUnused;
|
||||||
|
ImGui::PopStyleVar(2);
|
||||||
|
|
||||||
_imgui_end_child(); // IMGUI_TIMELINE_ITEM_CHILD
|
_imgui_end_child(); // IMGUI_TIMELINE_ITEM_CHILD
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
timeline_header();
|
timeline_header();
|
||||||
@@ -1185,12 +1189,91 @@ static void _imgui_timeline(Imgui* self)
|
|||||||
Anm2Frame* frame = anm2_frame_from_reference(self->anm2, self->reference);
|
Anm2Frame* frame = anm2_frame_from_reference(self->anm2, self->reference);
|
||||||
Anm2Item* item = anm2_item_from_reference(self->anm2, self->reference);
|
Anm2Item* item = anm2_item_from_reference(self->anm2, self->reference);
|
||||||
_imgui_begin_child(IMGUI_TIMELINE_ITEM_FOOTER_CHILD, self);
|
_imgui_begin_child(IMGUI_TIMELINE_ITEM_FOOTER_CHILD, self);
|
||||||
|
|
||||||
_imgui_button(IMGUI_TIMELINE_ADD_ITEM, self);
|
_imgui_button(IMGUI_TIMELINE_ADD_ITEM, self);
|
||||||
|
|
||||||
if (imgui_begin_popup(IMGUI_TIMELINE_ADD_ITEM.popup, self))
|
if (imgui_begin_popup_modal(IMGUI_TIMELINE_ADD_ITEM.popup, self, IMGUI_TIMELINE_ADD_ITEM.popupSize))
|
||||||
{
|
{
|
||||||
if (_imgui_selectable(IMGUI_TIMELINE_ADD_ITEM_LAYER, self)) anm2_layer_add(self->anm2);
|
static s32 selectedLayerID = ID_NONE;
|
||||||
if (_imgui_selectable(IMGUI_TIMELINE_ADD_ITEM_NULL, self)) anm2_null_add(self->anm2);
|
static s32 selectedNullID = ID_NONE;
|
||||||
|
s32& type = self->settings->timelineAddItemType;
|
||||||
|
|
||||||
|
_imgui_begin_child(IMGUI_TIMELINE_ADD_ITEM_TYPE_CHILD, self);
|
||||||
|
|
||||||
|
_imgui_radio_button(IMGUI_TIMELINE_ADD_ITEM_LAYER, self, type);
|
||||||
|
_imgui_radio_button(IMGUI_TIMELINE_ADD_ITEM_NULL, self, type);
|
||||||
|
|
||||||
|
_imgui_end_child(); // IMGUI_TIMELINE_ADD_ITEM_TYPE_CHILD
|
||||||
|
|
||||||
|
_imgui_begin_child(IMGUI_TIMELINE_ADD_ITEM_ITEMS_CHILD, self);
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case ANM2_LAYER:
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
for (auto & [id, layer] : self->anm2->layers)
|
||||||
|
{
|
||||||
|
ImGui::PushID(id);
|
||||||
|
|
||||||
|
ImguiItem layerItem = IMGUI_LAYER.copy
|
||||||
|
({
|
||||||
|
.isSelected = selectedLayerID == id,
|
||||||
|
.label = std::format(IMGUI_LAYER_FORMAT, id, layer.name),
|
||||||
|
.id = id
|
||||||
|
});
|
||||||
|
if (_imgui_atlas_selectable(layerItem, self)) selectedLayerID = id;
|
||||||
|
|
||||||
|
ImGui::PopID();
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ANM2_NULL:
|
||||||
|
{
|
||||||
|
for (auto & [id, null] : self->anm2->nulls)
|
||||||
|
{
|
||||||
|
ImGui::PushID(id);
|
||||||
|
|
||||||
|
ImguiItem nullItem = IMGUI_NULL.copy
|
||||||
|
({
|
||||||
|
.isSelected = selectedNullID == id,
|
||||||
|
.label = std::format(IMGUI_NULL_FORMAT, id, null.name),
|
||||||
|
.id = id
|
||||||
|
});
|
||||||
|
if (_imgui_atlas_selectable(nullItem, self)) selectedNullID = id;
|
||||||
|
|
||||||
|
ImGui::PopID();
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_imgui_end_child(); // IMGUI_TIMELINE_ADD_ITEM_ITEMS_CHILD
|
||||||
|
|
||||||
|
_imgui_begin_child(IMGUI_TIMELINE_ADD_ITEM_OPTIONS_CHILD, self);
|
||||||
|
|
||||||
|
if (self->anm2->layers.size() == 0) selectedLayerID = ID_NONE;
|
||||||
|
if (self->anm2->nulls.size() == 0) selectedNullID = ID_NONE;
|
||||||
|
|
||||||
|
bool isDisabled = type == ANM2_NONE ||
|
||||||
|
(type == ANM2_LAYER && selectedLayerID == ID_NONE) ||
|
||||||
|
(type == ANM2_NULL && selectedNullID == ID_NONE);
|
||||||
|
|
||||||
|
if (_imgui_button(IMGUI_TIMELINE_ADD_ITEM_ADD.copy({isDisabled}), self))
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case ANM2_LAYER: anm2_animation_layer_animation_add(animation, selectedLayerID); break;
|
||||||
|
case ANM2_NULL: anm2_animation_null_animation_add(animation, selectedNullID); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
imgui_close_current_popup(self);
|
||||||
|
}
|
||||||
|
if (_imgui_button(IMGUI_POPUP_CANCEL, self)) imgui_close_current_popup(self);
|
||||||
|
|
||||||
|
_imgui_end_child(); // IMGUI_TIMELINE_ADD_ITEM_OPTIONS_CHILD
|
||||||
|
|
||||||
imgui_end_popup(self);
|
imgui_end_popup(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1198,14 +1281,9 @@ static void _imgui_timeline(Imgui* self)
|
|||||||
{
|
{
|
||||||
switch (itemType)
|
switch (itemType)
|
||||||
{
|
{
|
||||||
case ANM2_LAYER:
|
case ANM2_LAYER: anm2_animation_layer_animation_remove(animation, itemID); break;
|
||||||
anm2_layer_remove(self->anm2, itemID);
|
case ANM2_NULL: anm2_animation_null_animation_remove(animation, itemID); break;
|
||||||
break;
|
default: break;
|
||||||
case ANM2_NULL:
|
|
||||||
anm2_null_remove(self->anm2, itemID);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
anm2_reference_item_clear(self->reference);
|
anm2_reference_item_clear(self->reference);
|
||||||
@@ -1260,8 +1338,7 @@ static void _imgui_timeline(Imgui* self)
|
|||||||
imgui_close_current_popup(self);
|
imgui_close_current_popup(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_imgui_button(IMGUI_POPUP_CANCEL, self))
|
if (_imgui_button(IMGUI_POPUP_CANCEL, self)) imgui_close_current_popup(self);
|
||||||
imgui_close_current_popup(self);
|
|
||||||
|
|
||||||
_imgui_end_child(); //IMGUI_BAKE_CHILD)
|
_imgui_end_child(); //IMGUI_BAKE_CHILD)
|
||||||
|
|
||||||
@@ -1356,14 +1433,13 @@ static void _imgui_taskbar(Imgui* self)
|
|||||||
|
|
||||||
if (self->isTryQuit) imgui_open_popup(IMGUI_EXIT_CONFIRMATION.label);
|
if (self->isTryQuit) imgui_open_popup(IMGUI_EXIT_CONFIRMATION.label);
|
||||||
|
|
||||||
_imgui_option_popup(IMGUI_EXIT_CONFIRMATION, self, &exitConfirmState);
|
_imgui_confirm_popup(IMGUI_EXIT_CONFIRMATION, self, &exitConfirmState);
|
||||||
|
|
||||||
switch (exitConfirmState)
|
switch (exitConfirmState)
|
||||||
{
|
{
|
||||||
case IMGUI_POPUP_STATE_CLOSED: self->isTryQuit = false; break;
|
|
||||||
case IMGUI_POPUP_STATE_OPEN: self->isTryQuit = true; break;
|
|
||||||
case IMGUI_POPUP_STATE_CONFIRM: self->isQuit = true; break;
|
case IMGUI_POPUP_STATE_CONFIRM: self->isQuit = true; break;
|
||||||
case IMGUI_POPUP_STATE_CANCEL: self->isTryQuit = false; break;
|
case IMGUI_POPUP_STATE_CANCEL: self->isTryQuit = false; break;
|
||||||
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_imgui_selectable(IMGUI_WIZARD.copy({}), self);
|
_imgui_selectable(IMGUI_WIZARD.copy({}), self);
|
||||||
@@ -1564,6 +1640,10 @@ static void _imgui_taskbar(Imgui* self)
|
|||||||
_imgui_input_text(IMGUI_RENDER_ANIMATION_FORMAT, self, format);
|
_imgui_input_text(IMGUI_RENDER_ANIMATION_FORMAT, self, format);
|
||||||
_imgui_combo(IMGUI_RENDER_ANIMATION_OUTPUT, self, &type);
|
_imgui_combo(IMGUI_RENDER_ANIMATION_OUTPUT, self, &type);
|
||||||
|
|
||||||
|
_imgui_end_child(); // IMGUI_RENDER_ANIMATION_CHILD
|
||||||
|
|
||||||
|
_imgui_begin_child(IMGUI_RENDER_ANIMATION_FOOTER_CHILD, self);
|
||||||
|
|
||||||
if (_imgui_button(IMGUI_RENDER_ANIMATION_CONFIRM, self))
|
if (_imgui_button(IMGUI_RENDER_ANIMATION_CONFIRM, self))
|
||||||
{
|
{
|
||||||
bool isRenderStart = true;
|
bool isRenderStart = true;
|
||||||
@@ -1609,7 +1689,7 @@ static void _imgui_taskbar(Imgui* self)
|
|||||||
if (_imgui_button(IMGUI_POPUP_CANCEL, self))
|
if (_imgui_button(IMGUI_POPUP_CANCEL, self))
|
||||||
imgui_close_current_popup(self);
|
imgui_close_current_popup(self);
|
||||||
|
|
||||||
_imgui_end_child(); //IMGUI_RENDER_ANIMATION_CHILD
|
_imgui_end_child(); // IMGUI_RENDER_ANIMATION_FOOTER_CHILD
|
||||||
|
|
||||||
imgui_end_popup(self);
|
imgui_end_popup(self);
|
||||||
}
|
}
|
||||||
@@ -1826,9 +1906,110 @@ static void _imgui_tools(Imgui* self)
|
|||||||
_imgui_end(); // IMGUI_TOOLS
|
_imgui_end(); // IMGUI_TOOLS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _imgui_layers(Imgui* self)
|
||||||
|
{
|
||||||
|
static s32 selectedLayerID = ID_NONE;
|
||||||
|
|
||||||
|
IMGUI_BEGIN_OR_RETURN(IMGUI_LAYERS, self);
|
||||||
|
_imgui_no_anm2_path_check(self);
|
||||||
|
|
||||||
|
ImVec2 size = ImGui::GetContentRegionAvail();
|
||||||
|
|
||||||
|
_imgui_begin_child(IMGUI_LAYERS_CHILD.copy({.size = {size.x, size.y - IMGUI_FOOTER_CHILD.size.y}}), self);
|
||||||
|
ImGui::SetScrollX(0.0f);
|
||||||
|
|
||||||
|
for (auto & [id, layer] : self->anm2->layers)
|
||||||
|
{
|
||||||
|
ImGui::PushID(id);
|
||||||
|
|
||||||
|
ImguiItem layerItem = IMGUI_LAYER.copy
|
||||||
|
({
|
||||||
|
.isSelected = selectedLayerID == id,
|
||||||
|
.label = std::format(IMGUI_LAYER_FORMAT, id, layer.name),
|
||||||
|
.size = {ImGui::GetContentRegionAvail().x - (IMGUI_LAYER_SPRITESHEET_ID.size.x * 2.0f), 0},
|
||||||
|
.id = id
|
||||||
|
});
|
||||||
|
if (_imgui_atlas_selectable_input_text(layerItem, self, layer.name)) selectedLayerID = id;
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
ImguiItem spritesheetItem = IMGUI_LAYER_SPRITESHEET_ID.copy
|
||||||
|
({
|
||||||
|
.isSelected = selectedLayerID == id,
|
||||||
|
.label = std::format(IMGUI_LAYER_FORMAT, id, layer.name),
|
||||||
|
.id = id
|
||||||
|
});
|
||||||
|
_imgui_atlas_selectable_input_int(spritesheetItem, self, layer.spritesheetID);
|
||||||
|
|
||||||
|
ImGui::PopID();
|
||||||
|
};
|
||||||
|
|
||||||
|
_imgui_end_child(); // layersChild
|
||||||
|
|
||||||
|
_imgui_begin_child(IMGUI_FOOTER_CHILD, self);
|
||||||
|
|
||||||
|
if (_imgui_button(IMGUI_LAYER_ADD.copy({self->anm2->path.empty()}), self))
|
||||||
|
selectedLayerID = anm2_layer_add(self->anm2);
|
||||||
|
|
||||||
|
if (_imgui_button(IMGUI_LAYER_REMOVE.copy({selectedLayerID == ID_NONE}), self))
|
||||||
|
{
|
||||||
|
anm2_layer_remove(self->anm2, selectedLayerID);
|
||||||
|
selectedLayerID = ID_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_imgui_end_child(); // IMGUI_FOOTER_CHILD
|
||||||
|
_imgui_end(); // IMGUI_LAYERS
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _imgui_nulls(Imgui* self)
|
||||||
|
{
|
||||||
|
static s32 selectedNullID = ID_NONE;
|
||||||
|
|
||||||
|
IMGUI_BEGIN_OR_RETURN(IMGUI_NULLS, self);
|
||||||
|
_imgui_no_anm2_path_check(self);
|
||||||
|
|
||||||
|
ImVec2 size = ImGui::GetContentRegionAvail();
|
||||||
|
|
||||||
|
_imgui_begin_child(IMGUI_NULLS_CHILD.copy({.size = {size.x, size.y - IMGUI_FOOTER_CHILD.size.y}}), self);
|
||||||
|
|
||||||
|
for (auto & [id, null] : self->anm2->nulls)
|
||||||
|
{
|
||||||
|
ImGui::PushID(id);
|
||||||
|
|
||||||
|
ImguiItem nullItem = IMGUI_NULL.copy
|
||||||
|
({
|
||||||
|
.isSelected = selectedNullID == id,
|
||||||
|
.label = std::format(IMGUI_NULL_FORMAT, id, null.name),
|
||||||
|
.id = id
|
||||||
|
});
|
||||||
|
|
||||||
|
if (_imgui_atlas_selectable_input_text(nullItem, self, null.name)) selectedNullID = id;
|
||||||
|
|
||||||
|
ImGui::PopID();
|
||||||
|
};
|
||||||
|
|
||||||
|
_imgui_end_child(); // nullsChild
|
||||||
|
|
||||||
|
_imgui_begin_child(IMGUI_FOOTER_CHILD, self);
|
||||||
|
|
||||||
|
if (_imgui_button(IMGUI_NULL_ADD.copy({self->anm2->path.empty()}), self))
|
||||||
|
selectedNullID = anm2_null_add(self->anm2);
|
||||||
|
|
||||||
|
if (_imgui_button(IMGUI_NULL_REMOVE.copy({selectedNullID == ID_NONE}), self))
|
||||||
|
{
|
||||||
|
anm2_null_remove(self->anm2, selectedNullID);
|
||||||
|
selectedNullID = ID_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_imgui_end_child(); // IMGUI_FOOTER_CHILD
|
||||||
|
_imgui_end(); // IMGUI_NULLS
|
||||||
|
}
|
||||||
|
|
||||||
static void _imgui_animations(Imgui* self)
|
static void _imgui_animations(Imgui* self)
|
||||||
{
|
{
|
||||||
IMGUI_BEGIN_OR_RETURN(IMGUI_ANIMATIONS, self);
|
IMGUI_BEGIN_OR_RETURN(IMGUI_ANIMATIONS, self);
|
||||||
|
_imgui_no_anm2_path_check(self);
|
||||||
|
|
||||||
ImVec2 size = ImGui::GetContentRegionAvail();
|
ImVec2 size = ImGui::GetContentRegionAvail();
|
||||||
|
|
||||||
_imgui_begin_child(IMGUI_ANIMATIONS_CHILD.copy({.size = {size.x, size.y - IMGUI_FOOTER_CHILD.size.y}}), self);
|
_imgui_begin_child(IMGUI_ANIMATIONS_CHILD.copy({.size = {size.x, size.y - IMGUI_FOOTER_CHILD.size.y}}), self);
|
||||||
@@ -1900,7 +2081,7 @@ static void _imgui_animations(Imgui* self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_imgui_button(IMGUI_ANIMATION_DUPLICATE.copy({!animation}), self))
|
if (_imgui_button(IMGUI_ANIMATION_DUPLICATE.copy({!animation}), self))
|
||||||
self->reference->animationID = anm2_animation_add(self->anm2, false, animation, self->reference->animationID);
|
self->reference->animationID = anm2_animation_add(self->anm2, animation, self->reference->animationID);
|
||||||
|
|
||||||
_imgui_button(IMGUI_ANIMATION_MERGE.copy({!animation}), self);
|
_imgui_button(IMGUI_ANIMATION_MERGE.copy({!animation}), self);
|
||||||
|
|
||||||
@@ -2035,6 +2216,8 @@ static void _imgui_events(Imgui* self)
|
|||||||
static s32 selectedID = ID_NONE;
|
static s32 selectedID = ID_NONE;
|
||||||
|
|
||||||
IMGUI_BEGIN_OR_RETURN(IMGUI_EVENTS, self);
|
IMGUI_BEGIN_OR_RETURN(IMGUI_EVENTS, self);
|
||||||
|
_imgui_no_anm2_path_check(self);
|
||||||
|
|
||||||
ImVec2 windowSize = ImGui::GetContentRegionAvail();
|
ImVec2 windowSize = ImGui::GetContentRegionAvail();
|
||||||
|
|
||||||
_imgui_begin_child(IMGUI_EVENTS_CHILD.copy({.size = {windowSize.x, windowSize.y - IMGUI_FOOTER_CHILD.size.y}}), self);
|
_imgui_begin_child(IMGUI_EVENTS_CHILD.copy({.size = {windowSize.x, windowSize.y - IMGUI_FOOTER_CHILD.size.y}}), self);
|
||||||
@@ -2091,6 +2274,7 @@ static void _imgui_spritesheets(Imgui* self)
|
|||||||
static s32 highlightedID = ID_NONE;
|
static s32 highlightedID = ID_NONE;
|
||||||
|
|
||||||
IMGUI_BEGIN_OR_RETURN(IMGUI_SPRITESHEETS, self);
|
IMGUI_BEGIN_OR_RETURN(IMGUI_SPRITESHEETS, self);
|
||||||
|
_imgui_no_anm2_path_check(self);
|
||||||
|
|
||||||
ImVec2 windowSize = ImGui::GetContentRegionAvail();
|
ImVec2 windowSize = ImGui::GetContentRegionAvail();
|
||||||
|
|
||||||
@@ -2170,9 +2354,6 @@ static void _imgui_spritesheets(Imgui* self)
|
|||||||
|
|
||||||
if (_imgui_button(IMGUI_SPRITESHEETS_RELOAD.copy({selectedIDs.empty()}), self))
|
if (_imgui_button(IMGUI_SPRITESHEETS_RELOAD.copy({selectedIDs.empty()}), self))
|
||||||
{
|
{
|
||||||
if (selectedIDs.size() > 0)
|
|
||||||
imgui_snapshot(self, IMGUI_ACTION_RELOAD_SPRITESHEET);
|
|
||||||
|
|
||||||
for (auto& id : selectedIDs)
|
for (auto& id : selectedIDs)
|
||||||
{
|
{
|
||||||
std::filesystem::path workingPath = std::filesystem::current_path();
|
std::filesystem::path workingPath = std::filesystem::current_path();
|
||||||
@@ -2182,6 +2363,8 @@ static void _imgui_spritesheets(Imgui* self)
|
|||||||
self->anm2->spritesheets[id].texture = texture;
|
self->anm2->spritesheets[id].texture = texture;
|
||||||
std::filesystem::current_path(workingPath);
|
std::filesystem::current_path(workingPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
imgui_log_push(self, IMGUI_LOG_RELOAD_SPRITESHEET);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_imgui_button(IMGUI_SPRITESHEETS_REPLACE.copy({highlightedID == ID_NONE}), self))
|
if (_imgui_button(IMGUI_SPRITESHEETS_REPLACE.copy({highlightedID == ID_NONE}), self))
|
||||||
@@ -2488,6 +2671,21 @@ static void _imgui_spritesheet_editor(Imgui* self)
|
|||||||
_imgui_begin_child(IMGUI_CANVAS_VIEW_CHILD, self);
|
_imgui_begin_child(IMGUI_CANVAS_VIEW_CHILD, self);
|
||||||
_imgui_drag_float(IMGUI_CANVAS_ZOOM, self, zoom);
|
_imgui_drag_float(IMGUI_CANVAS_ZOOM, self, zoom);
|
||||||
if (_imgui_button(IMGUI_SPRITESHEET_EDITOR_CENTER_VIEW.copy({pan == vec2()}), self)) pan = vec2();
|
if (_imgui_button(IMGUI_SPRITESHEET_EDITOR_CENTER_VIEW.copy({pan == vec2()}), self)) pan = vec2();
|
||||||
|
if (_imgui_button(IMGUI_SPRITESHEET_EDITOR_FIT.copy({self->editor->spritesheetID == ID_NONE}), self))
|
||||||
|
{
|
||||||
|
vec4 rect = {0, 0, self->anm2->spritesheets[self->editor->spritesheetID].texture.size.x,
|
||||||
|
self->anm2->spritesheets[self->editor->spritesheetID].texture.size.y};
|
||||||
|
|
||||||
|
if ((rect.z > 0 && rect.w > 0))
|
||||||
|
{
|
||||||
|
f32 scaleX = self->editor->canvas.size.x / rect.z;
|
||||||
|
f32 scaleY = self->editor->canvas.size.y / rect.w;
|
||||||
|
f32 fitScale = std::min(scaleX, scaleY);
|
||||||
|
|
||||||
|
zoom = UNIT_TO_PERCENT(fitScale);
|
||||||
|
pan = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
ImGui::Text(mousePositionString.c_str());
|
ImGui::Text(mousePositionString.c_str());
|
||||||
_imgui_end_child(); // IMGUI_CANVAS_VIEW_CHILD
|
_imgui_end_child(); // IMGUI_CANVAS_VIEW_CHILD
|
||||||
|
|
||||||
@@ -2558,8 +2756,8 @@ static void _imgui_spritesheet_editor(Imgui* self)
|
|||||||
{
|
{
|
||||||
if (self->settings->editorIsGridSnap)
|
if (self->settings->editorIsGridSnap)
|
||||||
{
|
{
|
||||||
position.x = roundf(position.x / gridSize.x) * gridSize.x + gridOffset.x - (gridSize.x * 0.5f);
|
position.x = roundf((position.x - gridSize.x) / gridSize.x) * gridSize.x + gridOffset.x - (gridSize.x * 0.5f);
|
||||||
position.y = roundf(position.y / gridSize.y) * gridSize.y + gridOffset.y - (gridSize.y * 0.5f);
|
position.y = roundf((position.y - gridSize.y) / gridSize.y) * gridSize.y + gridOffset.y - (gridSize.y * 0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
frame->pivot = position - frame->crop;
|
frame->pivot = position - frame->crop;
|
||||||
@@ -2770,6 +2968,8 @@ static void _imgui_dock(Imgui* self)
|
|||||||
_imgui_spritesheets(self);
|
_imgui_spritesheets(self);
|
||||||
_imgui_animation_preview(self);
|
_imgui_animation_preview(self);
|
||||||
_imgui_spritesheet_editor(self);
|
_imgui_spritesheet_editor(self);
|
||||||
|
_imgui_layers(self);
|
||||||
|
_imgui_nulls(self);
|
||||||
_imgui_timeline(self);
|
_imgui_timeline(self);
|
||||||
_imgui_onionskin(self);
|
_imgui_onionskin(self);
|
||||||
_imgui_frame_properties(self);
|
_imgui_frame_properties(self);
|
||||||
@@ -2875,20 +3075,15 @@ void imgui_update(Imgui* self)
|
|||||||
{
|
{
|
||||||
const char* droppedFile = event.drop.data;
|
const char* droppedFile = event.drop.data;
|
||||||
|
|
||||||
if (path_is_extension(droppedFile, ANM2_EXTENSION))
|
if (path_is_extension(droppedFile, ANM2_EXTENSION)) _imgui_anm2_open(self, droppedFile);
|
||||||
_imgui_anm2_open(self, droppedFile);
|
else if (path_is_extension(droppedFile, ANM2_SPRITESHEET_EXTENSION)) _imgui_spritesheet_add(self, droppedFile);
|
||||||
else if (path_is_extension(droppedFile, ANM2_SPRITESHEET_EXTENSION))
|
else imgui_log_push(self, IMGUI_LOG_DRAG_DROP_ERROR);
|
||||||
_imgui_spritesheet_add(self, droppedFile);
|
|
||||||
else
|
|
||||||
imgui_log_push(self, IMGUI_LOG_DRAG_DROP_ERROR);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SDL_EVENT_QUIT:
|
case SDL_EVENT_QUIT:
|
||||||
if (self->isTryQuit)
|
if (self->isTryQuit) self->isQuit = true;
|
||||||
self->isQuit = true;
|
else imgui_quit(self);
|
||||||
else
|
|
||||||
imgui_quit(self);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
235
src/imgui.h
235
src/imgui.h
@@ -59,7 +59,7 @@
|
|||||||
#define IMGUI_TIMELINE_FRAME_MULTIPLE 5
|
#define IMGUI_TIMELINE_FRAME_MULTIPLE 5
|
||||||
#define IMGUI_TIMELINE_MERGE
|
#define IMGUI_TIMELINE_MERGE
|
||||||
#define IMGUI_TOOL_COLOR_PICKER_DURATION 0.25f
|
#define IMGUI_TOOL_COLOR_PICKER_DURATION 0.25f
|
||||||
#define IMGUI_OPTION_POPUP_ROW_COUNT 2
|
#define IMGUI_CONFIRM_POPUP_ROW_COUNT 2
|
||||||
#define IMGUI_CHORD_REPEAT_TIME 0.25f
|
#define IMGUI_CHORD_REPEAT_TIME 0.25f
|
||||||
|
|
||||||
#define IMGUI_ACTION_FRAME_CROP "Frame Crop"
|
#define IMGUI_ACTION_FRAME_CROP "Frame Crop"
|
||||||
@@ -68,14 +68,13 @@
|
|||||||
#define IMGUI_ACTION_ANIMATION_SWAP "Animation Swap"
|
#define IMGUI_ACTION_ANIMATION_SWAP "Animation Swap"
|
||||||
#define IMGUI_ACTION_TRIGGER_MOVE "Trigger At Frame"
|
#define IMGUI_ACTION_TRIGGER_MOVE "Trigger At Frame"
|
||||||
#define IMGUI_ACTION_FRAME_DELAY "Frame Delay"
|
#define IMGUI_ACTION_FRAME_DELAY "Frame Delay"
|
||||||
#define IMGUI_ACTION_MOVE_PLAYHEAD "Move Playhead"
|
|
||||||
#define IMGUI_ACTION_DRAW "Draw"
|
#define IMGUI_ACTION_DRAW "Draw"
|
||||||
#define IMGUI_ACTION_ERASE "Erase"
|
#define IMGUI_ACTION_ERASE "Erase"
|
||||||
#define IMGUI_ACTION_MOVE "Move"
|
#define IMGUI_ACTION_MOVE "Move"
|
||||||
#define IMGUI_ACTION_SCALE "Scale"
|
#define IMGUI_ACTION_SCALE "Scale"
|
||||||
#define IMGUI_ACTION_ROTATE "Rotate"
|
#define IMGUI_ACTION_ROTATE "Rotate"
|
||||||
#define IMGUI_ACTION_CROP "Crop"
|
#define IMGUI_ACTION_CROP "Crop"
|
||||||
#define IMGUI_ACTION_RELOAD_SPRITESHEET "Reload Spritesheet(s)"
|
#define IMGUI_ACTION_ADD_SPRITESHEET "Add Spritesheet"
|
||||||
#define IMGUI_ACTION_REPLACE_SPRITESHEET "Replace Spritesheet"
|
#define IMGUI_ACTION_REPLACE_SPRITESHEET "Replace Spritesheet"
|
||||||
#define IMGUI_ACTION_OPEN_FILE "Open File"
|
#define IMGUI_ACTION_OPEN_FILE "Open File"
|
||||||
|
|
||||||
@@ -96,6 +95,9 @@
|
|||||||
#define IMGUI_LOG_RENDER_ANIMATION_FFMPEG_ERROR "FFmpeg could not render animation! Check paths or your FFmpeg installation."
|
#define IMGUI_LOG_RENDER_ANIMATION_FFMPEG_ERROR "FFmpeg could not render animation! Check paths or your FFmpeg installation."
|
||||||
#define IMGUI_LOG_SPRITESHEET_SAVE_FORMAT "Saved spritesheet #{} to: {}"
|
#define IMGUI_LOG_SPRITESHEET_SAVE_FORMAT "Saved spritesheet #{} to: {}"
|
||||||
#define IMGUI_LOG_DRAG_DROP_ERROR "Invalid file for dragging/dropping!"
|
#define IMGUI_LOG_DRAG_DROP_ERROR "Invalid file for dragging/dropping!"
|
||||||
|
#define IMGUI_LOG_ANIMATION_PASTE_ERROR "Failed to parse clipboard text as an animation."
|
||||||
|
#define IMGUI_LOG_FRAME_PASTE_ERROR "Failed to parse clipboard text as a frame."
|
||||||
|
#define IMGUI_LOG_RELOAD_SPRITESHEET "Reloaded spritesheet(s)."
|
||||||
|
|
||||||
#define IMGUI_NONE "None"
|
#define IMGUI_NONE "None"
|
||||||
#define IMGUI_ANIMATION_DEFAULT_FORMAT "(*) {}"
|
#define IMGUI_ANIMATION_DEFAULT_FORMAT "(*) {}"
|
||||||
@@ -110,6 +112,8 @@
|
|||||||
#define IMGUI_SPRITESHEET_FORMAT "#{} {}"
|
#define IMGUI_SPRITESHEET_FORMAT "#{} {}"
|
||||||
#define IMGUI_SPRITESHEET_ID_FORMAT "#{}"
|
#define IMGUI_SPRITESHEET_ID_FORMAT "#{}"
|
||||||
#define IMGUI_TIMELINE_ITEM_CHILD_FORMAT "#{} {}"
|
#define IMGUI_TIMELINE_ITEM_CHILD_FORMAT "#{} {}"
|
||||||
|
#define IMGUI_LAYER_FORMAT "#{} {}"
|
||||||
|
#define IMGUI_NULL_FORMAT "#{} {}"
|
||||||
#define IMGUI_TIMELINE_FRAME_LABEL_FORMAT "## {}"
|
#define IMGUI_TIMELINE_FRAME_LABEL_FORMAT "## {}"
|
||||||
#define IMGUI_SELECTABLE_INPUT_INT_FORMAT "#{}"
|
#define IMGUI_SELECTABLE_INPUT_INT_FORMAT "#{}"
|
||||||
#define IMGUI_TIMELINE_ANIMATION_NONE "Select an animation to show timeline..."
|
#define IMGUI_TIMELINE_ANIMATION_NONE "Select an animation to show timeline..."
|
||||||
@@ -347,7 +351,15 @@ static inline void imgui_copy(Imgui* self)
|
|||||||
|
|
||||||
static inline void imgui_paste(Imgui* self)
|
static inline void imgui_paste(Imgui* self)
|
||||||
{
|
{
|
||||||
clipboard_paste(self->clipboard);
|
if (!clipboard_paste(self->clipboard))
|
||||||
|
{
|
||||||
|
switch (self->clipboard->type)
|
||||||
|
{
|
||||||
|
case CLIPBOARD_FRAME: imgui_log_push(self, IMGUI_LOG_FRAME_PASTE_ERROR); break;
|
||||||
|
case CLIPBOARD_ANIMATION: imgui_log_push(self, IMGUI_LOG_ANIMATION_PASTE_ERROR); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void imgui_onionskin_toggle(Imgui* self)
|
static inline void imgui_onionskin_toggle(Imgui* self)
|
||||||
@@ -604,7 +616,7 @@ enum ImguiItemType
|
|||||||
IMGUI_DOCKSPACE,
|
IMGUI_DOCKSPACE,
|
||||||
IMGUI_CHILD,
|
IMGUI_CHILD,
|
||||||
IMGUI_TABLE,
|
IMGUI_TABLE,
|
||||||
IMGUI_OPTION_POPUP,
|
IMGUI_CONFIRM_POPUP,
|
||||||
IMGUI_SELECTABLE,
|
IMGUI_SELECTABLE,
|
||||||
IMGUI_BUTTON,
|
IMGUI_BUTTON,
|
||||||
IMGUI_RADIO_BUTTON,
|
IMGUI_RADIO_BUTTON,
|
||||||
@@ -631,6 +643,7 @@ struct ImguiItemOverride
|
|||||||
AtlasType atlas = ATLAS_NONE;
|
AtlasType atlas = ATLAS_NONE;
|
||||||
bool isMnemonicDisabled{};
|
bool isMnemonicDisabled{};
|
||||||
s32 value{};
|
s32 value{};
|
||||||
|
s32 rowCount{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ImguiItem;
|
struct ImguiItem;
|
||||||
@@ -754,6 +767,7 @@ struct ImguiItem
|
|||||||
if (override.size != ImVec2{}) out.size = override.size;
|
if (override.size != ImVec2{}) out.size = override.size;
|
||||||
if (override.max != 0) out.max = override.max;
|
if (override.max != 0) out.max = override.max;
|
||||||
if (override.value != 0) out.value = override.value;
|
if (override.value != 0) out.value = override.value;
|
||||||
|
if (override.rowCount != 0) out.rowCount = override.rowCount;
|
||||||
if (override.atlas != ATLAS_NONE) out.atlas = override.atlas;
|
if (override.atlas != ATLAS_NONE) out.atlas = override.atlas;
|
||||||
if (override.isMnemonicDisabled) out.isMnemonicDisabled = override.isMnemonicDisabled;
|
if (override.isMnemonicDisabled) out.isMnemonicDisabled = override.isMnemonicDisabled;
|
||||||
return out;
|
return out;
|
||||||
@@ -888,6 +902,11 @@ IMGUI_ITEM(IMGUI_OPEN_CONFIRMATION,
|
|||||||
self.text = "Unsaved changes will be lost!\nAre you sure you open a new file?"
|
self.text = "Unsaved changes will be lost!\nAre you sure you open a new file?"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
IMGUI_ITEM(IMGUI_NO_ANM2_PATH_CONFIRMATION,
|
||||||
|
self.label = "No Anm2 Path",
|
||||||
|
self.text = "You will need to load or make a new .anm2 file first!\n"
|
||||||
|
);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_WIZARD,
|
IMGUI_ITEM(IMGUI_WIZARD,
|
||||||
self.label = "&Wizard",
|
self.label = "&Wizard",
|
||||||
self.tooltip = "Opens the wizard menu, for neat functions related to the .anm2.",
|
self.tooltip = "Opens the wizard menu, for neat functions related to the .anm2.",
|
||||||
@@ -996,7 +1015,7 @@ IMGUI_ITEM(IMGUI_GENERATE_ANIMATION_FROM_GRID_GENERATE,
|
|||||||
self.label = "Generate",
|
self.label = "Generate",
|
||||||
self.tooltip = "Generate an animation with the used settings.",
|
self.tooltip = "Generate an animation with the used settings.",
|
||||||
self.snapshotAction = "Generate Animation from Grid",
|
self.snapshotAction = "Generate Animation from Grid",
|
||||||
self.rowCount = IMGUI_OPTION_POPUP_ROW_COUNT,
|
self.rowCount = IMGUI_CONFIRM_POPUP_ROW_COUNT,
|
||||||
self.isSameLine = true
|
self.isSameLine = true
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1103,7 +1122,7 @@ IMGUI_ITEM(IMGUI_SCALE_ANM2_SCALE,
|
|||||||
self.label = "Scale",
|
self.label = "Scale",
|
||||||
self.tooltip = "Scale the anm2 with the value specified.",
|
self.tooltip = "Scale the anm2 with the value specified.",
|
||||||
self.snapshotAction = "Scale Anm2",
|
self.snapshotAction = "Scale Anm2",
|
||||||
self.rowCount = IMGUI_OPTION_POPUP_ROW_COUNT,
|
self.rowCount = IMGUI_CONFIRM_POPUP_ROW_COUNT,
|
||||||
self.isSameLine = true
|
self.isSameLine = true
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1111,12 +1130,20 @@ IMGUI_ITEM(IMGUI_RENDER_ANIMATION,
|
|||||||
self.label = "&Render Animation",
|
self.label = "&Render Animation",
|
||||||
self.tooltip = "Renders the current animation preview; output options can be customized.",
|
self.tooltip = "Renders the current animation preview; output options can be customized.",
|
||||||
self.popup = "Render Animation",
|
self.popup = "Render Animation",
|
||||||
self.popupSize = {600, 125}
|
self.popupSize = {600, 150},
|
||||||
|
self.popupType = IMGUI_POPUP_CENTER_WINDOW
|
||||||
);
|
);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_RENDER_ANIMATION_CHILD,
|
IMGUI_ITEM(IMGUI_RENDER_ANIMATION_CHILD,
|
||||||
self.label = "## Render Animation Child",
|
self.label = "## Render Animation Child",
|
||||||
self.size = {600, 125}
|
self.size = {IMGUI_RENDER_ANIMATION.popupSize.x, IMGUI_RENDER_ANIMATION.popupSize.y - IMGUI_FOOTER_CHILD.size.y},
|
||||||
|
self.flags = true
|
||||||
|
);
|
||||||
|
|
||||||
|
IMGUI_ITEM(IMGUI_RENDER_ANIMATION_FOOTER_CHILD,
|
||||||
|
self.label = "## Render Animation Footer Child",
|
||||||
|
self.size = {IMGUI_RENDER_ANIMATION.popupSize.x, IMGUI_FOOTER_CHILD.size.y},
|
||||||
|
self.flags = true
|
||||||
);
|
);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_RENDER_ANIMATION_LOCATION_BROWSE,
|
IMGUI_ITEM(IMGUI_RENDER_ANIMATION_LOCATION_BROWSE,
|
||||||
@@ -1149,8 +1176,7 @@ IMGUI_ITEM(IMGUI_RENDER_ANIMATION_OUTPUT,
|
|||||||
self.label = "Output",
|
self.label = "Output",
|
||||||
self.tooltip = "Select the rendered animation output.\nIt can either be one animated image or a sequence of frames.",
|
self.tooltip = "Select the rendered animation output.\nIt can either be one animated image or a sequence of frames.",
|
||||||
self.items = {std::begin(RENDER_TYPE_STRINGS), std::end(RENDER_TYPE_STRINGS)},
|
self.items = {std::begin(RENDER_TYPE_STRINGS), std::end(RENDER_TYPE_STRINGS)},
|
||||||
self.value = RENDER_PNG,
|
self.value = RENDER_PNG
|
||||||
self.isSeparator = true
|
|
||||||
);
|
);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_RENDER_ANIMATION_FORMAT,
|
IMGUI_ITEM(IMGUI_RENDER_ANIMATION_FORMAT,
|
||||||
@@ -1166,7 +1192,7 @@ IMGUI_ITEM(IMGUI_RENDER_ANIMATION_CONFIRM,
|
|||||||
self.popupType = IMGUI_POPUP_CENTER_WINDOW,
|
self.popupType = IMGUI_POPUP_CENTER_WINDOW,
|
||||||
self.popupSize = {300, 60},
|
self.popupSize = {300, 60},
|
||||||
self.isSameLine = true,
|
self.isSameLine = true,
|
||||||
self.rowCount = IMGUI_OPTION_POPUP_ROW_COUNT
|
self.rowCount = IMGUI_CONFIRM_POPUP_ROW_COUNT
|
||||||
);
|
);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_RENDERING_ANIMATION_CHILD,
|
IMGUI_ITEM(IMGUI_RENDERING_ANIMATION_CHILD,
|
||||||
@@ -1259,6 +1285,73 @@ IMGUI_ITEM(IMGUI_DEFAULT_SETTINGS,
|
|||||||
self.isSizeToText = true
|
self.isSizeToText = true
|
||||||
);
|
);
|
||||||
|
|
||||||
|
IMGUI_ITEM(IMGUI_LAYERS,
|
||||||
|
self.label = "Layers",
|
||||||
|
self.flags = ImGuiWindowFlags_NoScrollbar |
|
||||||
|
ImGuiWindowFlags_NoScrollWithMouse
|
||||||
|
);
|
||||||
|
IMGUI_ITEM(IMGUI_LAYERS_CHILD, self.label = "## Layers Child", self.flags = true);
|
||||||
|
|
||||||
|
IMGUI_ITEM(IMGUI_LAYER,
|
||||||
|
self.label = "## Layer Item",
|
||||||
|
self.dragDrop = "## Layer Drag Drop",
|
||||||
|
self.atlas = ATLAS_LAYER,
|
||||||
|
self.idOffset = 3000
|
||||||
|
);
|
||||||
|
|
||||||
|
IMGUI_ITEM(IMGUI_LAYER_SPRITESHEET_ID,
|
||||||
|
self.label = "## Spritesheet ID",
|
||||||
|
self.tooltip = "Change the spritesheet ID this layer uses.",
|
||||||
|
self.atlas = ATLAS_SPRITESHEET,
|
||||||
|
self.size = {50, 0}
|
||||||
|
);
|
||||||
|
|
||||||
|
#define IMGUI_LAYERS_OPTIONS_ROW_COUNT 2
|
||||||
|
IMGUI_ITEM(IMGUI_LAYER_ADD,
|
||||||
|
self.label = "Add",
|
||||||
|
self.tooltip = "Adds a new layer.",
|
||||||
|
self.snapshotAction = "Add Layer",
|
||||||
|
self.rowCount = IMGUI_LAYERS_OPTIONS_ROW_COUNT,
|
||||||
|
self.isSameLine = true
|
||||||
|
);
|
||||||
|
|
||||||
|
IMGUI_ITEM(IMGUI_LAYER_REMOVE,
|
||||||
|
self.label = "Remove",
|
||||||
|
self.tooltip = "Removes the selected layer.\nThis will remove all layer animations that use this layer from all animations.",
|
||||||
|
self.snapshotAction = "Remove Layer",
|
||||||
|
self.rowCount = IMGUI_LAYERS_OPTIONS_ROW_COUNT
|
||||||
|
);
|
||||||
|
|
||||||
|
IMGUI_ITEM(IMGUI_NULLS,
|
||||||
|
self.label = "Nulls",
|
||||||
|
self.flags = ImGuiWindowFlags_NoScrollbar |
|
||||||
|
ImGuiWindowFlags_NoScrollWithMouse
|
||||||
|
);
|
||||||
|
IMGUI_ITEM(IMGUI_NULLS_CHILD, self.label = "## Nulls Child", self.flags = true);
|
||||||
|
|
||||||
|
IMGUI_ITEM(IMGUI_NULL,
|
||||||
|
self.label = "## Null Item",
|
||||||
|
self.dragDrop = "## Null Drag Drop",
|
||||||
|
self.atlas = ATLAS_NULL,
|
||||||
|
self.idOffset = 4000
|
||||||
|
);
|
||||||
|
|
||||||
|
#define IMGUI_NULLS_OPTIONS_ROW_COUNT 2
|
||||||
|
IMGUI_ITEM(IMGUI_NULL_ADD,
|
||||||
|
self.label = "Add",
|
||||||
|
self.tooltip = "Adds a null layer.",
|
||||||
|
self.snapshotAction = "Add Null",
|
||||||
|
self.rowCount = IMGUI_NULLS_OPTIONS_ROW_COUNT,
|
||||||
|
self.isSameLine = true
|
||||||
|
);
|
||||||
|
|
||||||
|
IMGUI_ITEM(IMGUI_NULL_REMOVE,
|
||||||
|
self.label = "Remove",
|
||||||
|
self.tooltip = "Removes the selected null.\nThis will remove all null animations that use this null from all animations.",
|
||||||
|
self.snapshotAction = "Remove Null",
|
||||||
|
self.rowCount = IMGUI_NULLS_OPTIONS_ROW_COUNT
|
||||||
|
);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_ANIMATIONS,
|
IMGUI_ITEM(IMGUI_ANIMATIONS,
|
||||||
self.label = "Animations",
|
self.label = "Animations",
|
||||||
self.flags = ImGuiWindowFlags_NoScrollbar |
|
self.flags = ImGuiWindowFlags_NoScrollbar |
|
||||||
@@ -1354,7 +1447,7 @@ IMGUI_ITEM(IMGUI_MERGE_CONFIRM,
|
|||||||
self.label = "Merge",
|
self.label = "Merge",
|
||||||
self.tooltip = "Merge the selected animations with the options set.",
|
self.tooltip = "Merge the selected animations with the options set.",
|
||||||
self.snapshotAction = "Merge Animations",
|
self.snapshotAction = "Merge Animations",
|
||||||
self.rowCount = IMGUI_OPTION_POPUP_ROW_COUNT,
|
self.rowCount = IMGUI_CONFIRM_POPUP_ROW_COUNT,
|
||||||
self.isSameLine = true
|
self.isSameLine = true
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1440,15 +1533,15 @@ IMGUI_ITEM(IMGUI_SPRITESHEETS_FOOTER_CHILD,
|
|||||||
#define IMGUI_SPRITESHEETS_OPTIONS_SECOND_ROW_COUNT 3
|
#define IMGUI_SPRITESHEETS_OPTIONS_SECOND_ROW_COUNT 3
|
||||||
IMGUI_ITEM(IMGUI_SPRITESHEET_ADD,
|
IMGUI_ITEM(IMGUI_SPRITESHEET_ADD,
|
||||||
self.label = "Add",
|
self.label = "Add",
|
||||||
self.tooltip = "Select an image to add as a spritesheet.",
|
self.tooltip = "Select a .png image to add as a spritesheet.",
|
||||||
self.rowCount = IMGUI_SPRITESHEETS_OPTIONS_FIRST_ROW_COUNT,
|
self.rowCount = IMGUI_SPRITESHEETS_OPTIONS_FIRST_ROW_COUNT,
|
||||||
self.isSameLine = true
|
self.isSameLine = true
|
||||||
);
|
);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_SPRITESHEETS_RELOAD,
|
IMGUI_ITEM(IMGUI_SPRITESHEETS_RELOAD,
|
||||||
self.label = "Reload",
|
self.label = "Reload",
|
||||||
self.tooltip = "Reload the selected spritesheet.",
|
self.tooltip = "Reload the selected spritesheet(s).",
|
||||||
self.snapshotAction = "Reload Spritesheet",
|
self.snapshotAction = "Reload Spritesheet(s)",
|
||||||
self.rowCount = IMGUI_SPRITESHEETS_OPTIONS_FIRST_ROW_COUNT,
|
self.rowCount = IMGUI_SPRITESHEETS_OPTIONS_FIRST_ROW_COUNT,
|
||||||
self.isSameLine = true
|
self.isSameLine = true
|
||||||
);
|
);
|
||||||
@@ -1490,7 +1583,9 @@ const ImVec2 IMGUI_CANVAS_CHILD_SIZE = {230, 85};
|
|||||||
IMGUI_ITEM(IMGUI_CANVAS_GRID_CHILD,
|
IMGUI_ITEM(IMGUI_CANVAS_GRID_CHILD,
|
||||||
self.label = "## Canvas Grid Child",
|
self.label = "## Canvas Grid Child",
|
||||||
self.size = IMGUI_CANVAS_CHILD_SIZE,
|
self.size = IMGUI_CANVAS_CHILD_SIZE,
|
||||||
self.flags = true
|
self.flags = true,
|
||||||
|
self.windowFlags = ImGuiWindowFlags_NoScrollbar |
|
||||||
|
ImGuiWindowFlags_NoScrollWithMouse
|
||||||
);
|
);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_CANVAS_GRID,
|
IMGUI_ITEM(IMGUI_CANVAS_GRID,
|
||||||
@@ -1525,7 +1620,9 @@ IMGUI_ITEM(IMGUI_CANVAS_GRID_OFFSET,
|
|||||||
IMGUI_ITEM(IMGUI_CANVAS_VIEW_CHILD,
|
IMGUI_ITEM(IMGUI_CANVAS_VIEW_CHILD,
|
||||||
self.label = "## View Child",
|
self.label = "## View Child",
|
||||||
self.size = IMGUI_CANVAS_CHILD_SIZE,
|
self.size = IMGUI_CANVAS_CHILD_SIZE,
|
||||||
self.flags = true
|
self.flags = true,
|
||||||
|
self.windowFlags = ImGuiWindowFlags_NoScrollbar |
|
||||||
|
ImGuiWindowFlags_NoScrollWithMouse
|
||||||
);
|
);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_CANVAS_ZOOM,
|
IMGUI_ITEM(IMGUI_CANVAS_ZOOM,
|
||||||
@@ -1537,12 +1634,12 @@ IMGUI_ITEM(IMGUI_CANVAS_ZOOM,
|
|||||||
self.value = CANVAS_ZOOM_DEFAULT
|
self.value = CANVAS_ZOOM_DEFAULT
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_CANVAS_VISUAL_CHILD,
|
IMGUI_ITEM(IMGUI_CANVAS_VISUAL_CHILD,
|
||||||
self.label = "## Animation Preview Visual Child",
|
self.label = "## Animation Preview Visual Child",
|
||||||
self.size = IMGUI_CANVAS_CHILD_SIZE,
|
self.size = IMGUI_CANVAS_CHILD_SIZE,
|
||||||
self.flags = true
|
self.flags = true,
|
||||||
|
self.windowFlags = ImGuiWindowFlags_NoScrollbar |
|
||||||
|
ImGuiWindowFlags_NoScrollWithMouse
|
||||||
);
|
);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_CANVAS_BACKGROUND_COLOR,
|
IMGUI_ITEM(IMGUI_CANVAS_BACKGROUND_COLOR,
|
||||||
@@ -1566,7 +1663,9 @@ IMGUI_ITEM(IMGUI_CANVAS_ANIMATION_OVERLAY_TRANSPARENCY,
|
|||||||
IMGUI_ITEM(IMGUI_CANVAS_HELPER_CHILD,
|
IMGUI_ITEM(IMGUI_CANVAS_HELPER_CHILD,
|
||||||
self.label = "## Animation Preview Helper Child",
|
self.label = "## Animation Preview Helper Child",
|
||||||
self.size = IMGUI_CANVAS_CHILD_SIZE,
|
self.size = IMGUI_CANVAS_CHILD_SIZE,
|
||||||
self.flags = true
|
self.flags = true,
|
||||||
|
self.windowFlags = ImGuiWindowFlags_NoScrollbar |
|
||||||
|
ImGuiWindowFlags_NoScrollWithMouse
|
||||||
);
|
);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_CANVAS_AXES,
|
IMGUI_ITEM(IMGUI_CANVAS_AXES,
|
||||||
@@ -1644,12 +1743,22 @@ IMGUI_ITEM(IMGUI_SPRITESHEET_EDITOR,
|
|||||||
self.flags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse
|
self.flags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#define IMGUI_SPRITESHEET_EDITOR_VIEW_ROW_COUNT 2
|
||||||
IMGUI_ITEM(IMGUI_SPRITESHEET_EDITOR_CENTER_VIEW,
|
IMGUI_ITEM(IMGUI_SPRITESHEET_EDITOR_CENTER_VIEW,
|
||||||
self.label = "Center View",
|
self.label = "Center View",
|
||||||
self.tooltip = "Centers the current view on the spritesheet editor.",
|
self.tooltip = "Centers the current view on the spritesheet editor.",
|
||||||
self.hotkey = HOTKEY_CENTER_VIEW,
|
self.hotkey = HOTKEY_CENTER_VIEW,
|
||||||
self.focusWindow = IMGUI_SPRITESHEET_EDITOR.label,
|
self.focusWindow = IMGUI_SPRITESHEET_EDITOR.label,
|
||||||
self.size = {-FLT_MIN, 0}
|
self.rowCount = IMGUI_SPRITESHEET_EDITOR_VIEW_ROW_COUNT,
|
||||||
|
self.isSameLine = true
|
||||||
|
);
|
||||||
|
|
||||||
|
IMGUI_ITEM(IMGUI_SPRITESHEET_EDITOR_FIT,
|
||||||
|
self.label = "Fit",
|
||||||
|
self.tooltip = "Adjust the view/pan based on the size of the spritesheet, to fit the canvas' size.",
|
||||||
|
self.hotkey = HOTKEY_FIT,
|
||||||
|
self.focusWindow = IMGUI_SPRITESHEET_EDITOR.label,
|
||||||
|
self.rowCount = IMGUI_SPRITESHEET_EDITOR_VIEW_ROW_COUNT
|
||||||
);
|
);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_FRAME_PROPERTIES, self.label = "Frame Properties");
|
IMGUI_ITEM(IMGUI_FRAME_PROPERTIES, self.label = "Frame Properties");
|
||||||
@@ -2000,6 +2109,20 @@ const inline ImguiItem* IMGUI_TIMELINE_ITEM_SELECTABLES[ANM2_COUNT]
|
|||||||
&IMGUI_TIMELINE_ITEM_TRIGGERS_SELECTABLE
|
&IMGUI_TIMELINE_ITEM_TRIGGERS_SELECTABLE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
IMGUI_ITEM(IMGUI_TIMELINE_SHOW_UNUSED,
|
||||||
|
self.label = "## Show Unused",
|
||||||
|
self.tooltip = "Layers/nulls without any frames will be hidden.",
|
||||||
|
self.snapshotAction = "Hide Unused",
|
||||||
|
self.atlas = ATLAS_SHOW_UNUSED
|
||||||
|
);
|
||||||
|
|
||||||
|
IMGUI_ITEM(IMGUI_TIMELINE_HIDE_UNUSED,
|
||||||
|
self.label = "## Hide Unused",
|
||||||
|
self.tooltip = "Layers/nulls without any frames will be shown.",
|
||||||
|
self.snapshotAction = "Show Unused",
|
||||||
|
self.atlas = ATLAS_HIDE_UNUSED
|
||||||
|
);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_TIMELINE_ITEM_VISIBLE,
|
IMGUI_ITEM(IMGUI_TIMELINE_ITEM_VISIBLE,
|
||||||
self.label = "## Visible",
|
self.label = "## Visible",
|
||||||
self.tooltip = "The item is visible.\nPress to set to invisible.",
|
self.tooltip = "The item is visible.\nPress to set to invisible.",
|
||||||
@@ -2028,12 +2151,6 @@ IMGUI_ITEM(IMGUI_TIMELINE_ITEM_HIDE_RECT,
|
|||||||
self.atlas = ATLAS_HIDE_RECT
|
self.atlas = ATLAS_HIDE_RECT
|
||||||
);
|
);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_TIMELINE_SPRITESHEET_ID,
|
|
||||||
self.label = "## Spritesheet ID",
|
|
||||||
self.tooltip = "Change the spritesheet ID this item uses.",
|
|
||||||
self.atlas = ATLAS_SPRITESHEET,
|
|
||||||
self.size = {32, 0}
|
|
||||||
);
|
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_TIMELINE_FRAMES_CHILD,
|
IMGUI_ITEM(IMGUI_TIMELINE_FRAMES_CHILD,
|
||||||
self.label = "## Timeline Frames Child",
|
self.label = "## Timeline Frames Child",
|
||||||
@@ -2095,36 +2212,68 @@ const inline ImguiItem* IMGUI_TIMELINE_FRAMES[ANM2_COUNT]
|
|||||||
IMGUI_ITEM(IMGUI_TIMELINE_ITEM_FOOTER_CHILD,
|
IMGUI_ITEM(IMGUI_TIMELINE_ITEM_FOOTER_CHILD,
|
||||||
self.label = "## Item Footer Child",
|
self.label = "## Item Footer Child",
|
||||||
self.size = {IMGUI_TIMELINE_ITEM_CHILD.size.x, IMGUI_FOOTER_CHILD.size.y},
|
self.size = {IMGUI_TIMELINE_ITEM_CHILD.size.x, IMGUI_FOOTER_CHILD.size.y},
|
||||||
self.flags = true
|
self.flags = true,
|
||||||
|
self.windowFlags = ImGuiWindowFlags_NoScrollbar |
|
||||||
|
ImGuiWindowFlags_NoScrollWithMouse
|
||||||
);
|
);
|
||||||
IMGUI_ITEM(IMGUI_TIMELINE_OPTIONS_FOOTER_CHILD,
|
IMGUI_ITEM(IMGUI_TIMELINE_OPTIONS_FOOTER_CHILD,
|
||||||
self.label = "## Options Footer Child",
|
self.label = "## Options Footer Child",
|
||||||
self.size = {0, IMGUI_FOOTER_CHILD.size.y},
|
self.size = {0, IMGUI_FOOTER_CHILD.size.y},
|
||||||
self.flags = true
|
self.flags = true,
|
||||||
|
self.windowFlags = ImGuiWindowFlags_NoScrollbar |
|
||||||
|
ImGuiWindowFlags_NoScrollWithMouse
|
||||||
);
|
);
|
||||||
|
|
||||||
#define IMGUI_TIMELINE_FOOTER_ITEM_CHILD_ITEM_COUNT 2
|
#define IMGUI_TIMELINE_FOOTER_ITEM_CHILD_ITEM_COUNT 2
|
||||||
IMGUI_ITEM(IMGUI_TIMELINE_ADD_ITEM,
|
IMGUI_ITEM(IMGUI_TIMELINE_ADD_ITEM,
|
||||||
self.label = "Add",
|
self.label = "Add",
|
||||||
self.tooltip = "Adds an item (layer or null) to the animation.",
|
self.tooltip = "Adds an item (layer or null) to the animation.\nMake sure to add a Layer/Null first in the Layers or Nulls windows.",
|
||||||
self.popup = "## Add Item Popup",
|
self.popup = "Add Item",
|
||||||
self.popupType = IMGUI_POPUP_BY_ITEM,
|
self.popupType = IMGUI_POPUP_CENTER_WINDOW,
|
||||||
|
self.popupSize = {300, 350},
|
||||||
self.rowCount = IMGUI_TIMELINE_FOOTER_ITEM_CHILD_ITEM_COUNT,
|
self.rowCount = IMGUI_TIMELINE_FOOTER_ITEM_CHILD_ITEM_COUNT,
|
||||||
self.isSameLine = true
|
self.isSameLine = true
|
||||||
);
|
);
|
||||||
|
|
||||||
|
IMGUI_ITEM(IMGUI_TIMELINE_ADD_ITEM_TYPE_CHILD,
|
||||||
|
self.label = "## Add Item Type Child",
|
||||||
|
self.size = {IMGUI_TIMELINE_ADD_ITEM.popupSize.x, 35},
|
||||||
|
self.flags = true
|
||||||
|
);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_TIMELINE_ADD_ITEM_LAYER,
|
IMGUI_ITEM(IMGUI_TIMELINE_ADD_ITEM_LAYER,
|
||||||
self.label = "Layer",
|
self.label = "Layer",
|
||||||
self.tooltip = "Adds a layer item.\nA layer item is a primary graphical item, using a spritesheet.",
|
self.tooltip = "Adds a layer item.\nA layer item is a primary graphical item, using a spritesheet.",
|
||||||
self.snapshotAction = "Add Layer",
|
self.isSizeToText = true,
|
||||||
self.isSizeToText = true
|
self.value = ANM2_LAYER,
|
||||||
|
self.isSameLine = true
|
||||||
);
|
);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_TIMELINE_ADD_ITEM_NULL,
|
IMGUI_ITEM(IMGUI_TIMELINE_ADD_ITEM_NULL,
|
||||||
self.label = "Null",
|
self.label = "Null",
|
||||||
self.tooltip = "Adds a null item.\nA null item is an invisible item, often accessed by the game engine.",
|
self.tooltip = "Adds a null item.\nA null item is an invisible item, often accessed by a game engine.",
|
||||||
self.snapshotAction = "Add Null",
|
self.isSizeToText = true,
|
||||||
self.isSizeToText = true
|
self.value = ANM2_NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
IMGUI_ITEM(IMGUI_TIMELINE_ADD_ITEM_ITEMS_CHILD,
|
||||||
|
self.label = "## Add Item Items",
|
||||||
|
self.size = {IMGUI_TIMELINE_ADD_ITEM.popupSize.x, 250},
|
||||||
|
self.flags = true
|
||||||
|
);
|
||||||
|
|
||||||
|
IMGUI_ITEM(IMGUI_TIMELINE_ADD_ITEM_OPTIONS_CHILD,
|
||||||
|
self.label = "## Add Item Options Child",
|
||||||
|
self.size = {IMGUI_TIMELINE_ADD_ITEM.popupSize.x, 35},
|
||||||
|
self.flags = true
|
||||||
|
);
|
||||||
|
|
||||||
|
IMGUI_ITEM(IMGUI_TIMELINE_ADD_ITEM_ADD,
|
||||||
|
self.label = "Add",
|
||||||
|
self.tooltip = "Add the selected item.",
|
||||||
|
self.snapshotAction = "Add Animation",
|
||||||
|
self.rowCount = IMGUI_CONFIRM_POPUP_ROW_COUNT,
|
||||||
|
self.isSameLine = true
|
||||||
);
|
);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_TIMELINE_REMOVE_ITEM,
|
IMGUI_ITEM(IMGUI_TIMELINE_REMOVE_ITEM,
|
||||||
@@ -2211,7 +2360,7 @@ IMGUI_ITEM(IMGUI_BAKE_CONFIRM,
|
|||||||
self.label = "Bake",
|
self.label = "Bake",
|
||||||
self.tooltip = "Bake the selected frame with the options selected.",
|
self.tooltip = "Bake the selected frame with the options selected.",
|
||||||
self.snapshotAction = "Bake Frames",
|
self.snapshotAction = "Bake Frames",
|
||||||
self.rowCount = IMGUI_OPTION_POPUP_ROW_COUNT,
|
self.rowCount = IMGUI_CONFIRM_POPUP_ROW_COUNT,
|
||||||
self.isSameLine = true
|
self.isSameLine = true
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -2353,17 +2502,17 @@ IMGUI_ITEM(IMGUI_CHANGE_INPUT_INT,
|
|||||||
self.step = 0
|
self.step = 0
|
||||||
);
|
);
|
||||||
|
|
||||||
#define IMGUI_OPTION_POPUP_ROW_COUNT 2
|
#define IMGUI_CONFIRM_POPUP_ROW_COUNT 2
|
||||||
IMGUI_ITEM(IMGUI_POPUP_OK,
|
IMGUI_ITEM(IMGUI_POPUP_OK,
|
||||||
self.label = "OK",
|
self.label = "OK",
|
||||||
self.tooltip = "Confirm the action.",
|
self.tooltip = "Confirm the action.",
|
||||||
self.rowCount = IMGUI_OPTION_POPUP_ROW_COUNT
|
self.rowCount = IMGUI_CONFIRM_POPUP_ROW_COUNT
|
||||||
);
|
);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_POPUP_CANCEL,
|
IMGUI_ITEM(IMGUI_POPUP_CANCEL,
|
||||||
self.label = "Cancel",
|
self.label = "Cancel",
|
||||||
self.tooltip = "Cancel the action.",
|
self.tooltip = "Cancel the action.",
|
||||||
self.rowCount = IMGUI_OPTION_POPUP_ROW_COUNT
|
self.rowCount = IMGUI_CONFIRM_POPUP_ROW_COUNT
|
||||||
);
|
);
|
||||||
|
|
||||||
IMGUI_ITEM(IMGUI_LOG_WINDOW,
|
IMGUI_ITEM(IMGUI_LOG_WINDOW,
|
||||||
|
@@ -40,7 +40,7 @@ void preview_tick(Preview* self)
|
|||||||
glReadPixels(0, 0, size.x, size.y, GL_RGBA, GL_UNSIGNED_BYTE, framebufferPixels.data());
|
glReadPixels(0, 0, size.x, size.y, GL_RGBA, GL_UNSIGNED_BYTE, framebufferPixels.data());
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||||
|
|
||||||
texture_from_rgba_init(&frameTexture, size, TEXTURE_CHANNELS, framebufferPixels.data());
|
texture_from_rgba_init(&frameTexture, size, framebufferPixels.data());
|
||||||
self->renderFrames.push_back(frameTexture);
|
self->renderFrames.push_back(frameTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,7 +199,7 @@ void preview_draw(Preview* self)
|
|||||||
if (self->settings->previewIsIcons && animation->rootAnimation.isVisible && root.isVisible)
|
if (self->settings->previewIsIcons && animation->rootAnimation.isVisible && root.isVisible)
|
||||||
root_draw(root, colorOffset, alphaOffset, isOnionskin);
|
root_draw(root, colorOffset, alphaOffset, isOnionskin);
|
||||||
|
|
||||||
for (auto [i, id] : self->anm2->layerMap)
|
for (auto id : animation->layerOrder)
|
||||||
layer_draw(rootModel, id, time, colorOffset, alphaOffset, isOnionskin);
|
layer_draw(rootModel, id, time, colorOffset, alphaOffset, isOnionskin);
|
||||||
|
|
||||||
if (self->settings->previewIsIcons)
|
if (self->settings->previewIsIcons)
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
void resources_init(Resources* self)
|
void resources_init(Resources* self)
|
||||||
{
|
{
|
||||||
texture_from_encoded_data_init(&self->atlas, TEXTURE_ATLAS_SIZE, TEXTURE_CHANNELS, (u8*)TEXTURE_ATLAS, TEXTURE_ATLAS_LENGTH);
|
texture_from_encoded_data_init(&self->atlas, TEXTURE_ATLAS_SIZE, (u8*)TEXTURE_ATLAS, TEXTURE_ATLAS_LENGTH);
|
||||||
|
|
||||||
for (s32 i = 0; i < SHADER_COUNT; i++)
|
for (s32 i = 0; i < SHADER_COUNT; i++)
|
||||||
shader_init(&self->shaders[i], SHADER_DATA[i].vertex, SHADER_DATA[i].fragment);
|
shader_init(&self->shaders[i], SHADER_DATA[i].vertex, SHADER_DATA[i].fragment);
|
||||||
|
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
#define SETTINGS_LIST \
|
#define SETTINGS_LIST \
|
||||||
/* name, symbol, type, defaultValue */ \
|
/* name, symbol, type, defaultValue */ \
|
||||||
X(windowSize, WINDOW_SIZE, TYPE_IVEC2_WH, {1280, 720}) \
|
X(windowSize, WINDOW_SIZE, TYPE_IVEC2_WH, {1600, 900}) \
|
||||||
X(isVsync, IS_VSYNC, TYPE_BOOL, true) \
|
X(isVsync, IS_VSYNC, TYPE_BOOL, true) \
|
||||||
\
|
\
|
||||||
X(hotkeyCenterView, HOTKEY_CENTER_VIEW, TYPE_STRING, "Home") \
|
X(hotkeyCenterView, HOTKEY_CENTER_VIEW, TYPE_STRING, "Home") \
|
||||||
@@ -130,6 +130,9 @@
|
|||||||
X(bakeIsRoundScale, BAKE_IS_ROUND_SCALE, TYPE_BOOL, true) \
|
X(bakeIsRoundScale, BAKE_IS_ROUND_SCALE, TYPE_BOOL, true) \
|
||||||
X(bakeIsRoundRotation, BAKE_IS_ROUND_ROTATION, TYPE_BOOL, true) \
|
X(bakeIsRoundRotation, BAKE_IS_ROUND_ROTATION, TYPE_BOOL, true) \
|
||||||
\
|
\
|
||||||
|
X(timelineAddItemType, TIMELINE_ADD_ITEM_TYPE, TYPE_INT, ANM2_LAYER) \
|
||||||
|
X(timelineIsShowUnused, TIMELINE_IS_SHOW_UNUSED, TYPE_BOOL, true) \
|
||||||
|
\
|
||||||
X(onionskinIsEnabled, ONIONSKIN_IS_ENABLED, TYPE_BOOL, false) \
|
X(onionskinIsEnabled, ONIONSKIN_IS_ENABLED, TYPE_BOOL, false) \
|
||||||
X(onionskinDrawOrder, ONIONSKIN_DRAW_ORDER, TYPE_INT, ONIONSKIN_BELOW) \
|
X(onionskinDrawOrder, ONIONSKIN_DRAW_ORDER, TYPE_INT, ONIONSKIN_BELOW) \
|
||||||
X(onionskinBeforeCount, ONIONSKIN_BEFORE_COUNT, TYPE_INT, 1) \
|
X(onionskinBeforeCount, ONIONSKIN_BEFORE_COUNT, TYPE_INT, 1) \
|
||||||
@@ -262,72 +265,86 @@ Collapsed=0
|
|||||||
|
|
||||||
[Window][Tools]
|
[Window][Tools]
|
||||||
Pos=8,40
|
Pos=8,40
|
||||||
Size=37,460
|
Size=38,516
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x0000000B,0
|
DockId=0x0000000B,0
|
||||||
|
|
||||||
[Window][Animations]
|
[Window][Animations]
|
||||||
Pos=1288,284
|
Pos=1289,307
|
||||||
Size=304,216
|
Size=303,249
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x0000000A,0
|
DockId=0x0000000A,0
|
||||||
|
|
||||||
[Window][Events]
|
[Window][Events]
|
||||||
Pos=1007,332
|
Pos=957,264
|
||||||
Size=279,168
|
Size=330,292
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000008,0
|
DockId=0x00000008,2
|
||||||
|
|
||||||
[Window][Spritesheets]
|
[Window][Spritesheets]
|
||||||
Pos=1288,40
|
Pos=1289,40
|
||||||
Size=304,242
|
Size=303,265
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000009,0
|
DockId=0x00000009,0
|
||||||
|
|
||||||
[Window][Animation Preview]
|
[Window][Animation Preview]
|
||||||
Pos=47,40
|
Pos=48,40
|
||||||
Size=958,460
|
Size=907,516
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x0000000C,0
|
DockId=0x0000000C,0
|
||||||
|
|
||||||
[Window][Spritesheet Editor]
|
[Window][Spritesheet Editor]
|
||||||
Pos=47,40
|
Pos=48,40
|
||||||
Size=958,460
|
Size=907,516
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x0000000C,1
|
DockId=0x0000000C,1
|
||||||
|
|
||||||
[Window][Timeline]
|
[Window][Timeline]
|
||||||
Pos=8,502
|
Pos=8,558
|
||||||
Size=1584,390
|
Size=1584,334
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000004,0
|
DockId=0x00000004,0
|
||||||
|
|
||||||
[Window][Frame Properties]
|
[Window][Frame Properties]
|
||||||
Pos=1007,40
|
Pos=957,40
|
||||||
Size=279,290
|
Size=330,222
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000007,0
|
DockId=0x00000007,0
|
||||||
|
|
||||||
[Window][Onionskin]
|
[Window][Onionskin]
|
||||||
Pos=8,502
|
Pos=957,264
|
||||||
Size=1584,390
|
Size=330,292
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000004,1
|
DockId=0x00000008,3
|
||||||
|
|
||||||
|
[Window][Layers]
|
||||||
|
Pos=957,264
|
||||||
|
Size=330,292
|
||||||
|
Collapsed=0
|
||||||
|
DockId=0x00000008,0
|
||||||
|
|
||||||
|
[Window][Nulls]
|
||||||
|
Pos=957,264
|
||||||
|
Size=330,292
|
||||||
|
Collapsed=0
|
||||||
|
DockId=0x00000008,1
|
||||||
|
|
||||||
|
|
||||||
[Docking][Data]
|
[Docking][Data]
|
||||||
DockSpace ID=0xFC02A410 Window=0x0E46F4F7 Pos=8,40 Size=1584,852 Split=Y
|
DockSpace ID=0xFC02A410 Window=0x0E46F4F7 Pos=8,40 Size=1584,852 Split=Y
|
||||||
DockNode ID=0x00000003 Parent=0xFC02A410 SizeRef=1902,568 Split=X
|
DockNode ID=0x00000003 Parent=0xFC02A410 SizeRef=1902,680 Split=X
|
||||||
DockNode ID=0x00000001 Parent=0x00000003 SizeRef=1595,1016 Split=X Selected=0x024430EF
|
DockNode ID=0x00000001 Parent=0x00000003 SizeRef=1017,1016 Split=X Selected=0x024430EF
|
||||||
DockNode ID=0x00000005 Parent=0x00000001 SizeRef=997,654 Split=X Selected=0x024430EF
|
DockNode ID=0x00000005 Parent=0x00000001 SizeRef=1264,654 Split=X Selected=0x024430EF
|
||||||
DockNode ID=0x0000000B Parent=0x00000005 SizeRef=37,654 Selected=0x18A5FDB9
|
DockNode ID=0x0000000B Parent=0x00000005 SizeRef=38,654 Selected=0x18A5FDB9
|
||||||
DockNode ID=0x0000000C Parent=0x00000005 SizeRef=958,654 CentralNode=1 Selected=0x024430EF
|
DockNode ID=0x0000000C Parent=0x00000005 SizeRef=1224,654 CentralNode=1 Selected=0x024430EF
|
||||||
DockNode ID=0x00000006 Parent=0x00000001 SizeRef=279,654 Split=Y Selected=0x754E368F
|
DockNode ID=0x00000006 Parent=0x00000001 SizeRef=330,654 Split=Y Selected=0x754E368F
|
||||||
DockNode ID=0x00000007 Parent=0x00000006 SizeRef=631,359 Selected=0x754E368F
|
DockNode ID=0x00000007 Parent=0x00000006 SizeRef=631,293 Selected=0x754E368F
|
||||||
DockNode ID=0x00000008 Parent=0x00000006 SizeRef=631,207 Selected=0x8A65D963
|
DockNode ID=0x00000008 Parent=0x00000006 SizeRef=631,385 Selected=0xCD8384B1
|
||||||
DockNode ID=0x00000002 Parent=0x00000003 SizeRef=304,1016 Split=Y Selected=0x4EFD0020
|
DockNode ID=0x00000002 Parent=0x00000003 SizeRef=303,1016 Split=Y Selected=0x4EFD0020
|
||||||
DockNode ID=0x00000009 Parent=0x00000002 SizeRef=634,299 Selected=0x4EFD0020
|
DockNode ID=0x00000009 Parent=0x00000002 SizeRef=634,349 Selected=0x4EFD0020
|
||||||
DockNode ID=0x0000000A Parent=0x00000002 SizeRef=634,267 Selected=0xC1986EE2
|
DockNode ID=0x0000000A Parent=0x00000002 SizeRef=634,329 Selected=0xC1986EE2
|
||||||
DockNode ID=0x00000004 Parent=0xFC02A410 SizeRef=1902,390 Selected=0x4F89F0DC
|
DockNode ID=0x00000004 Parent=0xFC02A410 SizeRef=1902,334 Selected=0x4F89F0DC
|
||||||
|
|
||||||
)";
|
)";
|
||||||
|
|
||||||
void settings_save(Settings* self);
|
void settings_save(Settings* self);
|
||||||
|
@@ -26,13 +26,13 @@ static void _snapshot_set(Snapshots* self, Snapshot* snapshot)
|
|||||||
self->preview->time = snapshot->time;
|
self->preview->time = snapshot->time;
|
||||||
self->action = snapshot->action;
|
self->action = snapshot->action;
|
||||||
|
|
||||||
//anm2_spritesheet_texture_pixels_upload(self->anm2);
|
anm2_spritesheet_texture_pixels_upload(self->anm2);
|
||||||
}
|
}
|
||||||
|
|
||||||
Snapshot snapshot_get(Snapshots* self)
|
Snapshot snapshot_get(Snapshots* self)
|
||||||
{
|
{
|
||||||
Snapshot snapshot = {*self->anm2, *self->reference, self->preview->time, self->action};
|
Snapshot snapshot = {*self->anm2, *self->reference, self->preview->time, self->action};
|
||||||
//anm2_spritesheet_texture_pixels_download(&snapshot.anm2);
|
anm2_spritesheet_texture_pixels_download(&snapshot.anm2);
|
||||||
return snapshot;
|
return snapshot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -116,6 +116,8 @@ bool sdl_init(State* self, bool isTestMode = false)
|
|||||||
|
|
||||||
void init(State* self)
|
void init(State* self)
|
||||||
{
|
{
|
||||||
|
log_info(STATE_INIT_INFO);
|
||||||
|
|
||||||
settings_init(&self->settings);
|
settings_init(&self->settings);
|
||||||
|
|
||||||
if (!sdl_init(self)) return;
|
if (!sdl_init(self)) return;
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
|
||||||
#define STATE_INIT_INFO "Initializing..."
|
#define STATE_INIT_INFO "Initializing anm2ed (Version 1.1)"
|
||||||
#define STATE_SDL_INIT_ERROR "Failed to initialize SDL! {}"
|
#define STATE_SDL_INIT_ERROR "Failed to initialize SDL! {}"
|
||||||
#define STATE_SDL_INIT_INFO "Initialized SDL"
|
#define STATE_SDL_INIT_INFO "Initialized SDL"
|
||||||
#define STATE_MIX_INIT_WARNING "Unable to initialize SDL_mixer! {}"
|
#define STATE_MIX_INIT_WARNING "Unable to initialize SDL_mixer! {}"
|
||||||
|
@@ -17,8 +17,7 @@
|
|||||||
|
|
||||||
static void _texture_gl_set(Texture* self, const u8* data)
|
static void _texture_gl_set(Texture* self, const u8* data)
|
||||||
{
|
{
|
||||||
if (self->id == GL_ID_NONE)
|
if (self->id == GL_ID_NONE) glGenTextures(1, &self->id);
|
||||||
glGenTextures(1, &self->id);
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, self->id);
|
glBindTexture(GL_TEXTURE_2D, self->id);
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, self->size.x, self->size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, self->size.x, self->size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||||
@@ -43,7 +42,7 @@ std::vector<u8> texture_download(const Texture* self)
|
|||||||
|
|
||||||
bool texture_from_path_init(Texture* self, const std::string& path)
|
bool texture_from_path_init(Texture* self, const std::string& path)
|
||||||
{
|
{
|
||||||
u8* data = stbi_load(path.c_str(), &self->size.x, &self->size.y, &self->channels, TEXTURE_CHANNELS);
|
u8* data = stbi_load(path.c_str(), &self->size.x, &self->size.y, nullptr, TEXTURE_CHANNELS);
|
||||||
|
|
||||||
if (!data)
|
if (!data)
|
||||||
{
|
{
|
||||||
@@ -60,13 +59,12 @@ bool texture_from_path_init(Texture* self, const std::string& path)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool texture_from_encoded_data_init(Texture* self, ivec2 size, s32 channels, const u8* data, u32 length)
|
bool texture_from_encoded_data_init(Texture* self, ivec2 size, const u8* data, u32 length)
|
||||||
{
|
{
|
||||||
*self = Texture{};
|
*self = Texture{};
|
||||||
self->size = size;
|
self->size = size;
|
||||||
self->channels = channels;
|
|
||||||
|
|
||||||
u8* textureData = stbi_load_from_memory(data, length, &self->size.x, &self->size.y, &self->channels, TEXTURE_CHANNELS);
|
u8* textureData = stbi_load_from_memory(data, length, &self->size.x, &self->size.y, nullptr, TEXTURE_CHANNELS);
|
||||||
|
|
||||||
if (!textureData)
|
if (!textureData)
|
||||||
{
|
{
|
||||||
@@ -79,11 +77,11 @@ bool texture_from_encoded_data_init(Texture* self, ivec2 size, s32 channels, con
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool texture_from_rgba_init(Texture* self, ivec2 size, s32 channels, const u8* data)
|
bool texture_from_rgba_init(Texture* self, ivec2 size, const u8* data)
|
||||||
{
|
{
|
||||||
*self = Texture{};
|
*self = Texture{};
|
||||||
self->size = size;
|
self->size = size;
|
||||||
self->channels = channels;
|
self->isInvalid = false;
|
||||||
|
|
||||||
_texture_gl_set(self, data);
|
_texture_gl_set(self, data);
|
||||||
|
|
||||||
|
@@ -12,14 +12,13 @@ struct Texture
|
|||||||
{
|
{
|
||||||
GLuint id = GL_ID_NONE;
|
GLuint id = GL_ID_NONE;
|
||||||
ivec2 size{};
|
ivec2 size{};
|
||||||
s32 channels = TEXTURE_CHANNELS;
|
|
||||||
bool isInvalid = true;
|
bool isInvalid = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool texture_from_encoded_data_init(Texture* self, ivec2 size, s32 channels, const u8* data, u32 length);
|
bool texture_from_encoded_data_init(Texture* self, ivec2 size, const u8* data, u32 length);
|
||||||
bool texture_from_gl_write(Texture* self, const std::string& path);
|
bool texture_from_gl_write(Texture* self, const std::string& path);
|
||||||
bool texture_from_path_init(Texture* self, const std::string& path);
|
bool texture_from_path_init(Texture* self, const std::string& path);
|
||||||
bool texture_from_rgba_init(Texture* self, ivec2 size, s32 channels, const u8* data);
|
bool texture_from_rgba_init(Texture* self, ivec2 size, const u8* data);
|
||||||
bool texture_from_rgba_write(const std::string& path, const u8* data, ivec2 size);
|
bool texture_from_rgba_write(const std::string& path, const u8* data, ivec2 size);
|
||||||
bool texture_pixel_set(Texture* self, ivec2 position, vec4 color);
|
bool texture_pixel_set(Texture* self, ivec2 position, vec4 color);
|
||||||
void texture_free(Texture* self);
|
void texture_free(Texture* self);
|
||||||
|
Reference in New Issue
Block a user