regions and a whole bunch of other shit
This commit is contained in:
@@ -147,7 +147,7 @@ else()
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic -O0 -pg)
|
||||
else()
|
||||
set(CMAKE_BUILD_TYPE "Release")
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic -O2)
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic -O3)
|
||||
endif()
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE m)
|
||||
endif()
|
||||
|
||||
@@ -16,6 +16,37 @@ using namespace anm2ed::types;
|
||||
using namespace anm2ed::util;
|
||||
using namespace glm;
|
||||
|
||||
namespace
|
||||
{
|
||||
void region_frames_sync(anm2ed::anm2::Anm2& anm2, bool clearInvalid)
|
||||
{
|
||||
for (auto& animation : anm2.animations.items)
|
||||
{
|
||||
for (auto& [layerId, layerAnimation] : animation.layerAnimations)
|
||||
{
|
||||
if (!anm2.content.layers.contains(layerId)) continue;
|
||||
auto& layer = anm2.content.layers.at(layerId);
|
||||
auto spritesheet = anm2.spritesheet_get(layer.spritesheetID);
|
||||
if (!spritesheet) continue;
|
||||
|
||||
for (auto& frame : layerAnimation.frames)
|
||||
{
|
||||
if (frame.regionID == -1) continue;
|
||||
auto regionIt = spritesheet->regions.find(frame.regionID);
|
||||
if (regionIt == spritesheet->regions.end())
|
||||
{
|
||||
if (clearInvalid) frame.regionID = -1;
|
||||
continue;
|
||||
}
|
||||
frame.crop = regionIt->second.crop;
|
||||
frame.size = regionIt->second.size;
|
||||
frame.pivot = regionIt->second.pivot;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace anm2ed::anm2
|
||||
{
|
||||
Anm2::Anm2() { info.createdOn = time::get("%m/%d/%Y %I:%M:%S %p"); }
|
||||
@@ -47,10 +78,13 @@ namespace anm2ed::anm2
|
||||
if (auto contentElement = element->FirstChildElement("Content")) content = Content((XMLElement*)contentElement);
|
||||
if (auto animationsElement = element->FirstChildElement("Animations"))
|
||||
animations = Animations((XMLElement*)animationsElement);
|
||||
|
||||
region_frames_sync(*this, true);
|
||||
}
|
||||
|
||||
XMLElement* Anm2::to_element(XMLDocument& document)
|
||||
{
|
||||
region_frames_sync(*this, true);
|
||||
auto element = document.NewElement("AnimatedActor");
|
||||
|
||||
info.serialize(document, element);
|
||||
|
||||
@@ -44,6 +44,9 @@ namespace anm2ed::anm2
|
||||
std::set<int> spritesheets_unused();
|
||||
bool spritesheets_deserialize(const std::string&, const std::filesystem::path&, types::merge::Type type,
|
||||
std::string*);
|
||||
std::vector<std::string> region_labels_get(Spritesheet&);
|
||||
std::vector<int> region_ids_get(Spritesheet&);
|
||||
std::set<int> regions_unused(Spritesheet&);
|
||||
|
||||
void layer_add(int&);
|
||||
std::set<int> layers_unused();
|
||||
@@ -75,7 +78,8 @@ namespace anm2ed::anm2
|
||||
Item* item_get(int, Type, int = -1);
|
||||
Reference layer_animation_add(Reference = {}, std::string = {}, int = 0,
|
||||
types::destination::Type = types::destination::ALL);
|
||||
Reference null_animation_add(Reference = {}, std::string = {}, bool = false, types::destination::Type = types::destination::ALL);
|
||||
Reference null_animation_add(Reference = {}, std::string = {}, bool = false,
|
||||
types::destination::Type = types::destination::ALL);
|
||||
|
||||
Frame* frame_get(int, Type, int, int = -1);
|
||||
void merge(const Anm2&, const std::filesystem::path&, const std::filesystem::path&);
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace anm2ed::anm2
|
||||
std::vector<std::string> Anm2::event_labels_get()
|
||||
{
|
||||
std::vector<std::string> labels{};
|
||||
labels.emplace_back("None");
|
||||
labels.emplace_back(localize.get(BASIC_NONE));
|
||||
for (auto& event : content.events | std::views::values)
|
||||
labels.emplace_back(event.name);
|
||||
return labels;
|
||||
@@ -40,7 +40,7 @@ namespace anm2ed::anm2
|
||||
|
||||
for (auto& animation : animations.items)
|
||||
for (auto& frame : animation.triggers.frames)
|
||||
used.insert(frame.eventID);
|
||||
if (frame.eventID != -1) used.insert(frame.eventID);
|
||||
|
||||
std::set<int> unused{};
|
||||
for (auto& id : content.events | std::views::keys)
|
||||
|
||||
@@ -55,6 +55,44 @@ namespace anm2ed::anm2
|
||||
return ids;
|
||||
}
|
||||
|
||||
std::vector<std::string> Anm2::region_labels_get(Spritesheet& spritesheet)
|
||||
{
|
||||
std::vector<std::string> labels{};
|
||||
labels.emplace_back(localize.get(BASIC_NONE));
|
||||
for (auto& region : spritesheet.regions | std::views::values)
|
||||
labels.emplace_back(region.name);
|
||||
return labels;
|
||||
}
|
||||
|
||||
std::vector<int> Anm2::region_ids_get(Spritesheet& spritesheet)
|
||||
{
|
||||
std::vector<int> ids{};
|
||||
ids.emplace_back(-1);
|
||||
for (auto& id : spritesheet.regions | std::views::keys)
|
||||
ids.emplace_back(id);
|
||||
return ids;
|
||||
}
|
||||
|
||||
std::set<int> Anm2::regions_unused(Spritesheet& spritesheet)
|
||||
{
|
||||
std::set<int> used{};
|
||||
|
||||
for (auto& animation : animations.items)
|
||||
{
|
||||
for (auto& layerAnimation : animation.layerAnimations | std::views::values)
|
||||
{
|
||||
for (auto& frame : layerAnimation.frames)
|
||||
if (frame.regionID != -1) used.insert(frame.regionID);
|
||||
}
|
||||
}
|
||||
|
||||
std::set<int> unused{};
|
||||
for (auto& id : spritesheet.regions | std::views::keys)
|
||||
if (!used.contains(id)) unused.insert(id);
|
||||
|
||||
return unused;
|
||||
}
|
||||
|
||||
bool Anm2::spritesheets_deserialize(const std::string& string, const std::filesystem::path& directory,
|
||||
merge::Type type, std::string* errorString)
|
||||
{
|
||||
|
||||
@@ -10,19 +10,12 @@ namespace anm2ed::anm2
|
||||
{
|
||||
Frame::Frame(XMLElement* element, Type type)
|
||||
{
|
||||
if (type != TRIGGER)
|
||||
switch (type)
|
||||
{
|
||||
case ROOT:
|
||||
case NULL_:
|
||||
element->QueryFloatAttribute("XPosition", &position.x);
|
||||
element->QueryFloatAttribute("YPosition", &position.y);
|
||||
if (type == LAYER)
|
||||
{
|
||||
element->QueryFloatAttribute("XPivot", &pivot.x);
|
||||
element->QueryFloatAttribute("YPivot", &pivot.y);
|
||||
element->QueryFloatAttribute("XCrop", &crop.x);
|
||||
element->QueryFloatAttribute("YCrop", &crop.y);
|
||||
element->QueryFloatAttribute("Width", &size.x);
|
||||
element->QueryFloatAttribute("Height", &size.y);
|
||||
}
|
||||
element->QueryFloatAttribute("XScale", &scale.x);
|
||||
element->QueryFloatAttribute("YScale", &scale.y);
|
||||
element->QueryIntAttribute("Delay", &duration);
|
||||
@@ -36,8 +29,32 @@ namespace anm2ed::anm2
|
||||
xml::query_color_attribute(element, "BlueOffset", colorOffset.b);
|
||||
element->QueryFloatAttribute("Rotation", &rotation);
|
||||
element->QueryBoolAttribute("Interpolated", &isInterpolated);
|
||||
}
|
||||
else
|
||||
break;
|
||||
case LAYER:
|
||||
element->QueryIntAttribute("RegionId", ®ionID);
|
||||
element->QueryFloatAttribute("XPosition", &position.x);
|
||||
element->QueryFloatAttribute("YPosition", &position.y);
|
||||
element->QueryFloatAttribute("XPivot", &pivot.x);
|
||||
element->QueryFloatAttribute("YPivot", &pivot.y);
|
||||
element->QueryFloatAttribute("XCrop", &crop.x);
|
||||
element->QueryFloatAttribute("YCrop", &crop.y);
|
||||
element->QueryFloatAttribute("Width", &size.x);
|
||||
element->QueryFloatAttribute("Height", &size.y);
|
||||
element->QueryFloatAttribute("XScale", &scale.x);
|
||||
element->QueryFloatAttribute("YScale", &scale.y);
|
||||
element->QueryIntAttribute("Delay", &duration);
|
||||
element->QueryBoolAttribute("Visible", &isVisible);
|
||||
xml::query_color_attribute(element, "RedTint", tint.r);
|
||||
xml::query_color_attribute(element, "GreenTint", tint.g);
|
||||
xml::query_color_attribute(element, "BlueTint", tint.b);
|
||||
xml::query_color_attribute(element, "AlphaTint", tint.a);
|
||||
xml::query_color_attribute(element, "RedOffset", colorOffset.r);
|
||||
xml::query_color_attribute(element, "GreenOffset", colorOffset.g);
|
||||
xml::query_color_attribute(element, "BlueOffset", colorOffset.b);
|
||||
element->QueryFloatAttribute("Rotation", &rotation);
|
||||
element->QueryBoolAttribute("Interpolated", &isInterpolated);
|
||||
break;
|
||||
case TRIGGER:
|
||||
{
|
||||
element->QueryIntAttribute("EventId", &eventID);
|
||||
|
||||
@@ -52,6 +69,10 @@ namespace anm2ed::anm2
|
||||
}
|
||||
|
||||
element->QueryIntAttribute("AtFrame", &atFrame);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,6 +101,7 @@ namespace anm2ed::anm2
|
||||
element->SetAttribute("Interpolated", isInterpolated);
|
||||
break;
|
||||
case LAYER:
|
||||
if (regionID != -1) element->SetAttribute("RegionId", regionID);
|
||||
element->SetAttribute("XPosition", position.x);
|
||||
element->SetAttribute("YPosition", position.y);
|
||||
element->SetAttribute("XPivot", pivot.x);
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace anm2ed::anm2
|
||||
int duration{FRAME_DURATION_MIN};
|
||||
int atFrame{-1};
|
||||
int eventID{-1};
|
||||
int regionID{-1};
|
||||
std::vector<int> soundIDs{};
|
||||
glm::vec2 pivot{};
|
||||
glm::vec2 crop{};
|
||||
@@ -45,6 +46,7 @@ namespace anm2ed::anm2
|
||||
std::optional<bool> isInterpolated{};
|
||||
std::optional<float> rotation{};
|
||||
std::optional<int> duration{};
|
||||
std::optional<int> regionID{};
|
||||
std::optional<float> pivotX{};
|
||||
std::optional<float> pivotY{};
|
||||
std::optional<float> cropX{};
|
||||
|
||||
@@ -186,6 +186,8 @@ namespace anm2ed::anm2
|
||||
|
||||
apply_scalar(frame.size.x, change.sizeX);
|
||||
apply_scalar(frame.size.y, change.sizeY);
|
||||
|
||||
if (change.regionID) frame.regionID = *change.regionID;
|
||||
}
|
||||
|
||||
apply_scalar(frame.position.x, change.positionX);
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
#include "spritesheet.h"
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include "path_.h"
|
||||
#include "working_directory.h"
|
||||
#include "xml_.h"
|
||||
#include "map_.h"
|
||||
|
||||
using namespace anm2ed::resource;
|
||||
using namespace anm2ed::util;
|
||||
using namespace anm2ed::types;
|
||||
using namespace tinyxml2;
|
||||
|
||||
namespace anm2ed::anm2
|
||||
@@ -20,6 +24,21 @@ namespace anm2ed::anm2
|
||||
// This will handle this case and make the paths OS-agnostic
|
||||
path = path::lower_case_backslash_handle(path);
|
||||
texture = Texture(path);
|
||||
|
||||
for (auto child = element->FirstChildElement("Region"); child; child = child->NextSiblingElement("Region"))
|
||||
{
|
||||
Region region{};
|
||||
int id{};
|
||||
child->QueryIntAttribute("Id", &id);
|
||||
xml::query_string_attribute(child, "Name", ®ion.name);
|
||||
child->QueryFloatAttribute("CropX", ®ion.crop.x);
|
||||
child->QueryFloatAttribute("CropY", ®ion.crop.y);
|
||||
child->QueryFloatAttribute("PivotX", ®ion.pivot.x);
|
||||
child->QueryFloatAttribute("PivotY", ®ion.pivot.y);
|
||||
child->QueryFloatAttribute("Width", ®ion.size.x);
|
||||
child->QueryFloatAttribute("Height", ®ion.size.y);
|
||||
regions.emplace(id, std::move(region));
|
||||
}
|
||||
}
|
||||
|
||||
Spritesheet::Spritesheet(const std::filesystem::path& directory, const std::filesystem::path& path)
|
||||
@@ -36,6 +55,20 @@ namespace anm2ed::anm2
|
||||
element->SetAttribute("Id", id);
|
||||
auto pathString = path::to_utf8(path);
|
||||
element->SetAttribute("Path", pathString.c_str());
|
||||
|
||||
for (auto [i, region] : regions)
|
||||
{
|
||||
auto regionElement = element->InsertNewChildElement("Region");
|
||||
regionElement->SetAttribute("Id", i);
|
||||
regionElement->SetAttribute("Name", region.name.c_str());
|
||||
regionElement->SetAttribute("CropX", region.crop.x);
|
||||
regionElement->SetAttribute("CropY", region.crop.y);
|
||||
regionElement->SetAttribute("PivotX", region.pivot.x);
|
||||
regionElement->SetAttribute("PivotY", region.pivot.y);
|
||||
regionElement->SetAttribute("Width", region.size.x);
|
||||
regionElement->SetAttribute("Height", region.size.y);
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
@@ -51,6 +84,64 @@ namespace anm2ed::anm2
|
||||
return xml::document_to_string(document);
|
||||
}
|
||||
|
||||
std::string Spritesheet::region_to_string(int id)
|
||||
{
|
||||
if (!regions.contains(id)) return {};
|
||||
|
||||
XMLDocument document{};
|
||||
auto element = document.NewElement("Region");
|
||||
auto& region = regions.at(id);
|
||||
element->SetAttribute("Id", id);
|
||||
element->SetAttribute("Name", region.name.c_str());
|
||||
element->SetAttribute("CropX", region.crop.x);
|
||||
element->SetAttribute("CropY", region.crop.y);
|
||||
element->SetAttribute("PivotX", region.pivot.x);
|
||||
element->SetAttribute("PivotY", region.pivot.y);
|
||||
element->SetAttribute("Width", region.size.x);
|
||||
element->SetAttribute("Height", region.size.y);
|
||||
document.InsertEndChild(element);
|
||||
|
||||
return xml::document_to_string(document);
|
||||
}
|
||||
|
||||
bool Spritesheet::regions_deserialize(const std::string& string, merge::Type type, std::string* errorString)
|
||||
{
|
||||
XMLDocument document{};
|
||||
|
||||
if (document.Parse(string.c_str()) == XML_SUCCESS)
|
||||
{
|
||||
int id{};
|
||||
|
||||
if (!document.FirstChildElement("Region"))
|
||||
{
|
||||
if (errorString) *errorString = "No valid region(s).";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto element = document.FirstChildElement("Region"); element; element = element->NextSiblingElement("Region"))
|
||||
{
|
||||
Region region{};
|
||||
element->QueryIntAttribute("Id", &id);
|
||||
xml::query_string_attribute(element, "Name", ®ion.name);
|
||||
element->QueryFloatAttribute("CropX", ®ion.crop.x);
|
||||
element->QueryFloatAttribute("CropY", ®ion.crop.y);
|
||||
element->QueryFloatAttribute("PivotX", ®ion.pivot.x);
|
||||
element->QueryFloatAttribute("PivotY", ®ion.pivot.y);
|
||||
element->QueryFloatAttribute("Width", ®ion.size.x);
|
||||
element->QueryFloatAttribute("Height", ®ion.size.y);
|
||||
|
||||
if (type == merge::APPEND) id = map::next_id_get(regions);
|
||||
regions[id] = std::move(region);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (errorString)
|
||||
*errorString = document.ErrorStr();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Spritesheet::save(const std::filesystem::path& directory, const std::filesystem::path& path)
|
||||
{
|
||||
WorkingDirectory workingDirectory(directory);
|
||||
@@ -59,7 +150,6 @@ namespace anm2ed::anm2
|
||||
}
|
||||
|
||||
void Spritesheet::reload(const std::filesystem::path& directory) { *this = Spritesheet(directory, this->path); }
|
||||
|
||||
bool Spritesheet::is_valid() { return texture.is_valid(); }
|
||||
|
||||
}
|
||||
|
||||
@@ -1,24 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <tinyxml2/tinyxml2.h>
|
||||
|
||||
#include "texture.h"
|
||||
#include "types.h"
|
||||
|
||||
namespace anm2ed::anm2
|
||||
{
|
||||
class Spritesheet
|
||||
{
|
||||
public:
|
||||
struct Region
|
||||
{
|
||||
std::string name{};
|
||||
glm::vec2 crop{};
|
||||
glm::vec2 pivot{};
|
||||
glm::vec2 size{};
|
||||
};
|
||||
|
||||
std::filesystem::path path{};
|
||||
resource::Texture texture;
|
||||
|
||||
std::map<int, Region> regions{};
|
||||
|
||||
Spritesheet() = default;
|
||||
Spritesheet(tinyxml2::XMLElement*, int&);
|
||||
Spritesheet(const std::filesystem::path&, const std::filesystem::path& = {});
|
||||
tinyxml2::XMLElement* to_element(tinyxml2::XMLDocument&, int);
|
||||
std::string to_string(int id);
|
||||
std::string region_to_string(int id);
|
||||
bool regions_deserialize(const std::string&, types::merge::Type, std::string* = nullptr);
|
||||
bool save(const std::filesystem::path&, const std::filesystem::path& = {});
|
||||
void serialize(tinyxml2::XMLDocument&, tinyxml2::XMLElement*, int);
|
||||
void reload(const std::filesystem::path&);
|
||||
|
||||
@@ -58,9 +58,10 @@ namespace anm2ed
|
||||
|
||||
Document::Document(Document&& other) noexcept
|
||||
: path(std::move(other.path)), snapshots(std::move(other.snapshots)), current(snapshots.current),
|
||||
anm2(current.anm2), reference(current.reference), playback(current.playback), animation(current.animation),
|
||||
merge(current.merge), event(current.event), layer(current.layer), null(current.null), sound(current.sound),
|
||||
spritesheet(current.spritesheet), frames(current.frames), message(current.message),
|
||||
playback(current.playback), animation(current.animation), event(current.event), frames(current.frames),
|
||||
items(current.items), layer(current.layer), merge(current.merge), null(current.null), region(current.region),
|
||||
sound(current.sound), spritesheet(current.spritesheet), anm2(current.anm2), reference(current.reference),
|
||||
frameTime(current.frameTime), message(current.message), regionBySpritesheet(std::move(other.regionBySpritesheet)),
|
||||
previewZoom(other.previewZoom), previewPan(other.previewPan), editorPan(other.editorPan),
|
||||
editorZoom(other.editorZoom), overlayIndex(other.overlayIndex), hash(other.hash), saveHash(other.saveHash),
|
||||
autosaveHash(other.autosaveHash), lastAutosaveTime(other.lastAutosaveTime), isValid(other.isValid),
|
||||
@@ -80,6 +81,7 @@ namespace anm2ed
|
||||
editorPan = other.editorPan;
|
||||
editorZoom = other.editorZoom;
|
||||
overlayIndex = other.overlayIndex;
|
||||
regionBySpritesheet = std::move(other.regionBySpritesheet);
|
||||
hash = other.hash;
|
||||
saveHash = other.saveHash;
|
||||
autosaveHash = other.autosaveHash;
|
||||
@@ -183,6 +185,17 @@ namespace anm2ed
|
||||
|
||||
auto sounds_set = [&]() { sound.labels_set(anm2.sound_labels_get(), anm2.sound_ids_get()); };
|
||||
|
||||
auto regions_set = [&]()
|
||||
{
|
||||
regionBySpritesheet.clear();
|
||||
for (auto& [id, spritesheet] : anm2.content.spritesheets)
|
||||
{
|
||||
Storage storage{};
|
||||
storage.labels_set(anm2.region_labels_get(spritesheet), anm2.region_ids_get(spritesheet));
|
||||
regionBySpritesheet.emplace(id, std::move(storage));
|
||||
}
|
||||
};
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case LAYERS:
|
||||
@@ -194,6 +207,7 @@ namespace anm2ed
|
||||
break;
|
||||
case SPRITESHEETS:
|
||||
spritesheets_set();
|
||||
regions_set();
|
||||
break;
|
||||
case SOUNDS:
|
||||
sounds_set();
|
||||
@@ -209,6 +223,7 @@ namespace anm2ed
|
||||
case ALL:
|
||||
events_set();
|
||||
spritesheets_set();
|
||||
regions_set();
|
||||
animations_set();
|
||||
sounds_set();
|
||||
break;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <map>
|
||||
|
||||
#include "snapshots.h"
|
||||
|
||||
@@ -33,20 +34,22 @@ namespace anm2ed
|
||||
Snapshots snapshots{};
|
||||
Snapshot& current = snapshots.current;
|
||||
|
||||
Playback& playback = current.playback;
|
||||
Storage& animation = current.animation;
|
||||
Storage& event = current.event;
|
||||
Storage& frames = current.frames;
|
||||
Storage& items = current.items;
|
||||
Storage& layer = current.layer;
|
||||
Storage& merge = current.merge;
|
||||
Storage& null = current.null;
|
||||
Storage& region = current.region;
|
||||
Storage& sound = current.sound;
|
||||
Storage& spritesheet = current.spritesheet;
|
||||
anm2::Anm2& anm2 = current.anm2;
|
||||
anm2::Reference& reference = current.reference;
|
||||
float& frameTime = current.frameTime;
|
||||
Playback& playback = current.playback;
|
||||
Storage& animation = current.animation;
|
||||
Storage& merge = current.merge;
|
||||
Storage& event = current.event;
|
||||
Storage& layer = current.layer;
|
||||
Storage& null = current.null;
|
||||
Storage& sound = current.sound;
|
||||
Storage& spritesheet = current.spritesheet;
|
||||
Storage& items = current.items;
|
||||
Storage& frames = current.frames;
|
||||
std::string& message = current.message;
|
||||
std::map<int, Storage> regionBySpritesheet{};
|
||||
|
||||
float previewZoom{200};
|
||||
glm::vec2 previewPan{};
|
||||
|
||||
@@ -31,6 +31,7 @@ namespace anm2ed::imgui
|
||||
{
|
||||
if (settings.windowIsAnimationPreview) animationPreview.update(manager, settings, resources);
|
||||
if (settings.windowIsAnimations) animations.update(manager, settings, resources, clipboard);
|
||||
if (settings.windowIsRegions) regions.update(manager, settings, resources, clipboard);
|
||||
if (settings.windowIsEvents) events.update(manager, settings, resources, clipboard);
|
||||
if (settings.windowIsFrameProperties) frameProperties.update(manager, settings);
|
||||
if (settings.windowIsLayers) layers.update(manager, settings, resources, clipboard);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "taskbar.h"
|
||||
#include "window/animation_preview.h"
|
||||
#include "window/animations.h"
|
||||
#include "window/regions.h"
|
||||
#include "window/events.h"
|
||||
#include "window/frame_properties.h"
|
||||
#include "window/layers.h"
|
||||
@@ -22,6 +23,7 @@ namespace anm2ed::imgui
|
||||
{
|
||||
AnimationPreview animationPreview;
|
||||
Animations animations;
|
||||
Regions regions;
|
||||
Events events;
|
||||
FrameProperties frameProperties;
|
||||
Layers layers;
|
||||
|
||||
@@ -562,12 +562,26 @@ namespace anm2ed::imgui
|
||||
auto texSize = vec2(texture.size);
|
||||
if (texSize.x <= 0.0f || texSize.y <= 0.0f) return;
|
||||
|
||||
auto layerModel = math::quad_model_get(frame.size, frame.position, frame.pivot,
|
||||
auto crop = frame.crop;
|
||||
auto size = frame.size;
|
||||
auto pivot = frame.pivot;
|
||||
if (frame.regionID != -1)
|
||||
{
|
||||
auto regionIt = spritesheet->regions.find(frame.regionID);
|
||||
if (regionIt != spritesheet->regions.end())
|
||||
{
|
||||
crop = regionIt->second.crop;
|
||||
size = regionIt->second.size;
|
||||
pivot = regionIt->second.pivot;
|
||||
}
|
||||
}
|
||||
|
||||
auto layerModel = math::quad_model_get(size, frame.position, pivot,
|
||||
math::percent_to_unit(frame.scale), frame.rotation);
|
||||
auto layerTransform = sampleTransform * layerModel;
|
||||
|
||||
auto uvMin = frame.crop / texSize;
|
||||
auto uvMax = (frame.crop + frame.size) / texSize;
|
||||
auto uvMin = crop / texSize;
|
||||
auto uvMax = (crop + size) / texSize;
|
||||
|
||||
vec3 frameColorOffset = frame.colorOffset + colorOffset + sampleColor;
|
||||
vec4 frameTint = frame.tint;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <limits>
|
||||
#include <ranges>
|
||||
#include <vector>
|
||||
|
||||
#include "math_.h"
|
||||
#include "strings.h"
|
||||
@@ -21,6 +22,21 @@ namespace anm2ed::imgui
|
||||
auto& document = *manager.get();
|
||||
auto& frames = document.frames.selection;
|
||||
auto& type = document.reference.itemType;
|
||||
auto regionLabelsString = std::vector<std::string>{localize.get(BASIC_NONE)};
|
||||
auto regionLabels = std::vector<const char*>{regionLabelsString[0].c_str()};
|
||||
auto regionIds = std::vector<int>{-1};
|
||||
|
||||
if (type == anm2::LAYER && document.reference.itemID != -1)
|
||||
{
|
||||
auto spritesheetID = document.anm2.content.layers.at(document.reference.itemID).spritesheetID;
|
||||
auto regionIt = document.regionBySpritesheet.find(spritesheetID);
|
||||
if (regionIt != document.regionBySpritesheet.end() && !regionIt->second.ids.empty() &&
|
||||
!regionIt->second.labels.empty())
|
||||
{
|
||||
regionLabels = regionIt->second.labels;
|
||||
regionIds = regionIt->second.ids;
|
||||
}
|
||||
}
|
||||
|
||||
if (frames.size() <= 1)
|
||||
{
|
||||
@@ -93,7 +109,8 @@ namespace anm2ed::imgui
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::BeginDisabled(type == anm2::ROOT || type == anm2::NULL_);
|
||||
bool isRegionSet = frame && frame->regionID != -1;
|
||||
ImGui::BeginDisabled(type == anm2::ROOT || type == anm2::NULL_ || isRegionSet);
|
||||
{
|
||||
auto cropEdit =
|
||||
drag_float2_persistent(localize.get(BASIC_CROP), frame ? &frame->crop : &dummy_value<vec2>(),
|
||||
@@ -124,7 +141,7 @@ namespace anm2ed::imgui
|
||||
document.change(Document::FRAMES);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_POSITION));
|
||||
|
||||
ImGui::BeginDisabled(type == anm2::ROOT || type == anm2::NULL_);
|
||||
ImGui::BeginDisabled(type == anm2::ROOT || type == anm2::NULL_ || isRegionSet);
|
||||
{
|
||||
auto pivotEdit =
|
||||
drag_float2_persistent(localize.get(BASIC_PIVOT), frame ? &frame->pivot : &dummy_value<vec2>(),
|
||||
@@ -179,6 +196,15 @@ namespace anm2ed::imgui
|
||||
else if (colorOffsetEdit == edit::END)
|
||||
document.change(Document::FRAMES);
|
||||
|
||||
ImGui::BeginDisabled(type != anm2::LAYER);
|
||||
if (combo_id_mapped(localize.get(BASIC_REGION), frame ? &useFrame.regionID : &dummy_value_negative<int>(),
|
||||
regionIds, regionLabels) &&
|
||||
frame)
|
||||
DOCUMENT_EDIT(document, localize.get(EDIT_SET_REGION_PROPERTIES), Document::FRAMES,
|
||||
frame->regionID = useFrame.regionID);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_REGION));
|
||||
ImGui::EndDisabled();
|
||||
|
||||
if (ImGui::Checkbox(localize.get(BASIC_VISIBLE), frame ? &useFrame.isVisible : &dummy_value<bool>()) &&
|
||||
frame)
|
||||
DOCUMENT_EDIT(document, localize.get(EDIT_FRAME_VISIBILITY), Document::FRAMES,
|
||||
|
||||
363
src/imgui/window/regions.cpp
Normal file
363
src/imgui/window/regions.cpp
Normal file
@@ -0,0 +1,363 @@
|
||||
#include "regions.h"
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include <filesystem>
|
||||
#include <format>
|
||||
|
||||
#include "document.h"
|
||||
#include "log.h"
|
||||
#include "map_.h"
|
||||
#include "math_.h"
|
||||
#include "path_.h"
|
||||
#include "strings.h"
|
||||
#include "toast.h"
|
||||
|
||||
#include "../../util/map_.h"
|
||||
|
||||
using namespace anm2ed::types;
|
||||
using namespace anm2ed::resource;
|
||||
using namespace anm2ed::util;
|
||||
using namespace glm;
|
||||
|
||||
namespace anm2ed::imgui
|
||||
{
|
||||
void Regions::update(Manager& manager, Settings& settings, Resources& resources, Clipboard& clipboard)
|
||||
{
|
||||
auto& document = *manager.get();
|
||||
auto& anm2 = document.anm2;
|
||||
auto& selection = document.region.selection;
|
||||
auto& frame = document.frames;
|
||||
auto& spritesheetReference = document.spritesheet.reference;
|
||||
auto& reference = document.region.reference;
|
||||
auto style = ImGui::GetStyle();
|
||||
|
||||
auto spritesheet = map::find(anm2.content.spritesheets, spritesheetReference);
|
||||
|
||||
auto remove_unused = [&]()
|
||||
{
|
||||
if (!spritesheet) return;
|
||||
|
||||
auto unused = anm2.regions_unused(*spritesheet);
|
||||
if (unused.empty()) return;
|
||||
|
||||
auto behavior = [&]()
|
||||
{
|
||||
for (auto& id : unused)
|
||||
{
|
||||
for (auto& animation : anm2.animations.items)
|
||||
for (auto& layerAnimation : animation.layerAnimations | std::views::values)
|
||||
for (auto& frame : layerAnimation.frames)
|
||||
if (frame.regionID == id) frame.regionID = -1;
|
||||
|
||||
spritesheet->regions.erase(id);
|
||||
}
|
||||
};
|
||||
|
||||
DOCUMENT_EDIT(document, localize.get(EDIT_REMOVE_UNUSED_REGIONS), Document::SPRITESHEETS, behavior());
|
||||
};
|
||||
|
||||
auto copy = [&]()
|
||||
{
|
||||
if (!spritesheet || selection.empty()) return;
|
||||
|
||||
std::string clipboardText{};
|
||||
for (auto& id : selection)
|
||||
clipboardText += spritesheet->region_to_string(id);
|
||||
clipboard.set(clipboardText);
|
||||
};
|
||||
|
||||
auto paste = [&]()
|
||||
{
|
||||
if (!spritesheet || clipboard.is_empty()) return;
|
||||
|
||||
auto behavior = [&]()
|
||||
{
|
||||
std::string errorString{};
|
||||
document.snapshot(localize.get(EDIT_PASTE_REGIONS));
|
||||
if (spritesheet->regions_deserialize(clipboard.get(), merge::APPEND, &errorString))
|
||||
document.change(Document::SPRITESHEETS);
|
||||
else
|
||||
{
|
||||
toasts.push(std::vformat(localize.get(TOAST_DESERIALIZE_REGIONS_FAILED), std::make_format_args(errorString)));
|
||||
logger.error(std::vformat(localize.get(TOAST_DESERIALIZE_REGIONS_FAILED, anm2ed::ENGLISH),
|
||||
std::make_format_args(errorString)));
|
||||
}
|
||||
};
|
||||
|
||||
DOCUMENT_EDIT(document, localize.get(EDIT_PASTE_REGIONS), Document::SPRITESHEETS, behavior());
|
||||
};
|
||||
|
||||
auto add_open = [&]()
|
||||
{
|
||||
reference = -1;
|
||||
editRegion = anm2::Spritesheet::Region{};
|
||||
propertiesPopup.open();
|
||||
};
|
||||
|
||||
auto properties_open = [&](int id)
|
||||
{
|
||||
if (!spritesheet || !spritesheet->regions.contains(id)) return;
|
||||
reference = id;
|
||||
propertiesPopup.open();
|
||||
};
|
||||
|
||||
auto context_menu = [&]()
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, style.WindowPadding);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing);
|
||||
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlappedByWindow) &&
|
||||
ImGui::IsMouseClicked(ImGuiMouseButton_Right))
|
||||
ImGui::OpenPopup("##Region Context Menu");
|
||||
|
||||
if (ImGui::BeginPopup("##Region Context Menu"))
|
||||
{
|
||||
if (ImGui::MenuItem(localize.get(SHORTCUT_STRING_UNDO), settings.shortcutUndo.c_str(), false,
|
||||
document.is_able_to_undo()))
|
||||
document.undo();
|
||||
|
||||
if (ImGui::MenuItem(localize.get(SHORTCUT_STRING_REDO), settings.shortcutRedo.c_str(), false,
|
||||
document.is_able_to_redo()))
|
||||
document.redo();
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::MenuItem(localize.get(BASIC_PROPERTIES), nullptr, false, selection.size() == 1))
|
||||
properties_open(*selection.begin());
|
||||
if (ImGui::MenuItem(localize.get(BASIC_ADD), settings.shortcutAdd.c_str())) add_open();
|
||||
if (ImGui::MenuItem(localize.get(BASIC_REMOVE_UNUSED), settings.shortcutRemove.c_str())) remove_unused();
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::MenuItem(localize.get(BASIC_COPY), settings.shortcutCopy.c_str(), false, !selection.empty())) copy();
|
||||
if (ImGui::MenuItem(localize.get(BASIC_PASTE), settings.shortcutPaste.c_str(), false, !clipboard.is_empty()))
|
||||
paste();
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
ImGui::PopStyleVar(2);
|
||||
};
|
||||
|
||||
if (ImGui::Begin(localize.get(LABEL_REGIONS_WINDOW), &settings.windowIsRegions))
|
||||
{
|
||||
if (!spritesheet)
|
||||
{
|
||||
ImGui::TextUnformatted(localize.get(TEXT_SELECT_SPRITESHEET));
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
auto childSize = size_without_footer_get();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2());
|
||||
if (ImGui::BeginChild("##Regions Child", childSize, ImGuiChildFlags_Borders))
|
||||
{
|
||||
auto regionChildSize = ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetTextLineHeightWithSpacing() * 4);
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2());
|
||||
|
||||
selection.start(spritesheet->regions.size());
|
||||
bool isValid = spritesheet->is_valid();
|
||||
auto& texture = isValid ? spritesheet->texture : resources.icons[icon::NONE];
|
||||
auto tintColor = !isValid ? ImVec4(1.0f, 0.25f, 0.25f, 1.0f) : ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
for (auto& [id, region] : spritesheet->regions)
|
||||
{
|
||||
auto nameCStr = region.name.c_str();
|
||||
auto isSelected = selection.contains(id);
|
||||
auto isReferenced = id == reference;
|
||||
|
||||
ImGui::PushID(id);
|
||||
|
||||
if (ImGui::BeginChild("##Region Child", regionChildSize, ImGuiChildFlags_Borders))
|
||||
{
|
||||
auto cursorPos = ImGui::GetCursorPos();
|
||||
|
||||
ImGui::SetNextItemSelectionUserData(id);
|
||||
ImGui::SetNextItemStorageID(id);
|
||||
if (ImGui::Selectable("##Region Selectable", isSelected, 0, regionChildSize))
|
||||
{
|
||||
reference = id;
|
||||
document.reference = {document.reference.animationIndex};
|
||||
frame.reference = -1;
|
||||
frame.selection.clear();
|
||||
}
|
||||
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) propertiesPopup.open();
|
||||
|
||||
auto viewport = ImGui::GetMainViewport();
|
||||
auto maxPreviewSize = to_vec2(viewport->Size) * 0.5f;
|
||||
vec2 regionSize = glm::max(region.size, vec2(1.0f));
|
||||
vec2 previewSize = regionSize;
|
||||
if (previewSize.x > maxPreviewSize.x || previewSize.y > maxPreviewSize.y)
|
||||
{
|
||||
auto scale = glm::min(maxPreviewSize.x / previewSize.x, maxPreviewSize.y / previewSize.y);
|
||||
previewSize *= scale;
|
||||
}
|
||||
auto uvMin = region.crop / vec2(texture.size);
|
||||
auto uvMax = (region.crop + region.size) / vec2(texture.size);
|
||||
|
||||
auto textWidth = ImGui::CalcTextSize(nameCStr).x;
|
||||
auto tooltipPadding = style.WindowPadding.x * 4.0f;
|
||||
auto minWidth = previewSize.x + style.ItemSpacing.x + textWidth + tooltipPadding;
|
||||
|
||||
ImGui::SetNextWindowSize(ImVec2(minWidth, 0), ImGuiCond_Appearing);
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, style.WindowPadding);
|
||||
if (ImGui::BeginItemTooltip())
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2());
|
||||
auto childFlags = ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY;
|
||||
auto noScrollFlags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse;
|
||||
|
||||
if (ImGui::BeginChild("##Region Tooltip Image Child", to_imvec2(previewSize), childFlags, noScrollFlags))
|
||||
ImGui::ImageWithBg(texture.id, to_imvec2(previewSize), to_imvec2(uvMin), to_imvec2(uvMax), ImVec4(),
|
||||
tintColor);
|
||||
ImGui::EndChild();
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
auto infoChildFlags = ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY;
|
||||
if (ImGui::BeginChild("##Region Info Tooltip Child", ImVec2(), infoChildFlags, noScrollFlags))
|
||||
{
|
||||
ImGui::PushFont(resources.fonts[font::BOLD].get(), font::SIZE);
|
||||
ImGui::TextUnformatted(nameCStr);
|
||||
ImGui::PopFont();
|
||||
|
||||
ImGui::TextUnformatted(std::vformat(localize.get(FORMAT_ID), std::make_format_args(id)).c_str());
|
||||
ImGui::TextUnformatted(
|
||||
std::vformat(localize.get(FORMAT_CROP), std::make_format_args(region.crop.x, region.crop.y))
|
||||
.c_str());
|
||||
ImGui::TextUnformatted(
|
||||
std::vformat(localize.get(FORMAT_SIZE), std::make_format_args(region.size.x, region.size.y))
|
||||
.c_str());
|
||||
ImGui::TextUnformatted(
|
||||
std::vformat(localize.get(FORMAT_PIVOT), std::make_format_args(region.pivot.x, region.pivot.y))
|
||||
.c_str());
|
||||
}
|
||||
ImGui::EndChild();
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::PopStyleVar(2);
|
||||
|
||||
auto imageSize = to_imvec2(vec2(regionChildSize.y));
|
||||
auto aspectRatio = region.size.y != 0.0f ? (float)region.size.x / region.size.y : 1.0f;
|
||||
|
||||
if (imageSize.x / imageSize.y > aspectRatio)
|
||||
imageSize.x = imageSize.y * aspectRatio;
|
||||
else
|
||||
imageSize.y = imageSize.x / aspectRatio;
|
||||
|
||||
ImGui::SetCursorPos(cursorPos);
|
||||
ImGui::ImageWithBg(texture.id, imageSize, to_imvec2(uvMin), to_imvec2(uvMax), ImVec4(), tintColor);
|
||||
|
||||
ImGui::SetCursorPos(ImVec2(regionChildSize.y + style.ItemSpacing.x,
|
||||
regionChildSize.y - regionChildSize.y / 2 - ImGui::GetTextLineHeight() / 2));
|
||||
|
||||
if (isReferenced) ImGui::PushFont(resources.fonts[font::ITALICS].get(), font::SIZE);
|
||||
ImGui::TextUnformatted(
|
||||
std::vformat(localize.get(FORMAT_SPRITESHEET), std::make_format_args(id, nameCStr)).c_str());
|
||||
if (isReferenced) ImGui::PopFont();
|
||||
}
|
||||
|
||||
ImGui::EndChild();
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
selection.finish();
|
||||
|
||||
if (shortcut(manager.chords[SHORTCUT_ADD], shortcut::FOCUSED)) add_open();
|
||||
if (shortcut(manager.chords[SHORTCUT_REMOVE], shortcut::FOCUSED)) remove_unused();
|
||||
if (shortcut(manager.chords[SHORTCUT_COPY], shortcut::FOCUSED)) copy();
|
||||
if (shortcut(manager.chords[SHORTCUT_PASTE], shortcut::FOCUSED)) paste();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
context_menu();
|
||||
|
||||
auto rowOneWidgetSize = widget_size_with_row_get(2);
|
||||
|
||||
shortcut(manager.chords[SHORTCUT_ADD]);
|
||||
if (ImGui::Button(localize.get(BASIC_ADD), rowOneWidgetSize)) add_open();
|
||||
set_item_tooltip_shortcut(localize.get(TOOLTIP_ADD_REGION), settings.shortcutAdd);
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
shortcut(manager.chords[SHORTCUT_REMOVE]);
|
||||
if (ImGui::Button(localize.get(BASIC_REMOVE_UNUSED), rowOneWidgetSize)) remove_unused();
|
||||
set_item_tooltip_shortcut(localize.get(TOOLTIP_REMOVE_UNUSED_REGIONS), settings.shortcutAdd);
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
|
||||
propertiesPopup.trigger();
|
||||
|
||||
if (ImGui::BeginPopupModal(propertiesPopup.label(), &propertiesPopup.isOpen, ImGuiWindowFlags_NoResize))
|
||||
{
|
||||
auto childSize = child_size_get(4);
|
||||
auto& region = reference == -1 ? editRegion : spritesheet->regions.at(reference);
|
||||
|
||||
if (propertiesPopup.isJustOpened) editRegion = anm2::Spritesheet::Region{};
|
||||
|
||||
if (ImGui::BeginChild("##Child", childSize, ImGuiChildFlags_Borders))
|
||||
{
|
||||
if (propertiesPopup.isJustOpened) ImGui::SetKeyboardFocusHere();
|
||||
input_text_string(localize.get(BASIC_NAME), ®ion.name);
|
||||
ImGui::SetItemTooltip("%s", localize.get(TOOLTIP_ITEM_NAME));
|
||||
|
||||
ImGui::DragFloat2(localize.get(BASIC_CROP), value_ptr(region.crop), DRAG_SPEED, 0.0f, 0.0f,
|
||||
math::vec2_format_get(region.crop));
|
||||
ImGui::DragFloat2(localize.get(BASIC_SIZE), value_ptr(region.size), DRAG_SPEED, 0.0f, 0.0f,
|
||||
math::vec2_format_get(region.size));
|
||||
ImGui::DragFloat2(localize.get(BASIC_PIVOT), value_ptr(region.pivot), DRAG_SPEED, 0.0f, 0.0f,
|
||||
math::vec2_format_get(region.pivot));
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
auto widgetSize = widget_size_with_row_get(2);
|
||||
|
||||
if (ImGui::Button(reference == -1 ? localize.get(BASIC_ADD) : localize.get(BASIC_CONFIRM), widgetSize))
|
||||
{
|
||||
if (reference == -1)
|
||||
{
|
||||
auto add = [&]()
|
||||
{
|
||||
auto id = map::next_id_get(spritesheet->regions);
|
||||
spritesheet->regions[id] = region;
|
||||
selection = {id};
|
||||
newRegionId = id;
|
||||
};
|
||||
|
||||
DOCUMENT_EDIT(document, localize.get(EDIT_ADD_REGION), Document::SPRITESHEETS, add());
|
||||
}
|
||||
else
|
||||
{
|
||||
auto set = [&]()
|
||||
{
|
||||
spritesheet->regions.at(reference) = region;
|
||||
selection = {reference};
|
||||
};
|
||||
|
||||
DOCUMENT_EDIT(document, localize.get(EDIT_SET_REGION_PROPERTIES), Document::SPRITESHEETS, set());
|
||||
}
|
||||
|
||||
frame.reference = -1;
|
||||
frame.selection.clear();
|
||||
|
||||
propertiesPopup.close();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button(localize.get(BASIC_CANCEL), widgetSize)) propertiesPopup.close();
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
propertiesPopup.end();
|
||||
}
|
||||
}
|
||||
19
src/imgui/window/regions.h
Normal file
19
src/imgui/window/regions.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "clipboard.h"
|
||||
#include "manager.h"
|
||||
#include "resources.h"
|
||||
#include "settings.h"
|
||||
|
||||
namespace anm2ed::imgui
|
||||
{
|
||||
class Regions
|
||||
{
|
||||
public:
|
||||
anm2::Spritesheet::Region editRegion{};
|
||||
int newRegionId{-1};
|
||||
imgui::PopupHelper propertiesPopup{imgui::PopupHelper(LABEL_REGION_PROPERTIES, imgui::POPUP_SMALL_NO_HEIGHT)};
|
||||
|
||||
void update(Manager&, Settings&, Resources&, Clipboard&);
|
||||
};
|
||||
}
|
||||
@@ -44,6 +44,8 @@ namespace anm2ed::imgui
|
||||
auto& shaderTexture = resources.shaders[shader::TEXTURE];
|
||||
auto& dashedShader = resources.shaders[shader::DASHED];
|
||||
auto& frames = document.frames.selection;
|
||||
auto& regionReference = document.region.reference;
|
||||
auto& regionSelection = document.region.selection;
|
||||
|
||||
auto reset_checker_pan = [&]()
|
||||
{
|
||||
@@ -216,6 +218,21 @@ namespace anm2ed::imgui
|
||||
transform * math::quad_model_get(PIVOT_SIZE, frame->crop + frame->pivot, PIVOT_SIZE * 0.5f);
|
||||
texture_render(shaderTexture, resources.icons[icon::PIVOT].id, pivotTransform, PIVOT_COLOR);
|
||||
}
|
||||
else if (regionReference != -1)
|
||||
{
|
||||
auto regionIt = spritesheet->regions.find(regionReference);
|
||||
if (regionIt != spritesheet->regions.end())
|
||||
{
|
||||
auto& region = regionIt->second;
|
||||
auto cropModel = math::quad_model_get(region.size, region.crop);
|
||||
auto cropTransform = transform * cropModel;
|
||||
rect_render(dashedShader, cropTransform, cropModel, color::RED);
|
||||
|
||||
auto pivotTransform =
|
||||
transform * math::quad_model_get(PIVOT_SIZE, region.crop + region.pivot, PIVOT_SIZE * 0.5f);
|
||||
texture_render(shaderTexture, resources.icons[icon::PIVOT].id, pivotTransform, PIVOT_COLOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unbind();
|
||||
@@ -303,6 +320,27 @@ namespace anm2ed::imgui
|
||||
|
||||
auto frame_change_apply = [&](anm2::FrameChange frameChange, anm2::ChangeType changeType = anm2::ADJUST)
|
||||
{ item->frames_change(frameChange, reference.itemType, changeType, frames); };
|
||||
auto region_set_all = [&](const vec2& crop, const vec2& size)
|
||||
{
|
||||
if (!spritesheet) return;
|
||||
for (auto id : regionSelection)
|
||||
{
|
||||
auto it = spritesheet->regions.find(id);
|
||||
if (it == spritesheet->regions.end()) continue;
|
||||
it->second.crop = crop;
|
||||
it->second.size = size;
|
||||
}
|
||||
};
|
||||
auto region_offset_all = [&](const vec2& delta)
|
||||
{
|
||||
if (!spritesheet) return;
|
||||
for (auto id : regionSelection)
|
||||
{
|
||||
auto it = spritesheet->regions.find(id);
|
||||
if (it == spritesheet->regions.end()) continue;
|
||||
it->second.crop += delta;
|
||||
}
|
||||
};
|
||||
|
||||
if (isMouseMiddleDown) useTool = tool::PAN;
|
||||
if (tool == tool::MOVE && isMouseRightDown) useTool = tool::CROP;
|
||||
@@ -315,7 +353,13 @@ namespace anm2ed::imgui
|
||||
bool isAreaAllowed = areaType == tool::ALL || areaType == tool::SPRITESHEET_EDITOR;
|
||||
bool isFrameRequired =
|
||||
!(useTool == tool::PAN || useTool == tool::DRAW || useTool == tool::ERASE || useTool == tool::COLOR_PICKER);
|
||||
bool isFrameAvailable = !isFrameRequired || frame;
|
||||
bool isRegionInUse =
|
||||
frame && frame->regionID != -1 && (useTool == tool::CROP || useTool == tool::MOVE);
|
||||
bool isFrameAvailable =
|
||||
!isFrameRequired ||
|
||||
(frame && !isRegionInUse) ||
|
||||
(useTool == tool::CROP && !frame && !regionSelection.empty()) ||
|
||||
(useTool == tool::MOVE && !frame && regionReference != -1);
|
||||
bool isSpritesheetRequired = useTool == tool::DRAW || useTool == tool::ERASE || useTool == tool::COLOR_PICKER;
|
||||
bool isSpritesheetAvailable = !isSpritesheetRequired || (spritesheet && spritesheet->texture.is_valid());
|
||||
auto cursor = (isAreaAllowed && isFrameAvailable && isSpritesheetAvailable) ? toolInfo.cursor
|
||||
@@ -329,6 +373,37 @@ namespace anm2ed::imgui
|
||||
if (isMouseDown || isMouseMiddleDown) pan += mouseDelta;
|
||||
break;
|
||||
case tool::MOVE:
|
||||
if (isRegionInUse) break;
|
||||
if (!frame && regionReference != -1)
|
||||
{
|
||||
if (!spritesheet) break;
|
||||
auto regionIt = spritesheet->regions.find(regionReference);
|
||||
if (regionIt == spritesheet->regions.end()) break;
|
||||
|
||||
auto& region = regionIt->second;
|
||||
if (isBegin) document.snapshot(localize.get(EDIT_REGION_MOVE));
|
||||
if (isMouseDown)
|
||||
region.pivot = ivec2(mousePos) - ivec2(region.crop);
|
||||
if (isLeftPressed) region.pivot.x -= step;
|
||||
if (isRightPressed) region.pivot.x += step;
|
||||
if (isUpPressed) region.pivot.y -= step;
|
||||
if (isDownPressed) region.pivot.y += step;
|
||||
|
||||
if (isDuring)
|
||||
{
|
||||
if (ImGui::BeginTooltip())
|
||||
{
|
||||
ImGui::TextUnformatted(
|
||||
std::vformat(localize.get(FORMAT_PIVOT), std::make_format_args(region.pivot.x, region.pivot.y))
|
||||
.c_str());
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
if (isEnd) document.change(Document::SPRITESHEETS);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!item || frames.empty()) break;
|
||||
if (isBegin) document.snapshot(localize.get(EDIT_FRAME_PIVOT));
|
||||
if (isMouseDown)
|
||||
@@ -358,7 +433,74 @@ namespace anm2ed::imgui
|
||||
if (isEnd) document.change(Document::FRAMES);
|
||||
break;
|
||||
case tool::CROP:
|
||||
if (!item || frames.empty()) break;
|
||||
if (isRegionInUse) break;
|
||||
if (frames.empty())
|
||||
{
|
||||
if (!spritesheet || regionSelection.empty()) break;
|
||||
if (isBegin) document.snapshot(localize.get(EDIT_REGION_CROP));
|
||||
|
||||
if (isMouseClicked)
|
||||
{
|
||||
cropAnchor = mousePos;
|
||||
region_set_all(vec2((int)cropAnchor.x, (int)cropAnchor.y), vec2());
|
||||
}
|
||||
if (isMouseDown)
|
||||
{
|
||||
auto [minPoint, maxPoint] = snap_rect(glm::min(cropAnchor, mousePos), glm::max(cropAnchor, mousePos));
|
||||
region_set_all(vec2(minPoint), vec2(maxPoint - minPoint));
|
||||
}
|
||||
if (isLeftPressed) region_offset_all(vec2(stepX * -1, 0));
|
||||
if (isRightPressed) region_offset_all(vec2(stepX, 0));
|
||||
if (isUpPressed) region_offset_all(vec2(0, stepY * -1));
|
||||
if (isDownPressed) region_offset_all(vec2(0, stepY));
|
||||
|
||||
if (isDuring)
|
||||
{
|
||||
if (!isMouseDown)
|
||||
{
|
||||
for (auto id : regionSelection)
|
||||
{
|
||||
auto it = spritesheet->regions.find(id);
|
||||
if (it == spritesheet->regions.end()) continue;
|
||||
|
||||
auto& region = it->second;
|
||||
auto minPoint = glm::min(region.crop, region.crop + region.size);
|
||||
auto maxPoint = glm::max(region.crop, region.crop + region.size);
|
||||
region.crop = minPoint;
|
||||
region.size = maxPoint - minPoint;
|
||||
|
||||
if (isGridSnap)
|
||||
{
|
||||
auto [snapMin, snapMax] = snap_rect(region.crop, region.crop + region.size);
|
||||
region.crop = snapMin;
|
||||
region.size = snapMax - snapMin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::BeginTooltip())
|
||||
{
|
||||
auto it = spritesheet->regions.find(*regionSelection.begin());
|
||||
if (it != spritesheet->regions.end())
|
||||
{
|
||||
ImGui::TextUnformatted(
|
||||
std::vformat(localize.get(FORMAT_CROP),
|
||||
std::make_format_args(it->second.crop.x, it->second.crop.y))
|
||||
.c_str());
|
||||
ImGui::TextUnformatted(
|
||||
std::vformat(localize.get(FORMAT_SIZE),
|
||||
std::make_format_args(it->second.size.x, it->second.size.y))
|
||||
.c_str());
|
||||
}
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
if (isEnd) document.change(Document::SPRITESHEETS);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!item) break;
|
||||
if (isBegin) document.snapshot(localize.get(EDIT_FRAME_CROP));
|
||||
|
||||
if (isMouseClicked)
|
||||
@@ -473,6 +615,12 @@ namespace anm2ed::imgui
|
||||
{
|
||||
if (ImGui::BeginTooltip())
|
||||
{
|
||||
if (isRegionInUse)
|
||||
ImGui::TextUnformatted(localize.get(TEXT_REGION_IN_USE));
|
||||
else
|
||||
if (useTool == tool::CROP)
|
||||
ImGui::TextUnformatted(localize.get(TEXT_SELECT_FRAME_OR_REGION));
|
||||
else
|
||||
ImGui::TextUnformatted(localize.get(TEXT_SELECT_FRAME));
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace anm2ed::imgui
|
||||
auto& anm2 = document.anm2;
|
||||
auto& selection = document.spritesheet.selection;
|
||||
auto& reference = document.spritesheet.reference;
|
||||
auto& region = document.region;
|
||||
auto style = ImGui::GetStyle();
|
||||
|
||||
auto add_open = [&]() { dialog.file_open(Dialog::SPRITESHEET_OPEN); };
|
||||
@@ -234,7 +235,12 @@ namespace anm2ed::imgui
|
||||
|
||||
ImGui::SetNextItemSelectionUserData(id);
|
||||
ImGui::SetNextItemStorageID(id);
|
||||
if (ImGui::Selectable("##Spritesheet Selectable", isSelected, 0, spritesheetChildSize)) reference = id;
|
||||
if (ImGui::Selectable("##Spritesheet Selectable", isSelected, 0, spritesheetChildSize))
|
||||
{
|
||||
reference = id;
|
||||
region.reference = -1;
|
||||
region.selection.clear();
|
||||
}
|
||||
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
|
||||
open_directory(spritesheet);
|
||||
if (newSpritesheetId == id)
|
||||
|
||||
@@ -93,6 +93,7 @@ namespace anm2ed::imgui
|
||||
auto& playback = document.playback;
|
||||
auto& reference = document.reference;
|
||||
auto& frames = document.frames;
|
||||
auto& region = document.region;
|
||||
auto animation = document.animation_get();
|
||||
|
||||
style = ImGui::GetStyle();
|
||||
@@ -392,6 +393,22 @@ namespace anm2ed::imgui
|
||||
auto start = reference.itemType == anm2::TRIGGER ? hoveredTime : insertIndex;
|
||||
if (item->frames_deserialize(clipboard.get(), reference.itemType, start, indices, &errorString))
|
||||
{
|
||||
if (reference.itemType == anm2::LAYER && reference.itemID != -1)
|
||||
{
|
||||
auto& layer = anm2.content.layers.at(reference.itemID);
|
||||
auto spritesheet = anm2.spritesheet_get(layer.spritesheetID);
|
||||
if (spritesheet)
|
||||
{
|
||||
for (auto i : indices)
|
||||
{
|
||||
if (!vector::in_bounds(item->frames, i)) continue;
|
||||
auto& frame = item->frames[i];
|
||||
if (frame.regionID != -1 && !spritesheet->regions.contains(frame.regionID))
|
||||
frame.regionID = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
frames.selection.clear();
|
||||
for (auto i : indices)
|
||||
frames.selection.insert(i);
|
||||
@@ -1137,6 +1154,8 @@ namespace anm2ed::imgui
|
||||
|
||||
reference = frameReference;
|
||||
isReferenced = true;
|
||||
region.reference = -1;
|
||||
region.selection.clear();
|
||||
if (isDifferentItem) frames_selection_set_reference();
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "change_all_frame_properties.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "math_.h"
|
||||
|
||||
@@ -37,6 +38,7 @@ namespace anm2ed::imgui::wizard
|
||||
auto& isInterpolatedSet = settings.changeIsInterpolatedSet;
|
||||
auto& isFlipXSet = settings.changeIsFlipXSet;
|
||||
auto& isFlipYSet = settings.changeIsFlipYSet;
|
||||
auto& isRegion = settings.changeIsRegion;
|
||||
auto& crop = settings.changeCrop;
|
||||
auto& size = settings.changeSize;
|
||||
auto& position = settings.changePosition;
|
||||
@@ -46,6 +48,7 @@ namespace anm2ed::imgui::wizard
|
||||
auto& duration = settings.changeDuration;
|
||||
auto& tint = settings.changeTint;
|
||||
auto& colorOffset = settings.changeColorOffset;
|
||||
auto& regionId = settings.changeRegionId;
|
||||
auto& isVisible = settings.changeIsVisible;
|
||||
auto& isInterpolated = settings.changeIsInterpolated;
|
||||
auto& isFlipX = settings.changeIsFlipX;
|
||||
@@ -180,15 +183,8 @@ namespace anm2ed::imgui::wizard
|
||||
checkboxLabel, isEnabled);
|
||||
};
|
||||
|
||||
#undef PROPERTIES_WIDGET
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImGui::GetStyle().ItemInnerSpacing);
|
||||
|
||||
ImGui::BeginDisabled(itemType != anm2::LAYER);
|
||||
float2_value("##Is Crop X", "##Is Crop Y", "##Crop X", localize.get(BASIC_CROP), isCropX, isCropY, crop);
|
||||
float2_value("##Is Size X", "##Is Size Y", "##Size X", localize.get(BASIC_SIZE), isSizeX, isSizeY, size);
|
||||
ImGui::EndDisabled();
|
||||
|
||||
float2_value("##Is Position X", "##Is Position Y", "##Position X", localize.get(BASIC_POSITION), isPositionX,
|
||||
isPositionY, position);
|
||||
|
||||
@@ -196,6 +192,11 @@ namespace anm2ed::imgui::wizard
|
||||
float2_value("##Is Pivot X", "##Is Pivot Y", "##Pivot X", localize.get(BASIC_PIVOT), isPivotX, isPivotY, pivot);
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::BeginDisabled(itemType != anm2::LAYER);
|
||||
float2_value("##Is Crop X", "##Is Crop Y", "##Crop X", localize.get(BASIC_CROP), isCropX, isCropY, crop);
|
||||
float2_value("##Is Size X", "##Is Size Y", "##Size X", localize.get(BASIC_SIZE), isSizeX, isSizeY, size);
|
||||
ImGui::EndDisabled();
|
||||
|
||||
float2_value("##Is Scale X", "##Is Scale Y", "##Scale X", localize.get(BASIC_SCALE), isScaleX, isScaleY, scale);
|
||||
|
||||
float_value("##Is Rotation", localize.get(BASIC_ROTATION), isRotation, rotation);
|
||||
@@ -209,6 +210,24 @@ namespace anm2ed::imgui::wizard
|
||||
"##Color Offset B", "##Color Offset G", localize.get(BASIC_COLOR_OFFSET), isColorOffsetR,
|
||||
isColorOffsetG, isColorOffsetB, colorOffset);
|
||||
|
||||
std::vector<int> fallbackIds{-1};
|
||||
std::vector<std::string> fallbackLabelsString{localize.get(BASIC_NONE)};
|
||||
std::vector<const char*> fallbackLabels{fallbackLabelsString[0].c_str()};
|
||||
|
||||
const Storage* regionStorage = nullptr;
|
||||
if (itemType == anm2::LAYER && document.reference.itemID != -1)
|
||||
{
|
||||
auto spritesheetID = document.anm2.content.layers.at(document.reference.itemID).spritesheetID;
|
||||
auto regionIt = document.regionBySpritesheet.find(spritesheetID);
|
||||
if (regionIt != document.regionBySpritesheet.end()) regionStorage = ®ionIt->second;
|
||||
}
|
||||
|
||||
auto regionIds = regionStorage && !regionStorage->ids.empty() ? regionStorage->ids : fallbackIds;
|
||||
auto regionLabels = regionStorage && !regionStorage->labels.empty() ? regionStorage->labels : fallbackLabels;
|
||||
|
||||
PROPERTIES_WIDGET(combo_id_mapped(localize.get(BASIC_REGION), ®ionId, regionIds, regionLabels), "##Is Region",
|
||||
isRegion);
|
||||
|
||||
bool_value("##Is Visible", localize.get(BASIC_VISIBLE), isVisibleSet, isVisible);
|
||||
|
||||
ImGui::SameLine();
|
||||
@@ -223,6 +242,8 @@ namespace anm2ed::imgui::wizard
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
#undef PROPERTIES_WIDGET
|
||||
|
||||
auto frame_change = [&](anm2::ChangeType changeType)
|
||||
{
|
||||
anm2::FrameChange frameChange;
|
||||
@@ -238,6 +259,7 @@ namespace anm2ed::imgui::wizard
|
||||
if (isScaleY) frameChange.scaleY = scale.y;
|
||||
if (isRotation) frameChange.rotation = std::make_optional(rotation);
|
||||
if (isDuration) frameChange.duration = std::make_optional(duration);
|
||||
if (isRegion) frameChange.regionID = std::make_optional(regionId);
|
||||
if (isTintR) frameChange.tintR = tint.r;
|
||||
if (isTintG) frameChange.tintG = tint.g;
|
||||
if (isTintB) frameChange.tintB = tint.b;
|
||||
@@ -260,8 +282,8 @@ namespace anm2ed::imgui::wizard
|
||||
|
||||
bool isAnyProperty = isCropX || isCropY || isSizeX || isSizeY || isPositionX || isPositionY || isPivotX ||
|
||||
isPivotY || isScaleX || isScaleY || isRotation || isDuration || isTintR || isTintG ||
|
||||
isTintB || isTintA || isColorOffsetR || isColorOffsetG || isColorOffsetB || isVisibleSet ||
|
||||
isInterpolatedSet || isFlipXSet || isFlipYSet;
|
||||
isTintB || isTintA || isColorOffsetR || isColorOffsetG || isColorOffsetB || isRegion ||
|
||||
isVisibleSet || isInterpolatedSet || isFlipXSet || isFlipYSet;
|
||||
|
||||
auto rowWidgetSize = widget_size_with_row_get(5);
|
||||
|
||||
|
||||
@@ -37,6 +37,8 @@ namespace anm2ed
|
||||
|
||||
constexpr auto SOCKET_ADDRESS = "127.0.0.1";
|
||||
constexpr auto SOCKET_PORT = 11414;
|
||||
constexpr uint32_t SOCKET_MAX_PATHS = 128;
|
||||
constexpr uint32_t SOCKET_MAX_PATH_LENGTH = 32768;
|
||||
|
||||
#ifdef _WIN32
|
||||
constexpr int SOCKET_ERROR_ADDRESS_IN_USE = WSAEADDRINUSE;
|
||||
@@ -153,6 +155,7 @@ namespace anm2ed
|
||||
uint32_t count{};
|
||||
if (!socket.receive(&count, sizeof(count))) return {};
|
||||
count = ntohl(count);
|
||||
if (count > SOCKET_MAX_PATHS) return {};
|
||||
|
||||
std::vector<std::string> paths;
|
||||
paths.reserve(count);
|
||||
@@ -162,6 +165,7 @@ namespace anm2ed
|
||||
uint32_t length{};
|
||||
if (!socket.receive(&length, sizeof(length))) return {};
|
||||
length = ntohl(length);
|
||||
if (length > SOCKET_MAX_PATH_LENGTH) return {};
|
||||
|
||||
std::string path(length, '\0');
|
||||
if (length > 0 && !socket.receive(path.data(), length)) return {};
|
||||
@@ -352,6 +356,8 @@ namespace anm2ed
|
||||
[this]()
|
||||
{
|
||||
while (isSocketRunning)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto client = socket.accept();
|
||||
if (!client.is_valid())
|
||||
@@ -360,19 +366,28 @@ namespace anm2ed
|
||||
continue;
|
||||
}
|
||||
|
||||
SDL_FlashWindow(window, SDL_FLASH_UNTIL_FOCUSED);
|
||||
|
||||
auto paths = socket_paths_receive(client);
|
||||
for (auto& path : paths)
|
||||
{
|
||||
if (path.empty()) continue;
|
||||
SDL_Event event{};
|
||||
event.type = SDL_EVENT_USER;
|
||||
event.drop.data = SDL_strdup(path.c_str());
|
||||
event.drop.windowID = window ? SDL_GetWindowID(window) : 0;
|
||||
event.user.code = 0;
|
||||
event.user.data1 = SDL_strdup(path.c_str());
|
||||
event.user.data2 = nullptr;
|
||||
event.user.windowID = 0;
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
logger.error(std::format("Socket thread error: {}", ex.what()));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
logger.error("Socket thread error: unknown exception");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace anm2ed
|
||||
|
||||
void Logger::write(const Level level, const std::string& message)
|
||||
{
|
||||
std::string formatted = std::format("{} {} {}", time::get("(%d-%B-%Y %I:%M:%S)"), LEVEL_STRINGS[level], message);
|
||||
std::string formatted = std::format("{} {} {}", LEVEL_STRINGS[level], time::get("(%d-%B-%Y %I:%M:%S)"), message);
|
||||
write_raw(formatted);
|
||||
}
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ namespace anm2ed
|
||||
X(BASIC_PIVOT, "Pivot", "Pivote", "Точка вращения", "枢轴", "중심점") \
|
||||
X(BASIC_POSITION, "Position", "Posicion", "Позиция", "位置", "위치") \
|
||||
X(BASIC_PROPERTIES, "Properties", "Propiedades", "Свойства", "属性", "속성") \
|
||||
X(BASIC_REGION, "Region", "Región", "Регион", "区域", "영역") \
|
||||
X(BASIC_RENAME, "Rename", "Renombrar", "Переименовать", "重命名", "이름 변경") \
|
||||
X(BASIC_RELOAD, "Reload", "Recargar", "Перезагрузить", "重新加载", "다시 불러오기") \
|
||||
X(BASIC_REMOVE, "Remove", "Remover", "Удалить", "删除", "제거") \
|
||||
@@ -89,6 +90,7 @@ namespace anm2ed
|
||||
X(BASIC_YES, "Yes", "Si", "Да", "是", "예") \
|
||||
X(BASIC_ZOOM, "Zoom", "Zoom", "Масштаб", "缩放", "확대") \
|
||||
X(EDIT_ADD_ANIMATION, "Add Animation", "Añadir Animacion", "Добавить анимацию", "添加动画", "애니메이션 추가") \
|
||||
X(EDIT_ADD_REGION, "Add Region", "Añadir Región", "Добавить регион", "添加区域", "영역 추가") \
|
||||
X(EDIT_ADD_EVENT, "Add Event", "Añadir Evento", "Добавить событие", "添加事件", "이벤트 추가") \
|
||||
X(EDIT_ADD_ITEM, "Add Item", "Añadir Item", "Добавить предмет", "添加物品", "항목 추가") \
|
||||
X(EDIT_ADD_LAYER, "Add Layer", "Añadir Capa", "Добавить слой", "添加动画层", "레이어 추가") \
|
||||
@@ -136,6 +138,7 @@ namespace anm2ed
|
||||
X(EDIT_PASTE_EVENTS, "Paste Event(s)", "Pegar Eventos", "Вставить события", "粘贴事件", "이벤트 붙여넣기") \
|
||||
X(EDIT_PASTE_FRAMES, "Paste Frame(s)", "Pegar Frames", "Вставить кадры", "粘贴帧", "프레임 붙여넣기") \
|
||||
X(EDIT_PASTE_LAYERS, "Paste Layer(s)", "Pegar Capa(s)", "Вставить слои", "粘贴动画层", "레이어 붙여넣기") \
|
||||
X(EDIT_PASTE_REGIONS, "Paste Region(s)", "Pegar Región(es)", "Вставить регионы", "粘贴区域", "영역 붙여넣기") \
|
||||
X(EDIT_PASTE_NULLS, "Paste Null(s)", "Pegar Null(s)", "Вставить нули", "粘贴Null", "Null 붙여넣기") \
|
||||
X(EDIT_PASTE_SOUNDS, "Paste Sound(s)", "Pegar Sonido(s)", "Вставить звук(и)", "粘贴声音", "사운드 붙여넣기") \
|
||||
X(EDIT_PASTE_SPRITESHEETS, "Paste Spritesheet(s)", "Pegar Spritesheet(s)", "Вставить спрайт-листы", "粘贴图集", "스프라이트 시트 붙여넣기") \
|
||||
@@ -144,6 +147,7 @@ namespace anm2ed
|
||||
X(EDIT_REMOVE_ANIMATIONS, "Remove Animation(s)", "Remover Animacion(es)", "Удалить анимации", "删除动画层", "애니메이션 제거") \
|
||||
X(EDIT_REMOVE_ITEMS, "Remove Item(s)", "Remover Item(s)", "Удалить предметы", "删除物品", "항목 제거") \
|
||||
X(EDIT_REMOVE_UNUSED_EVENTS, "Remove Unused Events", "Remover Eventos No Utilizados", "Удалить неизпользуемые события", "删除未使用的事件", "미사용 이벤트 제거") \
|
||||
X(EDIT_REMOVE_UNUSED_REGIONS, "Remove Unused Regions", "Remover Regiones No Utilizadas", "Удалить неиспользуемые регионы", "删除未使用的区域", "미사용 영역 제거") \
|
||||
X(EDIT_REMOVE_UNUSED_LAYERS, "Remove Unused Layers", "Remover Capas No Utilizadas", "Удалить неизпользуемые слои", "删除未使用的动画层", "미사용 레이어 제거") \
|
||||
X(EDIT_REMOVE_UNUSED_NULLS, "Remove Unused Nulls", "Remover Nulls No Utilizados", "Удалить неизпользуемые нули", "删除未使用的Null", "미사용 Null 제거") \
|
||||
X(EDIT_REMOVE_UNUSED_SOUNDS, "Remove Unused Sounds", "Remover Sonidos No Utilizados", "Удалить неизпользуемые звуки", "删除未使用的声音", "미사용 사운드 제거") \
|
||||
@@ -152,7 +156,10 @@ namespace anm2ed
|
||||
X(EDIT_REPLACE_SPRITESHEET, "Replace Spritesheet", "Reemplazar Spritesheet", "Заменить спрайт-лист", "替换图集", "스프라이트 시트 교체") \
|
||||
X(EDIT_REPLACE_SOUND, "Replace Sound", "Reemplazar Sonido", "Заменить звук", "替换声音", "사운드 교체") \
|
||||
X(EDIT_SET_LAYER_PROPERTIES, "Set Layer Properties", "Establecer Propiedades de Capa", "Установить свойства слоя", "更改动画层属性", "레이어 속성 설정") \
|
||||
X(EDIT_SET_REGION_PROPERTIES, "Set Region Properties", "Establecer propiedades de región", "Установить свойства региона", "更改区域属性", "영역 속성 설정") \
|
||||
X(EDIT_SET_NULL_PROPERTIES, "Set Null Properties", "Establecer Propiedades Null", "Установить свойства нуля", "更改Null属性", "Null 속성 설정") \
|
||||
X(EDIT_REGION_CROP, "Region Crop", "Recorte de región", "Обрезка региона", "区域裁剪", "영역 자르기") \
|
||||
X(EDIT_REGION_MOVE, "Region Pivot", "Pivote de región", "Пивот региона", "区域枢轴", "영역 피벗") \
|
||||
X(EDIT_SPLIT_FRAME, "Split Frame", "Dividir Frame", "Разделить кадр", "拆分帧", "프레임 분할") \
|
||||
X(EDIT_SHORTEN_FRAME, "Shorten Frame", "Acortar Frame", "Укоротить кадр", "缩短帧时长", "프레임 단축") \
|
||||
X(EDIT_TOGGLE_ITEM_VISIBILITY, "Toggle Item Visibility", "Alternar Visibilidad de item", "Переключить видимость предмета", "物品可见", "항목 표시/숨기기") \
|
||||
@@ -197,6 +204,7 @@ namespace anm2ed
|
||||
X(LABEL_ANIMATIONS_CHILD, "Animations", "Animaciones", "", "动画", "애니메이션") \
|
||||
X(LABEL_ANIMATIONS_MERGE_POPUP, "Merge Animations", "Combinar Animaciones", "Соединить анимации", "合并多个动画", "애니메이션 병합") \
|
||||
X(LABEL_ANIMATIONS_WINDOW, "Animations###Animations", "Animaciones###Animations", "Анимации###Animations", "动画###Animations", "애니메이션###Animations") \
|
||||
X(LABEL_REGIONS_WINDOW, "Regions###Regions", "Regiones###Regions", "Регионы###Regions", "区域###Regions", "영역###Regions") \
|
||||
X(LABEL_ANIMATION_LENGTH, "Animation Length", "Duracion de Animacion", "Длина анимации", "动画时长", "애니메이션 길이") \
|
||||
X(LABEL_ANIMATION_PREVIEW_WINDOW, "Animation Preview###Animation Preview", "Vista Previa de Animacion###Animation Preview", "Предпросмотр анимации###Animation Preview", "动画预放###Animation Preview", "애니메이션 프리뷰###Animation Preview") \
|
||||
X(LABEL_APPEND_FRAMES, "Append Frames", "Anteponer Frames", "Добавить кадры к концу", "在后面添加帧", "뒷프레임에 추가") \
|
||||
@@ -261,6 +269,7 @@ namespace anm2ed
|
||||
X(LABEL_LOCALIZATION, "Localization", "Localizacion", "Локализация", "本地化", "현지화") \
|
||||
X(LABEL_LOOP, "Loop", "Loop", "Цикл", "循环", "반복") \
|
||||
X(LABEL_MANAGER_ANM2_DRAG_DROP, "Anm2 Drag Drop", "Arrastrar y Soltar Anm2", "Anm2 Drag Drop", "Anm2 拖放", "Anm2 드래그 앤 드롭") \
|
||||
X(LABEL_REGION_PROPERTIES, "Region Properties", "Propiedades de región", "Свойства региона", "区域属性", "영역 속성") \
|
||||
X(LABEL_MANAGER_LAYER_PROPERTIES, "Layer Properties", "Propiedades de Capa", "Свойства слоя", "动画层属性", "레이어 속성") \
|
||||
X(LABEL_MANAGER_NULL_PROPERTIES, "Null Properties", "Propiedades Null", "Свойства нуля", "Null属性", "Null 속성") \
|
||||
X(LABEL_MANAGER_RENDERING_PROGRESS, "Rendering...", "Renderizando...", "Рендеринг...", "渲染中...", "렌더링 중...") \
|
||||
@@ -387,11 +396,14 @@ namespace anm2ed
|
||||
X(SHORTCUT_STRING_ZOOM_OUT, "Zoom Out", "Zoom Out", "Уменьшить", "视图缩小", "축소") \
|
||||
X(SNAPSHOT_RENAME_ANIMATION, "Rename Animation", "Renombrar Animacion", "Переименовать анимацию", "重命名动画", "애니메이션 이름 바꾸기") \
|
||||
X(TEXT_SELECT_FRAME, "Select a frame first!", "¡Selecciona primero un frame!", "Сначала выберите кадр!", "请先选择帧!", "먼저 프레임을 선택하세요!") \
|
||||
X(TEXT_SELECT_FRAME_OR_REGION, "Select a frame or region first!", "¡Selecciona primero un frame o región!", "Сначала выберите кадр или регион!", "请先选择帧或区域!", "먼저 프레임 또는 영역을 선택하세요!") \
|
||||
X(TEXT_SELECT_SPRITESHEET, "Select a spritesheet first!", "¡Selecciona primero un spritesheet!", "Сначала выберите спрайт-лист!", "请先选择图集!", "먼저 스프라이트 시트를 선택하세요!") \
|
||||
X(TEXT_TOOL_ANIMATION_PREVIEW, "This tool can only be used in Animation Preview!", "¡Esta herramienta solo se puede usar en Vista previa de animación!", "Этот инструмент можно использовать только в \"Предпросмотре анимации\"!", "该工具只能在“动画预放”中使用!", "이 도구는 애니메이션 프리뷰에서만 사용할 수 있습니다!") \
|
||||
X(TEXT_TOOL_SPRITESHEET_EDITOR, "This tool can only be used in Spritesheet Editor!", "¡Esta herramienta solo se puede usar en el Editor de spritesheets!", "Этот инструмент можно использовать только в \"Редакторе спрайт-листов\"!", "该工具只能在“图集编辑器”中使用!", "이 도구는 스프라이트 시트 편집기에서만 사용할 수 있습니다!") \
|
||||
X(TEXT_NEW_ANIMATION, "New Animation", "Nueva Animacion", "Новая анимация", "新动画", "새 애니메이션") \
|
||||
X(TEXT_NEW_EVENT, "New Event", "Nuevo Evento", "Новое событие", "新事件", "새 이벤트") \
|
||||
X(TEXT_NEW_REGION, "New Region", "Nueva Región", "Новый регион", "新区域", "새 영역") \
|
||||
X(TEXT_REGION_IN_USE, "A spritesheet region is in use; remove region to edit.", "Se está usando una región del spritesheet; elimina la región para editar.", "Регион спрайт-листа используется; удалите регион для редактирования.", "图集中有区域正在使用;移除区域后才能编辑。", "스프라이트 시트 영역이 사용 중입니다. 편집하려면 영역을 제거하세요.") \
|
||||
X(TEXT_RECORDING_PROGRESS, "Once recording is complete, rendering may take some time.\nPlease be patient...", "Una vez que el grabado este completo, renderizar puede tomar algo de tiempo. \nPor favor se paciente...", "Когда запись завершена, рендеринг может занять некоторое время.\nПожалуйста потерпите...", "录制完成时,渲染可能会花一些时间.\n请耐心等待...", "녹화가 완료되면 렌더링에 시간이 걸릴 수 있습니다.\n잠시만 기다려 주세요...") \
|
||||
X(TEXT_OPEN_DIRECTORY, "Double-click to open directory in file explorer.", "Haz doble click para abrir el directiorio en el buscador de archivos.", "Дважды нажмите, чтобы открыть директорию в проводнике.", "双击以在文件管理器中打开目录。", "더블 클릭하여 파일 탐색기로 디렉터리를 엽니다.") \
|
||||
X(TOAST_AUTOSAVE_FAILED, "Could not autosave document to: {0} ({1})", "No se pudo autoguardar el documento en: {0} ({1})", "Не получилось автосохранить документ в: {0} ({1})", "自动保存到 {0} ({1}) 失败", "{0}에 파일을 자동저장할 수 없습니다. ({1})") \
|
||||
@@ -401,6 +413,7 @@ namespace anm2ed
|
||||
X(TOAST_DESERIALIZE_FRAMES_FAILED, "Failed to deserialize frames:", "Falla al deserializar Frames:", "Не удалось десериализировать кадры: {0}", "反序列化帧失败: {0}", "프레임 역직렬화 실패: {0}") \
|
||||
X(TOAST_DESERIALIZE_FRAMES_NO_SELECTION, "Failed to deserialize frames: no selection.", "Falla al deserializar Frames: sin seleccion.", "Не удалось десериализировать кадры: ничего не выбрано.", "到所选帧", "프레임 역직렬화 실패. 선택한 것이 없습니다.") \
|
||||
X(TOAST_DESERIALIZE_LAYERS_FAILED, "Failed to deserialize layer(s):", "Falla al deserializar capas(s):", "Не удалось десериализировать слои: {0}", "反序列化动画层失败: {0}", "레이어 역직렬화 실패: {0}") \
|
||||
X(TOAST_DESERIALIZE_REGIONS_FAILED, "Failed to deserialize region(s): {0}", "Falla al deserializar región(es): {0}", "Не удалось десериализировать регионы: {0}", "反序列化区域失败: {0}", "영역 역직렬화 실패: {0}") \
|
||||
X(TOAST_DESERIALIZE_NULLS_FAILED, "Failed to deserialize null(s): {0}", "Falla al deserializar null(s): {0}", "Не удалось десериализировать нули: {0}", "反序列化Null失败: {0}", "Null 역직렬화 실패: {0}") \
|
||||
X(TOAST_DESERIALIZE_SPRITESHEETS_FAILED, "Failed to deserialize spritesheet(s): {0}", "Falla al deserializar spritesheet(s): {0}", "Не удалось десериализировать спрайт-листы: {0}", "反序列化图集失败: {0}", "스프라이트 시트 역직렬화 실패: {0}") \
|
||||
X(TOAST_EXPORT_RENDERED_ANIMATION, "Exported rendered animation to: {0}", "Se ha exportado la animacion renderizada a: {0}", "Рендерированные анимации экспортированы в: {0}", "渲染动画导出至: {0}", "{0}에 렌더링 된 애니메이션을 내보내기 했습니다.") \
|
||||
@@ -440,6 +453,7 @@ namespace anm2ed
|
||||
X(TOAST_SPRITESHEET_NO_FRAMES, "No frames captured for spritesheet export.", "No hay Frames capturados para exportar spritesheet.", "Ни один кадр не захвачен для экспорта спрайт-листа.", "导出图集需要捕获至少一帧.", "스프라이트 시트 내보내기용으로 캡처된 프레임이 없습니다.") \
|
||||
X(TOAST_UNDO, "Undo: {0}", "Deshacer: {0}", "Отмена: {0}", "撤销: {0}", "실행 취소: {0}") \
|
||||
X(TOOLTIP_ADD_ANIMATION, "Add a new animation.", "Añadir nueva animacion.", "Добавить новую анимацию.", "添加一个新动画.", "새 애니메이션을 추가합니다.") \
|
||||
X(TOOLTIP_ADD_REGION, "Add a new region to the spritesheet.\nRegions are parts of a spritesheet that can be defined and labeled to be reused in frames.", "Añadir una nueva región al spritesheet.\nLas regiones son partes de un spritesheet que pueden definirse y etiquetarse para reutilizarse en frames.", "Добавить новый регион в спрайт-лист.\nРегионы — это части спрайт-листа, которые можно определить и подписать, чтобы повторно использовать их в кадрах.", "添加一个新的区域到图集。\n区域是图集的一部分,可以被定义并标记以便在帧中重复使用。", "스프라이트 시트에 새 영역을 추가합니다.\n영역은 스프라이트 시트의 일부로, 정의하고 라벨을 붙여 프레임에서 재사용할 수 있습니다.") \
|
||||
X(TOOLTIP_ADD_EVENT, "Add an event.", "Añadir un evento.", "Добавить событие.", "添加一个事件.", "이벤트를 추가합니다.") \
|
||||
X(TOOLTIP_ADD_ITEM, "Add the item, with the settings specified.", "Añadir el Item, con las configuraciones especificadas.", "Добавить предмет с указанными настройками.", "按照指定的设置添加物品.", "지정된 설정으로 항목을 추가합니다.") \
|
||||
X(TOOLTIP_ADD_LAYER, "Add a layer.", "Añadir una capa.", "Добавить слой.", "添加一个动画层.", "레이어를 추가합니다.") \
|
||||
@@ -463,6 +477,7 @@ namespace anm2ed
|
||||
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_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_COLUMNS, "Set how many columns the spritesheet will have.", "Ajusta cuantas columnas va a tener el spritesheet.", "Установить сколько колонн будет иметь спрайт-лист.", "设置图集有多少列.", "스프라이트 시트의 열 수를 설정합니다.") \
|
||||
X(TOOLTIP_CROP, "Change the crop position the frame uses.", "Cambiar la poscicion de recortado que usa el Frame.", "Изменить позицию обрезки, которую использует кадр.", "更改当前帧的裁剪位置.", "프레임에 대응되는 스프라이트 시트를 어느 지점부터 사용할지 변경합니다.") \
|
||||
X(TOOLTIP_CUSTOM_RANGE, "Toggle using a custom range for the animation.", "Alterna usando un rango personalizado para la animacion.", "Переключить использование пользовательского диапазона для анимации.", "切换是否让动画使用自定义区间.", "애니메이션에 사용자 지정 길이를 사용할지 정합니다.") \
|
||||
@@ -531,6 +546,7 @@ namespace anm2ed
|
||||
X(TOOLTIP_RELOAD_SOUNDS, "Reloads the selected sounds.", "Recarga los sonidos seleccionados.", "Перезагружает выбранные звуки.", "重新加载所选声音.", "선택한 사운드를 다시 불러옵니다.") \
|
||||
X(TOOLTIP_REMOVE_ANIMATION, "Remove the selected animation(s).", "Remueve la(s) animacion(es) seleccionada(s).", "Удалить выбранные анимации.", "去除所选动画.", "선택한 애니메이션을 제거합니다.") \
|
||||
X(TOOLTIP_REMOVE_ITEMS, "Remove the selected item(s).", "Remueve el/los item(s) seleccionado(s).", "Удалить выбранные предметы.", "去除所选物品.", "선택한 항목을 제거합니다.") \
|
||||
X(TOOLTIP_REMOVE_UNUSED_REGIONS, "Remove unused regions (i.e., ones not used by any frame in any animation.)", "Remueve regiones no utilizadas (es decir, aquellas no usadas por ningun frame en ninguna animacion.)", "Удалить неиспользуемые регионы (т. е. те, которые не используются ни одним кадром ни в одной анимации.)", "移除未使用的区域(即未被任何动画中的任何帧使用的区域。)", "사용되지 않는 영역(어떤 애니메이션의 어떤 프레임에서도 사용되지 않는 것)를 제거합니다.") \
|
||||
X(TOOLTIP_REMOVE_UNUSED_EVENTS, "Remove unused events (i.e., ones not used by any trigger in any animation.)", "Remueve eventos no utilizados (i. e., aquellos no usados por algun trigger en ninguna animacion.)", "Удалить неиспользуемые события (т. е. события, которые не использует ни один триггер в ни одной анимации.)", "去除未使用的事件 (未被任何动画触发的事件.)", "사용되지 않는 이벤트(어떤 애니메이션의 트리거에서도 사용되지 않는 것)를 제거합니다.") \
|
||||
X(TOOLTIP_REMOVE_UNUSED_LAYERS, "Remove unused layers (i.e., ones not used in any animation.)", "Remueve capas no utilizadas (i. e., aquellos no usados en ninguna animacion.)", "Удалить неиспользуемые слои (т. е. слои, которые не используются ни одной анимацией.)", "去除未使用的动画层 (未被任何动画使用的那些)", "사용되지 않는 레이어(어떤 애니메이션에서도 사용되지 않는 것)를 제거합니다.") \
|
||||
X(TOOLTIP_REMOVE_UNUSED_NULLS, "Remove unused nulls (i.e., ones not used in any animation.)", "Remueve nulls no utilizados (i. e., aquellos no usados en ninguna animacion.)", "Удалить неиспользуемые нули (т. е. нули, которые не используются ни одной анимацией.)", "去除未使用的Null (未被任何动画使用的那些.)", "사용되지 않는 Null(어떤 애니메이션에서도 사용되지 않는 것)을 제거합니다.") \
|
||||
|
||||
@@ -94,6 +94,7 @@ namespace anm2ed
|
||||
X(CHANGE_IS_INTERPOLATED_SET, changeIsInterpolatedSet, STRING_UNDEFINED, BOOL, false) \
|
||||
X(CHANGE_IS_FLIP_X_SET, changeIsFlipXSet, STRING_UNDEFINED, BOOL, false) \
|
||||
X(CHANGE_IS_FLIP_Y_SET, changeIsFlipYSet, STRING_UNDEFINED, BOOL, false) \
|
||||
X(CHANGE_IS_REGION, changeIsRegion, STRING_UNDEFINED, BOOL, false) \
|
||||
X(CHANGE_CROP, changeCrop, STRING_UNDEFINED, VEC2, {}) \
|
||||
X(CHANGE_SIZE, changeSize, STRING_UNDEFINED, VEC2, {}) \
|
||||
X(CHANGE_POSITION, changePosition, STRING_UNDEFINED, VEC2, {}) \
|
||||
@@ -103,6 +104,7 @@ namespace anm2ed
|
||||
X(CHANGE_DURATION, changeDuration, STRING_UNDEFINED, INT, 0) \
|
||||
X(CHANGE_TINT, changeTint, STRING_UNDEFINED, VEC4, {}) \
|
||||
X(CHANGE_COLOR_OFFSET, changeColorOffset, STRING_UNDEFINED, VEC3, {}) \
|
||||
X(CHANGE_REGION_ID, changeRegionId, STRING_UNDEFINED, INT, -1) \
|
||||
X(CHANGE_IS_VISIBLE, changeIsVisible, STRING_UNDEFINED, BOOL, false) \
|
||||
X(CHANGE_IS_INTERPOLATED, changeIsInterpolated, STRING_UNDEFINED, BOOL, false) \
|
||||
X(CHANGE_IS_FLIP_X, changeIsFlipX, STRING_UNDEFINED, BOOL, false) \
|
||||
@@ -236,6 +238,7 @@ namespace anm2ed
|
||||
/* Symbol / Name / String / Type / Default */ \
|
||||
X(WINDOW_ANIMATIONS, windowIsAnimations, LABEL_ANIMATIONS_WINDOW, BOOL, true) \
|
||||
X(WINDOW_ANIMATION_PREVIEW, windowIsAnimationPreview, LABEL_ANIMATION_PREVIEW_WINDOW, BOOL, true) \
|
||||
X(WINDOW_REGIONS, windowIsRegions, LABEL_REGIONS_WINDOW, BOOL, true) \
|
||||
X(WINDOW_EVENTS, windowIsEvents, LABEL_EVENTS_WINDOW, BOOL, true) \
|
||||
X(WINDOW_FRAME_PROPERTIES, windowIsFrameProperties, LABEL_FRAME_PROPERTIES_WINDOW, BOOL, true) \
|
||||
X(WINDOW_LAYERS, windowIsLayers, LABEL_LAYERS_WINDOW, BOOL, true) \
|
||||
|
||||
@@ -18,19 +18,20 @@ namespace anm2ed
|
||||
class Snapshot
|
||||
{
|
||||
public:
|
||||
Playback playback{};
|
||||
Storage animation{};
|
||||
Storage event{};
|
||||
Storage frames{};
|
||||
Storage items{};
|
||||
Storage layer{};
|
||||
Storage merge{};
|
||||
Storage null{};
|
||||
Storage region{};
|
||||
Storage sound{};
|
||||
Storage spritesheet{};
|
||||
anm2::Anm2 anm2{};
|
||||
anm2::Reference reference{};
|
||||
float frameTime{};
|
||||
Playback playback{};
|
||||
Storage animation{};
|
||||
Storage merge{};
|
||||
Storage event{};
|
||||
Storage layer{};
|
||||
Storage null{};
|
||||
Storage sound{};
|
||||
Storage spritesheet{};
|
||||
Storage items{};
|
||||
Storage frames{};
|
||||
std::string message = snapshots::ACTION;
|
||||
};
|
||||
|
||||
|
||||
@@ -86,7 +86,8 @@ namespace anm2ed
|
||||
}
|
||||
case SDL_EVENT_USER: // Opening files
|
||||
{
|
||||
std::string droppedFile = event.drop.data ? event.drop.data : "";
|
||||
std::string droppedFile = event.user.data1 ? static_cast<const char*>(event.user.data1) : "";
|
||||
if (event.user.data1) SDL_free(event.user.data1);
|
||||
if (droppedFile.empty()) break;
|
||||
auto droppedPath = path::from_utf8(droppedFile);
|
||||
if (path::is_extension(droppedPath, "anm2"))
|
||||
|
||||
Reference in New Issue
Block a user