mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-28 18:32:50 +00:00
Fix slices' user data serialization on .ase format
This commit is contained in:
parent
2c0d0d3682
commit
02b225868d
@ -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
|
||||||
|
@ -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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user