Fix slices' user data serialization on .ase format

This commit is contained in:
David Capello 2017-04-12 08:57:02 -03:00
parent 2c0d0d3682
commit 02b225868d
2 changed files with 150 additions and 129 deletions

View File

@ -287,26 +287,23 @@ Insert this user data in the last read chunk. E.g. If we've read a
layer, this user data belongs to that layer, if we've read a cel, it layer, this user data belongs to that layer, if we've read a cel, it
belongs to that cel, etc. belongs to that cel, etc.
``` Field | Details |
DWORD Flags ----------- | -------------------------------- |
1 = Has text DWORD | Flags
2 = Has color | 1 - Has text
+ If flags have bit 1: | 2 - Has color
STRING Text If flags have bit 1 |
+ If flags have bit 2: STRING | Text
BYTE Color Red (0-255) If flags have bit 2 |
BYTE Color Green (0-255) BYTE | Color Red (0-255)
BYTE Color Blue (0-255) BYTE | Color Green (0-255)
BYTE Color Alpha (0-255) BYTE | Color Blue (0-255)
``` BYTE | Color Alpha (0-255)
### Slices Chunk (0x2021) ### Slice Chunk (0x2022)
Field | Details | Field | Details |
----------- | -------------------------------- | ----------- | -------------------------------- |
DWORD | Number of slices
BYTE[8] | Reserved
For each slice... |
DWORD | Number of "slice keys" DWORD | Number of "slice keys"
DWORD | Flags DWORD | Flags
| 1 - It's a 9-patches slice | 1 - It's a 9-patches slice

View File

