diff --git a/docs/files/ase.txt b/docs/files/ase.txt index 03ebf41e5..8019ae71c 100644 --- a/docs/files/ase.txt +++ b/docs/files/ase.txt @@ -19,6 +19,7 @@ BYTE An 8-bit unsigned integer value WORD A 16-bit unsigned integer value SIGNED WORD A 16-bit signed integer value DWORD A 32-bit unsigned integer value +FIXED A 32-bit fixed point (16.16) value BYTE[n] "n" bytes. STRING length=WORD (how many characters to read next) string=BYTE[length] @@ -156,6 +157,7 @@ Layer Chunk (0x2004) 8 = Background 16 = Prefer linked cels 32 = The layer group should be displayed collapsed + 64 = The layer is a reference layer WORD Layer type 0 = Normal (image) layer 1 = Group @@ -218,6 +220,20 @@ Cel Chunk (0x2005) http://www.ietf.org/rfc/rfc1951.txt +Cel Extra Chunk (0x2006) +---------------------------------------- + +Adds extra information to the latest read cel. + + DWORD Flags (set to zero) + 1 - precise bounds are set + FIXED Precise X position + FIXED Precise Y position + FIXED Width of the cel in the sprite (scaled in real-time) + FIXED Height of the cel in the sprite + BYTE[16] For future use (set to zero) + + Mask Chunk (0x2016) DEPRECATED ---------------------------------------- diff --git a/src/app/file/ase_format.cpp b/src/app/file/ase_format.cpp index 3b70bc488..2e52aef12 100644 --- a/src/app/file/ase_format.cpp +++ b/src/app/file/ase_format.cpp @@ -18,6 +18,7 @@ #include "base/file_handle.h" #include "base/path.h" #include "doc/doc.h" +#include "fixmath/fixmath.h" #include "ui/alert.h" #include "zlib.h" @@ -26,12 +27,13 @@ #define ASE_FILE_MAGIC 0xA5E0 #define ASE_FILE_FRAME_MAGIC 0xF1FA -#define ASE_FILE_FLAG_LAYER_WITH_OPACITY 1 +#define ASE_FILE_FLAG_LAYER_WITH_OPACITY 1 #define ASE_FILE_CHUNK_FLI_COLOR2 4 #define ASE_FILE_CHUNK_FLI_COLOR 11 #define ASE_FILE_CHUNK_LAYER 0x2004 #define ASE_FILE_CHUNK_CEL 0x2005 +#define ASE_FILE_CHUNK_CEL_EXTRA 0x2006 #define ASE_FILE_CHUNK_MASK 0x2016 #define ASE_FILE_CHUNK_PATH 0x2017 #define ASE_FILE_CHUNK_FRAME_TAGS 0x2018 @@ -50,6 +52,8 @@ #define ASE_USER_DATA_FLAG_HAS_TEXT 1 #define ASE_USER_DATA_FLAG_HAS_COLOR 2 +#define ASE_CEL_EXTRA_FLAG_PRECISE_BOUNDS 1 + namespace app { using namespace base; @@ -119,12 +123,15 @@ static void ase_file_write_palette_chunk(FILE* f, ASE_FrameHeader* frame_header, static Layer* ase_file_read_layer_chunk(FILE* f, ASE_Header* header, Sprite* sprite, Layer** previous_layer, int* current_level); static void ase_file_write_layer_chunk(FILE* f, ASE_FrameHeader* frame_header, const Layer* layer, int child_level); static Cel* ase_file_read_cel_chunk(FILE* f, Sprite* sprite, LayerList& allLayers, frame_t frame, PixelFormat pixelFormat, FileOp* fop, ASE_Header* header, size_t chunk_end); +static void ase_file_read_cel_extra_chunk(FILE* f, Cel* cel); static void ase_file_write_cel_chunk(FILE* f, ASE_FrameHeader* frame_header, const Cel* cel, const LayerImage* layer, const layer_t layer_index, const Sprite* sprite, const frame_t firstFrame); +static void ase_file_write_cel_extra_chunk(FILE* f, ASE_FrameHeader* frame_header, + const Cel* cel); static Mask* ase_file_read_mask_chunk(FILE* f); #if 0 static void ase_file_write_mask_chunk(FILE* f, ASE_FrameHeader* frame_header, Mask* mask); @@ -214,6 +221,7 @@ bool AseFormat::onLoad(FileOp* fop) // Prepare variables for layer chunks Layer* last_layer = sprite->root(); WithUserData* last_object_with_user_data = nullptr; + Cel* last_cel = nullptr; int current_level = -1; LayerList allLayers; @@ -287,11 +295,18 @@ bool AseFormat::onLoad(FileOp* fop) sprite->pixelFormat(), fop, &header, chunk_pos+chunk_size); if (cel) { + last_cel = cel; last_object_with_user_data = cel->data(); } break; } + case ASE_FILE_CHUNK_CEL_EXTRA: { + if (last_cel) + ase_file_read_cel_extra_chunk(f, last_cel); + break; + } + case ASE_FILE_CHUNK_MASK: { Mask* mask = ase_file_read_mask_chunk(f); if (mask) @@ -635,6 +650,9 @@ static layer_t ase_file_write_cels(FILE* f, ASE_FrameHeader* frame_header, static_cast(layer), layer_index, sprite, firstFrame); + if (layer->isReference()) + ase_file_write_cel_extra_chunk(f, frame_header, cel); + if (!cel->link() && !cel->data()->userData().isEmpty()) { ase_file_write_user_data_chunk(f, frame_header, @@ -1320,6 +1338,25 @@ static Cel* ase_file_read_cel_chunk(FILE* f, return cel.release(); } +static void ase_file_read_cel_extra_chunk(FILE* f, Cel* cel) +{ + // Read chunk data + int flags = fgetl(f); + if (flags & ASE_CEL_EXTRA_FLAG_PRECISE_BOUNDS) { + fixmath::fixed x = fgetl(f); + fixmath::fixed y = fgetl(f); + fixmath::fixed w = fgetl(f); + fixmath::fixed h = fgetl(f); + if (w && h) { + gfx::RectF bounds(fixmath::fixtof(x), + fixmath::fixtof(y), + fixmath::fixtof(w), + fixmath::fixtof(h)); + cel->setBoundsF(bounds); + } + } +} + static void ase_file_write_cel_chunk(FILE* f, ASE_FrameHeader* frame_header, const Cel* cel, const LayerImage* layer, @@ -1426,6 +1463,24 @@ static void ase_file_write_cel_chunk(FILE* f, ASE_FrameHeader* frame_header, } } +static void ase_file_write_cel_extra_chunk(FILE* f, + ASE_FrameHeader* frame_header, + const Cel* cel) +{ + ChunkWriter chunk(f, frame_header, ASE_FILE_CHUNK_CEL_EXTRA); + + ASSERT(cel->layer()->isReference()); + + gfx::RectF bounds = cel->boundsF(); + + fputl(ASE_CEL_EXTRA_FLAG_PRECISE_BOUNDS, f); + fputl(fixmath::ftofix(bounds.x), f); + fputl(fixmath::ftofix(bounds.y), f); + fputl(fixmath::ftofix(bounds.w), f); + fputl(fixmath::ftofix(bounds.h), f); + ase_file_write_padding(f, 16); +} + static Mask* ase_file_read_mask_chunk(FILE* f) { int c, u, v, byte;