diff --git a/docs/ase-file-specs.md b/docs/ase-file-specs.md index 2831e6356..eefcbe0c5 100644 --- a/docs/ase-file-specs.md +++ b/docs/ase-file-specs.md @@ -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 belongs to that cel, etc. -``` - DWORD Flags - 1 = Has text - 2 = Has color - + If flags have bit 1: - STRING Text - + If flags have bit 2: - BYTE Color Red (0-255) - BYTE Color Green (0-255) - BYTE Color Blue (0-255) - BYTE Color Alpha (0-255) -``` +Field | Details | +----------- | -------------------------------- | +DWORD | Flags + | 1 - Has text + | 2 - Has color +If flags have bit 1 | +STRING | Text +If flags have bit 2 | +BYTE | Color Red (0-255) +BYTE | Color Green (0-255) +BYTE | Color Blue (0-255) +BYTE | Color Alpha (0-255) -### Slices Chunk (0x2021) +### Slice Chunk (0x2022) Field | Details | ----------- | -------------------------------- | -DWORD | Number of slices -BYTE[8] | Reserved -For each slice... | DWORD | Number of "slice keys" DWORD | Flags | 1 - It's a 9-patches slice diff --git a/src/app/file/ase_format.cpp b/src/app/file/ase_format.cpp index 021b70e99..ff0694cec 100644 --- a/src/app/file/ase_format.cpp +++ b/src/app/file/ase_format.cpp @@ -13,6 +13,7 @@ #include "app/file/file.h" #include "app/file/file_format.h" #include "app/file/format_options.h" +#include "app/pref/preferences.h" #include "base/cfile.h" #include "base/exception.h" #include "base/file_handle.h" @@ -39,7 +40,8 @@ #define ASE_FILE_CHUNK_FRAME_TAGS 0x2018 #define ASE_FILE_CHUNK_PALETTE 0x2019 #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_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_write_frame_tags_chunk(FILE* f, ASE_FrameHeader* frame_header, const FrameTags* frameTags, const frame_t fromFrame, const frame_t toFrame); -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 void ase_file_read_slices_chunk(FILE* f, 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); +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_write_user_data_chunk(FILE* f, ASE_FrameHeader* frame_header, const UserData* userData); 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()); break; - case ASE_FILE_CHUNK_SLICES: - ase_file_read_slices_chunk(f, &sprite->slices()); + case ASE_FILE_CHUNK_SLICES: { + ase_file_read_slices_chunk(f, sprite->slices()); 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: { UserData userData; @@ -468,11 +481,10 @@ bool AseFormat::onSave(FileOp* fop) fop->roi().toFrame()); // Writer slice chunks - if (sprite->slices().size() > 0) - ase_file_write_slices_chunk(f, &frame_header, - &sprite->slices(), - fop->roi().fromFrame(), - fop->roi().toFrame()); + ase_file_write_slice_chunks(f, &frame_header, + sprite->slices(), + fop->roi().fromFrame(), + fop->roi().toFrame()); } // 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 fgetl(f); // 8 bytes reserved fgetl(f); for (size_t i=0; i slice(new Slice); - slice->setName(name); - - // For each key - for (size_t j=0; jinsert(frame, SliceKey(bounds, center, pivot)); + Slice* slice = ase_file_read_slice_chunk(f, slices); + // Set the user data + if (slice) { + // Default slice color + auto color = Preferences::instance().slices.defaultColor(); + slice->userData().setColor( + doc::rgba(color.getRed(), + color.getGreen(), + color.getBlue(), + color.getAlpha())); } - - slices->add(slice); - slice.release(); } } -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) +{ + 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(new Slice); + slice->setName(name); + + // For each key + for (size_t j=0; jinsert(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 toFrame) { - ChunkWriter chunk(f, frame_header, ASE_FILE_CHUNK_SLICES); - - size_t nslices = 0; - for (Slice* slice : *slices) { + for (Slice* slice : slices) { // Skip slices that are outside of the given ROI if (slice->range(fromFrame, toFrame).empty()) 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(0, f); // 8 reserved bytes - fputl(0, 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 - for (Slice* slice : *slices) { - // Skip slices that are outside of the given ROI - auto range = slice->range(fromFrame, toFrame); - if (range.empty()) - continue; + 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); - 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(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); - } + 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); } - - 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); - } + else { + fputl(0, f); + fputl(0, f); + 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)