mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-03 20:54:01 +00:00
New FLI/FLC encoder/decoder (fix #7)
This commit is contained in:
parent
2a0f8ca536
commit
3d700ab94c
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -13,3 +13,6 @@
|
||||
[submodule "third_party/libwebp"]
|
||||
path = third_party/libwebp
|
||||
url = https://chromium.googlesource.com/webm/libwebp
|
||||
[submodule "src/flic"]
|
||||
path = src/flic
|
||||
url = https://github.com/aseprite/flic.git
|
||||
|
@ -73,7 +73,6 @@ of the following projects created by third-parties:
|
||||
* [Google Test](http://code.google.com/p/googletest/) - [gtest license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/gtest-LICENSE.txt)
|
||||
* [XFree86](http://www.x.org/) - [XFree86 license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/XFree86-LICENSE.txt)
|
||||
* [curl](http://curl.haxx.se/) - [curl license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/curl-LICENSE.txt)
|
||||
* [gfli](https://github.com/aseprite/aseprite/blob/master/src/app/file/fli/README) - [GPL license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/GPL.txt)
|
||||
* [giflib](http://sourceforge.net/projects/giflib/) - [giflib license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/giflib-LICENSE.txt)
|
||||
* [libjpeg](http://www.ijg.org/) - [libjpeg license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/libjpeg-LICENSE.txt)
|
||||
* [libpng](http://www.libpng.org/pub/png/) - [libpng license](https://github.com/aseprite/aseprite/tree/master/docs/licenses/libpng-LICENSE.txt)
|
||||
|
@ -91,6 +91,7 @@ add_subdirectory(base)
|
||||
include_directories(${BASE_INCLUDE_DIR})
|
||||
|
||||
add_subdirectory(cfg)
|
||||
add_subdirectory(flic)
|
||||
add_subdirectory(css)
|
||||
add_subdirectory(doc)
|
||||
add_subdirectory(render)
|
||||
|
@ -16,6 +16,7 @@ because they don't depend on any other component.
|
||||
* [allegro](allegro/): Modified version of [Allegro](http://alleg.sourceforge.net/) library, used for keyboard/mouse input, and drawing 2D graphics on screen.
|
||||
* [base](base/): Core/basic stuff, multithreading, utf8, sha1, file system, memory, etc.
|
||||
* [css](css/): Pseudo-style sheet library.
|
||||
* [flic](flic/): Library to load/save FLI/FLC files
|
||||
* [gfx](gfx/): Abstract graphics structures like point, size, rectangle, region, color, etc.
|
||||
* [scripting](scripting/): JavaScript engine ([V8](https://code.google.com/p/v8/)).
|
||||
* [undo](undo/): Generic library to manage a history of undoable commands.
|
||||
|
@ -280,7 +280,6 @@ add_library(app-lib
|
||||
file/file.cpp
|
||||
file/file_format.cpp
|
||||
file/file_formats_manager.cpp
|
||||
file/fli/fli.cpp
|
||||
file/palette_file.cpp
|
||||
file/split_filename.cpp
|
||||
${file_formats}
|
||||
@ -411,6 +410,7 @@ target_link_libraries(app-lib
|
||||
doc-lib
|
||||
filters-lib
|
||||
fixmath-lib
|
||||
flic-lib
|
||||
gfx-lib
|
||||
net-lib
|
||||
render-lib
|
||||
|
@ -1,35 +0,0 @@
|
||||
GFLI
|
||||
----
|
||||
|
||||
This is the second version of my FLI plugin for "The GIMP". It now adds
|
||||
saving, and the fli load/save functions are separated from the GIMP
|
||||
interface, to allow them to be reused for other projects.
|
||||
|
||||
The saving supports currently only BRUN and LC chunks. LC2 chunks may
|
||||
be added in the future. You should make a backup as an animated GIF if
|
||||
possible, because saving is not tested very much.
|
||||
|
||||
gfli.c: Gimp wrapper for fli.c
|
||||
fli.c: functions to load/save FLI movies
|
||||
|
||||
Please write me about your experiences with this plug-in:
|
||||
<jchrr@hrz.uni-bielefeld.de>
|
||||
|
||||
This is another idea I had recently:
|
||||
The FLI format allows to add chunks with new data to a frame, that are
|
||||
skipped by readers that don't understand them.
|
||||
They will require a special reader. This is easy to write, because all the
|
||||
fli handling is in "fli.c", and can be reused for other programs.
|
||||
- MIDI events: Background musik ! (I'd need to recycle some code from
|
||||
"playmidi" and "timidity")
|
||||
- Text events (subtitles)
|
||||
- CD-Audio synchronisation
|
||||
- Trigger playback of external PCM files (digitized speech)
|
||||
|
||||
Known limitations:
|
||||
- The FLI format allows to change the palette from frame to frame. This does
|
||||
not work in Gimp, because Gimp allows only one palette per image. I'd have
|
||||
to translate the image to True-Color while loading.
|
||||
- Animations consume a lot of memory and swapping will slow the playback
|
||||
down.
|
||||
Jens Ch. Restemeier
|
@ -1,725 +0,0 @@
|
||||
/*
|
||||
* Written 1998 Jens Ch. Restemeier <jchrr@hrz.uni-bielefeld.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Modified by David Capello to use with Aseprite (2001-2012). */
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "fli.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/*
|
||||
* To avoid endian-problems I wrote these functions:
|
||||
*/
|
||||
static unsigned char fli_read_char(FILE *f)
|
||||
{
|
||||
unsigned char b;
|
||||
fread(&b,1,1,f);
|
||||
return b;
|
||||
}
|
||||
|
||||
static unsigned short fli_read_short(FILE *f)
|
||||
{
|
||||
unsigned char b[2];
|
||||
fread(&b,1,2,f);
|
||||
return (unsigned short)(b[1]<<8) | b[0];
|
||||
}
|
||||
|
||||
static unsigned long fli_read_long(FILE *f)
|
||||
{
|
||||
unsigned char b[4];
|
||||
fread(&b,1,4,f);
|
||||
return (unsigned long)(b[3]<<24) | (b[2]<<16) | (b[1]<<8) | b[0];
|
||||
}
|
||||
|
||||
static void fli_write_char(FILE *f, unsigned char b)
|
||||
{
|
||||
fwrite(&b,1,1,f);
|
||||
}
|
||||
|
||||
static void fli_write_short(FILE *f, unsigned short w)
|
||||
{
|
||||
unsigned char b[2];
|
||||
b[0]=w&255;
|
||||
b[1]=(w>>8)&255;
|
||||
fwrite(&b,1,2,f);
|
||||
}
|
||||
|
||||
static void fli_write_long(FILE *f, unsigned long l)
|
||||
{
|
||||
unsigned char b[4];
|
||||
b[0]=l&255;
|
||||
b[1]=(l>>8)&255;
|
||||
b[2]=(l>>16)&255;
|
||||
b[3]=(l>>24)&255;
|
||||
fwrite(&b,1,4,f);
|
||||
}
|
||||
|
||||
void fli_read_header(FILE *f, s_fli_header *fli_header)
|
||||
{
|
||||
fli_header->filesize=fli_read_long(f); /* 0 */
|
||||
fli_header->magic=fli_read_short(f); /* 4 */
|
||||
fli_header->frames=fli_read_short(f); /* 6 */
|
||||
fli_header->width=fli_read_short(f); /* 8 */
|
||||
fli_header->height=fli_read_short(f); /* 10 */
|
||||
fli_header->depth=fli_read_short(f); /* 12 */
|
||||
fli_header->flags=fli_read_short(f); /* 14 */
|
||||
if (fli_header->magic == HEADER_FLI) {
|
||||
/* FLI saves speed in 1/70s */
|
||||
fli_header->speed=fli_read_short(f)*14; /* 16 */
|
||||
} else {
|
||||
if (fli_header->magic == HEADER_FLC) {
|
||||
/* FLC saves speed in 1/1000s */
|
||||
fli_header->speed=fli_read_long(f); /* 16 */
|
||||
} else {
|
||||
fprintf(stderr, "error: magic number is wrong !\n");
|
||||
fli_header->magic = NO_HEADER;
|
||||
}
|
||||
}
|
||||
|
||||
if (fli_header->width == 0)
|
||||
fli_header->width = 320;
|
||||
|
||||
if (fli_header->height == 0)
|
||||
fli_header->height = 200;
|
||||
}
|
||||
|
||||
void fli_write_header(FILE *f, s_fli_header *fli_header)
|
||||
{
|
||||
fli_header->filesize=ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
fli_write_long(f, fli_header->filesize); /* 0 */
|
||||
fli_write_short(f, fli_header->magic); /* 4 */
|
||||
fli_write_short(f, fli_header->frames); /* 6 */
|
||||
fli_write_short(f, fli_header->width); /* 8 */
|
||||
fli_write_short(f, fli_header->height); /* 10 */
|
||||
fli_write_short(f, fli_header->depth); /* 12 */
|
||||
fli_write_short(f, fli_header->flags); /* 14 */
|
||||
if (fli_header->magic == HEADER_FLI) {
|
||||
/* FLI saves speed in 1/70s */
|
||||
fli_write_short(f, (unsigned short)fli_header->speed / 14); /* 16 */
|
||||
} else {
|
||||
if (fli_header->magic == HEADER_FLC) {
|
||||
/* FLC saves speed in 1/1000s */
|
||||
fli_write_long(f, fli_header->speed); /* 16 */
|
||||
fseek(f, 80, SEEK_SET);
|
||||
fli_write_long(f, fli_header->oframe1); /* 80 */
|
||||
fli_write_long(f, fli_header->oframe2); /* 84 */
|
||||
} else {
|
||||
fprintf(stderr, "error: magic number in header is wrong !\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fli_read_frame(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *old_cmap, unsigned char *framebuf, unsigned char *cmap)
|
||||
{
|
||||
s_fli_frame fli_frame;
|
||||
unsigned long framepos;
|
||||
int c;
|
||||
framepos=ftell(f);
|
||||
|
||||
fli_frame.size=fli_read_long(f);
|
||||
fli_frame.magic=fli_read_short(f);
|
||||
fli_frame.chunks=fli_read_short(f);
|
||||
|
||||
if (fli_frame.magic == FRAME) {
|
||||
fseek(f, framepos+16, SEEK_SET);
|
||||
for (c=0;c<fli_frame.chunks;c++) {
|
||||
s_fli_chunk chunk;
|
||||
unsigned long chunkpos;
|
||||
chunkpos = ftell(f);
|
||||
chunk.size=fli_read_long(f);
|
||||
chunk.magic=fli_read_short(f);
|
||||
switch (chunk.magic) {
|
||||
case FLI_COLOR: fli_read_color(f, fli_header, old_cmap, cmap); break;
|
||||
case FLI_COLOR_2: fli_read_color_2(f, fli_header, old_cmap, cmap); break;
|
||||
case FLI_BLACK: fli_read_black(f, fli_header, framebuf); break;
|
||||
case FLI_BRUN: fli_read_brun(f, fli_header, framebuf); break;
|
||||
case FLI_COPY: fli_read_copy(f, fli_header, framebuf); break;
|
||||
case FLI_LC: fli_read_lc(f, fli_header, old_framebuf, framebuf); break;
|
||||
case FLI_LC_2: fli_read_lc_2(f, fli_header, old_framebuf, framebuf); break;
|
||||
case FLI_MINI: /* unused, skip */ break;
|
||||
default: /* unknown, skip */ break;
|
||||
}
|
||||
if (chunk.size & 1) chunk.size++;
|
||||
fseek(f,chunkpos+chunk.size,SEEK_SET);
|
||||
}
|
||||
} /* else: unknown, skip */
|
||||
fseek(f, framepos+fli_frame.size, SEEK_SET);
|
||||
}
|
||||
|
||||
void fli_write_frame(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *old_cmap, unsigned char *framebuf, unsigned char *cmap, unsigned short codec_mask)
|
||||
{
|
||||
s_fli_frame fli_frame;
|
||||
unsigned long framepos, frameend;
|
||||
framepos=ftell(f);
|
||||
fseek(f, framepos+16, SEEK_SET);
|
||||
|
||||
switch (fli_header->frames) {
|
||||
case 0: fli_header->oframe1=framepos; break;
|
||||
case 1: fli_header->oframe2=framepos; break;
|
||||
}
|
||||
|
||||
fli_frame.size=0;
|
||||
fli_frame.magic=FRAME;
|
||||
fli_frame.chunks=0;
|
||||
|
||||
/*
|
||||
* create color chunk
|
||||
*/
|
||||
if (fli_header->magic == HEADER_FLI) {
|
||||
if (fli_write_color(f, fli_header, old_cmap, cmap)) fli_frame.chunks++;
|
||||
} else {
|
||||
if (fli_header->magic == HEADER_FLC) {
|
||||
if (fli_write_color_2(f, fli_header, old_cmap, cmap)) fli_frame.chunks++;
|
||||
} else {
|
||||
fprintf(stderr, "error: magic number in header is wrong !\n");
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (codec_mask & W_COLOR) {
|
||||
if (fli_write_color(f, fli_header, old_cmap, cmap)) fli_frame.chunks++;
|
||||
}
|
||||
if (codec_mask & W_COLOR_2) {
|
||||
if (fli_write_color_2(f, fli_header, old_cmap, cmap)) fli_frame.chunks++;
|
||||
}
|
||||
#endif
|
||||
/* create bitmap chunk */
|
||||
if (old_framebuf==NULL) {
|
||||
fli_write_brun(f, fli_header, framebuf);
|
||||
} else {
|
||||
fli_write_lc(f, fli_header, old_framebuf, framebuf);
|
||||
}
|
||||
fli_frame.chunks++;
|
||||
|
||||
frameend=ftell(f);
|
||||
fli_frame.size=frameend-framepos;
|
||||
fseek(f, framepos, SEEK_SET);
|
||||
fli_write_long(f, fli_frame.size);
|
||||
fli_write_short(f, fli_frame.magic);
|
||||
fli_write_short(f, fli_frame.chunks);
|
||||
fseek(f, frameend, SEEK_SET);
|
||||
fli_header->frames++;
|
||||
}
|
||||
|
||||
/*
|
||||
* palette chunks from the classical Autodesk Animator.
|
||||
*/
|
||||
void fli_read_color(FILE *f, s_fli_header *fli_header, unsigned char *old_cmap, unsigned char *cmap)
|
||||
{
|
||||
unsigned short num_packets, cnt_packets, col_pos;
|
||||
col_pos=0;
|
||||
num_packets=fli_read_short(f);
|
||||
for (cnt_packets=num_packets; cnt_packets>0; cnt_packets--) {
|
||||
unsigned short skip_col, num_col, col_cnt;
|
||||
skip_col=fli_read_char(f);
|
||||
num_col=fli_read_char(f);
|
||||
if (num_col==0) {
|
||||
for (col_pos=0; col_pos<768; col_pos++) {
|
||||
cmap[col_pos]=fli_read_char(f)<<2;
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (col_cnt=skip_col; (col_cnt>0) && (col_pos<768); col_cnt--) {
|
||||
cmap[col_pos]=old_cmap[col_pos];col_pos++;
|
||||
cmap[col_pos]=old_cmap[col_pos];col_pos++;
|
||||
cmap[col_pos]=old_cmap[col_pos];col_pos++;
|
||||
}
|
||||
for (col_cnt=num_col; (col_cnt>0) && (col_pos<768); col_cnt--) {
|
||||
cmap[col_pos++]=fli_read_char(f)<<2;
|
||||
cmap[col_pos++]=fli_read_char(f)<<2;
|
||||
cmap[col_pos++]=fli_read_char(f)<<2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int fli_write_color(FILE *f, s_fli_header *fli_header, unsigned char *old_cmap, unsigned char *cmap)
|
||||
{
|
||||
unsigned long chunkpos;
|
||||
unsigned short num_packets;
|
||||
s_fli_chunk chunk;
|
||||
chunkpos=ftell(f);
|
||||
fseek(f, chunkpos+8, SEEK_SET);
|
||||
num_packets=0;
|
||||
if (old_cmap==NULL) {
|
||||
unsigned short col_pos;
|
||||
num_packets=1;
|
||||
fli_write_char(f, 0); /* skip no color */
|
||||
fli_write_char(f, 0); /* 256 color */
|
||||
for (col_pos=0; col_pos<768; col_pos++) {
|
||||
fli_write_char(f, cmap[col_pos]>>2);
|
||||
}
|
||||
} else {
|
||||
unsigned short cnt_skip, cnt_col, col_pos, col_start;
|
||||
col_pos=0;
|
||||
do {
|
||||
cnt_skip=0;
|
||||
while ((col_pos<256) && (old_cmap[col_pos*3+0]==cmap[col_pos*3+0]) && (old_cmap[col_pos*3+1]==cmap[col_pos*3+1]) && (old_cmap[col_pos*3+2]==cmap[col_pos*3+2])) {
|
||||
cnt_skip++; col_pos++;
|
||||
}
|
||||
col_start=col_pos*3;
|
||||
cnt_col=0;
|
||||
while ((col_pos<256) && !((old_cmap[col_pos*3+0]==cmap[col_pos*3+0]) && (old_cmap[col_pos*3+1]==cmap[col_pos*3+1]) && (old_cmap[col_pos*3+2]==cmap[col_pos*3+2]))) {
|
||||
cnt_col++; col_pos++;
|
||||
}
|
||||
if (cnt_col>0) {
|
||||
num_packets++;
|
||||
fli_write_char(f, cnt_skip & 255);
|
||||
fli_write_char(f, cnt_col & 255);
|
||||
while (cnt_col>0) {
|
||||
fli_write_char(f, cmap[col_start++]>>2);
|
||||
fli_write_char(f, cmap[col_start++]>>2);
|
||||
fli_write_char(f, cmap[col_start++]>>2);
|
||||
cnt_col--;
|
||||
}
|
||||
}
|
||||
} while (col_pos<256);
|
||||
}
|
||||
|
||||
if (num_packets>0) {
|
||||
chunk.size=ftell(f)-chunkpos;
|
||||
chunk.magic=FLI_COLOR;
|
||||
|
||||
fseek(f, chunkpos, SEEK_SET);
|
||||
fli_write_long(f, chunk.size);
|
||||
fli_write_short(f, chunk.magic);
|
||||
fli_write_short(f, num_packets);
|
||||
|
||||
if (chunk.size & 1) chunk.size++;
|
||||
fseek(f,chunkpos+chunk.size,SEEK_SET);
|
||||
return 1;
|
||||
}
|
||||
fseek(f,chunkpos, SEEK_SET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* palette chunks from Autodesk Animator pro
|
||||
*/
|
||||
void fli_read_color_2(FILE *f, s_fli_header *fli_header, unsigned char *old_cmap, unsigned char *cmap)
|
||||
{
|
||||
unsigned short num_packets, cnt_packets, col_pos;
|
||||
num_packets=fli_read_short(f);
|
||||
col_pos=0;
|
||||
for (cnt_packets=num_packets; cnt_packets>0; cnt_packets--) {
|
||||
unsigned short skip_col, num_col, col_cnt;
|
||||
skip_col=fli_read_char(f);
|
||||
num_col=fli_read_char(f);
|
||||
if (num_col == 0) {
|
||||
for (col_pos=0; col_pos<768; col_pos++) {
|
||||
cmap[col_pos]=fli_read_char(f);
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (col_cnt=skip_col; (col_cnt>0) && (col_pos<768); col_cnt--) {
|
||||
cmap[col_pos]=old_cmap[col_pos];col_pos++;
|
||||
cmap[col_pos]=old_cmap[col_pos];col_pos++;
|
||||
cmap[col_pos]=old_cmap[col_pos];col_pos++;
|
||||
}
|
||||
for (col_cnt=num_col; (col_cnt>0) && (col_pos<768); col_cnt--) {
|
||||
cmap[col_pos++]=fli_read_char(f);
|
||||
cmap[col_pos++]=fli_read_char(f);
|
||||
cmap[col_pos++]=fli_read_char(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int fli_write_color_2(FILE *f, s_fli_header *fli_header, unsigned char *old_cmap, unsigned char *cmap)
|
||||
{
|
||||
unsigned long chunkpos;
|
||||
unsigned short num_packets;
|
||||
s_fli_chunk chunk;
|
||||
chunkpos=ftell(f);
|
||||
fseek(f, chunkpos+8, SEEK_SET);
|
||||
num_packets=0;
|
||||
if (old_cmap==NULL) {
|
||||
unsigned short col_pos;
|
||||
num_packets=1;
|
||||
fli_write_char(f, 0); /* skip no color */
|
||||
fli_write_char(f, 0); /* 256 color */
|
||||
for (col_pos=0; col_pos<768; col_pos++) {
|
||||
fli_write_char(f, cmap[col_pos]);
|
||||
}
|
||||
} else {
|
||||
unsigned short cnt_skip, cnt_col, col_pos, col_start;
|
||||
col_pos=0;
|
||||
do {
|
||||
cnt_skip=0;
|
||||
while ((col_pos<256) && (old_cmap[col_pos*3+0]==cmap[col_pos*3+0]) && (old_cmap[col_pos*3+1]==cmap[col_pos*3+1]) && (old_cmap[col_pos*3+2]==cmap[col_pos*3+2])) {
|
||||
cnt_skip++; col_pos++;
|
||||
}
|
||||
col_start=col_pos*3;
|
||||
cnt_col=0;
|
||||
while ((col_pos<256) && !((old_cmap[col_pos*3+0]==cmap[col_pos*3+0]) && (old_cmap[col_pos*3+1]==cmap[col_pos*3+1]) && (old_cmap[col_pos*3+2]==cmap[col_pos*3+2]))) {
|
||||
cnt_col++; col_pos++;
|
||||
}
|
||||
if (cnt_col>0) {
|
||||
num_packets++;
|
||||
fli_write_char(f, (unsigned char)cnt_skip);
|
||||
fli_write_char(f, (unsigned char)cnt_col);
|
||||
while (cnt_col>0) {
|
||||
fli_write_char(f, cmap[col_start++]);
|
||||
fli_write_char(f, cmap[col_start++]);
|
||||
fli_write_char(f, cmap[col_start++]);
|
||||
cnt_col--;
|
||||
}
|
||||
}
|
||||
} while (col_pos<256);
|
||||
}
|
||||
|
||||
if (num_packets>0) {
|
||||
chunk.size=ftell(f)-chunkpos;
|
||||
chunk.magic=FLI_COLOR_2;
|
||||
|
||||
fseek(f, chunkpos, SEEK_SET);
|
||||
fli_write_long(f, chunk.size);
|
||||
fli_write_short(f, chunk.magic);
|
||||
fli_write_short(f, num_packets);
|
||||
|
||||
if (chunk.size & 1) chunk.size++;
|
||||
fseek(f,chunkpos+chunk.size,SEEK_SET);
|
||||
return 1;
|
||||
}
|
||||
fseek(f,chunkpos, SEEK_SET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* completely black frame
|
||||
*/
|
||||
void fli_read_black(FILE *f, s_fli_header *fli_header, unsigned char *framebuf)
|
||||
{
|
||||
memset(framebuf, 0, fli_header->width * fli_header->height);
|
||||
}
|
||||
|
||||
void fli_write_black(FILE *f, s_fli_header *fli_header, unsigned char *framebuf)
|
||||
{
|
||||
s_fli_chunk chunk;
|
||||
|
||||
chunk.size=6;
|
||||
chunk.magic=FLI_BLACK;
|
||||
|
||||
fli_write_long(f, chunk.size);
|
||||
fli_write_short(f, chunk.magic);
|
||||
}
|
||||
|
||||
/*
|
||||
* Uncompressed frame
|
||||
*/
|
||||
void fli_read_copy(FILE *f, s_fli_header *fli_header, unsigned char *framebuf)
|
||||
{
|
||||
fread(framebuf, fli_header->width, fli_header->height, f);
|
||||
}
|
||||
|
||||
void fli_write_copy(FILE *f, s_fli_header *fli_header, unsigned char *framebuf)
|
||||
{
|
||||
|
||||
unsigned long chunkpos;
|
||||
s_fli_chunk chunk;
|
||||
chunkpos=ftell(f);
|
||||
fseek(f, chunkpos+6, SEEK_SET);
|
||||
fwrite(framebuf, fli_header->width, fli_header->height, f);
|
||||
chunk.size=ftell(f)-chunkpos;
|
||||
chunk.magic=FLI_COPY;
|
||||
|
||||
fseek(f, chunkpos, SEEK_SET);
|
||||
fli_write_long(f, chunk.size);
|
||||
fli_write_short(f, chunk.magic);
|
||||
|
||||
if (chunk.size & 1) chunk.size++;
|
||||
fseek(f,chunkpos+chunk.size,SEEK_SET);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a RLE algorithm, used for the first image of an animation
|
||||
*/
|
||||
void fli_read_brun(FILE *f, s_fli_header *fli_header, unsigned char *framebuf)
|
||||
{
|
||||
unsigned short yc;
|
||||
unsigned char *pos;
|
||||
for (yc=0; yc < fli_header->height; yc++) {
|
||||
unsigned short xc, pc, pcnt;
|
||||
pc=fli_read_char(f);
|
||||
xc=0;
|
||||
pos=framebuf+(fli_header->width * yc);
|
||||
for (pcnt=pc; pcnt>0; pcnt--) {
|
||||
unsigned short ps;
|
||||
ps=fli_read_char(f);
|
||||
if (ps & 0x80) {
|
||||
unsigned short len;
|
||||
for (len=-(signed char)ps; len>0; len--) {
|
||||
pos[xc++]=fli_read_char(f);
|
||||
}
|
||||
} else {
|
||||
unsigned char val;
|
||||
val=fli_read_char(f);
|
||||
memset(&(pos[xc]), val, ps);
|
||||
xc+=ps;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fli_write_brun(FILE *f, s_fli_header *fli_header, unsigned char *framebuf)
|
||||
{
|
||||
unsigned long chunkpos;
|
||||
s_fli_chunk chunk;
|
||||
unsigned short yc;
|
||||
unsigned char *linebuf;
|
||||
|
||||
chunkpos=ftell(f);
|
||||
fseek(f, chunkpos+6, SEEK_SET);
|
||||
|
||||
for (yc=0; yc < fli_header->height; yc++) {
|
||||
unsigned short xc, t1, pc, tc;
|
||||
unsigned long linepos, lineend, bc;
|
||||
linepos=ftell(f); bc=0;
|
||||
fseek(f, 1, SEEK_CUR);
|
||||
linebuf=framebuf + (yc*fli_header->width);
|
||||
xc=0; tc=0; t1=0;
|
||||
while (xc < fli_header->width) {
|
||||
pc=1;
|
||||
while ((pc<120) && ((xc+pc)<fli_header->width) && (linebuf[xc+pc] == linebuf[xc])) {
|
||||
pc++;
|
||||
}
|
||||
if (pc>2) {
|
||||
if (tc>0) {
|
||||
bc++;
|
||||
fli_write_char(f, (tc-1)^0xFF);
|
||||
fwrite(linebuf+t1, 1, tc, f);
|
||||
tc=0;
|
||||
}
|
||||
bc++;
|
||||
fli_write_char(f, (unsigned char)pc);
|
||||
fli_write_char(f, linebuf[xc]);
|
||||
t1=xc+pc;
|
||||
} else {
|
||||
tc+=pc;
|
||||
if (tc>120) {
|
||||
bc++;
|
||||
fli_write_char(f, (tc-1)^0xFF);
|
||||
fwrite(linebuf+t1, 1, tc, f);
|
||||
tc=0;
|
||||
t1=xc+pc;
|
||||
}
|
||||
}
|
||||
xc+=pc;
|
||||
}
|
||||
if (tc>0) {
|
||||
bc++;
|
||||
fli_write_char(f, (tc-1)^0xFF);
|
||||
fwrite(linebuf+t1, 1, tc, f);
|
||||
tc=0;
|
||||
}
|
||||
lineend=ftell(f);
|
||||
fseek(f, linepos, SEEK_SET);
|
||||
fli_write_char(f, (unsigned char)bc);
|
||||
fseek(f, lineend, SEEK_SET);
|
||||
}
|
||||
|
||||
chunk.size=ftell(f)-chunkpos;
|
||||
chunk.magic=FLI_BRUN;
|
||||
|
||||
fseek(f, chunkpos, SEEK_SET);
|
||||
fli_write_long(f, chunk.size);
|
||||
fli_write_short(f, chunk.magic);
|
||||
|
||||
if (chunk.size & 1) chunk.size++;
|
||||
fseek(f,chunkpos+chunk.size,SEEK_SET);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the delta-compression method from the classic Autodesk Animator.
|
||||
* It's basically the RLE method from above, but it allows to skip unchanged
|
||||
* lines at the beginning and end of an image, and unchanged pixels in a line
|
||||
* This chunk is used in FLI files.
|
||||
*/
|
||||
void fli_read_lc(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *framebuf)
|
||||
{
|
||||
unsigned short yc, firstline, numline;
|
||||
unsigned char *pos;
|
||||
memcpy(framebuf, old_framebuf, fli_header->width * fli_header->height);
|
||||
firstline = fli_read_short(f);
|
||||
numline = fli_read_short(f);
|
||||
for (yc=0; yc < numline; yc++) {
|
||||
unsigned short xc, pc, pcnt;
|
||||
pc=fli_read_char(f);
|
||||
xc=0;
|
||||
pos=framebuf+(fli_header->width * (firstline+yc));
|
||||
for (pcnt=pc; pcnt>0; pcnt--) {
|
||||
unsigned short ps,skip;
|
||||
skip=fli_read_char(f);
|
||||
ps=fli_read_char(f);
|
||||
xc+=skip;
|
||||
if (ps & 0x80) {
|
||||
unsigned char val;
|
||||
ps=-(signed char)ps;
|
||||
val=fli_read_char(f);
|
||||
memset(&(pos[xc]), val, ps);
|
||||
xc+=ps;
|
||||
} else {
|
||||
fread(&(pos[xc]), ps, 1, f);
|
||||
xc+=ps;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fli_write_lc(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *framebuf)
|
||||
{
|
||||
unsigned long chunkpos;
|
||||
s_fli_chunk chunk;
|
||||
unsigned short yc, firstline, numline, lastline;
|
||||
unsigned char *linebuf, *old_linebuf;
|
||||
|
||||
chunkpos=ftell(f);
|
||||
fseek(f, chunkpos+6, SEEK_SET);
|
||||
|
||||
/* first check, how many lines are unchanged at the beginning */
|
||||
firstline=0;
|
||||
while ((memcmp(old_framebuf+(firstline*fli_header->width), framebuf+(firstline*fli_header->width), fli_header->width)==0) && (firstline<fli_header->height)) firstline++;
|
||||
|
||||
/* then check from the end, how many lines are unchanged */
|
||||
if (firstline<fli_header->height) {
|
||||
lastline=fli_header->height-1;
|
||||
while ((memcmp(old_framebuf+(lastline*fli_header->width), framebuf+(lastline*fli_header->width), fli_header->width)==0) && (lastline>firstline)) lastline--;
|
||||
numline=(lastline-firstline)+1;
|
||||
} else {
|
||||
numline=0;
|
||||
}
|
||||
if (numline==0) firstline=0;
|
||||
|
||||
fli_write_short(f, firstline);
|
||||
fli_write_short(f, numline);
|
||||
|
||||
for (yc=0; yc < numline; yc++) {
|
||||
unsigned short xc, sc, cc, tc;
|
||||
unsigned long linepos, lineend, bc;
|
||||
linepos=ftell(f); bc=0;
|
||||
fseek(f, 1, SEEK_CUR);
|
||||
|
||||
linebuf=framebuf + ((firstline+yc)*fli_header->width);
|
||||
old_linebuf=old_framebuf + ((firstline+yc)*fli_header->width);
|
||||
xc=0;
|
||||
while (xc < fli_header->width) {
|
||||
sc=0;
|
||||
while ((linebuf[xc]==old_linebuf[xc]) && (xc<fli_header->width) && (sc<255)) {
|
||||
xc++; sc++;
|
||||
}
|
||||
fli_write_char(f, (unsigned char)sc);
|
||||
cc=1;
|
||||
while ((linebuf[xc]==linebuf[xc+cc]) && ((xc+cc)<fli_header->width) && (cc<120)) {
|
||||
cc++;
|
||||
}
|
||||
if (cc>2) {
|
||||
bc++;
|
||||
fli_write_char(f, (cc-1)^0xFF);
|
||||
fli_write_char(f, linebuf[xc]);
|
||||
xc+=cc;
|
||||
} else {
|
||||
tc=0;
|
||||
do {
|
||||
sc=0;
|
||||
while ((linebuf[tc+xc+sc]==old_linebuf[tc+xc+sc]) && ((tc+xc+sc)<fli_header->width) && (sc<5)) {
|
||||
sc++;
|
||||
}
|
||||
cc=1;
|
||||
while ((linebuf[tc+xc]==linebuf[tc+xc+cc]) && ((tc+xc+cc)<fli_header->width) && (cc<10)) {
|
||||
cc++;
|
||||
}
|
||||
tc++;
|
||||
} while ((tc<120) && (cc<9) && (sc<4) && ((xc+tc)<fli_header->width));
|
||||
bc++;
|
||||
fli_write_char(f, (unsigned char)tc);
|
||||
fwrite(linebuf+xc, tc, 1, f);
|
||||
xc+=tc;
|
||||
}
|
||||
}
|
||||
lineend=ftell(f);
|
||||
fseek(f, linepos, SEEK_SET);
|
||||
fli_write_char(f, (unsigned char)bc);
|
||||
fseek(f, lineend, SEEK_SET);
|
||||
}
|
||||
|
||||
chunk.size=ftell(f)-chunkpos;
|
||||
chunk.magic=FLI_LC;
|
||||
|
||||
fseek(f, chunkpos, SEEK_SET);
|
||||
fli_write_long(f, chunk.size);
|
||||
fli_write_short(f, chunk.magic);
|
||||
|
||||
if (chunk.size & 1) chunk.size++;
|
||||
fseek(f,chunkpos+chunk.size,SEEK_SET);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This is an enhanced version of the old delta-compression used by
|
||||
* the autodesk animator pro. It's word-oriented, and allows to skip
|
||||
* larger parts of the image. This chunk is used in FLC files.
|
||||
*/
|
||||
void fli_read_lc_2(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *framebuf)
|
||||
{
|
||||
unsigned short yc, lc, numline;
|
||||
unsigned char *pos;
|
||||
memcpy(framebuf, old_framebuf, fli_header->width * fli_header->height);
|
||||
yc=0;
|
||||
numline = fli_read_short(f);
|
||||
for (lc=0; lc < numline; lc++) {
|
||||
unsigned short xc, pc, pcnt, lpf, lpn;
|
||||
pc=fli_read_short(f);
|
||||
lpf=0; lpn=0;
|
||||
while (pc & 0x8000) {
|
||||
if (pc & 0x4000) {
|
||||
yc+=-(signed short)pc;
|
||||
} else {
|
||||
lpf=1;lpn=pc&0xFF;
|
||||
}
|
||||
pc=fli_read_short(f);
|
||||
}
|
||||
xc=0;
|
||||
pos=framebuf+(fli_header->width * yc);
|
||||
for (pcnt=pc; pcnt>0; pcnt--) {
|
||||
unsigned short ps,skip;
|
||||
skip=fli_read_char(f);
|
||||
ps=fli_read_char(f);
|
||||
xc+=skip;
|
||||
if (ps & 0x80) {
|
||||
unsigned char v1,v2;
|
||||
ps=-(signed char)ps;
|
||||
v1=fli_read_char(f);
|
||||
v2=fli_read_char(f);
|
||||
while (ps>0) {
|
||||
pos[xc++]=v1;
|
||||
pos[xc++]=v2;
|
||||
ps--;
|
||||
}
|
||||
} else {
|
||||
fread(&(pos[xc]), ps, 2, f);
|
||||
xc+=ps << 1;
|
||||
}
|
||||
}
|
||||
if (lpf) pos[xc]=(unsigned char)lpn;
|
||||
yc++;
|
||||
}
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
/*
|
||||
* Written 1998 Jens Ch. Restemeier <jchrr@hrz.uni-bielefeld.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
#ifndef APP_FILE_FLI_FLI_H_INCLUDED
|
||||
#define APP_FILE_FLI_FLI_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
/** structures */
|
||||
|
||||
typedef struct _fli_header {
|
||||
unsigned long filesize;
|
||||
unsigned short magic;
|
||||
unsigned short frames;
|
||||
unsigned short width;
|
||||
unsigned short height;
|
||||
unsigned short depth;
|
||||
unsigned short flags;
|
||||
unsigned long speed;
|
||||
unsigned long created;
|
||||
unsigned long creator;
|
||||
unsigned long updated;
|
||||
unsigned short aspect_x, aspect_y;
|
||||
unsigned long oframe1, oframe2;
|
||||
} s_fli_header;
|
||||
|
||||
typedef struct _fli_frame {
|
||||
unsigned long size;
|
||||
unsigned short magic;
|
||||
unsigned short chunks;
|
||||
} s_fli_frame;
|
||||
|
||||
typedef struct _fli_chunk {
|
||||
unsigned long size;
|
||||
unsigned short magic;
|
||||
unsigned char *data;
|
||||
} s_fli_chunk;
|
||||
|
||||
/** chunk magics */
|
||||
#define NO_HEADER 0
|
||||
#define HEADER_FLI 0xAF11
|
||||
#define HEADER_FLC 0xAF12
|
||||
#define FRAME 0xF1FA
|
||||
|
||||
/** codec magics */
|
||||
#define FLI_COLOR 11
|
||||
#define FLI_BLACK 13
|
||||
#define FLI_BRUN 15
|
||||
#define FLI_COPY 16
|
||||
#define FLI_LC 12
|
||||
#define FLI_LC_2 7
|
||||
#define FLI_COLOR_2 4
|
||||
#define FLI_MINI 18
|
||||
|
||||
/** codec masks */
|
||||
#define W_COLOR 0x0001
|
||||
#define W_BLACK 0x0002
|
||||
#define W_BRUN 0x0004
|
||||
#define W_COPY 0x0008
|
||||
#define W_LC 0x0010
|
||||
#define W_LC_2 0x0020
|
||||
#define W_COLOR_2 0x0040
|
||||
#define W_MINI 0x0080
|
||||
#define W_ALL 0xFFFF
|
||||
|
||||
/** functions */
|
||||
void fli_read_header(FILE *f, s_fli_header *fli_header);
|
||||
void fli_read_frame(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *old_cmap, unsigned char *framebuf, unsigned char *cmap);
|
||||
|
||||
void fli_read_color(FILE *f, s_fli_header *fli_header, unsigned char *old_cmap, unsigned char *cmap);
|
||||
void fli_read_color_2(FILE *f, s_fli_header *fli_header, unsigned char *old_cmap, unsigned char *cmap);
|
||||
void fli_read_black(FILE *f, s_fli_header *fli_header, unsigned char *framebuf);
|
||||
void fli_read_brun(FILE *f, s_fli_header *fli_header, unsigned char *framebuf);
|
||||
void fli_read_copy(FILE *f, s_fli_header *fli_header, unsigned char *framebuf);
|
||||
void fli_read_lc(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *framebuf);
|
||||
void fli_read_lc_2(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *framebuf);
|
||||
|
||||
void fli_write_header(FILE *f, s_fli_header *fli_header);
|
||||
void fli_write_frame(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *old_cmap, unsigned char *framebuf, unsigned char *cmap, unsigned short codec_mask);
|
||||
|
||||
int fli_write_color(FILE *f, s_fli_header *fli_header, unsigned char *old_cmap, unsigned char *cmap);
|
||||
int fli_write_color_2(FILE *f, s_fli_header *fli_header, unsigned char *old_cmap, unsigned char *cmap);
|
||||
void fli_write_black(FILE *f, s_fli_header *fli_header, unsigned char *framebuf);
|
||||
void fli_write_brun(FILE *f, s_fli_header *fli_header, unsigned char *framebuf);
|
||||
void fli_write_copy(FILE *f, s_fli_header *fli_header, unsigned char *framebuf);
|
||||
void fli_write_lc(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *framebuf);
|
||||
void fli_write_lc_2(FILE *f, s_fli_header *fli_header, unsigned char *old_framebuf, unsigned char *framebuf);
|
||||
|
||||
#endif
|
@ -12,11 +12,11 @@
|
||||
#include "app/document.h"
|
||||
#include "app/file/file.h"
|
||||
#include "app/file/file_format.h"
|
||||
#include "app/file/fli/fli.h"
|
||||
#include "app/file/format_options.h"
|
||||
#include "app/modules/palettes.h"
|
||||
#include "base/file_handle.h"
|
||||
#include "doc/doc.h"
|
||||
#include "flic/flic.h"
|
||||
#include "render/render.h"
|
||||
|
||||
#include <cstdio>
|
||||
@ -25,8 +25,6 @@ namespace app {
|
||||
|
||||
using namespace base;
|
||||
|
||||
static int get_time_precision(Sprite *sprite);
|
||||
|
||||
class FliFormat : public FileFormat {
|
||||
const char* onGetName() const { return "flc"; }
|
||||
const char* onGetExtensions() const { return "flc,fli"; }
|
||||
@ -52,223 +50,195 @@ FileFormat* CreateFliFormat()
|
||||
|
||||
bool FliFormat::onLoad(FileOp* fop)
|
||||
{
|
||||
#define SETPAL() \
|
||||
do { \
|
||||
for (c=0; c<256; c++) { \
|
||||
pal->setEntry(c, rgba(cmap[c*3], \
|
||||
cmap[c*3+1], \
|
||||
cmap[c*3+2], 255)); \
|
||||
} \
|
||||
pal->setFrame(frpos_out); \
|
||||
sprite->setPalette(pal, true); \
|
||||
} while (0)
|
||||
|
||||
unsigned char cmap[768];
|
||||
unsigned char omap[768];
|
||||
s_fli_header fli_header;
|
||||
int c, w, h;
|
||||
frame_t frpos_in;
|
||||
frame_t frpos_out;
|
||||
#ifdef USE_LINK
|
||||
int index = 0; // TODO this is used to create linked cels
|
||||
#endif
|
||||
|
||||
// Open the file to read in binary mode
|
||||
FileHandle handle(open_file_with_exception(fop->filename, "rb"));
|
||||
FILE* f = handle.get();
|
||||
flic::StdioFileInterface finterface(f);
|
||||
flic::Decoder decoder(&finterface);
|
||||
|
||||
fli_read_header(f, &fli_header);
|
||||
fseek(f, 128, SEEK_SET);
|
||||
|
||||
if (fli_header.magic == NO_HEADER) {
|
||||
flic::Header header;
|
||||
if (!decoder.readHeader(header)) {
|
||||
fop_error(fop, "The file doesn't have a FLIC header\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Size by frame
|
||||
w = fli_header.width;
|
||||
h = fli_header.height;
|
||||
int w = header.width;
|
||||
int h = header.height;
|
||||
|
||||
// Create the bitmaps
|
||||
base::UniquePtr<Image> bmp(Image::create(IMAGE_INDEXED, w, h));
|
||||
base::UniquePtr<Image> old(Image::create(IMAGE_INDEXED, w, h));
|
||||
base::UniquePtr<Palette> pal(new Palette(frame_t(0), 256));
|
||||
// Create a temporal bitmap
|
||||
ImageRef bmp(Image::create(IMAGE_INDEXED, w, h));
|
||||
Palette pal(0, 1);
|
||||
Cel* prevCel = nullptr;
|
||||
|
||||
// Create the image
|
||||
// Create the sprite
|
||||
Sprite* sprite = new Sprite(IMAGE_INDEXED, w, h, 256);
|
||||
LayerImage* layer = new LayerImage(sprite);
|
||||
sprite->folder()->addLayer(layer);
|
||||
layer->configureAsBackground();
|
||||
|
||||
// Set frames and speed
|
||||
sprite->setTotalFrames(frame_t(fli_header.frames));
|
||||
sprite->setDurationForAllFrames(fli_header.speed);
|
||||
sprite->setTotalFrames(frame_t(header.frames));
|
||||
sprite->setDurationForAllFrames(header.speed);
|
||||
|
||||
// Write frame by frame
|
||||
for (frpos_in = frpos_out = frame_t(0);
|
||||
frpos_in < sprite->totalFrames();
|
||||
++frpos_in) {
|
||||
flic::Frame fliFrame;
|
||||
flic::Colormap oldFliColormap;
|
||||
fliFrame.pixels = bmp->getPixelAddress(0, 0);
|
||||
fliFrame.rowstride = IndexedTraits::getRowStrideBytes(bmp->width());
|
||||
|
||||
frame_t frame_out = 0;
|
||||
for (frame_t frame_in=0;
|
||||
frame_in<sprite->totalFrames();
|
||||
++frame_in) {
|
||||
// Read the frame
|
||||
fli_read_frame(f, &fli_header,
|
||||
(unsigned char *)old->getPixelAddress(0, 0), omap,
|
||||
(unsigned char *)bmp->getPixelAddress(0, 0), cmap);
|
||||
if (!decoder.readFrame(fliFrame)) {
|
||||
fop_error(fop, "Error reading frame %d\n", frame_in);
|
||||
continue;
|
||||
}
|
||||
|
||||
// First frame, or the frames changes, or the palette changes
|
||||
if ((frpos_in == 0) ||
|
||||
(count_diff_between_images(old, bmp))
|
||||
#ifndef USE_LINK /* TODO this should be configurable through a check-box */
|
||||
|| (memcmp(omap, cmap, 768) != 0)
|
||||
#endif
|
||||
) {
|
||||
// The image changes?
|
||||
if (frpos_in != 0)
|
||||
++frpos_out;
|
||||
// Palette change
|
||||
bool palChange = false;
|
||||
if (frame_out == 0 || oldFliColormap != fliFrame.colormap) {
|
||||
oldFliColormap = fliFrame.colormap;
|
||||
|
||||
pal.resize(fliFrame.colormap.size());
|
||||
for (int c=0; c<int(fliFrame.colormap.size()); c++) {
|
||||
pal.setEntry(c, rgba(fliFrame.colormap[c].r,
|
||||
fliFrame.colormap[c].g,
|
||||
fliFrame.colormap[c].b, 255));
|
||||
}
|
||||
pal.setFrame(frame_out);
|
||||
sprite->setPalette(&pal, true);
|
||||
|
||||
palChange = true;
|
||||
}
|
||||
|
||||
// First frame, or the frame changes
|
||||
if (!prevCel ||
|
||||
(count_diff_between_images(prevCel->image(), bmp.get()))) {
|
||||
// Add the new frame
|
||||
ImageRef image(Image::createCopy(bmp));
|
||||
Cel* cel = new Cel(frpos_out, image);
|
||||
ImageRef image(Image::createCopy(bmp.get()));
|
||||
Cel* cel = new Cel(frame_out, image);
|
||||
layer->addCel(cel);
|
||||
|
||||
// First frame or the palette changes
|
||||
if ((frpos_in == 0) || (memcmp(omap, cmap, 768) != 0))
|
||||
SETPAL();
|
||||
prevCel = cel;
|
||||
++frame_out;
|
||||
}
|
||||
#ifdef USE_LINK
|
||||
// The palette changes
|
||||
else if (memcmp(omap, cmap, 768) != 0) {
|
||||
++frpos_out;
|
||||
SETPAL();
|
||||
else if (palChange) {
|
||||
Cel* cel = Cel::createLink(prevCel);
|
||||
cel->setFrame(frame_out);
|
||||
layer->addCel(cel);
|
||||
|
||||
// Add link
|
||||
Cel* cel = new Cel(frpos_out, index);
|
||||
layer_add_cel(layer, cel);
|
||||
++frame_out;
|
||||
}
|
||||
#endif
|
||||
// The palette and the image don't change: add duration to the last added frame
|
||||
else {
|
||||
sprite->setFrameDuration(frpos_out,
|
||||
sprite->frameDuration(frpos_out)+fli_header.speed);
|
||||
sprite->setFrameDuration(
|
||||
frame_out-1, sprite->frameDuration(frame_out-1) + header.speed);
|
||||
}
|
||||
|
||||
// Update the old image and color-map to the new ones to compare later
|
||||
copy_image(old, bmp);
|
||||
memcpy(omap, cmap, 768);
|
||||
if (header.frames > 0)
|
||||
fop_progress(fop, (float)(frame_in+1) / (float)(header.frames));
|
||||
|
||||
// Update progress
|
||||
fop_progress(fop, (float)(frpos_in+1) / (float)(sprite->totalFrames()));
|
||||
if (fop_is_stop(fop))
|
||||
break;
|
||||
|
||||
// Just one frame?
|
||||
if (fop->oneframe)
|
||||
break;
|
||||
}
|
||||
|
||||
// Update number of frames
|
||||
sprite->setTotalFrames(frpos_out+1);
|
||||
if (frame_out > 0)
|
||||
sprite->setTotalFrames(frame_out);
|
||||
|
||||
fop->createDocument(sprite);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SAVE
|
||||
bool FliFormat::onSave(FileOp* fop)
|
||||
{
|
||||
Sprite* sprite = fop->document->sprite();
|
||||
unsigned char cmap[768];
|
||||
unsigned char omap[768];
|
||||
s_fli_header fli_header;
|
||||
int c, times;
|
||||
Palette *pal;
|
||||
|
||||
/* prepare fli header */
|
||||
fli_header.filesize = 0;
|
||||
fli_header.frames = 0;
|
||||
fli_header.width = sprite->width();
|
||||
fli_header.height = sprite->height();
|
||||
|
||||
if ((fli_header.width == 320) && (fli_header.height == 200))
|
||||
fli_header.magic = HEADER_FLI;
|
||||
else
|
||||
fli_header.magic = HEADER_FLC;
|
||||
|
||||
fli_header.depth = 8;
|
||||
fli_header.flags = 3;
|
||||
fli_header.speed = get_time_precision(sprite);
|
||||
fli_header.created = 0;
|
||||
fli_header.updated = 0;
|
||||
fli_header.aspect_x = 1;
|
||||
fli_header.aspect_y = 1;
|
||||
fli_header.oframe1 = fli_header.oframe2 = 0;
|
||||
|
||||
/* open the file to write in binary mode */
|
||||
FileHandle handle(open_file_with_exception(fop->filename, "wb"));
|
||||
FILE* f = handle.get();
|
||||
|
||||
fseek(f, 128, SEEK_SET);
|
||||
|
||||
// Create the bitmaps
|
||||
base::UniquePtr<Image> bmp(Image::create(IMAGE_INDEXED, sprite->width(), sprite->height()));
|
||||
base::UniquePtr<Image> old(Image::create(IMAGE_INDEXED, sprite->width(), sprite->height()));
|
||||
render::Render render;
|
||||
|
||||
// Write frame by frame
|
||||
for (frame_t frpos(0);
|
||||
frpos < sprite->totalFrames();
|
||||
++frpos) {
|
||||
// Get color map
|
||||
pal = sprite->palette(frpos);
|
||||
for (c=0; c<256; c++) {
|
||||
cmap[3*c ] = rgba_getr(pal->getEntry(c));
|
||||
cmap[3*c+1] = rgba_getg(pal->getEntry(c));
|
||||
cmap[3*c+2] = rgba_getb(pal->getEntry(c));
|
||||
}
|
||||
|
||||
// Render the frame in the bitmap
|
||||
render.renderSprite(bmp, sprite, frpos);
|
||||
|
||||
// How many times this frame should be written to get the same
|
||||
// time that it has in the sprite
|
||||
times = sprite->frameDuration(frpos) / fli_header.speed;
|
||||
|
||||
for (c=0; c<times; c++) {
|
||||
// Write this frame
|
||||
if (frpos == 0 && c == 0)
|
||||
fli_write_frame(f, &fli_header, NULL, NULL,
|
||||
(unsigned char *)bmp->getPixelAddress(0, 0), cmap, W_ALL);
|
||||
else
|
||||
fli_write_frame(f, &fli_header,
|
||||
(unsigned char *)old->getPixelAddress(0, 0), omap,
|
||||
(unsigned char *)bmp->getPixelAddress(0, 0), cmap, W_ALL);
|
||||
|
||||
// Update the old image and color-map to the new ones to compare later
|
||||
copy_image(old, bmp);
|
||||
memcpy(omap, cmap, 768);
|
||||
}
|
||||
|
||||
// Update progress
|
||||
fop_progress(fop, (float)(frpos+1) / (float)(sprite->totalFrames()));
|
||||
}
|
||||
|
||||
// Write the header and close the file
|
||||
fli_write_header(f, &fli_header);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int get_time_precision(Sprite *sprite)
|
||||
{
|
||||
int precision = 1000;
|
||||
// Check if all frames have the same duration
|
||||
bool constantFrameRate = true;
|
||||
for (frame_t c(1); c < sprite->totalFrames(); ++c) {
|
||||
if (sprite->frameDuration(c-1) != sprite->frameDuration(c)) {
|
||||
constantFrameRate = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (constantFrameRate)
|
||||
return sprite->frameDuration(0);
|
||||
|
||||
int precision = 1000;
|
||||
for (frame_t c(0); c < sprite->totalFrames() && precision > 1; ++c) {
|
||||
int len = sprite->frameDuration(c);
|
||||
|
||||
while (len / precision == 0)
|
||||
precision /= 10;
|
||||
}
|
||||
|
||||
return precision;
|
||||
}
|
||||
|
||||
bool FliFormat::onSave(FileOp* fop)
|
||||
{
|
||||
Sprite* sprite = fop->document->sprite();
|
||||
|
||||
// Open the file to write in binary mode
|
||||
FileHandle handle(open_file_with_exception(fop->filename, "wb"));
|
||||
FILE* f = handle.get();
|
||||
flic::StdioFileInterface finterface(f);
|
||||
flic::Encoder encoder(&finterface);
|
||||
|
||||
flic::Header header;
|
||||
header.frames = 0;
|
||||
header.width = sprite->width();
|
||||
header.height = sprite->height();
|
||||
header.speed = get_time_precision(sprite);
|
||||
encoder.writeHeader(header);
|
||||
|
||||
// Create the bitmaps
|
||||
ImageRef bmp(Image::create(IMAGE_INDEXED, sprite->width(), sprite->height()));
|
||||
render::Render render;
|
||||
|
||||
// Write frame by frame
|
||||
flic::Frame fliFrame;
|
||||
fliFrame.pixels = bmp->getPixelAddress(0, 0);
|
||||
fliFrame.rowstride = IndexedTraits::getRowStrideBytes(bmp->width());
|
||||
for (frame_t frame_it=0;
|
||||
frame_it <= sprite->totalFrames();
|
||||
++frame_it) {
|
||||
frame_t frame = (frame_it % sprite->totalFrames());
|
||||
const Palette* pal = sprite->palette(frame);
|
||||
int size = MIN(256, pal->size());
|
||||
|
||||
for (int c=0; c<size; c++) {
|
||||
color_t color = pal->getEntry(c);
|
||||
fliFrame.colormap[c].r = rgba_getr(color);
|
||||
fliFrame.colormap[c].g = rgba_getg(color);
|
||||
fliFrame.colormap[c].b = rgba_getb(color);
|
||||
}
|
||||
|
||||
// Render the frame in the bitmap
|
||||
render.renderSprite(bmp.get(), sprite, frame);
|
||||
|
||||
// How many times this frame should be written to get the same
|
||||
// time that it has in the sprite
|
||||
if (frame_it < sprite->totalFrames()) {
|
||||
int times = sprite->frameDuration(frame) / header.speed;
|
||||
times = MAX(1, times);
|
||||
for (int c=0; c<times; c++)
|
||||
encoder.writeFrame(fliFrame);
|
||||
}
|
||||
else {
|
||||
encoder.writeRingFrame(fliFrame);
|
||||
}
|
||||
|
||||
// Update progress
|
||||
fop_progress(fop, (float)(frame_it+1) / (float)(sprite->totalFrames()+1));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace app
|
||||
|
1
src/flic
Submodule
1
src/flic
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 357b71838560fd5ff1043719b4ebe4f2a8d0e6e4
|
Loading…
x
Reference in New Issue
Block a user