Update about music: "Digital Antidepressant" by Soundbin on Newgrounds
This commit is contained in:
@@ -1 +1 @@
|
|||||||
/home/anon/sda/Personal/Repos/anm2ed/build/compile_commands.json
|
/home/anon/sda/Personal/Repos/anm2ed/out/build/linux-debug/compile_commands.json
|
||||||
@@ -1,474 +0,0 @@
|
|||||||
#include "anm2.hpp"
|
|
||||||
|
|
||||||
#include <tinyxml2/tinyxml2.h>
|
|
||||||
|
|
||||||
#include "file_.hpp"
|
|
||||||
#include "path_.hpp"
|
|
||||||
#include "xml_.hpp"
|
|
||||||
|
|
||||||
namespace anm2ed::anm2_new
|
|
||||||
{
|
|
||||||
using namespace tinyxml2;
|
|
||||||
|
|
||||||
template <typename Enum, std::size_t N>
|
|
||||||
constexpr std::string_view enum_string_get(const std::array<std::pair<Enum, std::string_view>, N>& mappings,
|
|
||||||
Enum value)
|
|
||||||
{
|
|
||||||
for (const auto& [mappedValue, mappedString] : mappings)
|
|
||||||
if (mappedValue == value) return mappedString;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Enum, std::size_t N>
|
|
||||||
constexpr Enum string_enum_get(const std::array<std::pair<Enum, std::string_view>, N>& mappings,
|
|
||||||
std::string_view value, Enum fallback)
|
|
||||||
{
|
|
||||||
for (const auto& [mappedValue, mappedString] : mappings)
|
|
||||||
if (mappedString == value) return mappedValue;
|
|
||||||
return fallback;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool is_flag_set(Anm2::Flags flags, Anm2::Flag flag) { return (flags & flag) != 0; }
|
|
||||||
|
|
||||||
std::filesystem::path asset_path_resolve(const std::filesystem::path& directory,
|
|
||||||
const std::filesystem::path& assetPath)
|
|
||||||
{
|
|
||||||
if (assetPath.empty()) return {};
|
|
||||||
|
|
||||||
auto resolved = assetPath.is_absolute() ? assetPath : directory / assetPath;
|
|
||||||
resolved = util::path::lower_case_backslash_handle(resolved);
|
|
||||||
if (util::path::is_exist(resolved)) return resolved;
|
|
||||||
return util::path::lower_case_backslash_handle(assetPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string_view Anm2::Element::tag_get(Type type) { return enum_string_get(TYPE_TAGS, type); }
|
|
||||||
|
|
||||||
Anm2::Element::Type Anm2::Element::type_get(std::string_view tag, Type parentType)
|
|
||||||
{
|
|
||||||
(void)parentType;
|
|
||||||
return string_enum_get(TYPE_TAGS, tag, UNKNOWN);
|
|
||||||
}
|
|
||||||
|
|
||||||
Anm2::Element::Element(const std::filesystem::path& path, std::string* errorString)
|
|
||||||
{
|
|
||||||
XMLDocument document{};
|
|
||||||
if (!document_load(document, path, errorString)) return;
|
|
||||||
if (auto* root = document.RootElement()) *this = from_xml(root);
|
|
||||||
}
|
|
||||||
|
|
||||||
Anm2::Element::Element(std::string_view xml, Source, std::string* errorString)
|
|
||||||
{
|
|
||||||
XMLDocument document{};
|
|
||||||
if (!document_parse(document, xml, errorString)) return;
|
|
||||||
if (auto* root = document.RootElement()) *this = from_xml(root);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Anm2::Element::document_load(XMLDocument& document, const std::filesystem::path& path, std::string* errorString)
|
|
||||||
{
|
|
||||||
util::File file(path, "rb");
|
|
||||||
if (!file)
|
|
||||||
{
|
|
||||||
if (errorString) *errorString = "Could not open file.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (document.LoadFile(file.get()) != XML_SUCCESS)
|
|
||||||
{
|
|
||||||
if (errorString) *errorString = document.ErrorStr();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Anm2::Element::document_parse(XMLDocument& document, std::string_view xml, std::string* errorString)
|
|
||||||
{
|
|
||||||
if (document.Parse(xml.data(), xml.size()) != XML_SUCCESS)
|
|
||||||
{
|
|
||||||
if (errorString) *errorString = document.ErrorStr();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Anm2::Element::attributes_read(const XMLElement* element, Type parentType)
|
|
||||||
{
|
|
||||||
if (!element) return;
|
|
||||||
|
|
||||||
util::xml::query_string_attribute(element, "CreatedBy", createdBy);
|
|
||||||
util::xml::query_string_attribute(element, "CreatedOn", createdOn);
|
|
||||||
util::xml::query_string_attribute(element, "DefaultAnimation", defaultAnimation);
|
|
||||||
util::xml::query_string_attribute(element, "Name", name);
|
|
||||||
util::xml::query_path_attribute(element, "Path", path);
|
|
||||||
|
|
||||||
util::xml::query_int_attribute(element, "Id", id);
|
|
||||||
util::xml::query_int_attribute(element, "LayerId", layerId);
|
|
||||||
util::xml::query_int_attribute(element, "NullId", nullId);
|
|
||||||
util::xml::query_int_attribute(element, "SpritesheetId", spritesheetId);
|
|
||||||
util::xml::query_int_attribute(element, "EventId", eventId);
|
|
||||||
util::xml::query_int_attribute(element, "RegionId", regionId);
|
|
||||||
util::xml::query_int_attribute(element, "AtFrame", atFrame);
|
|
||||||
util::xml::query_int_attribute(element, "FrameNum", frameNum);
|
|
||||||
util::xml::query_int_attribute(element, "Fps", fps);
|
|
||||||
util::xml::query_int_attribute(element, "Version", version);
|
|
||||||
util::xml::query_int_attribute(element, "Delay", delay);
|
|
||||||
|
|
||||||
util::xml::query_float_attribute(element, "XCrop", crop.x);
|
|
||||||
util::xml::query_float_attribute(element, "YCrop", crop.y);
|
|
||||||
util::xml::query_float_attribute(element, "Width", size.x);
|
|
||||||
util::xml::query_float_attribute(element, "Height", size.y);
|
|
||||||
util::xml::query_float_attribute(element, "XPivot", pivot.x);
|
|
||||||
util::xml::query_float_attribute(element, "YPivot", pivot.y);
|
|
||||||
util::xml::query_float_attribute(element, "XPosition", position.x);
|
|
||||||
util::xml::query_float_attribute(element, "YPosition", position.y);
|
|
||||||
util::xml::query_float_attribute(element, "XScale", scale.x);
|
|
||||||
util::xml::query_float_attribute(element, "YScale", scale.y);
|
|
||||||
util::xml::query_float_attribute(element, "Rotation", rotation);
|
|
||||||
|
|
||||||
util::xml::query_color_attribute(element, "RedTint", tint.r);
|
|
||||||
util::xml::query_color_attribute(element, "GreenTint", tint.g);
|
|
||||||
util::xml::query_color_attribute(element, "BlueTint", tint.b);
|
|
||||||
util::xml::query_color_attribute(element, "AlphaTint", tint.a);
|
|
||||||
util::xml::query_color_attribute(element, "RedOffset", colorOffset.r);
|
|
||||||
util::xml::query_color_attribute(element, "GreenOffset", colorOffset.g);
|
|
||||||
util::xml::query_color_attribute(element, "BlueOffset", colorOffset.b);
|
|
||||||
|
|
||||||
util::xml::query_bool_attribute(element, "Visible", isVisible);
|
|
||||||
util::xml::query_bool_attribute(element, "ShowRect", isShowRect);
|
|
||||||
util::xml::query_bool_attribute(element, "Loop", isLoop);
|
|
||||||
|
|
||||||
if (const char* value = element->Attribute("Origin")) origin = string_enum_get(ORIGIN_STRINGS, value, CUSTOM);
|
|
||||||
|
|
||||||
if (const char* value = element->Attribute("Interpolated"))
|
|
||||||
{
|
|
||||||
auto view = std::string_view(value);
|
|
||||||
if (view == "true" || view == "1")
|
|
||||||
interpolation = LINEAR;
|
|
||||||
else if (view == "false" || view == "0")
|
|
||||||
interpolation = NONE;
|
|
||||||
else
|
|
||||||
interpolation = string_enum_get(INTERPOLATION_STRINGS, view, NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == SOUND && parentType == TRIGGER) path.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Anm2::Element::attributes_write(XMLElement* element, Type parentType, Flags flags) const
|
|
||||||
{
|
|
||||||
if (!element) return;
|
|
||||||
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case INFO:
|
|
||||||
util::xml::set_string_attribute(element, "CreatedBy", createdBy);
|
|
||||||
util::xml::set_string_attribute(element, "CreatedOn", createdOn);
|
|
||||||
util::xml::set_int_attribute(element, "Fps", fps);
|
|
||||||
util::xml::set_int_attribute(element, "Version", version);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SPRITESHEET:
|
|
||||||
if (id > -1) util::xml::set_int_attribute(element, "Id", id);
|
|
||||||
util::xml::set_path_attribute(element, "Path", path);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case REGION:
|
|
||||||
if (id > -1) util::xml::set_int_attribute(element, "Id", id);
|
|
||||||
util::xml::set_string_attribute(element, "Name", name);
|
|
||||||
util::xml::set_float_attribute(element, "XCrop", crop.x);
|
|
||||||
util::xml::set_float_attribute(element, "YCrop", crop.y);
|
|
||||||
util::xml::set_float_attribute(element, "Width", size.x);
|
|
||||||
util::xml::set_float_attribute(element, "Height", size.y);
|
|
||||||
|
|
||||||
if (origin == CUSTOM)
|
|
||||||
{
|
|
||||||
util::xml::set_float_attribute(element, "XPivot", pivot.x);
|
|
||||||
util::xml::set_float_attribute(element, "YPivot", pivot.y);
|
|
||||||
}
|
|
||||||
else if (auto value = enum_string_get(ORIGIN_STRINGS, origin); !value.empty())
|
|
||||||
element->SetAttribute("Origin", value.data());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case LAYER:
|
|
||||||
if (id > -1) util::xml::set_int_attribute(element, "Id", id);
|
|
||||||
util::xml::set_string_attribute(element, "Name", name);
|
|
||||||
if (spritesheetId > -1) util::xml::set_int_attribute(element, "SpritesheetId", spritesheetId);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NULL_ELEMENT:
|
|
||||||
if (id > -1) util::xml::set_int_attribute(element, "Id", id);
|
|
||||||
util::xml::set_string_attribute(element, "Name", name);
|
|
||||||
util::xml::set_bool_attribute(element, "ShowRect", isShowRect);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EVENT:
|
|
||||||
if (id > -1) util::xml::set_int_attribute(element, "Id", id);
|
|
||||||
util::xml::set_string_attribute(element, "Name", name);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SOUND:
|
|
||||||
if (id > -1)
|
|
||||||
{
|
|
||||||
if (parentType == TRIGGER)
|
|
||||||
util::xml::set_int_attribute(element, "Id", id);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
util::xml::set_int_attribute(element, "Id", id);
|
|
||||||
util::xml::set_path_attribute(element, "Path", path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ANIMATIONS:
|
|
||||||
util::xml::set_string_attribute(element, "DefaultAnimation", defaultAnimation);
|
|
||||||
break;
|
|
||||||
case ANIMATION:
|
|
||||||
util::xml::set_string_attribute(element, "Name", name);
|
|
||||||
util::xml::set_int_attribute(element, "FrameNum", frameNum);
|
|
||||||
util::xml::set_bool_attribute(element, "Loop", isLoop);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case LAYER_ANIMATION:
|
|
||||||
if (layerId > -1) util::xml::set_int_attribute(element, "LayerId", layerId);
|
|
||||||
util::xml::set_bool_attribute(element, "Visible", isVisible);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NULL_ANIMATION:
|
|
||||||
if (nullId > -1) util::xml::set_int_attribute(element, "NullId", nullId);
|
|
||||||
util::xml::set_bool_attribute(element, "Visible", isVisible);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TRIGGER:
|
|
||||||
if (eventId > -1) util::xml::set_int_attribute(element, "EventId", eventId);
|
|
||||||
util::xml::set_int_attribute(element, "AtFrame", atFrame);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FRAME:
|
|
||||||
{
|
|
||||||
bool isNoRegions = is_flag_set(flags, NO_REGIONS);
|
|
||||||
bool isFrameNoRegionValues = is_flag_set(flags, FRAME_NO_REGION_VALUES);
|
|
||||||
bool isRegionValid = parentType == LAYER_ANIMATION && !isNoRegions && regionId != -1;
|
|
||||||
bool isWriteRegionValues = parentType == LAYER_ANIMATION && (!isFrameNoRegionValues || !isRegionValid);
|
|
||||||
|
|
||||||
if (isRegionValid) util::xml::set_int_attribute(element, "RegionId", regionId);
|
|
||||||
util::xml::set_float_attribute(element, "XPosition", position.x);
|
|
||||||
util::xml::set_float_attribute(element, "YPosition", position.y);
|
|
||||||
|
|
||||||
if (isWriteRegionValues)
|
|
||||||
{
|
|
||||||
util::xml::set_float_attribute(element, "XPivot", pivot.x);
|
|
||||||
util::xml::set_float_attribute(element, "YPivot", pivot.y);
|
|
||||||
util::xml::set_float_attribute(element, "XCrop", crop.x);
|
|
||||||
util::xml::set_float_attribute(element, "YCrop", crop.y);
|
|
||||||
util::xml::set_float_attribute(element, "Width", size.x);
|
|
||||||
util::xml::set_float_attribute(element, "Height", size.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
util::xml::set_float_attribute(element, "XScale", scale.x);
|
|
||||||
util::xml::set_float_attribute(element, "YScale", scale.y);
|
|
||||||
util::xml::set_int_attribute(element, "Delay", delay);
|
|
||||||
util::xml::set_bool_attribute(element, "Visible", isVisible);
|
|
||||||
util::xml::set_color_attribute(element, "RedTint", tint.r);
|
|
||||||
util::xml::set_color_attribute(element, "GreenTint", tint.g);
|
|
||||||
util::xml::set_color_attribute(element, "BlueTint", tint.b);
|
|
||||||
util::xml::set_color_attribute(element, "AlphaTint", tint.a);
|
|
||||||
util::xml::set_color_attribute(element, "RedOffset", colorOffset.r);
|
|
||||||
util::xml::set_color_attribute(element, "GreenOffset", colorOffset.g);
|
|
||||||
util::xml::set_color_attribute(element, "BlueOffset", colorOffset.b);
|
|
||||||
util::xml::set_float_attribute(element, "Rotation", rotation);
|
|
||||||
|
|
||||||
if (is_flag_set(flags, INTERPOLATION_BOOL_ONLY) || interpolation == LINEAR || interpolation == NONE)
|
|
||||||
element->SetAttribute("Interpolated", interpolation == LINEAR);
|
|
||||||
else if (auto value = enum_string_get(INTERPOLATION_STRINGS, interpolation); !value.empty())
|
|
||||||
element->SetAttribute("Interpolated", value.data());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ACTOR:
|
|
||||||
case CONTENT:
|
|
||||||
case SPRITESHEETS:
|
|
||||||
case LAYERS:
|
|
||||||
case NULLS:
|
|
||||||
case EVENTS:
|
|
||||||
case SOUNDS:
|
|
||||||
case ROOT_ANIMATION:
|
|
||||||
case LAYER_ANIMATIONS:
|
|
||||||
case NULL_ANIMATIONS:
|
|
||||||
case TRIGGERS:
|
|
||||||
case UNKNOWN:
|
|
||||||
case TYPE_COUNT:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Anm2::Element Anm2::Element::from_xml(const XMLElement* element, Type parentType)
|
|
||||||
{
|
|
||||||
Element parsed{};
|
|
||||||
if (!element) return parsed;
|
|
||||||
|
|
||||||
parsed.type = type_get(element->Name(), parentType);
|
|
||||||
if (parsed.type == UNKNOWN) return parsed;
|
|
||||||
|
|
||||||
parsed.attributes_read(element, parentType);
|
|
||||||
|
|
||||||
for (const XMLElement* child = element->FirstChildElement(); child; child = child->NextSiblingElement())
|
|
||||||
if (auto parsedChild = from_xml(child, parsed.type); parsedChild.type != UNKNOWN)
|
|
||||||
parsed.children.push_back(std::move(parsedChild));
|
|
||||||
|
|
||||||
return parsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
XMLElement* Anm2::Element::to_xml(XMLDocument& document, Type parentType, Flags flags) const
|
|
||||||
{
|
|
||||||
auto tagName = tag_get(type);
|
|
||||||
if (tagName.empty()) return nullptr;
|
|
||||||
|
|
||||||
auto* element = document.NewElement(tagName.data());
|
|
||||||
attributes_write(element, parentType, flags);
|
|
||||||
|
|
||||||
for (const auto& child : children)
|
|
||||||
{
|
|
||||||
if (is_flag_set(flags, NO_SOUNDS) && (child.type == SOUNDS || child.type == SOUND)) continue;
|
|
||||||
if (is_flag_set(flags, NO_REGIONS) && child.type == REGION) continue;
|
|
||||||
if (auto* childElement = child.to_xml(document, type, flags)) element->InsertEndChild(childElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Anm2::Element::serialize(const std::filesystem::path& path, std::string* errorString,
|
|
||||||
Compatibility compatibility) const
|
|
||||||
{
|
|
||||||
XMLDocument document{};
|
|
||||||
if (auto* element = to_xml(document, UNKNOWN, Anm2::flags_get(compatibility)))
|
|
||||||
document.InsertFirstChild(element);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (errorString) *errorString = "No supported element to serialize.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
util::File file(path, "wb");
|
|
||||||
if (!file)
|
|
||||||
{
|
|
||||||
if (errorString) *errorString = "Could not open file for writing.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (document.SaveFile(file.get()) != XML_SUCCESS)
|
|
||||||
{
|
|
||||||
if (errorString) *errorString = document.ErrorStr();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Anm2::Element::to_string(Compatibility compatibility) const
|
|
||||||
{
|
|
||||||
XMLDocument document{};
|
|
||||||
if (auto* element = to_xml(document, UNKNOWN, Anm2::flags_get(compatibility))) document.InsertFirstChild(element);
|
|
||||||
return util::xml::document_to_string(document);
|
|
||||||
}
|
|
||||||
|
|
||||||
Anm2::Element* Anm2::Element::child_get(Type childType, std::size_t index)
|
|
||||||
{
|
|
||||||
std::size_t matchIndex{};
|
|
||||||
for (auto& child : children)
|
|
||||||
if (child.type == childType && matchIndex++ == index) return &child;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Anm2::Element* Anm2::Element::child_get(Type childType, std::size_t index) const
|
|
||||||
{
|
|
||||||
std::size_t matchIndex{};
|
|
||||||
for (const auto& child : children)
|
|
||||||
if (child.type == childType && matchIndex++ == index) return &child;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Anm2::Element*> Anm2::Element::children_get(Type childType)
|
|
||||||
{
|
|
||||||
std::vector<Element*> matches{};
|
|
||||||
for (auto& child : children)
|
|
||||||
if (child.type == childType) matches.push_back(&child);
|
|
||||||
return matches;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<const Anm2::Element*> Anm2::Element::children_get(Type childType) const
|
|
||||||
{
|
|
||||||
std::vector<const Element*> matches{};
|
|
||||||
for (const auto& child : children)
|
|
||||||
if (child.type == childType) matches.push_back(&child);
|
|
||||||
return matches;
|
|
||||||
}
|
|
||||||
|
|
||||||
Anm2::Anm2(const std::filesystem::path& filepath, std::string* errorString)
|
|
||||||
: path(filepath), root(filepath, errorString)
|
|
||||||
{
|
|
||||||
isValid = root.type == Element::ACTOR;
|
|
||||||
assets_reload();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Anm2::serialize(const std::filesystem::path& filepath, std::string* errorString,
|
|
||||||
Compatibility compatibility) const
|
|
||||||
{
|
|
||||||
return root.serialize(filepath, errorString, compatibility);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Anm2::to_string(Compatibility compatibility) const { return root.to_string(compatibility); }
|
|
||||||
|
|
||||||
void Anm2::assets_reload()
|
|
||||||
{
|
|
||||||
spritesheets.clear();
|
|
||||||
sounds.clear();
|
|
||||||
|
|
||||||
auto directory = path.parent_path();
|
|
||||||
for (auto* element : elements_get(Element::SPRITESHEET))
|
|
||||||
if (element->id > -1 && !element->path.empty())
|
|
||||||
spritesheets[element->id] = resource::Texture(asset_path_resolve(directory, element->path));
|
|
||||||
|
|
||||||
for (auto* element : elements_get(Element::SOUND))
|
|
||||||
if (element->id > -1 && !element->path.empty())
|
|
||||||
sounds[element->id] = resource::Audio(asset_path_resolve(directory, element->path));
|
|
||||||
}
|
|
||||||
|
|
||||||
Anm2::Element* Anm2::element_get(Element::Type type, std::size_t index)
|
|
||||||
{
|
|
||||||
auto matches = elements_get(type);
|
|
||||||
return index < matches.size() ? matches[index] : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Anm2::Element* Anm2::element_get(Element::Type type, std::size_t index) const
|
|
||||||
{
|
|
||||||
auto matches = elements_get(type);
|
|
||||||
return index < matches.size() ? matches[index] : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Anm2::Element*> Anm2::elements_get(Element::Type type)
|
|
||||||
{
|
|
||||||
std::vector<Element*> matches{};
|
|
||||||
elements_collect(root, type, matches);
|
|
||||||
return matches;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<const Anm2::Element*> Anm2::elements_get(Element::Type type) const
|
|
||||||
{
|
|
||||||
std::vector<const Element*> matches{};
|
|
||||||
elements_collect(root, type, matches);
|
|
||||||
return matches;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Anm2::elements_collect(Element& element, Element::Type type, std::vector<Element*>& out)
|
|
||||||
{
|
|
||||||
if (element.type == type) out.push_back(&element);
|
|
||||||
for (auto& child : element.children)
|
|
||||||
elements_collect(child, type, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Anm2::elements_collect(const Element& element, Element::Type type, std::vector<const Element*>& out)
|
|
||||||
{
|
|
||||||
if (element.type == type) out.push_back(&element);
|
|
||||||
for (const auto& child : element.children)
|
|
||||||
elements_collect(child, type, out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,233 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <filesystem>
|
|
||||||
#include <string>
|
|
||||||
#include <string_view>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <glm/glm/vec2.hpp>
|
|
||||||
#include <glm/glm/vec3.hpp>
|
|
||||||
#include <glm/glm/vec4.hpp>
|
|
||||||
|
|
||||||
#include "audio.hpp"
|
|
||||||
#include "texture.hpp"
|
|
||||||
|
|
||||||
namespace tinyxml2
|
|
||||||
{
|
|
||||||
class XMLDocument;
|
|
||||||
class XMLElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace anm2ed::anm2_new
|
|
||||||
{
|
|
||||||
class Anm2
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum Compatibility
|
|
||||||
{
|
|
||||||
ISAAC,
|
|
||||||
ANM2ED,
|
|
||||||
ANM2ED_LIMITED,
|
|
||||||
COMPATIBILITY_COUNT
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Flag
|
|
||||||
{
|
|
||||||
NO_SOUNDS = 1 << 0,
|
|
||||||
NO_REGIONS = 1 << 1,
|
|
||||||
FRAME_NO_REGION_VALUES = 1 << 2,
|
|
||||||
INTERPOLATION_BOOL_ONLY = 1 << 3
|
|
||||||
};
|
|
||||||
|
|
||||||
using Flags = int;
|
|
||||||
|
|
||||||
inline static constexpr std::array<Flags, COMPATIBILITY_COUNT> COMPATIBILITY_FLAGS = {{
|
|
||||||
NO_SOUNDS | NO_REGIONS | FRAME_NO_REGION_VALUES | INTERPOLATION_BOOL_ONLY,
|
|
||||||
0,
|
|
||||||
FRAME_NO_REGION_VALUES,
|
|
||||||
}};
|
|
||||||
|
|
||||||
class Element
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum Source
|
|
||||||
{
|
|
||||||
STRING
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Type
|
|
||||||
{
|
|
||||||
UNKNOWN,
|
|
||||||
ACTOR,
|
|
||||||
INFO,
|
|
||||||
CONTENT,
|
|
||||||
SPRITESHEETS,
|
|
||||||
SPRITESHEET,
|
|
||||||
REGION,
|
|
||||||
LAYERS,
|
|
||||||
LAYER,
|
|
||||||
NULLS,
|
|
||||||
NULL_ELEMENT,
|
|
||||||
EVENTS,
|
|
||||||
EVENT,
|
|
||||||
SOUNDS,
|
|
||||||
SOUND,
|
|
||||||
ANIMATIONS,
|
|
||||||
ANIMATION,
|
|
||||||
ROOT_ANIMATION,
|
|
||||||
LAYER_ANIMATIONS,
|
|
||||||
LAYER_ANIMATION,
|
|
||||||
NULL_ANIMATIONS,
|
|
||||||
NULL_ANIMATION,
|
|
||||||
TRIGGERS,
|
|
||||||
TRIGGER,
|
|
||||||
FRAME,
|
|
||||||
TYPE_COUNT
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Origin
|
|
||||||
{
|
|
||||||
TOP_LEFT,
|
|
||||||
ORIGIN_CENTER,
|
|
||||||
CUSTOM
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Interpolation
|
|
||||||
{
|
|
||||||
NONE,
|
|
||||||
LINEAR,
|
|
||||||
EASE_IN,
|
|
||||||
EASE_OUT,
|
|
||||||
EASE_IN_OUT
|
|
||||||
};
|
|
||||||
|
|
||||||
inline static constexpr std::array<std::pair<Type, std::string_view>, TYPE_COUNT - 1> TYPE_TAGS = {{
|
|
||||||
{ACTOR, "AnimatedActor"},
|
|
||||||
{INFO, "Info"},
|
|
||||||
{CONTENT, "Content"},
|
|
||||||
{SPRITESHEETS, "Spritesheets"},
|
|
||||||
{SPRITESHEET, "Spritesheet"},
|
|
||||||
{REGION, "Region"},
|
|
||||||
{LAYERS, "Layers"},
|
|
||||||
{LAYER, "Layer"},
|
|
||||||
{NULLS, "Nulls"},
|
|
||||||
{NULL_ELEMENT, "Null"},
|
|
||||||
{EVENTS, "Events"},
|
|
||||||
{EVENT, "Event"},
|
|
||||||
{SOUNDS, "Sounds"},
|
|
||||||
{SOUND, "Sound"},
|
|
||||||
{ANIMATIONS, "Animations"},
|
|
||||||
{ANIMATION, "Animation"},
|
|
||||||
{ROOT_ANIMATION, "RootAnimation"},
|
|
||||||
{LAYER_ANIMATIONS, "LayerAnimations"},
|
|
||||||
{LAYER_ANIMATION, "LayerAnimation"},
|
|
||||||
{NULL_ANIMATIONS, "NullAnimations"},
|
|
||||||
{NULL_ANIMATION, "NullAnimation"},
|
|
||||||
{TRIGGERS, "Triggers"},
|
|
||||||
{TRIGGER, "Trigger"},
|
|
||||||
{FRAME, "Frame"},
|
|
||||||
}};
|
|
||||||
|
|
||||||
inline static constexpr std::array<std::pair<Origin, std::string_view>, 2> ORIGIN_STRINGS = {{
|
|
||||||
{TOP_LEFT, "TopLeft"},
|
|
||||||
{ORIGIN_CENTER, "Center"},
|
|
||||||
}};
|
|
||||||
|
|
||||||
inline static constexpr std::array<std::pair<Interpolation, std::string_view>, 3> INTERPOLATION_STRINGS = {{
|
|
||||||
{EASE_IN, "EaseIn"},
|
|
||||||
{EASE_OUT, "EaseOut"},
|
|
||||||
{EASE_IN_OUT, "EaseInOut"},
|
|
||||||
}};
|
|
||||||
|
|
||||||
Type type{UNKNOWN};
|
|
||||||
std::vector<Element> children{};
|
|
||||||
|
|
||||||
std::string createdBy{};
|
|
||||||
std::string createdOn{};
|
|
||||||
std::string defaultAnimation{};
|
|
||||||
std::string name{};
|
|
||||||
std::filesystem::path path{};
|
|
||||||
|
|
||||||
int id{-1};
|
|
||||||
int layerId{-1};
|
|
||||||
int nullId{-1};
|
|
||||||
int spritesheetId{-1};
|
|
||||||
int eventId{-1};
|
|
||||||
int regionId{-1};
|
|
||||||
int atFrame{-1};
|
|
||||||
int frameNum{};
|
|
||||||
int fps{30};
|
|
||||||
int version{};
|
|
||||||
int delay{1};
|
|
||||||
|
|
||||||
glm::vec2 crop{};
|
|
||||||
glm::vec2 size{};
|
|
||||||
glm::vec2 pivot{};
|
|
||||||
glm::vec2 position{};
|
|
||||||
glm::vec2 scale{100.0f, 100.0f};
|
|
||||||
glm::vec4 tint{1.0f, 1.0f, 1.0f, 1.0f};
|
|
||||||
glm::vec3 colorOffset{};
|
|
||||||
float rotation{};
|
|
||||||
|
|
||||||
bool isVisible{true};
|
|
||||||
bool isShowRect{false};
|
|
||||||
bool isLoop{false};
|
|
||||||
Origin origin{CUSTOM};
|
|
||||||
Interpolation interpolation{NONE};
|
|
||||||
|
|
||||||
Element() = default;
|
|
||||||
explicit Element(const std::filesystem::path&, std::string* = nullptr);
|
|
||||||
Element(std::string_view, Source, std::string* = nullptr);
|
|
||||||
|
|
||||||
bool serialize(const std::filesystem::path&, std::string* = nullptr, Compatibility = ANM2ED) const;
|
|
||||||
std::string to_string(Compatibility = ANM2ED) const;
|
|
||||||
|
|
||||||
Element* child_get(Type, std::size_t index = 0);
|
|
||||||
const Element* child_get(Type, std::size_t index = 0) const;
|
|
||||||
std::vector<Element*> children_get(Type);
|
|
||||||
std::vector<const Element*> children_get(Type) const;
|
|
||||||
|
|
||||||
static std::string_view tag_get(Type);
|
|
||||||
static Type type_get(std::string_view, Type = UNKNOWN);
|
|
||||||
static Element from_xml(const tinyxml2::XMLElement*, Type = UNKNOWN);
|
|
||||||
static bool document_load(tinyxml2::XMLDocument&, const std::filesystem::path&, std::string*);
|
|
||||||
static bool document_parse(tinyxml2::XMLDocument&, std::string_view, std::string*);
|
|
||||||
|
|
||||||
tinyxml2::XMLElement* to_xml(tinyxml2::XMLDocument&, Type = UNKNOWN, Flags = 0) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void attributes_read(const tinyxml2::XMLElement*, Type = UNKNOWN);
|
|
||||||
void attributes_write(tinyxml2::XMLElement*, Type = UNKNOWN, Flags = 0) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool isValid{true};
|
|
||||||
std::filesystem::path path{};
|
|
||||||
Element root{};
|
|
||||||
std::unordered_map<int, resource::Texture> spritesheets{};
|
|
||||||
std::unordered_map<int, resource::Audio> sounds{};
|
|
||||||
|
|
||||||
Anm2() = default;
|
|
||||||
explicit Anm2(const std::filesystem::path&, std::string* = nullptr);
|
|
||||||
|
|
||||||
bool serialize(const std::filesystem::path&, std::string* = nullptr, Compatibility = ANM2ED) const;
|
|
||||||
std::string to_string(Compatibility = ANM2ED) const;
|
|
||||||
void assets_reload();
|
|
||||||
|
|
||||||
static constexpr Flags flags_get(Compatibility compatibility)
|
|
||||||
{
|
|
||||||
return COMPATIBILITY_FLAGS[static_cast<std::size_t>(compatibility)];
|
|
||||||
}
|
|
||||||
|
|
||||||
Element* element_get(Element::Type, std::size_t index = 0);
|
|
||||||
const Element* element_get(Element::Type, std::size_t index = 0) const;
|
|
||||||
std::vector<Element*> elements_get(Element::Type);
|
|
||||||
std::vector<const Element*> elements_get(Element::Type) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
static void elements_collect(Element&, Element::Type, std::vector<Element*>&);
|
|
||||||
static void elements_collect(const Element&, Element::Type, std::vector<const Element*>&);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -34,10 +34,10 @@ namespace anm2ed::imgui::wizard
|
|||||||
{"Simon Parzer"},
|
{"Simon Parzer"},
|
||||||
{"Matt Kapuszczak"},
|
{"Matt Kapuszczak"},
|
||||||
{""},
|
{""},
|
||||||
{"XM Music", font::BOLD},
|
{"Music", font::BOLD},
|
||||||
{"Drozerix"},
|
{"Soundbin"},
|
||||||
{"\"Keygen Wraith\""},
|
{"\"Digital Antidepressant\""},
|
||||||
{"https://modarchive.org/module.php?207854"},
|
{"https://soundbin.newgrounds.com/"},
|
||||||
{"License: CC0"},
|
{"License: CC0"},
|
||||||
{""},
|
{""},
|
||||||
{"Libraries", font::BOLD},
|
{"Libraries", font::BOLD},
|
||||||
|
|||||||
+30398
-30330
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user