@ -13,6 +13,7 @@
#include "app/file/file.h" #include "app/file/file.h"
#include "app/file/file_format.h" #include "app/file/file_format.h"
#include "app/file/format_options.h" #include "app/file/format_options.h"
#include "app/pref/preferences.h"
#include "base/cfile.h" #include "base/cfile.h"
#include "base/exception.h" #include "base/exception.h"
#include "base/file_handle.h" #include "base/file_handle.h"
@ -39,7 +40,8 @@
#define ASE_FILE_CHUNK_FRAME_TAGS 0x2018 #define ASE_FILE_CHUNK_FRAME_TAGS 0x2018
#define ASE_FILE_CHUNK_PALETTE 0x2019 #define ASE_FILE_CHUNK_PALETTE 0x2019
#define ASE_FILE_CHUNK_USER_DATA 0x2020 #define ASE_FILE_CHUNK_USER_DATA 0x2020
#define ASE_FILE_CHUNK_SLICES 0x2021 #define ASE_FILE_CHUNK_SLICES 0x2021 // Deprecated chunk (used on dev versions only between v1.2-beta7 and v1.2-beta8)
#define ASE_FILE_CHUNK_SLICE 0x2022
#define ASE_FILE_LAYER_IMAGE 0 #define ASE_FILE_LAYER_IMAGE 0
#define ASE_FILE_LAYER_GROUP 1 #define ASE_FILE_LAYER_GROUP 1
@ -143,9 +145,12 @@ static void ase_file_write_mask_chunk(FILE* f, ASE_FrameHeader* frame_header, Ma
static void ase_file_read_frame_tags_chunk(FILE* f, FrameTags* frameTags); static void ase_file_read_frame_tags_chunk(FILE* f, FrameTags* frameTags);
static void ase_file_write_frame_tags_chunk(FILE* f, ASE_FrameHeader* frame_header, const FrameTags* frameTags, static void ase_file_write_frame_tags_chunk(FILE* f, ASE_FrameHeader* frame_header, const FrameTags* frameTags,
const frame_t fromFrame, const frame_t toFrame); const frame_t fromFrame, const frame_t toFrame);
static void ase_file_read_slices_chunk(FILE* f, Slices* slices); static void ase_file_read_slices_chunk(FILE* f, Slices& slices);
static void ase_file_write_slices_chunk(FILE* f, ASE_FrameHeader* frame_header, const Slices* slices, static Slice* ase_file_read_slice_chunk(FILE* f, Slices& slices);
static void ase_file_write_slice_chunks(FILE* f, ASE_FrameHeader* frame_header, const Slices& slices,
const frame_t fromFrame, const frame_t toFrame); const frame_t fromFrame, const frame_t toFrame);
static void ase_file_write_slice_chunk(FILE* f, ASE_FrameHeader* frame_header, Slice* slice,
const frame_t fromFrame, const frame_t toFrame);
static void ase_file_read_user_data_chunk(FILE* f, UserData* userData); static void ase_file_read_user_data_chunk(FILE* f, UserData* userData);
static void ase_file_write_user_data_chunk(FILE* f, ASE_FrameHeader* frame_header, const UserData* userData); static void ase_file_write_user_data_chunk(FILE* f, ASE_FrameHeader* frame_header, const UserData* userData);
static bool ase_has_groups(LayerGroup* group); static bool ase_has_groups(LayerGroup* group);
@ -332,9 +337,17 @@ bool AseFormat::onLoad(FileOp* fop)
ase_file_read_frame_tags_chunk(f, &sprite->frameTags()); ase_file_read_frame_tags_chunk(f, &sprite->frameTags());
break; break;
case ASE_FILE_CHUNK_SLICES: case ASE_FILE_CHUNK_SLICES: {
ase_file_read_slices_chunk(f, &sprite->slices()); ase_file_read_slices_chunk(f, sprite->slices());
break; break;
}
case ASE_FILE_CHUNK_SLICE: {
Slice* slice = ase_file_read_slice_chunk(f, sprite->slices());
if (slice)
last_object_with_user_data = slice;
break;
}
case ASE_FILE_CHUNK_USER_DATA: { case ASE_FILE_CHUNK_USER_DATA: {
UserData userData; UserData userData;
@ -468,11 +481,10 @@ bool AseFormat::onSave(FileOp* fop)
fop->roi().toFrame()); fop->roi().toFrame());
// Writer slice chunks // Writer slice chunks
if (sprite->slices().size() > 0) ase_file_write_slice_chunks(f, &frame_header,
ase_file_write_slices_chunk(f, &frame_header, sprite->slices(),
&sprite->slices(), fop->roi().fromFrame(),
fop->roi().fromFrame(), fop->roi().toFrame());
fop->roi().toFrame());
} }
// Write cel chunks // Write cel chunks
@ -1687,135 +1699,147 @@ static void ase_file_write_user_data_chunk(FILE* f, ASE_FrameHeader* frame_heade
} }
} }
static void ase_file_read_slices_chunk(FILE* f, Slices* slices) static void ase_file_read_slices_chunk(FILE* f, Slices& slices)
{ {
size_t nslices = fgetl(f); // Number of slices size_t nslices = fgetl(f); // Number of slices
fgetl(f); // 8 bytes reserved fgetl(f); // 8 bytes reserved
fgetl(f); fgetl(f);
for (size_t i=0; i<nslices; ++i) { for (size_t i=0; i<nslices; ++i) {
size_t nkeys = fgetl(f); // Number of keys Slice* slice = ase_file_read_slice_chunk(f, slices);
int flags = fgetl(f); // Flags // Set the user data
fgetl(f); // 4 bytes reserved if (slice) {
std::string name = ase_file_read_string(f); // Name // Default slice color
auto color = Preferences::instance().slices.defaultColor();
base::UniquePtr<Slice> slice(new Slice); slice->userData().setColor(
slice->setName(name); doc::rgba(color.getRed(),
color.getGreen(),
// For each key color.getBlue(),
for (size_t j=0; j<nkeys; ++j) { color.getAlpha()));
gfx::Rect bounds, center;
gfx::Point pivot = SliceKey::NoPivot;
frame_t frame = fgetl(f);
bounds.x = fgetl(f);
bounds.y = fgetl(f);
bounds.w = fgetl(f);
bounds.h = fgetl(f);
if (flags & ASE_SLICE_FLAG_HAS_CENTER_BOUNDS) {
center.x = fgetl(f);
center.y = fgetl(f);
center.w = fgetl(f);
center.h = fgetl(f);
}
if (flags & ASE_SLICE_FLAG_HAS_PIVOT_POINT) {
pivot.x = fgetl(f);
pivot.y = fgetl(f);
}
slice->insert(frame, SliceKey(bounds, center, pivot));
} }
slices->add(slice);
slice.release();
} }
} }
static void ase_file_write_slices_chunk(FILE* f, ASE_FrameHeader* frame_header, static Slice* ase_file_read_slice_chunk(FILE* f, Slices& slices)
const Slices* slices, {
size_t nkeys = fgetl(f); // Number of keys
int flags = fgetl(f); // Flags
fgetl(f); // 4 bytes reserved
std::string name = ase_file_read_string(f); // Name
base::UniquePtr<Slice> slice(new Slice);
slice->setName(name);
// For each key
for (size_t j=0; j<nkeys; ++j) {
gfx::Rect bounds, center;
gfx::Point pivot = SliceKey::NoPivot;
frame_t frame = fgetl(f);
bounds.x = fgetl(f);
bounds.y = fgetl(f);
bounds.w = fgetl(f);
bounds.h = fgetl(f);
if (flags & ASE_SLICE_FLAG_HAS_CENTER_BOUNDS) {
center.x = fgetl(f);
center.y = fgetl(f);
center.w = fgetl(f);
center.h = fgetl(f);
}
if (flags & ASE_SLICE_FLAG_HAS_PIVOT_POINT) {
pivot.x = fgetl(f);
pivot.y = fgetl(f);
}
slice->insert(frame, SliceKey(bounds, center, pivot));
}
slices.add(slice);
return slice.release();
}
static void ase_file_write_slice_chunks(FILE* f, ASE_FrameHeader* frame_header,
const Slices& slices,
const frame_t fromFrame, const frame_t fromFrame,
const frame_t toFrame) const frame_t toFrame)
{ {
ChunkWriter chunk(f, frame_header, ASE_FILE_CHUNK_SLICES); for (Slice* slice : slices) {
size_t nslices = 0;
for (Slice* slice : *slices) {
// Skip slices that are outside of the given ROI // Skip slices that are outside of the given ROI
if (slice->range(fromFrame, toFrame).empty()) if (slice->range(fromFrame, toFrame).empty())
continue; continue;
++nslices; ase_file_write_slice_chunk(f, frame_header, slice,
fromFrame, toFrame);
if (!slice->userData().isEmpty())
ase_file_write_user_data_chunk(f, frame_header, &slice->userData());
}
}
static void ase_file_write_slice_chunk(FILE* f, ASE_FrameHeader* frame_header,
Slice* slice,
const frame_t fromFrame,
const frame_t toFrame)
{
ChunkWriter chunk(f, frame_header, ASE_FILE_CHUNK_SLICE);
auto range = slice->range(fromFrame, toFrame);
ASSERT(!range.empty());
int flags = 0;
for (auto key : range) {
if (key) {
if (key->hasCenter()) flags |= ASE_SLICE_FLAG_HAS_CENTER_BOUNDS;
if (key->hasPivot()) flags |= ASE_SLICE_FLAG_HAS_PIVOT_POINT;
}
} }
fputl(nslices, f); fputl(range.countKeys(), f); // number of keys
fputl(0, f); // 8 reserved bytes fputl(flags, f); // flags
fputl(0, f); fputl(0, f); // 4 bytes reserved
ase_file_write_string(f, slice->name()); // slice name
for (Slice* slice : *slices) { frame_t frame = fromFrame;
// Skip slices that are outside of the given ROI const SliceKey* oldKey = nullptr;
auto range = slice->range(fromFrame, toFrame); for (auto key : range) {
if (range.empty()) if (frame == fromFrame || key != oldKey) {
continue; fputl(frame, f);
fputl(key ? key->bounds().x: 0, f);
fputl(key ? key->bounds().y: 0, f);
fputl(key ? key->bounds().w: 0, f);
fputl(key ? key->bounds().h: 0, f);
int flags = 0; if (flags & ASE_SLICE_FLAG_HAS_CENTER_BOUNDS) {
for (auto key : range) { if (key && key->hasCenter()) {
if (key) { fputl(key->center().x, f);
if (key->hasCenter()) flags |= ASE_SLICE_FLAG_HAS_CENTER_BOUNDS; fputl(key->center().y, f);
if (key->hasPivot()) flags |= ASE_SLICE_FLAG_HAS_PIVOT_POINT; fputl(key->center().w, f);
} fputl(key->center().h, f);
}
fputl(range.countKeys(), f); // number of keys
fputl(flags, f); // flags
fputl(0, f); // 4 bytes reserved
ase_file_write_string(f, slice->name()); // slice name
frame_t frame = fromFrame;
const SliceKey* oldKey = nullptr;
for (auto key : range) {
if (frame == fromFrame || key != oldKey) {
fputl(frame, f);
fputl(key ? key->bounds().x: 0, f);
fputl(key ? key->bounds().y: 0, f);
fputl(key ? key->bounds().w: 0, f);
fputl(key ? key->bounds().h: 0, f);
if (flags & ASE_SLICE_FLAG_HAS_CENTER_BOUNDS) {
if (key && key->hasCenter()) {
fputl(key->center().x, f);
fputl(key->center().y, f);
fputl(key->center().w, f);
fputl(key->center().h, f);
}
else {
fputl(0, f);
fputl(0, f);
fputl(0, f);
fputl(0, f);
}
} }
else {
if (flags & ASE_SLICE_FLAG_HAS_PIVOT_POINT) { fputl(0, f);
if (key && key->hasPivot()) { fputl(0, f);
fputl(key->pivot().x, f); fputl(0, f);
fputl(key->pivot().y, f); fputl(0, f);
}
else {
fputl(0, f);
fputl(0, f);
}
} }
oldKey = key;
} }
++frame;
}
--nslices; if (flags & ASE_SLICE_FLAG_HAS_PIVOT_POINT) {
if (key && key->hasPivot()) {
fputl(key->pivot().x, f);
fputl(key->pivot().y, f);
}
else {
fputl(0, f);
fputl(0, f);
}
}
oldKey = key;
}
++frame;
} }
ASSERT(nslices == 0);
} }
static bool ase_has_groups(LayerGroup* group) static bool ase_has_groups(LayerGroup* group)