fuck git and fuck vs code
This commit is contained in:
@@ -134,6 +134,8 @@ namespace anm2ed::anm2
|
||||
return length;
|
||||
}
|
||||
|
||||
void Animation::fit_length() { frameNum = length(); }
|
||||
|
||||
vec4 Animation::rect(bool isRootTransform)
|
||||
{
|
||||
constexpr ivec2 CORNERS[4] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
namespace anm2ed::anm2
|
||||
{
|
||||
constexpr auto FRAME_NUM_MIN = 1;
|
||||
constexpr auto FRAME_NUM_MAX = FRAME_DELAY_MAX;
|
||||
constexpr auto FRAME_NUM_MAX = FRAME_DURATION_MAX;
|
||||
|
||||
class Animation
|
||||
{
|
||||
@@ -30,6 +30,7 @@ namespace anm2ed::anm2
|
||||
void serialize(tinyxml2::XMLDocument&, tinyxml2::XMLElement*);
|
||||
std::string to_string();
|
||||
int length();
|
||||
void fit_length();
|
||||
glm::vec4 rect(bool);
|
||||
};
|
||||
|
||||
|
||||
@@ -12,10 +12,7 @@ using namespace glm;
|
||||
|
||||
namespace anm2ed::anm2
|
||||
{
|
||||
Anm2::Anm2()
|
||||
{
|
||||
info.createdOn = time::get("%d-%B-%Y %I:%M:%S");
|
||||
}
|
||||
Anm2::Anm2() { info.createdOn = time::get("%d-%B-%Y %I:%M:%S"); }
|
||||
|
||||
Anm2::Anm2(const std::string& path, std::string* errorString)
|
||||
{
|
||||
@@ -37,25 +34,6 @@ namespace anm2ed::anm2
|
||||
animations = Animations((XMLElement*)animationsElement);
|
||||
}
|
||||
|
||||
bool Anm2::serialize(const std::string& path, std::string* errorString)
|
||||
{
|
||||
XMLDocument document;
|
||||
|
||||
auto* element = document.NewElement("AnimatedActor");
|
||||
document.InsertFirstChild(element);
|
||||
|
||||
info.serialize(document, element);
|
||||
content.serialize(document, element);
|
||||
animations.serialize(document, element);
|
||||
|
||||
if (document.SaveFile(path.c_str()) != XML_SUCCESS)
|
||||
{
|
||||
if (errorString) *errorString = document.ErrorStr();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
XMLElement* Anm2::to_element(XMLDocument& document)
|
||||
{
|
||||
auto element = document.NewElement("AnimatedActor");
|
||||
@@ -68,6 +46,19 @@ namespace anm2ed::anm2
|
||||
return element;
|
||||
}
|
||||
|
||||
bool Anm2::serialize(const std::string& path, std::string* errorString)
|
||||
{
|
||||
XMLDocument document;
|
||||
document.InsertFirstChild(to_element(document));
|
||||
|
||||
if (document.SaveFile(path.c_str()) != XML_SUCCESS)
|
||||
{
|
||||
if (errorString) *errorString = document.ErrorStr();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string Anm2::to_string()
|
||||
{
|
||||
XMLDocument document{};
|
||||
@@ -75,15 +66,12 @@ namespace anm2ed::anm2
|
||||
return xml::document_to_string(document);
|
||||
}
|
||||
|
||||
uint64_t Anm2::hash()
|
||||
{
|
||||
return std::hash<std::string>{}(to_string());
|
||||
}
|
||||
uint64_t Anm2::hash() { return std::hash<std::string>{}(to_string()); }
|
||||
|
||||
Frame* Anm2::frame_get(Reference reference)
|
||||
Frame* Anm2::frame_get(int animationIndex, Type itemType, int frameIndex, int itemID)
|
||||
{
|
||||
if (auto item = item_get(reference); item)
|
||||
if (vector::in_bounds(item->frames, reference.frameIndex)) return &item->frames[reference.frameIndex];
|
||||
if (auto item = item_get(animationIndex, itemType, itemID); item)
|
||||
if (vector::in_bounds(item->frames, frameIndex)) return &item->frames[frameIndex];
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,6 @@ namespace anm2ed::anm2
|
||||
Type itemType{NONE};
|
||||
int itemID{-1};
|
||||
int frameIndex{-1};
|
||||
int frameTime{-1};
|
||||
|
||||
auto operator<=>(const Reference&) const = default;
|
||||
};
|
||||
@@ -40,22 +39,23 @@ namespace anm2ed::anm2
|
||||
|
||||
Spritesheet* spritesheet_get(int);
|
||||
bool spritesheet_add(const std::string&, const std::string&, int&);
|
||||
void spritesheet_remove(int);
|
||||
std::vector<std::string> spritesheet_labels_get();
|
||||
std::set<int> spritesheets_unused();
|
||||
bool spritesheets_deserialize(const std::string&, const std::string&, types::merge::Type type, std::string*);
|
||||
|
||||
void layer_add(int&);
|
||||
std::set<int> layers_unused(Reference = {});
|
||||
std::set<int> layers_unused();
|
||||
std::set<int> layers_unused(Animation&);
|
||||
bool layers_deserialize(const std::string&, types::merge::Type, std::string*);
|
||||
|
||||
void null_add(int&);
|
||||
std::set<int> nulls_unused(Reference = {});
|
||||
std::set<int> nulls_unused();
|
||||
std::set<int> nulls_unused(Animation&);
|
||||
bool nulls_deserialize(const std::string&, types::merge::Type, std::string*);
|
||||
|
||||
void event_add(int&);
|
||||
std::vector<std::string> event_labels_get();
|
||||
std::set<int> events_unused(Reference = {});
|
||||
std::set<int> events_unused();
|
||||
bool events_deserialize(const std::string&, types::merge::Type, std::string*);
|
||||
|
||||
bool sound_add(const std::string& directory, const std::string& path, int& id);
|
||||
@@ -63,16 +63,16 @@ namespace anm2ed::anm2
|
||||
std::set<int> sounds_unused();
|
||||
bool sounds_deserialize(const std::string&, const std::string&, types::merge::Type, std::string*);
|
||||
|
||||
Animation* animation_get(Reference);
|
||||
Animation* animation_get(int);
|
||||
std::vector<std::string> animation_labels_get();
|
||||
int animations_merge(int, std::set<int>&, types::merge::Type = types::merge::APPEND, bool = true);
|
||||
bool animations_deserialize(const std::string&, int, std::set<int>&, std::string* = nullptr);
|
||||
|
||||
Item* item_get(Reference);
|
||||
Item* item_get(int, Type, int = -1);
|
||||
Reference layer_animation_add(Reference = {}, std::string = {}, int = 0,
|
||||
types::locale::Type = types::locale::GLOBAL);
|
||||
Reference null_animation_add(Reference = {}, std::string = {}, types::locale::Type = types::locale::GLOBAL);
|
||||
|
||||
Frame* frame_get(Reference);
|
||||
Frame* frame_get(int, Type, int, int = -1);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,10 +8,7 @@ using namespace tinyxml2;
|
||||
|
||||
namespace anm2ed::anm2
|
||||
{
|
||||
Animation* Anm2::animation_get(Reference reference)
|
||||
{
|
||||
return vector::find(animations.items, reference.animationIndex);
|
||||
}
|
||||
Animation* Anm2::animation_get(int animationIndex) { return vector::find(animations.items, animationIndex); }
|
||||
|
||||
std::vector<std::string> Anm2::animation_labels_get()
|
||||
{
|
||||
|
||||
@@ -25,17 +25,13 @@ namespace anm2ed::anm2
|
||||
return labels;
|
||||
}
|
||||
|
||||
std::set<int> Anm2::events_unused(Reference reference)
|
||||
std::set<int> Anm2::events_unused()
|
||||
{
|
||||
std::set<int> used{};
|
||||
|
||||
if (auto animation = animation_get(reference); animation)
|
||||
for (auto& frame : animation->triggers.frames)
|
||||
for (auto& animation : animations.items)
|
||||
for (auto& frame : animation.triggers.frames)
|
||||
used.insert(frame.eventID);
|
||||
else
|
||||
for (auto& animation : animations.items)
|
||||
for (auto& frame : animation.triggers.frames)
|
||||
used.insert(frame.eventID);
|
||||
|
||||
std::set<int> unused{};
|
||||
for (auto& id : content.events | std::views::keys)
|
||||
|
||||
@@ -9,18 +9,18 @@ using namespace anm2ed::util;
|
||||
|
||||
namespace anm2ed::anm2
|
||||
{
|
||||
Item* Anm2::item_get(Reference reference)
|
||||
Item* Anm2::item_get(int animationIndex, Type type, int id)
|
||||
{
|
||||
if (Animation* animation = animation_get(reference))
|
||||
if (Animation* animation = animation_get(animationIndex))
|
||||
{
|
||||
switch (reference.itemType)
|
||||
switch (type)
|
||||
{
|
||||
case ROOT:
|
||||
return &animation->rootAnimation;
|
||||
case LAYER:
|
||||
return unordered_map::find(animation->layerAnimations, reference.itemID);
|
||||
return unordered_map::find(animation->layerAnimations, id);
|
||||
case NULL_:
|
||||
return map::find(animation->nullAnimations, reference.itemID);
|
||||
return map::find(animation->nullAnimations, id);
|
||||
case TRIGGER:
|
||||
return &animation->triggers;
|
||||
default:
|
||||
@@ -51,7 +51,7 @@ namespace anm2ed::anm2
|
||||
}
|
||||
else if (locale == locale::LOCAL)
|
||||
{
|
||||
if (auto animation = animation_get(reference))
|
||||
if (auto animation = animation_get(reference.animationIndex))
|
||||
if (!animation->layerAnimations.contains(id)) add(animation, id);
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace anm2ed::anm2
|
||||
}
|
||||
else if (locale == locale::LOCAL)
|
||||
{
|
||||
if (auto animation = animation_get(reference))
|
||||
if (auto animation = animation_get(reference.animationIndex))
|
||||
if (!animation->nullAnimations.contains(id)) add(animation, id);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,18 +16,14 @@ namespace anm2ed::anm2
|
||||
content.layers[id] = Layer();
|
||||
}
|
||||
|
||||
std::set<int> Anm2::layers_unused(Reference reference)
|
||||
std::set<int> Anm2::layers_unused()
|
||||
{
|
||||
std::set<int> used{};
|
||||
std::set<int> unused{};
|
||||
|
||||
if (auto animation = animation_get(reference); animation)
|
||||
for (auto& id : animation->layerAnimations | std::views::keys)
|
||||
for (auto& animation : animations.items)
|
||||
for (auto& id : animation.layerAnimations | std::views::keys)
|
||||
used.insert(id);
|
||||
else
|
||||
for (auto& animation : animations.items)
|
||||
for (auto& id : animation.layerAnimations | std::views::keys)
|
||||
used.insert(id);
|
||||
|
||||
for (auto& id : content.layers | std::views::keys)
|
||||
if (!used.contains(id)) unused.insert(id);
|
||||
@@ -35,6 +31,16 @@ namespace anm2ed::anm2
|
||||
return unused;
|
||||
}
|
||||
|
||||
std::set<int> Anm2::layers_unused(Animation& animation)
|
||||
{
|
||||
std::set<int> unused{};
|
||||
|
||||
for (auto& id : content.layers | std::views::keys)
|
||||
if (!animation.layerAnimations.contains(id)) unused.insert(id);
|
||||
|
||||
return unused;
|
||||
}
|
||||
|
||||
bool Anm2::layers_deserialize(const std::string& string, merge::Type type, std::string* errorString)
|
||||
{
|
||||
XMLDocument document{};
|
||||
|
||||
@@ -16,18 +16,14 @@ namespace anm2ed::anm2
|
||||
content.nulls[id] = Null();
|
||||
}
|
||||
|
||||
std::set<int> Anm2::nulls_unused(Reference reference)
|
||||
std::set<int> Anm2::nulls_unused()
|
||||
{
|
||||
std::set<int> used{};
|
||||
std::set<int> unused{};
|
||||
|
||||
if (auto animation = animation_get(reference); animation)
|
||||
for (auto& id : animation->nullAnimations | std::views::keys)
|
||||
for (auto& animation : animations.items)
|
||||
for (auto& id : animation.nullAnimations | std::views::keys)
|
||||
used.insert(id);
|
||||
else
|
||||
for (auto& animation : animations.items)
|
||||
for (auto& id : animation.nullAnimations | std::views::keys)
|
||||
used.insert(id);
|
||||
|
||||
for (auto& id : content.nulls | std::views::keys)
|
||||
if (!used.contains(id)) unused.insert(id);
|
||||
@@ -35,6 +31,16 @@ namespace anm2ed::anm2
|
||||
return unused;
|
||||
}
|
||||
|
||||
std::set<int> Anm2::nulls_unused(Animation& animation)
|
||||
{
|
||||
std::set<int> unused{};
|
||||
|
||||
for (auto& id : content.nulls | std::views::keys)
|
||||
if (!animation.nullAnimations.contains(id)) unused.insert(id);
|
||||
|
||||
return unused;
|
||||
}
|
||||
|
||||
bool Anm2::nulls_deserialize(const std::string& string, merge::Type type, std::string* errorString)
|
||||
{
|
||||
XMLDocument document{};
|
||||
|
||||
@@ -16,11 +16,6 @@ namespace anm2ed::anm2
|
||||
return map::find(content.spritesheets, id);
|
||||
}
|
||||
|
||||
void Anm2::spritesheet_remove(int id)
|
||||
{
|
||||
content.spritesheets.erase(id);
|
||||
}
|
||||
|
||||
bool Anm2::spritesheet_add(const std::string& directory, const std::string& path, int& id)
|
||||
{
|
||||
Spritesheet spritesheet(directory, path);
|
||||
|
||||
@@ -24,6 +24,10 @@ namespace anm2ed::anm2
|
||||
if (auto eventsElement = element->FirstChildElement("Events"))
|
||||
for (auto child = eventsElement->FirstChildElement("Event"); child; child = child->NextSiblingElement("Event"))
|
||||
events[id] = Event(child, id);
|
||||
|
||||
if (auto eventsElement = element->FirstChildElement("Sounds"))
|
||||
for (auto child = eventsElement->FirstChildElement("Sound"); child; child = child->NextSiblingElement("Sound"))
|
||||
sounds[id] = Sound(child, id);
|
||||
}
|
||||
|
||||
void Content::serialize(XMLDocument& document, XMLElement* parent)
|
||||
@@ -50,6 +54,11 @@ namespace anm2ed::anm2
|
||||
event.serialize(document, eventsElement, id);
|
||||
element->InsertEndChild(eventsElement);
|
||||
|
||||
auto soundsElement = document.NewElement("Sounds");
|
||||
for (auto& [id, sound] : sounds)
|
||||
sound.serialize(document, soundsElement, id);
|
||||
element->InsertEndChild(soundsElement);
|
||||
|
||||
parent->InsertEndChild(element);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "anm2_type.h"
|
||||
#include "event.h"
|
||||
#include "layer.h"
|
||||
#include "null.h"
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace anm2ed::anm2
|
||||
}
|
||||
element->QueryFloatAttribute("XScale", &scale.x);
|
||||
element->QueryFloatAttribute("YScale", &scale.y);
|
||||
element->QueryIntAttribute("Delay", &delay);
|
||||
element->QueryIntAttribute("Delay", &duration);
|
||||
element->QueryBoolAttribute("Visible", &isVisible);
|
||||
xml::query_color_attribute(element, "RedTint", tint.r);
|
||||
xml::query_color_attribute(element, "GreenTint", tint.g);
|
||||
@@ -40,6 +40,7 @@ namespace anm2ed::anm2
|
||||
else
|
||||
{
|
||||
element->QueryIntAttribute("EventId", &eventID);
|
||||
element->QueryIntAttribute("SoundId", &soundID);
|
||||
element->QueryIntAttribute("AtFrame", &atFrame);
|
||||
}
|
||||
}
|
||||
@@ -54,7 +55,7 @@ namespace anm2ed::anm2
|
||||
case NULL_:
|
||||
element->SetAttribute("XPosition", position.x);
|
||||
element->SetAttribute("YPosition", position.y);
|
||||
element->SetAttribute("Delay", delay);
|
||||
element->SetAttribute("Delay", duration);
|
||||
element->SetAttribute("Visible", isVisible);
|
||||
element->SetAttribute("XScale", scale.x);
|
||||
element->SetAttribute("YScale", scale.y);
|
||||
@@ -79,7 +80,7 @@ namespace anm2ed::anm2
|
||||
element->SetAttribute("Height", size.y);
|
||||
element->SetAttribute("XScale", scale.x);
|
||||
element->SetAttribute("YScale", scale.y);
|
||||
element->SetAttribute("Delay", delay);
|
||||
element->SetAttribute("Delay", duration);
|
||||
element->SetAttribute("Visible", isVisible);
|
||||
element->SetAttribute("RedTint", math::float_to_uint8(tint.r));
|
||||
element->SetAttribute("GreenTint", math::float_to_uint8(tint.g));
|
||||
@@ -93,6 +94,7 @@ namespace anm2ed::anm2
|
||||
break;
|
||||
case TRIGGER:
|
||||
element->SetAttribute("EventId", eventID);
|
||||
element->SetAttribute("SoundId", soundID);
|
||||
element->SetAttribute("AtFrame", atFrame);
|
||||
break;
|
||||
default:
|
||||
@@ -114,9 +116,9 @@ namespace anm2ed::anm2
|
||||
return xml::document_to_string(document);
|
||||
}
|
||||
|
||||
void Frame::shorten() { delay = glm::clamp(--delay, FRAME_DELAY_MIN, FRAME_DELAY_MAX); }
|
||||
void Frame::shorten() { duration = glm::clamp(--duration, FRAME_DURATION_MIN, FRAME_DURATION_MAX); }
|
||||
|
||||
void Frame::extend() { delay = glm::clamp(++delay, FRAME_DELAY_MIN, FRAME_DELAY_MAX); }
|
||||
void Frame::extend() { duration = glm::clamp(++duration, FRAME_DURATION_MIN, FRAME_DURATION_MAX); }
|
||||
|
||||
bool Frame::is_visible(Type type)
|
||||
{
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
|
||||
namespace anm2ed::anm2
|
||||
{
|
||||
constexpr auto FRAME_DELAY_MIN = 1;
|
||||
constexpr auto FRAME_DELAY_MAX = 100000;
|
||||
constexpr auto FRAME_DURATION_MIN = 1;
|
||||
constexpr auto FRAME_DURATION_MAX = 100000;
|
||||
|
||||
#define MEMBERS \
|
||||
X(isVisible, bool, true) \
|
||||
X(isInterpolated, bool, false) \
|
||||
X(rotation, float, 0.0f) \
|
||||
X(delay, int, FRAME_DELAY_MIN) \
|
||||
X(duration, int, FRAME_DURATION_MIN) \
|
||||
X(atFrame, int, -1) \
|
||||
X(eventID, int, -1) \
|
||||
X(soundID, int, -1) \
|
||||
@@ -53,5 +53,4 @@ namespace anm2ed::anm2
|
||||
};
|
||||
|
||||
#undef MEMBERS
|
||||
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "item.h"
|
||||
#include <algorithm>
|
||||
#include <ranges>
|
||||
|
||||
#include "vector_.h"
|
||||
@@ -30,6 +31,8 @@ namespace anm2ed::anm2
|
||||
if (type == NULL_) element->SetAttribute("NullId", id);
|
||||
if (type == LAYER || type == NULL_) element->SetAttribute("Visible", isVisible);
|
||||
|
||||
if (type == TRIGGER) frames_sort_by_at_frame();
|
||||
|
||||
for (auto& frame : frames)
|
||||
frame.serialize(document, element, type);
|
||||
|
||||
@@ -57,11 +60,16 @@ namespace anm2ed::anm2
|
||||
length = frame.atFrame > length ? frame.atFrame : length;
|
||||
else
|
||||
for (auto& frame : frames)
|
||||
length += frame.delay;
|
||||
length += frame.duration;
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
void Item::frames_sort_by_at_frame()
|
||||
{
|
||||
std::sort(frames.begin(), frames.end(), [](const Frame& a, const Frame& b) { return a.atFrame < b.atFrame; });
|
||||
}
|
||||
|
||||
Frame Item::frame_generate(float time, Type type)
|
||||
{
|
||||
Frame frame{};
|
||||
@@ -70,8 +78,8 @@ namespace anm2ed::anm2
|
||||
if (frames.empty()) return frame;
|
||||
|
||||
Frame* frameNext = nullptr;
|
||||
int delayCurrent = 0;
|
||||
int delayNext = 0;
|
||||
int durationCurrent = 0;
|
||||
int durationNext = 0;
|
||||
|
||||
for (auto [i, iFrame] : std::views::enumerate(frames))
|
||||
{
|
||||
@@ -87,9 +95,9 @@ namespace anm2ed::anm2
|
||||
{
|
||||
frame = iFrame;
|
||||
|
||||
delayNext += frame.delay;
|
||||
durationNext += frame.duration;
|
||||
|
||||
if (time >= delayCurrent && time < delayNext)
|
||||
if (time >= durationCurrent && time < durationNext)
|
||||
{
|
||||
if (i + 1 < (int)frames.size())
|
||||
frameNext = &frames[i + 1];
|
||||
@@ -98,13 +106,13 @@ namespace anm2ed::anm2
|
||||
break;
|
||||
}
|
||||
|
||||
delayCurrent += frame.delay;
|
||||
durationCurrent += frame.duration;
|
||||
}
|
||||
}
|
||||
|
||||
if (type != TRIGGER && frame.isInterpolated && frameNext && frame.delay > 1)
|
||||
if (type != TRIGGER && frame.isInterpolated && frameNext && frame.duration > 1)
|
||||
{
|
||||
auto interpolation = (time - delayCurrent) / (delayNext - delayCurrent);
|
||||
auto interpolation = (time - durationCurrent) / (durationNext - durationCurrent);
|
||||
|
||||
frame.rotation = glm::mix(frame.rotation, frameNext->rotation, interpolation);
|
||||
frame.position = glm::mix(frame.position, frameNext->position, interpolation);
|
||||
@@ -133,7 +141,7 @@ namespace anm2ed::anm2
|
||||
{
|
||||
case ADJUST:
|
||||
if (change.rotation) frame.rotation = *change.rotation;
|
||||
if (change.delay) frame.delay = std::max(FRAME_DELAY_MIN, *change.delay);
|
||||
if (change.duration) frame.duration = std::max(FRAME_DURATION_MIN, *change.duration);
|
||||
if (change.crop) frame.crop = *change.crop;
|
||||
if (change.pivot) frame.pivot = *change.pivot;
|
||||
if (change.position) frame.position = *change.position;
|
||||
@@ -145,7 +153,7 @@ namespace anm2ed::anm2
|
||||
|
||||
case ADD:
|
||||
if (change.rotation) frame.rotation += *change.rotation;
|
||||
if (change.delay) frame.delay = std::max(FRAME_DELAY_MIN, frame.delay + *change.delay);
|
||||
if (change.duration) frame.duration = std::max(FRAME_DURATION_MIN, frame.duration + *change.duration);
|
||||
if (change.crop) frame.crop += *change.crop;
|
||||
if (change.pivot) frame.pivot += *change.pivot;
|
||||
if (change.position) frame.position += *change.position;
|
||||
@@ -157,7 +165,7 @@ namespace anm2ed::anm2
|
||||
|
||||
case SUBTRACT:
|
||||
if (change.rotation) frame.rotation -= *change.rotation;
|
||||
if (change.delay) frame.delay = std::max(FRAME_DELAY_MIN, frame.delay - *change.delay);
|
||||
if (change.duration) frame.duration = std::max(FRAME_DURATION_MIN, frame.duration - *change.duration);
|
||||
if (change.crop) frame.crop -= *change.crop;
|
||||
if (change.pivot) frame.pivot -= *change.pivot;
|
||||
if (change.position) frame.position -= *change.position;
|
||||
@@ -177,22 +185,50 @@ namespace anm2ed::anm2
|
||||
|
||||
if (document.Parse(string.c_str()) == XML_SUCCESS)
|
||||
{
|
||||
if (!document.FirstChildElement("Frame"))
|
||||
int count{};
|
||||
if (document.FirstChildElement("Frame") && type != anm2::TRIGGER)
|
||||
{
|
||||
if (errorString) *errorString = "No valid frame(s).";
|
||||
start = std::clamp(start, 0, (int)frames.size());
|
||||
for (auto element = document.FirstChildElement("Frame"); element;
|
||||
element = element->NextSiblingElement("Frame"))
|
||||
{
|
||||
auto index = start + count;
|
||||
frames.insert(frames.begin() + start + count, Frame(element, type));
|
||||
indices.insert(index);
|
||||
count++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (document.FirstChildElement("Trigger") && type == anm2::TRIGGER)
|
||||
{
|
||||
auto has_conflict = [&](int value)
|
||||
{
|
||||
for (auto& trigger : frames)
|
||||
if (trigger.atFrame == value) return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
for (auto element = document.FirstChildElement("Trigger"); element;
|
||||
element = element->NextSiblingElement("Trigger"))
|
||||
{
|
||||
Frame trigger(element, type);
|
||||
trigger.atFrame = start + count;
|
||||
while (has_conflict(trigger.atFrame))
|
||||
trigger.atFrame++;
|
||||
frames.push_back(trigger);
|
||||
indices.insert(trigger.atFrame);
|
||||
count++;
|
||||
}
|
||||
|
||||
frames_sort_by_at_frame();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (errorString) *errorString = type == anm2::TRIGGER ? "No valid trigger(s)." : "No valid frame(s).";
|
||||
return false;
|
||||
}
|
||||
|
||||
int count{};
|
||||
for (auto element = document.FirstChildElement("Frame"); element; element = element->NextSiblingElement("Frame"))
|
||||
{
|
||||
auto index = start + count;
|
||||
frames.insert(frames.begin() + start + count, Frame(element, type));
|
||||
indices.insert(index);
|
||||
count++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (errorString)
|
||||
*errorString = document.ErrorStr();
|
||||
@@ -205,18 +241,18 @@ namespace anm2ed::anm2
|
||||
if (!vector::in_bounds(frames, index)) return;
|
||||
|
||||
Frame& frame = frames[index];
|
||||
if (frame.delay == FRAME_DELAY_MIN) return;
|
||||
if (frame.duration == FRAME_DURATION_MIN) return;
|
||||
|
||||
Frame frameNext = vector::in_bounds(frames, index + 1) ? frames[index + 1] : frame;
|
||||
|
||||
int delay{};
|
||||
int duration{};
|
||||
int i = index;
|
||||
|
||||
while (delay < frame.delay)
|
||||
while (duration < frame.duration)
|
||||
{
|
||||
Frame baked = frame;
|
||||
float interpolation = (float)delay / frame.delay;
|
||||
baked.delay = std::min(interval, frame.delay - delay);
|
||||
float interpolation = (float)duration / frame.duration;
|
||||
baked.duration = std::min(interval, frame.duration - duration);
|
||||
baked.isInterpolated = (i == index) ? frame.isInterpolated : false;
|
||||
baked.rotation = glm::mix(frame.rotation, frameNext.rotation, interpolation);
|
||||
baked.position = glm::mix(frame.position, frameNext.position, interpolation);
|
||||
@@ -232,16 +268,17 @@ namespace anm2ed::anm2
|
||||
frames.insert(frames.begin() + i, baked);
|
||||
i++;
|
||||
|
||||
delay += baked.delay;
|
||||
duration += baked.duration;
|
||||
}
|
||||
}
|
||||
|
||||
void Item::frames_generate_from_grid(ivec2 startPosition, ivec2 size, ivec2 pivot, int columns, int count, int delay)
|
||||
void Item::frames_generate_from_grid(ivec2 startPosition, ivec2 size, ivec2 pivot, int columns, int count,
|
||||
int duration)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Frame frame{};
|
||||
frame.delay = delay;
|
||||
frame.duration = duration;
|
||||
frame.pivot = pivot;
|
||||
frame.size = size;
|
||||
frame.crop = startPosition + ivec2(size.x * (i % columns), size.y * (i / columns));
|
||||
@@ -249,4 +286,11 @@ namespace anm2ed::anm2
|
||||
frames.emplace_back(frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Item::frame_index_from_at_frame_get(int atFrame)
|
||||
{
|
||||
for (auto [i, frame] : std::views::enumerate(frames))
|
||||
if (frame.atFrame == atFrame) return i;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,5 +24,7 @@ namespace anm2ed::anm2
|
||||
bool frames_deserialize(const std::string&, Type, int, std::set<int>&, std::string*);
|
||||
void frames_bake(int, int, bool, bool);
|
||||
void frames_generate_from_grid(glm::ivec2, glm::ivec2, glm::ivec2, int, int, int);
|
||||
void frames_sort_by_at_frame();
|
||||
int frame_index_from_at_frame_get(int);
|
||||
};
|
||||
}
|
||||
@@ -9,10 +9,7 @@ using namespace tinyxml2;
|
||||
|
||||
namespace anm2ed::anm2
|
||||
{
|
||||
Sound::Sound(const Sound& other) : path(other.path)
|
||||
{
|
||||
audio = path.empty() ? Audio() : Audio(path.c_str());
|
||||
}
|
||||
Sound::Sound(const Sound& other) : path(other.path) { audio = path.empty() ? Audio() : Audio(path.c_str()); }
|
||||
|
||||
Sound& Sound::operator=(const Sound& other)
|
||||
{
|
||||
@@ -49,6 +46,11 @@ namespace anm2ed::anm2
|
||||
return element;
|
||||
}
|
||||
|
||||
void Sound::serialize(XMLDocument& document, XMLElement* parent, int id)
|
||||
{
|
||||
parent->InsertEndChild(to_element(document, id));
|
||||
}
|
||||
|
||||
std::string Sound::to_string(int id)
|
||||
{
|
||||
XMLDocument document{};
|
||||
@@ -56,18 +58,9 @@ namespace anm2ed::anm2
|
||||
return xml::document_to_string(document);
|
||||
}
|
||||
|
||||
void Sound::reload(const std::string& directory)
|
||||
{
|
||||
*this = Sound(directory, this->path);
|
||||
}
|
||||
void Sound::reload(const std::string& directory) { *this = Sound(directory, this->path); }
|
||||
|
||||
bool Sound::is_valid()
|
||||
{
|
||||
return audio.is_valid();
|
||||
}
|
||||
bool Sound::is_valid() { return audio.is_valid(); }
|
||||
|
||||
void Sound::play()
|
||||
{
|
||||
audio.play();
|
||||
}
|
||||
void Sound::play() { audio.play(); }
|
||||
}
|
||||
@@ -25,6 +25,7 @@ namespace anm2ed::anm2
|
||||
Sound(const std::string&, const std::string&);
|
||||
tinyxml2::XMLElement* to_element(tinyxml2::XMLDocument&, int);
|
||||
std::string to_string(int);
|
||||
void serialize(tinyxml2::XMLDocument&, tinyxml2::XMLElement*, int);
|
||||
void reload(const std::string&);
|
||||
bool is_valid();
|
||||
void play();
|
||||
|
||||
@@ -56,14 +56,8 @@ namespace anm2ed::anm2
|
||||
return texture.write_png(this->path);
|
||||
}
|
||||
|
||||
void Spritesheet::reload(const std::string& directory)
|
||||
{
|
||||
*this = Spritesheet(directory, this->path);
|
||||
}
|
||||
void Spritesheet::reload(const std::string& directory) { *this = Spritesheet(directory, this->path); }
|
||||
|
||||
bool Spritesheet::is_valid()
|
||||
{
|
||||
return texture.is_valid();
|
||||
}
|
||||
bool Spritesheet::is_valid() { return texture.is_valid(); }
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user