mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-28 16:11:35 +00:00
Add io part for layers UUIDs
This commit is contained in:
parent
86ad09291f
commit
c3cfae666b
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -44,6 +44,7 @@
|
||||
#include "doc/tilesets.h"
|
||||
#include "doc/user_data_io.h"
|
||||
#include "doc/util.h"
|
||||
#include "doc/uuid_io.h"
|
||||
#include "fixmath/fixmath.h"
|
||||
|
||||
#include <fstream>
|
||||
@ -450,6 +451,10 @@ private:
|
||||
type == ObjectType::LayerTilemap);
|
||||
|
||||
std::string name = read_string(s);
|
||||
base::Uuid uuid;
|
||||
if (m_serial >= SerialFormat::Ver3)
|
||||
uuid = read_uuid(s);
|
||||
|
||||
std::unique_ptr<Layer> lay;
|
||||
|
||||
switch (type) {
|
||||
@ -495,13 +500,15 @@ private:
|
||||
break;
|
||||
}
|
||||
|
||||
if (lay) {
|
||||
UserData userData = read_user_data(s, m_serial);
|
||||
lay->setUserData(userData);
|
||||
return lay.release();
|
||||
}
|
||||
else
|
||||
if (!lay)
|
||||
return nullptr;
|
||||
|
||||
if (m_serial >= SerialFormat::Ver3)
|
||||
lay->setUuid(uuid);
|
||||
|
||||
UserData userData = read_user_data(s, m_serial);
|
||||
lay->setUserData(userData);
|
||||
return lay.release();
|
||||
}
|
||||
|
||||
Cel* readCel(std::ifstream& s) { return read_cel(s, this, false); }
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2025 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -41,6 +41,7 @@
|
||||
#include "doc/tileset_io.h"
|
||||
#include "doc/tilesets.h"
|
||||
#include "doc/user_data_io.h"
|
||||
#include "doc/uuid_io.h"
|
||||
#include "fixmath/fixmath.h"
|
||||
|
||||
#include <fstream>
|
||||
@ -250,6 +251,7 @@ private:
|
||||
write32(s, static_cast<int>(lay->flags())); // Flags
|
||||
write16(s, static_cast<int>(lay->type())); // Type
|
||||
write_string(s, lay->name());
|
||||
write_uuid(s, lay->uuid());
|
||||
|
||||
switch (lay->type()) {
|
||||
case ObjectType::LayerImage:
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "base/file_handle.h"
|
||||
#include "base/fs.h"
|
||||
#include "base/mem_utils.h"
|
||||
#include "base/uuid.h"
|
||||
#include "dio/aseprite_common.h"
|
||||
#include "dio/aseprite_decoder.h"
|
||||
#include "dio/decode_delegate.h"
|
||||
@ -542,7 +543,8 @@ static void ase_file_prepare_header(FILE* f,
|
||||
sprite->pixelFormat() == IMAGE_INDEXED ? 8 :
|
||||
0);
|
||||
header->flags = (ASE_FILE_FLAG_LAYER_WITH_OPACITY |
|
||||
(composeGroups ? ASE_FILE_FLAG_COMPOSITE_GROUPS : 0));
|
||||
(composeGroups ? ASE_FILE_FLAG_COMPOSITE_GROUPS : 0) |
|
||||
(sprite->useUuidsForLayers() ? ASE_FILE_FLAG_LAYER_WITH_UUID : 0));
|
||||
header->speed = sprite->frameDuration(firstFrame);
|
||||
header->next = 0;
|
||||
header->frit = 0;
|
||||
@ -786,6 +788,13 @@ static void ase_file_write_palette_chunk(FILE* f,
|
||||
}
|
||||
}
|
||||
|
||||
static void ase_file_write_uuid(FILE* f, const base::Uuid& uuid)
|
||||
{
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
fputc(uuid[i], f);
|
||||
}
|
||||
}
|
||||
|
||||
static void ase_file_write_layer_chunk(FILE* f,
|
||||
const dio::AsepriteHeader* header,
|
||||
dio::AsepriteFrameHeader* frame_header,
|
||||
@ -835,6 +844,9 @@ static void ase_file_write_layer_chunk(FILE* f,
|
||||
// Tileset index
|
||||
if (layer->isTilemap())
|
||||
fputl(static_cast<const LayerTilemap*>(layer)->tilesetIndex(), f);
|
||||
|
||||
if ((header->flags & ASE_FILE_FLAG_LAYER_WITH_UUID) == ASE_FILE_FLAG_LAYER_WITH_UUID)
|
||||
ase_file_write_uuid(f, layer->uuid());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@ -1676,9 +1688,7 @@ static void ase_file_write_property_value(FILE* f, const UserData::Variant& valu
|
||||
}
|
||||
case USER_DATA_PROPERTY_TYPE_UUID: {
|
||||
auto& uuid = *std::get_if<base::Uuid>(&value);
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
fputc(uuid[i], f);
|
||||
}
|
||||
ase_file_write_uuid(f, uuid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Document IO Library
|
||||
// Copyright (c) 2018-2023 Igara Studio S.A.
|
||||
// Copyright (c) 2018-2025 Igara Studio S.A.
|
||||
// Copyright (c) 2001-2018 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -19,6 +19,7 @@
|
||||
|
||||
#define ASE_FILE_FLAG_LAYER_WITH_OPACITY 1
|
||||
#define ASE_FILE_FLAG_COMPOSITE_GROUPS 2
|
||||
#define ASE_FILE_FLAG_LAYER_WITH_UUID 4
|
||||
|
||||
#define ASE_FILE_CHUNK_FLI_COLOR2 4
|
||||
#define ASE_FILE_CHUNK_FLI_COLOR 11
|
||||
|
@ -75,6 +75,9 @@ bool AsepriteDecoder::decode()
|
||||
sprite->setGridBounds(
|
||||
gfx::Rect(header.grid_x, header.grid_y, header.grid_width, header.grid_height));
|
||||
|
||||
sprite->setUseUuidsForLayers((header.flags & ASE_FILE_FLAG_LAYER_WITH_UUID) ==
|
||||
ASE_FILE_FLAG_LAYER_WITH_UUID);
|
||||
|
||||
// Prepare variables for layer chunks
|
||||
doc::Layer* last_layer = sprite->root();
|
||||
doc::WithUserData* last_object_with_user_data = sprite.get();
|
||||
@ -577,48 +580,53 @@ doc::Layer* AsepriteDecoder::readLayerChunk(AsepriteHeader* header,
|
||||
break;
|
||||
}
|
||||
|
||||
if (layer) {
|
||||
const bool composeGroups = (header->flags & ASE_FILE_FLAG_COMPOSITE_GROUPS);
|
||||
if (!layer)
|
||||
return nullptr;
|
||||
|
||||
if ((layer->isImage() || (layer->isGroup() && composeGroups)) &&
|
||||
// Only transparent layers can have blend mode and opacity
|
||||
!(flags & int(doc::LayerFlags::Background))) {
|
||||
layer->setBlendMode((doc::BlendMode)blendmode);
|
||||
if (header->flags & ASE_FILE_FLAG_LAYER_WITH_OPACITY)
|
||||
layer->setOpacity(opacity);
|
||||
}
|
||||
// Read UUID if usage is enabled
|
||||
if (sprite->useUuidsForLayers())
|
||||
layer->setUuid(readUuid());
|
||||
|
||||
// flags
|
||||
layer->setFlags(
|
||||
static_cast<doc::LayerFlags>(flags & static_cast<int>(doc::LayerFlags::PersistentFlagsMask)));
|
||||
const bool composeGroups = (header->flags & ASE_FILE_FLAG_COMPOSITE_GROUPS);
|
||||
|
||||
// name
|
||||
layer->setName(name.c_str());
|
||||
|
||||
// Child level
|
||||
if (child_level == *current_level)
|
||||
(*previous_layer)->parent()->addLayer(layer);
|
||||
else if (child_level > *current_level)
|
||||
static_cast<doc::LayerGroup*>(*previous_layer)->addLayer(layer);
|
||||
else if (child_level < *current_level) {
|
||||
doc::LayerGroup* parent = (*previous_layer)->parent();
|
||||
ASSERT(parent);
|
||||
if (parent) {
|
||||
int levels = (*current_level - child_level);
|
||||
while (levels--) {
|
||||
ASSERT(parent->parent());
|
||||
if (!parent->parent())
|
||||
break;
|
||||
parent = parent->parent();
|
||||
}
|
||||
parent->addLayer(layer);
|
||||
}
|
||||
}
|
||||
|
||||
*previous_layer = layer;
|
||||
*current_level = child_level;
|
||||
if ((layer->isImage() || (layer->isGroup() && composeGroups)) &&
|
||||
// Only transparent layers can have blend mode and opacity
|
||||
!(flags & int(doc::LayerFlags::Background))) {
|
||||
layer->setBlendMode((doc::BlendMode)blendmode);
|
||||
if (header->flags & ASE_FILE_FLAG_LAYER_WITH_OPACITY)
|
||||
layer->setOpacity(opacity);
|
||||
}
|
||||
|
||||
// flags
|
||||
layer->setFlags(
|
||||
static_cast<doc::LayerFlags>(flags & static_cast<int>(doc::LayerFlags::PersistentFlagsMask)));
|
||||
|
||||
// name
|
||||
layer->setName(name.c_str());
|
||||
|
||||
// Child level
|
||||
if (child_level == *current_level)
|
||||
(*previous_layer)->parent()->addLayer(layer);
|
||||
else if (child_level > *current_level)
|
||||
static_cast<doc::LayerGroup*>(*previous_layer)->addLayer(layer);
|
||||
else if (child_level < *current_level) {
|
||||
doc::LayerGroup* parent = (*previous_layer)->parent();
|
||||
ASSERT(parent);
|
||||
if (parent) {
|
||||
int levels = (*current_level - child_level);
|
||||
while (levels--) {
|
||||
ASSERT(parent->parent());
|
||||
if (!parent->parent())
|
||||
break;
|
||||
parent = parent->parent();
|
||||
}
|
||||
parent->addLayer(layer);
|
||||
}
|
||||
}
|
||||
|
||||
*previous_layer = layer;
|
||||
*current_level = child_level;
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
@ -1433,12 +1441,7 @@ const doc::UserData::Variant AsepriteDecoder::readPropertyValue(uint16_t type)
|
||||
return value;
|
||||
}
|
||||
case USER_DATA_PROPERTY_TYPE_UUID: {
|
||||
base::Uuid value;
|
||||
uint8_t* bytes = value.bytes();
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
bytes[i] = read8();
|
||||
}
|
||||
return value;
|
||||
return readUuid();
|
||||
}
|
||||
default: {
|
||||
throw base::Exception(
|
||||
@ -1474,4 +1477,14 @@ void AsepriteDecoder::readTilesData(doc::Tileset* tileset, const AsepriteExterna
|
||||
}
|
||||
}
|
||||
|
||||
base::Uuid AsepriteDecoder::readUuid()
|
||||
{
|
||||
base::Uuid value;
|
||||
uint8_t* bytes = value.bytes();
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
bytes[i] = read8();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
} // namespace dio
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define DIO_ASEPRITE_DECODER_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "base/uuid.h"
|
||||
#include "dio/aseprite_common.h"
|
||||
#include "dio/decoder.h"
|
||||
#include "doc/frame.h"
|
||||
@ -77,6 +78,7 @@ private:
|
||||
const AsepriteExternalFiles& extFiles);
|
||||
const doc::UserData::Variant readPropertyValue(uint16_t type);
|
||||
void readTilesData(doc::Tileset* tileset, const AsepriteExternalFiles& extFiles);
|
||||
base::Uuid readUuid();
|
||||
|
||||
doc::LayerList m_allLayers;
|
||||
std::vector<uint32_t> m_tilesetFlags;
|
||||
|
@ -82,7 +82,8 @@ add_library(doc-lib
|
||||
tilesets.cpp
|
||||
user_data.cpp
|
||||
user_data_io.cpp
|
||||
util.cpp)
|
||||
util.cpp
|
||||
uuid_io.cpp)
|
||||
|
||||
target_link_libraries(doc-lib
|
||||
laf-gfx
|
||||
|
@ -1,10 +1,11 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2019 Igara Studio S.A.
|
||||
// Copyright (c) 2019-2025 Igara Studio S.A.
|
||||
// Copyright (c) 2001-2018 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#include "doc/uuid_io.h"
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
@ -40,6 +41,7 @@ void write_layer(std::ostream& os, const Layer* layer)
|
||||
{
|
||||
write32(os, layer->id());
|
||||
write_string(os, layer->name());
|
||||
write_uuid(os, layer->uuid());
|
||||
|
||||
write32(os, static_cast<int>(layer->flags())); // Flags
|
||||
write16(os, static_cast<int>(layer->type())); // Type
|
||||
@ -112,6 +114,10 @@ Layer* read_layer(std::istream& is, SubObjectsFromSprite* subObjects, const Seri
|
||||
{
|
||||
ObjectId id = read32(is);
|
||||
std::string name = read_string(is);
|
||||
base::Uuid uuid;
|
||||
if (serial >= SerialFormat::Ver3)
|
||||
uuid = read_uuid(is);
|
||||
|
||||
uint32_t flags = read32(is); // Flags
|
||||
uint16_t layer_type = read16(is); // Type
|
||||
std::unique_ptr<Layer> layer;
|
||||
@ -187,12 +193,16 @@ Layer* read_layer(std::istream& is, SubObjectsFromSprite* subObjects, const Seri
|
||||
|
||||
const UserData userData = read_user_data(is, serial);
|
||||
|
||||
if (layer) {
|
||||
layer->setName(name);
|
||||
layer->setFlags(static_cast<LayerFlags>(flags));
|
||||
layer->setId(id);
|
||||
layer->setUserData(userData);
|
||||
}
|
||||
if (!layer)
|
||||
return nullptr;
|
||||
|
||||
if (serial >= SerialFormat::Ver3)
|
||||
layer->setUuid(uuid);
|
||||
|
||||
layer->setName(name);
|
||||
layer->setFlags(static_cast<LayerFlags>(flags));
|
||||
layer->setId(id);
|
||||
layer->setUserData(userData);
|
||||
|
||||
return layer.release();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (c) 2020-2024 Igara Studio S.A.
|
||||
// Copyright (c) 2020-2025 Igara Studio S.A.
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
@ -19,7 +19,8 @@ enum class SerialFormat : uint16_t {
|
||||
Ver0 = 0, // Old version
|
||||
Ver1 = 1, // New version with tilesets
|
||||
Ver2 = 2, // Version 2 adds custom properties to user data
|
||||
LastVer = Ver2
|
||||
Ver3 = 3, // Version 3 adds UUIDs to layers
|
||||
LastVer = Ver3
|
||||
};
|
||||
|
||||
} // namespace doc
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2023 Igara Studio S.A.
|
||||
// Copyright (c) 2023-2025 Igara Studio S.A.
|
||||
// Copyright (c) 2001-2015 David Capello
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
@ -14,6 +14,7 @@
|
||||
#include "base/serialization.h"
|
||||
#include "doc/string_io.h"
|
||||
#include "doc/user_data.h"
|
||||
#include "doc/uuid_io.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
@ -86,9 +87,7 @@ static void write_property_value(std::ostream& os, const UserData::Variant& vari
|
||||
}
|
||||
case USER_DATA_PROPERTY_TYPE_UUID: {
|
||||
auto uuid = get_value<base::Uuid>(variant);
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
write8(os, uuid[i]);
|
||||
}
|
||||
write_uuid(os, uuid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -207,12 +206,7 @@ static UserData::Variant read_property_value(std::istream& is, uint16_t type)
|
||||
return value;
|
||||
}
|
||||
case USER_DATA_PROPERTY_TYPE_UUID: {
|
||||
base::Uuid value;
|
||||
uint8_t* bytes = value.bytes();
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
bytes[i] = read8(is);
|
||||
}
|
||||
return value;
|
||||
return read_uuid(is);
|
||||
}
|
||||
}
|
||||
|
||||
|
33
src/doc/uuid_io.cpp
Normal file
33
src/doc/uuid_io.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2025 Igara Studio S.A.
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#include "doc/uuid_io.h"
|
||||
|
||||
#include "base/serialization.h"
|
||||
#include "base/uuid.h"
|
||||
|
||||
namespace doc {
|
||||
|
||||
using namespace base::serialization;
|
||||
|
||||
base::Uuid read_uuid(std::istream& is)
|
||||
{
|
||||
base::Uuid value;
|
||||
uint8_t* bytes = value.bytes();
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
bytes[i] = read8(is);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void write_uuid(std::ostream& os, const base::Uuid& uuid)
|
||||
{
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
write8(os, uuid[i]);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace doc
|
23
src/doc/uuid_io.h
Normal file
23
src/doc/uuid_io.h
Normal file
@ -0,0 +1,23 @@
|
||||
// Aseprite Document Library
|
||||
// Copyright (c) 2025 Igara Studio S.A.
|
||||
//
|
||||
// This file is released under the terms of the MIT license.
|
||||
// Read LICENSE.txt for more information.
|
||||
|
||||
#ifndef DOC_UUID_IO_H_INCLUDED
|
||||
#define DOC_UUID_IO_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "base/uuid.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace doc {
|
||||
|
||||
base::Uuid read_uuid(std::istream& is);
|
||||
|
||||
void write_uuid(std::ostream& os, const base::Uuid& uuid);
|
||||
|
||||
} // namespace doc
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user