Auto bake frames! new attributes!
This commit is contained in:
+114
-35
@@ -87,11 +87,9 @@ namespace anm2ed
|
|||||||
|
|
||||||
constexpr std::array<std::string_view, (std::size_t)Origin::COUNT> ORIGIN_VALUES = {"", "TopLeft", "Center"};
|
constexpr std::array<std::string_view, (std::size_t)Origin::COUNT> ORIGIN_VALUES = {"", "TopLeft", "Center"};
|
||||||
|
|
||||||
constexpr std::array<Flags, (std::size_t)Compatibility::COUNT> COMPATIBILITY_FLAGS = {
|
|
||||||
NO_SOUNDS | NO_REGIONS | NO_GROUPS | FRAME_NO_REGION_VALUES | INTERPOLATION_BOOL_ONLY, 0,
|
|
||||||
NO_GROUPS | FRAME_NO_REGION_VALUES};
|
|
||||||
|
|
||||||
void groups_flatten(Element&);
|
void groups_flatten(Element&);
|
||||||
|
bool is_track(const Element&);
|
||||||
|
float interpolation_factor(Interpolation, float);
|
||||||
|
|
||||||
bool anm2_document_load(Anm2& anm2, XMLDocument& document, std::string* errorString)
|
bool anm2_document_load(Anm2& anm2, XMLDocument& document, std::string* errorString)
|
||||||
{
|
{
|
||||||
@@ -110,13 +108,6 @@ namespace anm2ed
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Flags flags_for(Compatibility compatibility)
|
|
||||||
{
|
|
||||||
auto index = (std::size_t)compatibility;
|
|
||||||
if (index >= COMPATIBILITY_FLAGS.size()) return 0;
|
|
||||||
return COMPATIBILITY_FLAGS[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
ElementType element_type_get(std::string_view tag)
|
ElementType element_type_get(std::string_view tag)
|
||||||
{
|
{
|
||||||
for (std::size_t i = 0; i < ELEMENT_TAGS.size(); ++i)
|
for (std::size_t i = 0; i < ELEMENT_TAGS.size(); ++i)
|
||||||
@@ -195,12 +186,12 @@ namespace anm2ed
|
|||||||
|
|
||||||
int color_write(float value) { return math::float_to_uint8(glm::clamp(value, 0.0f, 1.0f)); }
|
int color_write(float value) { return math::float_to_uint8(glm::clamp(value, 0.0f, 1.0f)); }
|
||||||
|
|
||||||
Interpolation interpolation_read(const XMLElement* element)
|
Interpolation interpolation_read(const XMLElement* element, const char* attribute)
|
||||||
{
|
{
|
||||||
bool isFallback{};
|
bool isFallback{};
|
||||||
if (element) element->QueryBoolAttribute("Interpolated", &isFallback);
|
if (element) element->QueryBoolAttribute(attribute, &isFallback);
|
||||||
|
|
||||||
auto value = element ? element->Attribute("Interpolated") : nullptr;
|
auto value = element ? element->Attribute(attribute) : nullptr;
|
||||||
if (!value) return Interpolation::NONE;
|
if (!value) return Interpolation::NONE;
|
||||||
|
|
||||||
for (std::size_t i = 0; i < INTERPOLATION_VALUES.size(); ++i)
|
for (std::size_t i = 0; i < INTERPOLATION_VALUES.size(); ++i)
|
||||||
@@ -209,10 +200,11 @@ namespace anm2ed
|
|||||||
return isFallback ? Interpolation::LINEAR : Interpolation::NONE;
|
return isFallback ? Interpolation::LINEAR : Interpolation::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void interpolation_write(XMLElement* element, Interpolation interpolation, Flags flags)
|
Interpolation interpolation_read(const XMLElement* element) { return interpolation_read(element, "Interpolated"); }
|
||||||
|
|
||||||
|
void interpolation_write(XMLElement* element, Interpolation interpolation)
|
||||||
{
|
{
|
||||||
if (has_flag(flags, INTERPOLATION_BOOL_ONLY) || interpolation == Interpolation::NONE ||
|
if (interpolation == Interpolation::NONE || interpolation == Interpolation::LINEAR)
|
||||||
interpolation == Interpolation::LINEAR)
|
|
||||||
{
|
{
|
||||||
element->SetAttribute("Interpolated", interpolation == Interpolation::LINEAR);
|
element->SetAttribute("Interpolated", interpolation == Interpolation::LINEAR);
|
||||||
return;
|
return;
|
||||||
@@ -273,6 +265,50 @@ namespace anm2ed
|
|||||||
if (out.type == ElementType::REGION && out.origin == Origin::CENTER) out.pivot = glm::ivec2(out.size / 2.0f);
|
if (out.type == ElementType::REGION && out.origin == Origin::CENTER) out.pivot = glm::ivec2(out.size / 2.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool bake_attributes_read(const XMLElement* element, Interpolation& interpolation, int& originalDelay, int& bakeCount)
|
||||||
|
{
|
||||||
|
if (!element || !element->Attribute("BakeInterpolation")) return false;
|
||||||
|
|
||||||
|
interpolation = interpolation_read(element, "BakeInterpolation");
|
||||||
|
element->QueryIntAttribute("OriginalDelay", &originalDelay);
|
||||||
|
element->QueryIntAttribute("BakeCount", &bakeCount);
|
||||||
|
return bakeCount > 0 && originalDelay >= FRAME_DURATION_MIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
const XMLElement* bake_frames_skip(const XMLElement* element, int bakeCount)
|
||||||
|
{
|
||||||
|
for (int i = 0; element && i < bakeCount; ++i)
|
||||||
|
element = element->NextSiblingElement();
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
void element_children_read(Element& out, const XMLElement* element)
|
||||||
|
{
|
||||||
|
auto child = element->FirstChildElement();
|
||||||
|
while (child)
|
||||||
|
{
|
||||||
|
auto childType = element_type_get(child->Name() ? child->Name() : "");
|
||||||
|
if (childType == ElementType::FRAME && is_track(out))
|
||||||
|
{
|
||||||
|
Interpolation bakeInterpolation{};
|
||||||
|
int originalDelay{};
|
||||||
|
int bakeCount{};
|
||||||
|
if (bake_attributes_read(child, bakeInterpolation, originalDelay, bakeCount))
|
||||||
|
{
|
||||||
|
auto restored = element_read(child);
|
||||||
|
restored.interpolation = bakeInterpolation;
|
||||||
|
restored.duration = originalDelay;
|
||||||
|
out.children.push_back(std::move(restored));
|
||||||
|
child = bake_frames_skip(child, bakeCount);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out.children.push_back(element_read(child));
|
||||||
|
child = child->NextSiblingElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Element element_read(const XMLElement* element)
|
Element element_read(const XMLElement* element)
|
||||||
{
|
{
|
||||||
Element out{};
|
Element out{};
|
||||||
@@ -282,8 +318,7 @@ namespace anm2ed
|
|||||||
out.type = element_type_get(out.tag);
|
out.type = element_type_get(out.tag);
|
||||||
element_attributes_read(out, element);
|
element_attributes_read(out, element);
|
||||||
|
|
||||||
for (auto child = element->FirstChildElement(); child; child = child->NextSiblingElement())
|
element_children_read(out, element);
|
||||||
out.children.push_back(element_read(child));
|
|
||||||
|
|
||||||
if (out.type == ElementType::TRIGGER && out.soundId != -1)
|
if (out.type == ElementType::TRIGGER && out.soundId != -1)
|
||||||
{
|
{
|
||||||
@@ -308,11 +343,13 @@ namespace anm2ed
|
|||||||
|
|
||||||
bool element_write_skip(const Element& element, ElementType parentType, Flags flags)
|
bool element_write_skip(const Element& element, ElementType parentType, Flags flags)
|
||||||
{
|
{
|
||||||
if (element.type == ElementType::SOUNDS && (has_flag(flags, NO_SOUNDS) || element.children.empty())) return true;
|
if (element.type == ElementType::SOUNDS && (!has_flag(flags, SERIALIZE_SOUNDS) || element.children.empty()))
|
||||||
if (element.type == ElementType::SOUND_ELEMENT && parentType == ElementType::TRIGGER && has_flag(flags, NO_SOUNDS))
|
|
||||||
return true;
|
return true;
|
||||||
if (element.type == ElementType::REGION && has_flag(flags, NO_REGIONS)) return true;
|
if (element.type == ElementType::SOUND_ELEMENT && parentType == ElementType::TRIGGER &&
|
||||||
if (element.type == ElementType::GROUP && has_flag(flags, NO_GROUPS)) return true;
|
!has_flag(flags, SERIALIZE_SOUNDS))
|
||||||
|
return true;
|
||||||
|
if (element.type == ElementType::REGION && !has_flag(flags, SERIALIZE_REGIONS)) return true;
|
||||||
|
if (element.type == ElementType::GROUP && !has_flag(flags, SERIALIZE_GROUPS)) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,10 +357,8 @@ namespace anm2ed
|
|||||||
{
|
{
|
||||||
if (parentType == ElementType::LAYER_ANIMATION)
|
if (parentType == ElementType::LAYER_ANIMATION)
|
||||||
{
|
{
|
||||||
bool isNoRegions = has_flag(flags, NO_REGIONS);
|
bool isHasValidRegion = has_flag(flags, SERIALIZE_REGIONS) && element.regionId != -1;
|
||||||
bool isFrameNoRegionValues = has_flag(flags, FRAME_NO_REGION_VALUES);
|
bool isWriteRegionValues = has_flag(flags, SERIALIZE_REDUNDANT_FRAME_REGION_VALUES) || !isHasValidRegion;
|
||||||
bool isHasValidRegion = !isNoRegions && element.regionId != -1;
|
|
||||||
bool isWriteRegionValues = !isFrameNoRegionValues || !isHasValidRegion;
|
|
||||||
|
|
||||||
if (isHasValidRegion) out->SetAttribute("RegionId", element.regionId);
|
if (isHasValidRegion) out->SetAttribute("RegionId", element.regionId);
|
||||||
if (isWriteRegionValues)
|
if (isWriteRegionValues)
|
||||||
@@ -351,7 +386,7 @@ namespace anm2ed
|
|||||||
out->SetAttribute("GreenOffset", color_write(element.colorOffset.g));
|
out->SetAttribute("GreenOffset", color_write(element.colorOffset.g));
|
||||||
out->SetAttribute("BlueOffset", color_write(element.colorOffset.b));
|
out->SetAttribute("BlueOffset", color_write(element.colorOffset.b));
|
||||||
out->SetAttribute("Rotation", element.rotation);
|
out->SetAttribute("Rotation", element.rotation);
|
||||||
interpolation_write(out, element.interpolation, flags);
|
interpolation_write(out, element.interpolation);
|
||||||
}
|
}
|
||||||
|
|
||||||
void element_attributes_write(XMLElement* out, const Element& element, ElementType parentType, Flags flags)
|
void element_attributes_write(XMLElement* out, const Element& element, ElementType parentType, Flags flags)
|
||||||
@@ -419,13 +454,13 @@ namespace anm2ed
|
|||||||
{
|
{
|
||||||
out->SetAttribute("LayerId", element.layerId);
|
out->SetAttribute("LayerId", element.layerId);
|
||||||
out->SetAttribute("Visible", element.isVisible);
|
out->SetAttribute("Visible", element.isVisible);
|
||||||
if (element.groupId != -1 && !has_flag(flags, NO_GROUPS)) out->SetAttribute("GroupId", element.groupId);
|
if (element.groupId != -1 && has_flag(flags, SERIALIZE_GROUPS)) out->SetAttribute("GroupId", element.groupId);
|
||||||
}
|
}
|
||||||
else if (element.type == ElementType::NULL_ANIMATION)
|
else if (element.type == ElementType::NULL_ANIMATION)
|
||||||
{
|
{
|
||||||
out->SetAttribute("NullId", element.nullId);
|
out->SetAttribute("NullId", element.nullId);
|
||||||
out->SetAttribute("Visible", element.isVisible);
|
out->SetAttribute("Visible", element.isVisible);
|
||||||
if (element.groupId != -1 && !has_flag(flags, NO_GROUPS)) out->SetAttribute("GroupId", element.groupId);
|
if (element.groupId != -1 && has_flag(flags, SERIALIZE_GROUPS)) out->SetAttribute("GroupId", element.groupId);
|
||||||
}
|
}
|
||||||
else if (element.type == ElementType::FRAME)
|
else if (element.type == ElementType::FRAME)
|
||||||
frame_attributes_write(out, element, parentType, flags);
|
frame_attributes_write(out, element, parentType, flags);
|
||||||
@@ -436,15 +471,61 @@ namespace anm2ed
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bake_attributes_write(XMLElement* out, Interpolation interpolation, int bakeCount, int originalDelay)
|
||||||
|
{
|
||||||
|
auto value = INTERPOLATION_VALUES[(std::size_t)interpolation];
|
||||||
|
if (!value.empty()) out->SetAttribute("BakeInterpolation", value.data());
|
||||||
|
out->SetAttribute("BakeCount", bakeCount);
|
||||||
|
out->SetAttribute("OriginalDelay", originalDelay);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_frame_bake_serialized(const Element& frame, Flags flags)
|
||||||
|
{
|
||||||
|
return has_flag(flags, SERIALIZE_BAKE_SPECIAL_INTERPOLATED_FRAMES) && frame.type == ElementType::FRAME &&
|
||||||
|
frame.interpolation != Interpolation::NONE && frame.interpolation != Interpolation::LINEAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
XMLElement* element_to_xml(XMLDocument& document, const Element& element, ElementType parentType, Flags flags);
|
||||||
|
|
||||||
|
void baked_frames_insert(XMLDocument& document, XMLElement* out, const Element& track, int index, Flags flags)
|
||||||
|
{
|
||||||
|
const auto& original = track.children[index];
|
||||||
|
auto nextFrame = index + 1 < (int)track.children.size() && track.children[index + 1].type == ElementType::FRAME
|
||||||
|
? track.children[index + 1]
|
||||||
|
: original;
|
||||||
|
auto bakeCount = std::max(original.duration, FRAME_DURATION_MIN);
|
||||||
|
|
||||||
|
for (int bakeIndex = 0; bakeIndex < bakeCount; ++bakeIndex)
|
||||||
|
{
|
||||||
|
auto baked = original;
|
||||||
|
auto amount = interpolation_factor(original.interpolation, (float)bakeIndex / (float)bakeCount);
|
||||||
|
baked.duration = FRAME_DURATION_MIN;
|
||||||
|
baked.interpolation = Interpolation::NONE;
|
||||||
|
baked.rotation = glm::mix(original.rotation, nextFrame.rotation, amount);
|
||||||
|
baked.position = glm::mix(original.position, nextFrame.position, amount);
|
||||||
|
baked.scale = glm::mix(original.scale, nextFrame.scale, amount);
|
||||||
|
baked.colorOffset = glm::mix(original.colorOffset, nextFrame.colorOffset, amount);
|
||||||
|
baked.tint = glm::mix(original.tint, nextFrame.tint, amount);
|
||||||
|
auto frame = element_to_xml(document, baked, track.type, flags);
|
||||||
|
if (bakeIndex == 0) bake_attributes_write(frame, original.interpolation, bakeCount, original.duration);
|
||||||
|
out->InsertEndChild(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
XMLElement* element_to_xml(XMLDocument& document, const Element& element, ElementType parentType, Flags flags)
|
XMLElement* element_to_xml(XMLDocument& document, const Element& element, ElementType parentType, Flags flags)
|
||||||
{
|
{
|
||||||
auto tag = element.type == ElementType::UNKNOWN ? std::string_view(element.tag) : element_tag_get(element.type);
|
auto tag = element.type == ElementType::UNKNOWN ? std::string_view(element.tag) : element_tag_get(element.type);
|
||||||
auto out = document.NewElement(tag.empty() ? element.tag.c_str() : tag.data());
|
auto out = document.NewElement(tag.empty() ? element.tag.c_str() : tag.data());
|
||||||
element_attributes_write(out, element, parentType, flags);
|
element_attributes_write(out, element, parentType, flags);
|
||||||
|
|
||||||
for (const auto& child : element.children)
|
for (int i = 0; i < (int)element.children.size(); ++i)
|
||||||
{
|
{
|
||||||
if (!element_write_skip(child, element.type, flags))
|
const auto& child = element.children[i];
|
||||||
|
if (element_write_skip(child, element.type, flags)) continue;
|
||||||
|
|
||||||
|
if (is_track(element) && is_frame_bake_serialized(child, flags))
|
||||||
|
baked_frames_insert(document, out, element, i, flags);
|
||||||
|
else
|
||||||
out->InsertEndChild(element_to_xml(document, child, element.type, flags));
|
out->InsertEndChild(element_to_xml(document, child, element.type, flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1216,10 +1297,8 @@ namespace anm2ed
|
|||||||
XMLElement* Anm2::to_element(XMLDocument& document, Options options) const
|
XMLElement* Anm2::to_element(XMLDocument& document, Options options) const
|
||||||
{
|
{
|
||||||
auto serialized = normalized_for_serialize();
|
auto serialized = normalized_for_serialize();
|
||||||
if (options.isBakeSpecialInterpolatedFrames)
|
|
||||||
serialized.special_interpolated_frames_bake(1, options.isRoundScale, options.isRoundRotation);
|
|
||||||
serialized.region_frames_sync(true);
|
serialized.region_frames_sync(true);
|
||||||
return element_to_xml(document, serialized.root, flags_for(options.compatibility));
|
return element_to_xml(document, serialized.root, ElementType::UNKNOWN, options.flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint64_t Anm2::hash(Options options) const { return std::hash<std::string>{}(to_string(options)); }
|
std::uint64_t Anm2::hash(Options options) const { return std::hash<std::string>{}(to_string(options)); }
|
||||||
|
|||||||
+14
-26
@@ -71,14 +71,6 @@ namespace anm2ed
|
|||||||
COUNT
|
COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Compatibility
|
|
||||||
{
|
|
||||||
ISAAC,
|
|
||||||
ANM2ED,
|
|
||||||
ANM2ED_LIMITED,
|
|
||||||
COUNT
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class ItemType
|
enum class ItemType
|
||||||
{
|
{
|
||||||
NONE,
|
NONE,
|
||||||
@@ -102,10 +94,6 @@ namespace anm2ed
|
|||||||
inline constexpr int FPS_MIN = 1;
|
inline constexpr int FPS_MIN = 1;
|
||||||
inline constexpr int FPS_MAX = 120;
|
inline constexpr int FPS_MAX = 120;
|
||||||
|
|
||||||
inline constexpr int ISAAC = (int)Compatibility::ISAAC;
|
|
||||||
inline constexpr int ANM2ED = (int)Compatibility::ANM2ED;
|
|
||||||
inline constexpr int ANM2ED_LIMITED = (int)Compatibility::ANM2ED_LIMITED;
|
|
||||||
|
|
||||||
enum class SpritesheetMergeOrigin
|
enum class SpritesheetMergeOrigin
|
||||||
{
|
{
|
||||||
APPEND_RIGHT,
|
APPEND_RIGHT,
|
||||||
@@ -189,23 +177,23 @@ namespace anm2ed
|
|||||||
|
|
||||||
enum Flag
|
enum Flag
|
||||||
{
|
{
|
||||||
NO_SOUNDS = 1 << 0,
|
SERIALIZE_GROUPS = 1 << 0,
|
||||||
NO_REGIONS = 1 << 1,
|
SERIALIZE_REGIONS = 1 << 1,
|
||||||
FRAME_NO_REGION_VALUES = 1 << 2,
|
SERIALIZE_SOUNDS = 1 << 2,
|
||||||
INTERPOLATION_BOOL_ONLY = 1 << 3,
|
SERIALIZE_REDUNDANT_FRAME_REGION_VALUES = 1 << 3,
|
||||||
NO_GROUPS = 1 << 4
|
SERIALIZE_BAKE_SPECIAL_INTERPOLATED_FRAMES = 1 << 4
|
||||||
};
|
};
|
||||||
|
|
||||||
using Flags = int;
|
using Flags = int;
|
||||||
|
|
||||||
constexpr bool has_flag(Flags flags, Flag flag) { return (flags & flag) != 0; }
|
constexpr bool has_flag(Flags flags, Flag flag) { return (flags & flag) != 0; }
|
||||||
|
constexpr Flags SERIALIZE_EDITOR_DEFAULT =
|
||||||
|
SERIALIZE_GROUPS | SERIALIZE_REGIONS | SERIALIZE_SOUNDS | SERIALIZE_REDUNDANT_FRAME_REGION_VALUES;
|
||||||
|
constexpr Flags SERIALIZE_DEFAULT = SERIALIZE_EDITOR_DEFAULT | SERIALIZE_BAKE_SPECIAL_INTERPOLATED_FRAMES;
|
||||||
|
|
||||||
struct Options
|
struct Options
|
||||||
{
|
{
|
||||||
Compatibility compatibility{Compatibility::ANM2ED};
|
Flags flags{SERIALIZE_DEFAULT};
|
||||||
bool isBakeSpecialInterpolatedFrames{};
|
|
||||||
bool isRoundScale{true};
|
|
||||||
bool isRoundRotation{true};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FrameChange
|
struct FrameChange
|
||||||
@@ -286,13 +274,13 @@ namespace anm2ed
|
|||||||
auto operator<=>(const Reference&) const = default;
|
auto operator<=>(const Reference&) const = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
Flags flags_for(Compatibility);
|
|
||||||
Element element_make(ElementType);
|
Element element_make(ElementType);
|
||||||
Element element_read(const tinyxml2::XMLElement*);
|
Element element_read(const tinyxml2::XMLElement*);
|
||||||
std::string element_to_string(const Element&, Flags = 0);
|
std::string element_to_string(const Element&, Flags = SERIALIZE_EDITOR_DEFAULT);
|
||||||
std::string element_to_string(const Element&, ElementType, Flags = 0);
|
std::string element_to_string(const Element&, ElementType, Flags = SERIALIZE_EDITOR_DEFAULT);
|
||||||
tinyxml2::XMLElement* element_to_xml(tinyxml2::XMLDocument&, const Element&, Flags = 0);
|
tinyxml2::XMLElement* element_to_xml(tinyxml2::XMLDocument&, const Element&, Flags = SERIALIZE_EDITOR_DEFAULT);
|
||||||
tinyxml2::XMLElement* element_to_xml(tinyxml2::XMLDocument&, const Element&, ElementType, Flags = 0);
|
tinyxml2::XMLElement* element_to_xml(tinyxml2::XMLDocument&, const Element&, ElementType,
|
||||||
|
Flags = SERIALIZE_EDITOR_DEFAULT);
|
||||||
Element* element_child_first_get(Element&, ElementType);
|
Element* element_child_first_get(Element&, ElementType);
|
||||||
const Element* element_child_first_get(const Element&, ElementType);
|
const Element* element_child_first_get(const Element&, ElementType);
|
||||||
Element* element_child_id_get(Element&, ElementType, int);
|
Element* element_child_id_get(Element&, ElementType, int);
|
||||||
|
|||||||
+4
-19
@@ -28,15 +28,6 @@ using namespace glm;
|
|||||||
|
|
||||||
namespace anm2ed::document
|
namespace anm2ed::document
|
||||||
{
|
{
|
||||||
Options save_options_get(Compatibility compatibility, bool isBakeSpecialInterpolatedFrames, bool isRoundScale,
|
|
||||||
bool isRoundRotation)
|
|
||||||
{
|
|
||||||
return {.compatibility = compatibility,
|
|
||||||
.isBakeSpecialInterpolatedFrames = isBakeSpecialInterpolatedFrames,
|
|
||||||
.isRoundScale = isRoundScale,
|
|
||||||
.isRoundRotation = isRoundRotation};
|
|
||||||
}
|
|
||||||
|
|
||||||
ItemType item_type_get(int type) { return static_cast<ItemType>(type); }
|
ItemType item_type_get(int type) { return static_cast<ItemType>(type); }
|
||||||
|
|
||||||
int animation_count_get(const Anm2& data)
|
int animation_count_get(const Anm2& data)
|
||||||
@@ -321,14 +312,11 @@ namespace anm2ed
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Document::save(const std::filesystem::path& path, std::string* errorString, Compatibility compatibility,
|
bool Document::save(const std::filesystem::path& path, std::string* errorString, Options options)
|
||||||
bool isBakeSpecialInterpolatedFramesOnSave, bool isRoundScale, bool isRoundRotation)
|
|
||||||
{
|
{
|
||||||
auto absolutePath = !path.empty() ? path : this->path;
|
auto absolutePath = !path.empty() ? path : this->path;
|
||||||
auto absolutePathUtf8 = path::to_utf8(absolutePath);
|
auto absolutePathUtf8 = path::to_utf8(absolutePath);
|
||||||
if (anm2.save(absolutePath, errorString,
|
if (anm2.save(absolutePath, errorString, options))
|
||||||
document::save_options_get(compatibility, isBakeSpecialInterpolatedFramesOnSave, isRoundScale,
|
|
||||||
isRoundRotation)))
|
|
||||||
{
|
{
|
||||||
this->path = absolutePath;
|
this->path = absolutePath;
|
||||||
toasts.push(std::vformat(localize.get(TOAST_SAVE_DOCUMENT), std::make_format_args(absolutePathUtf8)));
|
toasts.push(std::vformat(localize.get(TOAST_SAVE_DOCUMENT), std::make_format_args(absolutePathUtf8)));
|
||||||
@@ -367,14 +355,11 @@ namespace anm2ed
|
|||||||
return restorePath;
|
return restorePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Document::autosave(std::string* errorString, Compatibility compatibility,
|
bool Document::autosave(std::string* errorString, Options options)
|
||||||
bool isBakeSpecialInterpolatedFramesOnSave, bool isRoundScale, bool isRoundRotation)
|
|
||||||
{
|
{
|
||||||
auto autosavePath = autosave_path_get();
|
auto autosavePath = autosave_path_get();
|
||||||
auto autosavePathUtf8 = path::to_utf8(autosavePath);
|
auto autosavePathUtf8 = path::to_utf8(autosavePath);
|
||||||
if (anm2.save(autosavePath, errorString,
|
if (anm2.save(autosavePath, errorString, options))
|
||||||
document::save_options_get(compatibility, isBakeSpecialInterpolatedFramesOnSave, isRoundScale,
|
|
||||||
isRoundRotation)))
|
|
||||||
{
|
{
|
||||||
autosaveHash = hash;
|
autosaveHash = hash;
|
||||||
lastAutosaveTime = 0.0f;
|
lastAutosaveTime = 0.0f;
|
||||||
|
|||||||
+2
-4
@@ -88,8 +88,7 @@ namespace anm2ed
|
|||||||
Document& operator=(const Document&) = delete;
|
Document& operator=(const Document&) = delete;
|
||||||
Document(Document&&) noexcept;
|
Document(Document&&) noexcept;
|
||||||
Document& operator=(Document&&) noexcept;
|
Document& operator=(Document&&) noexcept;
|
||||||
bool save(const std::filesystem::path& = {}, std::string* = nullptr, Compatibility = Compatibility::ANM2ED,
|
bool save(const std::filesystem::path& = {}, std::string* = nullptr, Options = {});
|
||||||
bool = false, bool = true, bool = true);
|
|
||||||
void anm2_change(ChangeType);
|
void anm2_change(ChangeType);
|
||||||
void assets_sync(ChangeType = ALL);
|
void assets_sync(ChangeType = ALL);
|
||||||
void texture_change(int);
|
void texture_change(int);
|
||||||
@@ -131,8 +130,7 @@ namespace anm2ed
|
|||||||
void sound_add(const std::filesystem::path&);
|
void sound_add(const std::filesystem::path&);
|
||||||
void sounds_add(const std::vector<std::filesystem::path>&);
|
void sounds_add(const std::vector<std::filesystem::path>&);
|
||||||
|
|
||||||
bool autosave(std::string* = nullptr, Compatibility = Compatibility::ANM2ED, bool = false, bool = true,
|
bool autosave(std::string* = nullptr, Options = {});
|
||||||
bool = true);
|
|
||||||
std::filesystem::path autosave_path_get();
|
std::filesystem::path autosave_path_get();
|
||||||
std::filesystem::path path_from_autosave_get(const std::filesystem::path&);
|
std::filesystem::path path_from_autosave_get(const std::filesystem::path&);
|
||||||
|
|
||||||
|
|||||||
+14
-7
@@ -17,6 +17,17 @@ using namespace anm2ed::util;
|
|||||||
|
|
||||||
namespace anm2ed::imgui
|
namespace anm2ed::imgui
|
||||||
{
|
{
|
||||||
|
Options save_options_get(const Settings& settings)
|
||||||
|
{
|
||||||
|
Flags flags{};
|
||||||
|
if (settings.fileIsSerializeGroups) flags |= SERIALIZE_GROUPS;
|
||||||
|
if (settings.fileIsSerializeRegions) flags |= SERIALIZE_REGIONS;
|
||||||
|
if (settings.fileIsSerializeSounds) flags |= SERIALIZE_SOUNDS;
|
||||||
|
if (settings.fileIsKeepRedundantFrameRegionValues) flags |= SERIALIZE_REDUNDANT_FRAME_REGION_VALUES;
|
||||||
|
if (settings.fileIsBakeSpecialInterpolatedFrames) flags |= SERIALIZE_BAKE_SPECIAL_INTERPOLATED_FRAMES;
|
||||||
|
return {.flags = flags};
|
||||||
|
}
|
||||||
|
|
||||||
void Documents::update(Taskbar& taskbar, Manager& manager, Settings& settings, Resources& resources, bool& isQuitting)
|
void Documents::update(Taskbar& taskbar, Manager& manager, Settings& settings, Resources& resources, bool& isQuitting)
|
||||||
{
|
{
|
||||||
auto viewport = ImGui::GetMainViewport();
|
auto viewport = ImGui::GetMainViewport();
|
||||||
@@ -42,14 +53,10 @@ namespace anm2ed::imgui
|
|||||||
document.lastAutosaveTime += ImGui::GetIO().DeltaTime;
|
document.lastAutosaveTime += ImGui::GetIO().DeltaTime;
|
||||||
if (document.lastAutosaveTime > time::SECOND_M)
|
if (document.lastAutosaveTime > time::SECOND_M)
|
||||||
{
|
{
|
||||||
auto compatibility = (Compatibility)settings.fileCompatibility;
|
auto options = save_options_get(settings);
|
||||||
auto bakeFrames = settings.fileBakeSpecialInterpolatedFramesOnSave;
|
|
||||||
auto isRoundScale = settings.bakeIsRoundScale;
|
|
||||||
auto isRoundRotation = settings.bakeIsRoundRotation;
|
|
||||||
manager.command_push({i,
|
manager.command_push({i,
|
||||||
[compatibility, bakeFrames, isRoundScale, isRoundRotation](Manager& manager,
|
[options](Manager& manager, Document& document)
|
||||||
Document& document)
|
{ manager.autosave(document, options); }});
|
||||||
{ manager.autosave(document, compatibility, bakeFrames, isRoundScale, isRoundRotation); }});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-81
@@ -23,30 +23,31 @@ using namespace glm;
|
|||||||
|
|
||||||
namespace anm2ed::imgui
|
namespace anm2ed::imgui
|
||||||
{
|
{
|
||||||
bool Taskbar::save_requires_special_prompt(Manager& manager, Settings& settings, int index) const
|
Options save_options_get(Settings& settings)
|
||||||
{
|
{
|
||||||
auto* document = manager.get(index);
|
Flags flags{};
|
||||||
return document && settings.fileIsSpecialInterpolatedFramesOnSaveReminder &&
|
if (settings.fileIsSerializeGroups) flags |= SERIALIZE_GROUPS;
|
||||||
document->anm2.is_special_interpolated_frames();
|
if (settings.fileIsSerializeRegions) flags |= SERIALIZE_REGIONS;
|
||||||
|
if (settings.fileIsSerializeSounds) flags |= SERIALIZE_SOUNDS;
|
||||||
|
if (settings.fileIsKeepRedundantFrameRegionValues) flags |= SERIALIZE_REDUNDANT_FRAME_REGION_VALUES;
|
||||||
|
if (settings.fileIsBakeSpecialInterpolatedFrames) flags |= SERIALIZE_BAKE_SPECIAL_INTERPOLATED_FRAMES;
|
||||||
|
return {.flags = flags};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Taskbar::save_execute(Manager& manager, Settings& settings, const PendingSave& request, bool bakeFrames)
|
bool Taskbar::save_execute(Manager& manager, Settings& settings, const PendingSave& request)
|
||||||
{
|
{
|
||||||
return manager.save(request.index, request.path, (Compatibility)settings.fileCompatibility, bakeFrames,
|
return manager.save(request.index, request.path, save_options_get(settings));
|
||||||
settings.bakeIsRoundScale, settings.bakeIsRoundRotation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Taskbar::save_enqueue(Manager& manager, Settings& settings, const PendingSave& request, bool bakeFrames)
|
void Taskbar::save_enqueue(Manager& manager, Settings& settings, const PendingSave& request)
|
||||||
{
|
{
|
||||||
auto index = request.index;
|
auto index = request.index;
|
||||||
auto path = request.path;
|
auto path = request.path;
|
||||||
auto compatibility = (Compatibility)settings.fileCompatibility;
|
auto options = save_options_get(settings);
|
||||||
auto isRoundScale = settings.bakeIsRoundScale;
|
|
||||||
auto isRoundRotation = settings.bakeIsRoundRotation;
|
|
||||||
|
|
||||||
manager.command_push({.runManager =
|
manager.command_push({.runManager =
|
||||||
[=](Manager& manager)
|
[=](Manager& manager)
|
||||||
{ manager.save(index, path, compatibility, bakeFrames, isRoundScale, isRoundRotation); }});
|
{ manager.save(index, path, options); }});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Taskbar::save_request(Manager& manager, Settings& settings, int index, const std::filesystem::path& path,
|
bool Taskbar::save_request(Manager& manager, Settings& settings, int index, const std::filesystem::path& path,
|
||||||
@@ -55,26 +56,13 @@ namespace anm2ed::imgui
|
|||||||
auto* document = manager.get(index);
|
auto* document = manager.get(index);
|
||||||
if (!document) return false;
|
if (!document) return false;
|
||||||
|
|
||||||
if (settings.fileIsSpecialInterpolatedFramesOnSaveReminder && document->anm2.is_special_interpolated_frames())
|
|
||||||
{
|
|
||||||
pendingSave = {.index = index,
|
|
||||||
.path = path,
|
|
||||||
.isOpen = true,
|
|
||||||
.disableReminder = false,
|
|
||||||
.autoBakeFrames = settings.fileBakeSpecialInterpolatedFramesOnSave,
|
|
||||||
.isQueued = isQueued};
|
|
||||||
specialInterpolatedFramesReminderPopup.open();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
PendingSave request{.index = index, .path = path};
|
PendingSave request{.index = index, .path = path};
|
||||||
auto bakeFrames = settings.fileBakeSpecialInterpolatedFramesOnSave;
|
|
||||||
if (isQueued)
|
if (isQueued)
|
||||||
{
|
{
|
||||||
save_enqueue(manager, settings, request, bakeFrames);
|
save_enqueue(manager, settings, request);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return save_execute(manager, settings, request, bakeFrames);
|
return save_execute(manager, settings, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Taskbar::save_manual(Manager& manager, Settings& settings, int index, const std::filesystem::path& path)
|
bool Taskbar::save_manual(Manager& manager, Settings& settings, int index, const std::filesystem::path& path)
|
||||||
@@ -139,9 +127,7 @@ namespace anm2ed::imgui
|
|||||||
|
|
||||||
if (ImGui::MenuItem(localize.get(BASIC_SAVE), settings.shortcutSave.c_str(), false, document))
|
if (ImGui::MenuItem(localize.get(BASIC_SAVE), settings.shortcutSave.c_str(), false, document))
|
||||||
{
|
{
|
||||||
if (save_requires_special_prompt(manager, settings, manager.selected))
|
if (settings.fileIsWarnOverwrite)
|
||||||
save_request(manager, settings, manager.selected, document->path, true);
|
|
||||||
else if (settings.fileIsWarnOverwrite)
|
|
||||||
overwritePopup.open();
|
overwritePopup.open();
|
||||||
else
|
else
|
||||||
save_request(manager, settings, manager.selected, document->path, true);
|
save_request(manager, settings, manager.selected, document->path, true);
|
||||||
@@ -334,63 +320,13 @@ namespace anm2ed::imgui
|
|||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
specialInterpolatedFramesReminderPopup.trigger();
|
|
||||||
if (ImGui::BeginPopupModal(specialInterpolatedFramesReminderPopup.label(),
|
|
||||||
&specialInterpolatedFramesReminderPopup.isOpen, ImGuiWindowFlags_NoResize))
|
|
||||||
{
|
|
||||||
ImGui::TextWrapped("%s", localize.get(LABEL_SPECIAL_INTERPOLATED_FRAMES_REMINDER_PROMPT));
|
|
||||||
ImGui::Spacing();
|
|
||||||
ImGui::Checkbox(localize.get(LABEL_DONT_NOTIFY_ME_AGAIN), &pendingSave.disableReminder);
|
|
||||||
ImGui::BeginDisabled(!pendingSave.disableReminder);
|
|
||||||
ImGui::Checkbox(localize.get(LABEL_AUTOMATICALLY_BAKE_THESE_FRAMES_ON_SAVE), &pendingSave.autoBakeFrames);
|
|
||||||
ImGui::EndDisabled();
|
|
||||||
|
|
||||||
auto widgetSize = widget_size_with_row_get(3);
|
|
||||||
if (ImGui::Button(localize.get(LABEL_SAVE_BAKE_FRAMES), widgetSize))
|
|
||||||
{
|
|
||||||
if (pendingSave.disableReminder) settings.fileIsSpecialInterpolatedFramesOnSaveReminder = false;
|
|
||||||
settings.fileBakeSpecialInterpolatedFramesOnSave = pendingSave.autoBakeFrames;
|
|
||||||
if (pendingSave.isQueued)
|
|
||||||
save_enqueue(manager, settings, pendingSave, true);
|
|
||||||
else
|
|
||||||
save_execute(manager, settings, pendingSave, true);
|
|
||||||
pendingSave = {};
|
|
||||||
specialInterpolatedFramesReminderPopup.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button(localize.get(LABEL_SAVE_DONT_BAKE_FRAMES), widgetSize))
|
|
||||||
{
|
|
||||||
if (pendingSave.disableReminder) settings.fileIsSpecialInterpolatedFramesOnSaveReminder = false;
|
|
||||||
settings.fileBakeSpecialInterpolatedFramesOnSave = pendingSave.autoBakeFrames;
|
|
||||||
if (pendingSave.isQueued)
|
|
||||||
save_enqueue(manager, settings, pendingSave, false);
|
|
||||||
else
|
|
||||||
save_execute(manager, settings, pendingSave, false);
|
|
||||||
pendingSave = {};
|
|
||||||
specialInterpolatedFramesReminderPopup.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button(localize.get(BASIC_CANCEL), widgetSize))
|
|
||||||
{
|
|
||||||
pendingSave = {};
|
|
||||||
specialInterpolatedFramesReminderPopup.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
specialInterpolatedFramesReminderPopup.end();
|
|
||||||
|
|
||||||
aboutPopup.end();
|
aboutPopup.end();
|
||||||
|
|
||||||
if (shortcut(manager.chords[SHORTCUT_NEW], shortcut::GLOBAL)) dialog.file_save(Dialog::ANM2_CREATE);
|
if (shortcut(manager.chords[SHORTCUT_NEW], shortcut::GLOBAL)) dialog.file_save(Dialog::ANM2_CREATE);
|
||||||
if (shortcut(manager.chords[SHORTCUT_OPEN], shortcut::GLOBAL)) dialog.file_open(Dialog::ANM2_OPEN, true);
|
if (shortcut(manager.chords[SHORTCUT_OPEN], shortcut::GLOBAL)) dialog.file_open(Dialog::ANM2_OPEN, true);
|
||||||
if (shortcut(manager.chords[SHORTCUT_SAVE], shortcut::GLOBAL))
|
if (shortcut(manager.chords[SHORTCUT_SAVE], shortcut::GLOBAL))
|
||||||
{
|
{
|
||||||
if (save_requires_special_prompt(manager, settings))
|
if (settings.fileIsWarnOverwrite)
|
||||||
save_request(manager, settings, manager.selected, {}, true);
|
|
||||||
else if (settings.fileIsWarnOverwrite)
|
|
||||||
overwritePopup.open();
|
overwritePopup.open();
|
||||||
else
|
else
|
||||||
save_request(manager, settings, manager.selected, {}, true);
|
save_request(manager, settings, manager.selected, {}, true);
|
||||||
|
|||||||
@@ -24,9 +24,6 @@ namespace anm2ed::imgui
|
|||||||
{
|
{
|
||||||
int index{-1};
|
int index{-1};
|
||||||
std::filesystem::path path{};
|
std::filesystem::path path{};
|
||||||
bool isOpen{};
|
|
||||||
bool disableReminder{};
|
|
||||||
bool autoBakeFrames{};
|
|
||||||
bool isQueued{};
|
bool isQueued{};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -40,18 +37,14 @@ namespace anm2ed::imgui
|
|||||||
PopupHelper generatePopup{PopupHelper(LABEL_TASKBAR_GENERATE_ANIMATION_FROM_GRID)};
|
PopupHelper generatePopup{PopupHelper(LABEL_TASKBAR_GENERATE_ANIMATION_FROM_GRID)};
|
||||||
PopupHelper changePopup{PopupHelper(LABEL_CHANGE_ALL_FRAME_PROPERTIES, imgui::POPUP_NORMAL_NO_HEIGHT)};
|
PopupHelper changePopup{PopupHelper(LABEL_CHANGE_ALL_FRAME_PROPERTIES, imgui::POPUP_NORMAL_NO_HEIGHT)};
|
||||||
PopupHelper overwritePopup{PopupHelper(LABEL_TASKBAR_OVERWRITE_FILE, imgui::POPUP_SMALL_NO_HEIGHT)};
|
PopupHelper overwritePopup{PopupHelper(LABEL_TASKBAR_OVERWRITE_FILE, imgui::POPUP_SMALL_NO_HEIGHT)};
|
||||||
PopupHelper specialInterpolatedFramesReminderPopup{
|
|
||||||
PopupHelper(LABEL_SPECIAL_INTERPOLATED_FRAMES_REMINDER_POPUP, imgui::POPUP_NORMAL_NO_HEIGHT)};
|
|
||||||
PopupHelper renderPopup{PopupHelper(LABEL_TASKBAR_RENDER_ANIMATION, imgui::POPUP_SMALL_NO_HEIGHT)};
|
PopupHelper renderPopup{PopupHelper(LABEL_TASKBAR_RENDER_ANIMATION, imgui::POPUP_SMALL_NO_HEIGHT)};
|
||||||
PopupHelper configurePopup{PopupHelper(LABEL_TASKBAR_CONFIGURE)};
|
PopupHelper configurePopup{PopupHelper(LABEL_TASKBAR_CONFIGURE)};
|
||||||
PopupHelper aboutPopup{PopupHelper(LABEL_TASKBAR_ABOUT)};
|
PopupHelper aboutPopup{PopupHelper(LABEL_TASKBAR_ABOUT)};
|
||||||
Settings editSettings{};
|
Settings editSettings{};
|
||||||
bool isQuittingMode{};
|
bool isQuittingMode{};
|
||||||
PendingSave pendingSave{};
|
|
||||||
|
|
||||||
bool save_requires_special_prompt(Manager&, Settings&, int = -1) const;
|
bool save_execute(Manager&, Settings&, const PendingSave&);
|
||||||
bool save_execute(Manager&, Settings&, const PendingSave&, bool);
|
void save_enqueue(Manager&, Settings&, const PendingSave&);
|
||||||
void save_enqueue(Manager&, Settings&, const PendingSave&, bool);
|
|
||||||
bool save_request(Manager&, Settings&, int = -1, const std::filesystem::path& = {}, bool = false);
|
bool save_request(Manager&, Settings&, int = -1, const std::filesystem::path& = {}, bool = false);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -1530,14 +1530,16 @@ namespace anm2ed::imgui
|
|||||||
ImGui::EndDragDropSource();
|
ImGui::EndDragDropSource();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isDropLineActive{};
|
||||||
|
bool isDropLineAfter{};
|
||||||
if (ImGui::BeginDragDropTarget())
|
if (ImGui::BeginDragDropTarget())
|
||||||
{
|
{
|
||||||
if (auto payload = ImGui::AcceptDragDropPayload(
|
if (auto payload = ImGui::AcceptDragDropPayload(
|
||||||
"Region Drag Drop",
|
"Region Drag Drop",
|
||||||
ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect))
|
ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect))
|
||||||
{
|
{
|
||||||
auto isDropAfter = is_drop_after(regionRowMin, regionRowMax);
|
isDropLineActive = true;
|
||||||
drop_line_draw(ImGui::GetWindowDrawList(), regionChildMin, regionChildMax, isDropAfter);
|
isDropLineAfter = is_drop_after(regionRowMin, regionRowMax);
|
||||||
|
|
||||||
auto payloadIds = (int*)(payload->Data);
|
auto payloadIds = (int*)(payload->Data);
|
||||||
int payloadCount = (int)(payload->DataSize / sizeof(int));
|
int payloadCount = (int)(payload->DataSize / sizeof(int));
|
||||||
@@ -1553,7 +1555,7 @@ namespace anm2ed::imgui
|
|||||||
{
|
{
|
||||||
std::sort(indices.begin(), indices.end());
|
std::sort(indices.begin(), indices.end());
|
||||||
auto movedIds = window.dragSelection;
|
auto movedIds = window.dragSelection;
|
||||||
auto targetIndex = i + (isDropAfter ? 1 : 0);
|
auto targetIndex = i + (isDropLineAfter ? 1 : 0);
|
||||||
auto targetSpritesheetReference = spritesheetReference;
|
auto targetSpritesheetReference = spritesheetReference;
|
||||||
manager.command_push(
|
manager.command_push(
|
||||||
{manager.selected, [&window, indices, movedIds, targetIndex,
|
{manager.selected, [&window, indices, movedIds, targetIndex,
|
||||||
@@ -1595,6 +1597,9 @@ namespace anm2ed::imgui
|
|||||||
if (isReferenced) ImGui::PushFont(resources.fonts[font::ITALICS].get(), font::SIZE);
|
if (isReferenced) ImGui::PushFont(resources.fonts[font::ITALICS].get(), font::SIZE);
|
||||||
ImGui::TextUnformatted(nameCStr);
|
ImGui::TextUnformatted(nameCStr);
|
||||||
if (isReferenced) ImGui::PopFont();
|
if (isReferenced) ImGui::PopFont();
|
||||||
|
|
||||||
|
if (isDropLineActive)
|
||||||
|
drop_line_draw(ImGui::GetWindowDrawList(), regionChildMin, regionChildMax, isDropLineAfter);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
|
|||||||
@@ -68,25 +68,23 @@ namespace anm2ed::imgui::wizard
|
|||||||
input_int_range(localize.get(LABEL_STACK_SIZE), temporary.fileSnapshotStackSize, 0, 100);
|
input_int_range(localize.get(LABEL_STACK_SIZE), temporary.fileSnapshotStackSize, 0, 100);
|
||||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_STACK_SIZE));
|
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_STACK_SIZE));
|
||||||
|
|
||||||
ImGui::SeparatorText(localize.get(LABEL_COMPATIBILITY));
|
ImGui::SeparatorText(localize.get(LABEL_SERIALIZATION));
|
||||||
ImGui::RadioButton(localize.get(LABEL_ISAAC), &temporary.fileCompatibility, ISAAC);
|
ImGui::Checkbox(localize.get(LABEL_GROUPS), &temporary.fileIsSerializeGroups);
|
||||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_COMPATIBILITY_ISAAC));
|
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_SERIALIZE_GROUPS));
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::RadioButton(localize.get(LABEL_ANM2ED), &temporary.fileCompatibility, ANM2ED);
|
ImGui::Checkbox(localize.get(LABEL_REGIONS), &temporary.fileIsSerializeRegions);
|
||||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_COMPATIBILITY_ANM2ED));
|
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_SERIALIZE_REGIONS));
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::RadioButton(localize.get(LABEL_ANM2ED_LIMITED), &temporary.fileCompatibility, ANM2ED_LIMITED);
|
ImGui::Checkbox(localize.get(LABEL_SOUNDS), &temporary.fileIsSerializeSounds);
|
||||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_COMPATIBILITY_ANM2ED_LIMITED));
|
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_SERIALIZE_SOUNDS));
|
||||||
|
|
||||||
ImGui::Checkbox(localize.get(LABEL_SPECIAL_INTERPOLATED_FRAMES_REMINDER_ON_SAVE),
|
ImGui::Checkbox(localize.get(LABEL_KEEP_REDUNDANT_FRAME_REGION_VALUES),
|
||||||
&temporary.fileIsSpecialInterpolatedFramesOnSaveReminder);
|
&temporary.fileIsKeepRedundantFrameRegionValues);
|
||||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_SPECIAL_INTERPOLATED_FRAMES_REMINDER_ON_SAVE));
|
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_KEEP_REDUNDANT_FRAME_REGION_VALUES));
|
||||||
|
|
||||||
ImGui::BeginDisabled(temporary.fileIsSpecialInterpolatedFramesOnSaveReminder);
|
|
||||||
ImGui::Checkbox(localize.get(LABEL_BAKE_SPECIAL_INTERPOLATED_FRAMES_ON_SAVE),
|
ImGui::Checkbox(localize.get(LABEL_BAKE_SPECIAL_INTERPOLATED_FRAMES_ON_SAVE),
|
||||||
&temporary.fileBakeSpecialInterpolatedFramesOnSave);
|
&temporary.fileIsBakeSpecialInterpolatedFrames);
|
||||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_BAKE_SPECIAL_INTERPOLATED_FRAMES_ON_SAVE));
|
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_BAKE_SPECIAL_INTERPOLATED_FRAMES_ON_SAVE));
|
||||||
ImGui::EndDisabled();
|
|
||||||
|
|
||||||
ImGui::SeparatorText(localize.get(LABEL_OPTIONS));
|
ImGui::SeparatorText(localize.get(LABEL_OPTIONS));
|
||||||
ImGui::Checkbox(localize.get(LABEL_OVERWRITE_WARNING), &temporary.fileIsWarnOverwrite);
|
ImGui::Checkbox(localize.get(LABEL_OVERWRITE_WARNING), &temporary.fileIsWarnOverwrite);
|
||||||
|
|||||||
+6
-11
@@ -132,8 +132,7 @@ namespace anm2ed
|
|||||||
|
|
||||||
void Manager::new_(const std::filesystem::path& path) { open(path, true); }
|
void Manager::new_(const std::filesystem::path& path) { open(path, true); }
|
||||||
|
|
||||||
bool Manager::save(int index, const std::filesystem::path& path, Compatibility compatibility,
|
bool Manager::save(int index, const std::filesystem::path& path, Options options)
|
||||||
bool isBakeSpecialInterpolatedFramesOnSave, bool isRoundScale, bool isRoundRotation)
|
|
||||||
{
|
{
|
||||||
if (auto document = get(index); document)
|
if (auto document = get(index); document)
|
||||||
{
|
{
|
||||||
@@ -143,8 +142,7 @@ namespace anm2ed
|
|||||||
savePath.replace_extension(".anm2");
|
savePath.replace_extension(".anm2");
|
||||||
ensure_parent_directory_exists(savePath);
|
ensure_parent_directory_exists(savePath);
|
||||||
|
|
||||||
if (!document->save(savePath, &errorString, compatibility, isBakeSpecialInterpolatedFramesOnSave, isRoundScale,
|
if (!document->save(savePath, &errorString, options))
|
||||||
isRoundRotation))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const auto autosavePath = document->autosave_path_get();
|
const auto autosavePath = document->autosave_path_get();
|
||||||
@@ -162,19 +160,16 @@ namespace anm2ed
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Manager::save(const std::filesystem::path& path, Compatibility compatibility,
|
bool Manager::save(const std::filesystem::path& path, Options options)
|
||||||
bool isBakeSpecialInterpolatedFramesOnSave, bool isRoundScale, bool isRoundRotation)
|
|
||||||
{
|
{
|
||||||
return save(selected, path, compatibility, isBakeSpecialInterpolatedFramesOnSave, isRoundScale, isRoundRotation);
|
return save(selected, path, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::autosave(Document& document, Compatibility compatibility, bool isBakeSpecialInterpolatedFramesOnSave,
|
void Manager::autosave(Document& document, Options options)
|
||||||
bool isRoundScale, bool isRoundRotation)
|
|
||||||
{
|
{
|
||||||
std::string errorString{};
|
std::string errorString{};
|
||||||
auto autosavePath = document.autosave_path_get();
|
auto autosavePath = document.autosave_path_get();
|
||||||
if (!document.autosave(&errorString, compatibility, isBakeSpecialInterpolatedFramesOnSave, isRoundScale,
|
if (!document.autosave(&errorString, options))
|
||||||
isRoundRotation))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
autosaveFiles.erase(std::remove(autosaveFiles.begin(), autosaveFiles.end(), autosavePath), autosaveFiles.end());
|
autosaveFiles.erase(std::remove(autosaveFiles.begin(), autosaveFiles.end(), autosavePath), autosaveFiles.end());
|
||||||
|
|||||||
+3
-5
@@ -84,11 +84,9 @@ namespace anm2ed
|
|||||||
void commands_run();
|
void commands_run();
|
||||||
Document* open(const std::filesystem::path&, bool = false, bool = true);
|
Document* open(const std::filesystem::path&, bool = false, bool = true);
|
||||||
void new_(const std::filesystem::path&);
|
void new_(const std::filesystem::path&);
|
||||||
bool save(int, const std::filesystem::path& = {}, Compatibility = Compatibility::ANM2ED, bool = false, bool = true,
|
bool save(int, const std::filesystem::path& = {}, Options = {});
|
||||||
bool = true);
|
bool save(const std::filesystem::path& = {}, Options = {});
|
||||||
bool save(const std::filesystem::path& = {}, Compatibility = Compatibility::ANM2ED, bool = false, bool = true,
|
void autosave(Document&, Options = {});
|
||||||
bool = true);
|
|
||||||
void autosave(Document&, Compatibility = Compatibility::ANM2ED, bool = false, bool = true, bool = true);
|
|
||||||
void set(int);
|
void set(int);
|
||||||
void close(int);
|
void close(int);
|
||||||
void layer_properties_open(int = -1);
|
void layer_properties_open(int = -1);
|
||||||
|
|||||||
@@ -251,15 +251,11 @@ namespace anm2ed
|
|||||||
X(LABEL_CLAMP, "Clamp", "Clamp", "Ограничить", "限制数值范围", "작업 영역 제한") \
|
X(LABEL_CLAMP, "Clamp", "Clamp", "Ограничить", "限制数值范围", "작업 영역 제한") \
|
||||||
X(LABEL_CLEAR_LIST, "Clear List", "Limpiar Lista", "Стереть список", "清除列表", "기록 삭제") \
|
X(LABEL_CLEAR_LIST, "Clear List", "Limpiar Lista", "Стереть список", "清除列表", "기록 삭제") \
|
||||||
X(LABEL_CLOSE, "Close", "Cerrar", "Закрыть", "关闭", "닫기") \
|
X(LABEL_CLOSE, "Close", "Cerrar", "Закрыть", "关闭", "닫기") \
|
||||||
X(LABEL_COMPATIBILITY, "Compatibility", "Compatibilidad", "Совместимость", "兼容性", "호환성") \
|
X(LABEL_SERIALIZATION, "Serialization", "Serialización", "Сериализация", "序列化", "직렬화") \
|
||||||
X(LABEL_SPECIAL_INTERPOLATED_FRAMES_REMINDER_ON_SAVE, "Remind me when saving a document with frames with special interpolation modes", "Recordatorio de frames con interpolación especial al guardar", "Напоминание о кадрах со специальной интерполяцией при сохранении", "保存时特殊插值帧提醒", "저장 시 특수 보간 프레임 알림") \
|
X(LABEL_GROUPS, "Groups", "Grupos", "Группы", "组", "그룹") \
|
||||||
|
X(LABEL_REGIONS, "Regions", "Regiones", "Регионы", "区域", "영역") \
|
||||||
|
X(LABEL_KEEP_REDUNDANT_FRAME_REGION_VALUES, "Keep redundant frame information for frames with regions", "Mantener información redundante en frames con regiones", "Сохранять избыточные данные кадров с регионами", "保留带区域帧的冗余信息", "영역이 있는 프레임의 중복 정보 유지") \
|
||||||
X(LABEL_BAKE_SPECIAL_INTERPOLATED_FRAMES_ON_SAVE, "Automatically bake frames with special interpolation modes", "Hornear frames con interpolación especial al guardar", "Запекать кадры со специальной интерполяцией при сохранении", "保存时烘焙特殊插值帧", "저장 시 특수 보간 프레임 베이크") \
|
X(LABEL_BAKE_SPECIAL_INTERPOLATED_FRAMES_ON_SAVE, "Automatically bake frames with special interpolation modes", "Hornear frames con interpolación especial al guardar", "Запекать кадры со специальной интерполяцией при сохранении", "保存时烘焙特殊插值帧", "저장 시 특수 보간 프레임 베이크") \
|
||||||
X(LABEL_SPECIAL_INTERPOLATED_FRAMES_REMINDER_POPUP, "Special Interpolated Frames Reminder", "Recordatorio de frames con interpolación especial", "Напоминание о кадрах со специальной интерполяцией", "特殊插值帧提醒", "특수 보간 프레임 알림") \
|
|
||||||
X(LABEL_SPECIAL_INTERPOLATED_FRAMES_REMINDER_PROMPT, "Your document includes frames with special interpolation modes. The Binding of Isaac: Rebirth does not support these special interpolation modes for frames and animations will not be rendered correctly. However, these frames can be baked to maintain the animation. Would you like to automatically bake these frames now?", "Su documento incluye frames con modos de interpolación especial. The Binding of Isaac: Rebirth no admite estos modos de interpolación especial para frames y las animaciones no se renderizarán correctamente. Sin embargo, estos frames pueden hornearse para mantener la animación. ¿Desea hornear automáticamente estos frames ahora?", "Ваш документ содержит кадры со специальными режимами интерполяции. The Binding of Isaac: Rebirth не поддерживает эти специальные режимы интерполяции для кадров, и анимации не будут отображаться корректно. Однако эти кадры можно запечь, чтобы сохранить анимацию. Хотите автоматически запечь эти кадры сейчас?", "您的文档包含使用特殊插值模式的帧。The Binding of Isaac: Rebirth 不支持这些帧的特殊插值模式,动画将无法正确渲染。不过,这些帧可以通过烘焙来保持动画效果。是否要立即自动烘焙这些帧?", "문서에 특수 보간 모드를 사용하는 프레임이 포함되어 있습니다. The Binding of Isaac: Rebirth는 이러한 프레임의 특수 보간 모드를 지원하지 않으며 애니메이션이 올바르게 렌더링되지 않습니다. 하지만 이러한 프레임은 애니메이션을 유지하도록 베이크할 수 있습니다. 지금 이 프레임들을 자동으로 베이크하시겠습니까?") \
|
|
||||||
X(LABEL_DONT_NOTIFY_ME_AGAIN, "Don't notify me again", "No volver a notificarme", "Больше не уведомлять", "不再提醒我", "다시 알리지 않기") \
|
|
||||||
X(LABEL_AUTOMATICALLY_BAKE_THESE_FRAMES_ON_SAVE, "Automatically bake these frames on save", "Hornear automáticamente estos frames al guardar", "Автоматически запекать эти кадры при сохранении", "保存时自动烘焙这些帧", "저장 시 이 프레임 자동 베이크") \
|
|
||||||
X(LABEL_SAVE_BAKE_FRAMES, "Save (Bake Frames)", "Guardar (Hornear frames)", "Сохранить (Запечь кадры)", "保存(烘焙帧)", "저장 (프레임 베이크)") \
|
|
||||||
X(LABEL_SAVE_DONT_BAKE_FRAMES, "Save (Don't Bake Frames)", "Guardar (No hornear frames)", "Сохранить (Не запекать кадры)", "保存(不烘焙帧)", "저장 (프레임을 베이크하지 않음)") \
|
|
||||||
X(LABEL_CUSTOM_RANGE, "Custom Range", "Rango Personalizado", "Пользовательский диапазон", "自定义范围", "길이 맞춤설정") \
|
X(LABEL_CUSTOM_RANGE, "Custom Range", "Rango Personalizado", "Пользовательский диапазон", "自定义范围", "길이 맞춤설정") \
|
||||||
X(LABEL_DELETE, "Delete", "Borrar", "Удалить", "删除", "삭제") \
|
X(LABEL_DELETE, "Delete", "Borrar", "Удалить", "删除", "삭제") \
|
||||||
X(LABEL_DELETE_ANIMATIONS_AFTER, "Delete Animations After", "Borrar Animaciones Despues", "Удалить анимации после", "删除之后的动画", "기존 애니메이션 삭제") \
|
X(LABEL_DELETE_ANIMATIONS_AFTER, "Delete Animations After", "Borrar Animaciones Despues", "Удалить анимации после", "删除之后的动画", "기존 애니메이션 삭제") \
|
||||||
@@ -305,9 +301,6 @@ namespace anm2ed
|
|||||||
X(LABEL_LAYERS_CHILD, "Layers List", "Lista de Capas", "", "动画层列表", "레이어 목록") \
|
X(LABEL_LAYERS_CHILD, "Layers List", "Lista de Capas", "", "动画层列表", "레이어 목록") \
|
||||||
X(LABEL_LAYERS_WINDOW, "Layers###Layers", "Capas###Layers", "Слои###Layers", "动画层###Layers", "레이어###Layers") \
|
X(LABEL_LAYERS_WINDOW, "Layers###Layers", "Capas###Layers", "Слои###Layers", "动画层###Layers", "레이어###Layers") \
|
||||||
X(LABEL_THIS_ANIMATION, "This Animation", "Esta Animacion", "Эта анимация", "此动画", "이 애니메이션") \
|
X(LABEL_THIS_ANIMATION, "This Animation", "Esta Animacion", "Эта анимация", "此动画", "이 애니메이션") \
|
||||||
X(LABEL_ISAAC, "Isaac", "Isaac", "Isaac", "Isaac", "Isaac") \
|
|
||||||
X(LABEL_ANM2ED, "Anm2Ed", "Anm2Ed", "Anm2Ed", "Anm2Ed", "Anm2Ed") \
|
|
||||||
X(LABEL_ANM2ED_LIMITED, "Anm2Ed Limited", "Anm2Ed Limitado", "Anm2Ed Ограниченный", "Anm2Ed 限制版", "Anm2Ed 제한") \
|
|
||||||
X(LABEL_DESTINATION, "Destination", "Destino", "Назначение", "目标", "대상") \
|
X(LABEL_DESTINATION, "Destination", "Destino", "Назначение", "目标", "대상") \
|
||||||
X(LABEL_ITEMS, "Items", "Items", "Предметы", "物品", "항목") \
|
X(LABEL_ITEMS, "Items", "Items", "Предметы", "物品", "항목") \
|
||||||
X(LABEL_LOCALIZATION, "Localization", "Localizacion", "Локализация", "本地化", "현지화") \
|
X(LABEL_LOCALIZATION, "Localization", "Localizacion", "Локализация", "本地化", "현지화") \
|
||||||
@@ -552,11 +545,11 @@ namespace anm2ed
|
|||||||
X(TOOLTIP_CHANGE_ALL_NULLS, "The frame property changes will apply to null frames.", "Los cambios de propiedades de frame se aplicaran a los frames null.", "Изменения свойств кадра будут применены к нулевым кадрам.", "帧属性更改将应用于 Null 帧。", "프레임 속성 변경 사항을 Null 프레임에 적용합니다.") \
|
X(TOOLTIP_CHANGE_ALL_NULLS, "The frame property changes will apply to null frames.", "Los cambios de propiedades de frame se aplicaran a los frames null.", "Изменения свойств кадра будут применены к нулевым кадрам.", "帧属性更改将应用于 Null 帧。", "프레임 속성 변경 사항을 Null 프레임에 적용합니다.") \
|
||||||
X(TOOLTIP_CENTER_VIEW, "Centers the view.", "Centra la vista.", "Центрирует вид.", "居中视角.", "미리보기 화면을 가운데에 맞춥니다.") \
|
X(TOOLTIP_CENTER_VIEW, "Centers the view.", "Centra la vista.", "Центрирует вид.", "居中视角.", "미리보기 화면을 가운데에 맞춥니다.") \
|
||||||
X(TOOLTIP_CLOSE_SETTINGS, "Close without updating settings.", "Cerrar sin actualizar las configuraciones.", "Закрыть без обновления настройки.", "关闭但不保存设置.", "설정을 갱신하지 않고 닫습니다.") \
|
X(TOOLTIP_CLOSE_SETTINGS, "Close without updating settings.", "Cerrar sin actualizar las configuraciones.", "Закрыть без обновления настройки.", "关闭但不保存设置.", "설정을 갱신하지 않고 닫습니다.") \
|
||||||
X(TOOLTIP_COMPATIBILITY_ISAAC, "Sets the output file format to that of The Binding of Isaac: Rebirth's.\nThis removes the following:\n- Sounds\n- Regions\n- Special interpolation modes\nNOTE: This will not serialize this data and it won't be able to be recovered.", "Establece el formato del archivo de salida al de The Binding of Isaac: Rebirth.\nEsto elimina lo siguiente:\n- Sonidos\n- Regiones\n- Modos especiales de interpolación\nNOTA: Estos datos no se serializaran y no podran recuperarse.", "Устанавливает формат выходного файла как у The Binding of Isaac: Rebirth.\nЭто удаляет следующее:\n- Звуки\n- Регионы\n- Специальные режимы интерполяции\nПРИМЕЧАНИЕ: Эти данные не будут сериализованы, и их нельзя будет восстановить.", "将输出文件格式设置为 The Binding of Isaac: Rebirth 的格式。\n这会移除以下内容:\n- 声音\n- 区域\n- 特殊插值模式\n注意:这些数据不会被序列化,且无法恢复。", "출력 파일 형식을 The Binding of Isaac: Rebirth의 형식으로 설정합니다.\n다음 항목이 제거됩니다:\n- 사운드\n- 영역\n- 특수 보간 모드\n참고: 이 데이터는 직렬화되지 않으며 복구할 수 없습니다.") \
|
X(TOOLTIP_SERIALIZE_GROUPS, "Serialize animation groups.\nThe Binding of Isaac: Rebirth does not support groups.", "Serializa grupos de animación.\nThe Binding of Isaac: Rebirth no admite grupos.", "Сериализует группы анимации.\nThe Binding of Isaac: Rebirth не поддерживает группы.", "序列化动画组。\nThe Binding of Isaac: Rebirth 不支持组。", "애니메이션 그룹을 직렬화합니다.\nThe Binding of Isaac: Rebirth는 그룹을 지원하지 않습니다.") \
|
||||||
X(TOOLTIP_COMPATIBILITY_ANM2ED, "Sets the output file format to that of this editor.\nAll features will be serialized, including:\n- Sounds\n- Regions\n- Special interpolation modes", "Establece el formato del archivo de salida al de este editor.\nTodas las funciones se serializaran, incluyendo:\n- Sonidos\n- Regiones\n- Modos especiales de interpolación", "Устанавливает формат выходного файла как у этого редактора.\nВсе возможности будут сериализованы, включая:\n- Звуки\n- Регионы\n- Специальные режимы интерполяции", "将输出文件格式设置为本编辑器的格式。\n所有功能都会被序列化,包括:\n- 声音\n- 区域\n- 特殊插值模式", "출력 파일 형식을 이 편집기의 형식으로 설정합니다.\n다음 기능을 포함한 모든 기능이 직렬화됩니다:\n- 사운드\n- 영역\n- 특수 보간 모드") \
|
X(TOOLTIP_SERIALIZE_REGIONS, "Serialize spritesheet regions.\nThe Binding of Isaac: Rebirth does not support regions.", "Serializa regiones de spritesheet.\nThe Binding of Isaac: Rebirth no admite regiones.", "Сериализует регионы спрайт-листа.\nThe Binding of Isaac: Rebirth не поддерживает регионы.", "序列化图集区域。\nThe Binding of Isaac: Rebirth 不支持区域。", "스프라이트 시트 영역을 직렬화합니다.\nThe Binding of Isaac: Rebirth는 영역을 지원하지 않습니다.") \
|
||||||
X(TOOLTIP_COMPATIBILITY_ANM2ED_LIMITED, "Sets the output file format to that of this editor.\nThis will additionally remove redundant Region-specific information in frames.", "Establece el formato del archivo de salida al de este editor.\nEsto ademas eliminara informacion redundante especifica de Region en los frames.", "Устанавливает формат выходного файла как у этого редактора.\nДополнительно это удалит избыточную информацию, связанную с регионами, в кадрах.", "将输出文件格式设置为本编辑器的格式。\n此外,这还会移除帧中冗余的区域专用信息。", "출력 파일 형식을 이 편집기의 형식으로 설정합니다.\n추가로 프레임 내 중복된 영역 관련 정보를 제거합니다.") \
|
X(TOOLTIP_SERIALIZE_SOUNDS, "Serialize sounds.\nThe Binding of Isaac: Rebirth does not support sounds in Anm2 files.", "Serializa sonidos.\nThe Binding of Isaac: Rebirth no admite sonidos en archivos Anm2.", "Сериализует звуки.\nThe Binding of Isaac: Rebirth не поддерживает звуки в Anm2-файлах.", "序列化声音。\nThe Binding of Isaac: Rebirth 不支持 Anm2 文件中的声音。", "사운드를 직렬화합니다.\nThe Binding of Isaac: Rebirth는 Anm2 파일의 사운드를 지원하지 않습니다.") \
|
||||||
X(TOOLTIP_SPECIAL_INTERPOLATED_FRAMES_REMINDER_ON_SAVE, "When manually saving a document with special interpolation modes, display a reminder before saving and let you choose whether to bake those frames.", "Al guardar manualmente un documento con modos de interpolación especial, mostrar un recordatorio antes de guardar y permitir elegir si se hornean esos frames.", "При ручном сохранении документа со специальными режимами интерполяции показывать напоминание перед сохранением и позволять выбрать, нужно ли запекать эти кадры.", "手动保存包含特殊插值模式的文档时,在保存前显示提醒,并允许您选择是否烘焙这些帧。", "특수 보간 모드가 있는 문서를 수동 저장할 때 저장 전에 알림을 표시하고 해당 프레임을 베이크할지 선택할 수 있습니다.") \
|
X(TOOLTIP_KEEP_REDUNDANT_FRAME_REGION_VALUES, "Keep crop, size, and pivot values on frames with regions.\nThis saves information; The Binding of Isaac: Rebirth still needs these values.", "Mantiene los valores de recorte, tamaño y pivote en frames con regiones.\nEsto guarda información; The Binding of Isaac: Rebirth todavía necesita estos valores.", "Сохраняет значения обрезки, размера и точки вращения в кадрах с регионами.\nЭто сохраняет информацию; The Binding of Isaac: Rebirth всё равно нужны эти значения.", "保留带区域帧的裁剪、大小和枢轴值。\n这会保存信息;The Binding of Isaac: Rebirth 仍然需要这些值。", "영역이 있는 프레임의 자르기, 크기, 중심점 값을 유지합니다.\n이 정보는 저장됩니다; The Binding of Isaac: Rebirth에도 이 값들이 필요합니다.") \
|
||||||
X(TOOLTIP_BAKE_SPECIAL_INTERPOLATED_FRAMES_ON_SAVE, "When saving, frames that do not use the None or Linear interpolation modes will automatically be baked in-place when saving the file.\nThe Binding of Isaac: Rebirth does not support extended interpolation features.", "Al guardar, los frames que no usen los modos de interpolación None o Linear se hornearán automáticamente en su lugar al guardar el archivo.\nThe Binding of Isaac: Rebirth no soporta funciones extendidas de interpolación.", "При сохранении кадры, которые не используют режимы интерполяции None или Linear, будут автоматически запекаться на месте при сохранении файла.\nThe Binding of Isaac: Rebirth не поддерживает расширенные возможности интерполяции.", "保存文件时,不使用 None 或 Linear 插值模式的帧将自动在保存时原地烘焙。\nThe Binding of Isaac: Rebirth 不支持扩展插值功能。", "저장할 때 None 또는 Linear 보간 모드를 사용하지 않는 프레임은 파일 저장 시 자동으로 제자리 베이크됩니다.\nThe Binding of Isaac: Rebirth는 확장 보간 기능을 지원하지 않습니다.") \
|
X(TOOLTIP_BAKE_SPECIAL_INTERPOLATED_FRAMES_ON_SAVE, "Bake frames with special interpolation modes only in the saved file.\nAnm2Ed restores them when loading, and the file works in The Binding of Isaac: Rebirth as-is.", "Hornea frames con modos de interpolación especial solo en el archivo guardado.\nAnm2Ed los restaura al cargar, y el archivo funciona en The Binding of Isaac: Rebirth tal cual.", "Запекает кадры со специальными режимами интерполяции только в сохраняемом файле.\nAnm2Ed восстанавливает их при загрузке, а файл сразу работает в The Binding of Isaac: Rebirth.", "仅在保存的文件中烘焙带特殊插值模式的帧。\nAnm2Ed 加载时会还原它们,文件可直接用于 The Binding of Isaac: Rebirth。", "저장되는 파일에서만 특수 보간 모드 프레임을 베이크합니다.\nAnm2Ed는 로드할 때 이를 복원하며, 파일은 The Binding of Isaac: Rebirth에서 그대로 작동합니다.") \
|
||||||
X(TOOLTIP_COLOR_OFFSET, "Change the color added onto the frame.", "Cambia el color añadido al Frame.", "Изменить цвет, который добавлен на кадр.", "更改覆盖在帧上的颜色.", "프레임에 더해지는 색을 변경합니다.") \
|
X(TOOLTIP_COLOR_OFFSET, "Change the color added onto the frame.", "Cambia el color añadido al Frame.", "Изменить цвет, который добавлен на кадр.", "更改覆盖在帧上的颜色.", "프레임에 더해지는 색을 변경합니다.") \
|
||||||
X(TOOLTIP_REGION, "Set the spritesheet region the frame will use.", "Establece la región del spritesheet que usará el frame.", "Установить регион спрайт-листа, который будет использовать кадр.", "设置帧将使用的图集区域.", "프레임이 사용할 스프라이트 시트 영역을 설정합니다.") \
|
X(TOOLTIP_REGION, "Set the spritesheet region the frame will use.", "Establece la región del spritesheet que usará el frame.", "Установить регион спрайт-листа, который будет использовать кадр.", "设置帧将使用的图集区域.", "프레임이 사용할 스프라이트 시트 영역을 설정합니다.") \
|
||||||
X(TOOLTIP_REGION_PROPERTIES_ORIGIN, "Use a preset origin for the region.", "Usa un origen predefinido para la región.", "Использовать предустановленную точку отсчета для региона.", "为区域使用预设原点。", "영역에 사전 설정된 원점을 사용합니다.") \
|
X(TOOLTIP_REGION_PROPERTIES_ORIGIN, "Use a preset origin for the region.", "Usa un origen predefinido para la región.", "Использовать предустановленную точку отсчета для региона.", "为区域使用预设原点。", "영역에 사전 설정된 원점을 사용합니다.") \
|
||||||
|
|||||||
+5
-5
@@ -64,12 +64,12 @@ namespace anm2ed
|
|||||||
\
|
\
|
||||||
X(FILE_IS_AUTOSAVE, fileIsAutosave, STRING_UNDEFINED, BOOL, true) \
|
X(FILE_IS_AUTOSAVE, fileIsAutosave, STRING_UNDEFINED, BOOL, true) \
|
||||||
X(FILE_IS_WARN_OVERWRITE, fileIsWarnOverwrite, STRING_UNDEFINED, BOOL, true) \
|
X(FILE_IS_WARN_OVERWRITE, fileIsWarnOverwrite, STRING_UNDEFINED, BOOL, true) \
|
||||||
X(FILE_IS_SPECIAL_INTERPOLATED_FRAMES_ON_SAVE_REMINDER, fileIsSpecialInterpolatedFramesOnSaveReminder, \
|
|
||||||
STRING_UNDEFINED, BOOL, true) \
|
|
||||||
X(FILE_BAKE_SPECIAL_INTERPOLATED_FRAMES_ON_SAVE, fileBakeSpecialInterpolatedFramesOnSave, STRING_UNDEFINED, BOOL, \
|
|
||||||
true) \
|
|
||||||
X(FILE_SNAPSHOT_STACK_SIZE, fileSnapshotStackSize, STRING_UNDEFINED, INT, 50) \
|
X(FILE_SNAPSHOT_STACK_SIZE, fileSnapshotStackSize, STRING_UNDEFINED, INT, 50) \
|
||||||
X(FILE_COMPATIBILITY, fileCompatibility, STRING_UNDEFINED, INT, ANM2ED) \
|
X(FILE_IS_SERIALIZE_GROUPS, fileIsSerializeGroups, STRING_UNDEFINED, BOOL, true) \
|
||||||
|
X(FILE_IS_SERIALIZE_REGIONS, fileIsSerializeRegions, STRING_UNDEFINED, BOOL, true) \
|
||||||
|
X(FILE_IS_SERIALIZE_SOUNDS, fileIsSerializeSounds, STRING_UNDEFINED, BOOL, true) \
|
||||||
|
X(FILE_IS_KEEP_REDUNDANT_FRAME_REGION_VALUES, fileIsKeepRedundantFrameRegionValues, STRING_UNDEFINED, BOOL, true) \
|
||||||
|
X(FILE_IS_BAKE_SPECIAL_INTERPOLATED_FRAMES, fileIsBakeSpecialInterpolatedFrames, STRING_UNDEFINED, BOOL, true) \
|
||||||
\
|
\
|
||||||
X(KEYBOARD_REPEAT_DELAY, keyboardRepeatDelay, STRING_UNDEFINED, FLOAT, 0.300f) \
|
X(KEYBOARD_REPEAT_DELAY, keyboardRepeatDelay, STRING_UNDEFINED, FLOAT, 0.300f) \
|
||||||
X(KEYBOARD_REPEAT_RATE, keyboardRepeatRate, STRING_UNDEFINED, FLOAT, 0.050f) \
|
X(KEYBOARD_REPEAT_RATE, keyboardRepeatRate, STRING_UNDEFINED, FLOAT, 0.050f) \
|
||||||
|
|||||||
@@ -53,6 +53,6 @@ Alternatively, if you have subscribed to the mod, you can find the latest releas
|
|||||||
[h3]Happy animating![/h3]
|
[h3]Happy animating![/h3]
|
||||||
[img]https://files.catbox.moe/4auc1c.gif[/img]
|
[img]https://files.catbox.moe/4auc1c.gif[/img]
|
||||||
</description>
|
</description>
|
||||||
<version>2.21</version>
|
<version>2.22</version>
|
||||||
<visibility>Public</visibility>
|
<visibility>Public</visibility>
|
||||||
</metadata>
|
</metadata>
|
||||||
|
|||||||
Reference in New Issue
Block a user