You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libksquirrel/kernel/kls_fli/fmt_codec_fli.cpp

450 lines
9.3 KiB

/* This file is part of ksquirrel-libs (http://ksquirrel.sf.net)
Copyright (c) 2005 Dmitry Baryshev <ksquirrel@tut.by>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation;
either version 2 of the License, or (at your option) any later
version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
as32 with this library; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "ksquirrel-libs/fmt_types.h"
#include "ksquirrel-libs/fileio.h"
#include "ksquirrel-libs/error.h"
#include "ksquirrel-libs/fmt_utils.h"
#include "fmt_codec_fli_defs.h"
#include "fmt_codec_fli.h"
#include "../xpm/codec_fli.xpm"
/*
*
* The FLI file format (sometimes called Flic)
* is one of the most popular
* animation formats found in the MS-DOS and Windows environments today. FLI is
* used widely in animation programs, computer games, and CAD applications
* requiring 3D manipulation of vector drawings. Flic, in common
* with most animation formats, does not support either audio or video data, but
* instead stores only sequences of still image data.
*
*/
// maximum number of frames in FLI is 1024
#define MAX_FRAME 1024
fmt_codec::fmt_codec() : fmt_codec_base()
{}
fmt_codec::~fmt_codec()
{}
void fmt_codec::options(codec_options *o)
{
o->version = "0.3.2";
o->name = "FLI Animation";
o->filter = "*.fli ";
o->config = "";
o->mime = "";
o->mimetype = "video/x-flic";
o->pixmap = codec_fli;
o->readable = true;
o->canbemultiple = true;
o->writestatic = false;
o->writeanimated = false;
o->needtempfile = false;
}
s32 fmt_codec::read_init(const std::string &file)
{
frs.open(file.c_str(), ios::binary | ios::in);
if(!frs.good())
return SQE_R_NOFILE;
if(!frs.readK(&flic, sizeof(FLICHEADER)))
return SQE_R_BADFILE;
if(flic.FileId != 0xAF11)// && flic.FileId != 0xAF12)
return SQE_R_BADFILE;
if(flic.Flags != 3)
cerr << "libSQ_read_fli: WARNING: Flags != 3" << endl;
memset(pal, 0, 768);
currentImage = -1;
buf = (u8**)calloc(flic.Height, sizeof(u8*));
if(!buf)
return SQE_R_NOMEMORY;
for(s32 i = 0;i < flic.Height;i++)
{
buf[i] = (u8*)0;
}
for(s32 i = 0;i < flic.Height;i++)
{
buf[i] = (u8*)calloc(flic.Width, sizeof(u8));
if(!buf[i])
return SQE_R_NOMEMORY;
}
finfo.animated = false;
return SQE_OK;
}
s32 fmt_codec::read_next()
{
currentImage++;
if(currentImage == flic.NumberOfFrames || currentImage == MAX_FRAME)
return SQE_NOTOK;
fmt_image image;
image.w = flic.Width;
image.h = flic.Height;
image.bpp = 8;
image.delay = (s32)((float)flic.FrameDelay * 14.3);
finfo.animated = (currentImage) ? true : false;
// prs32f("%dx%d@%d, delay: %d\n", flic.Width, flic.Height, flic.PixelDepth, finfo.image[currentImage].delay);
CHUNKHEADER chunk;
CHUNKHEADER subchunk;
u16 subchunks;
fstream::pos_type pos = frs.tellg();
// prs32f("POS AFTER HEADER: %d\n", pos);
while(true)
{
if(!skip_flood(frs))
return SQE_R_BADFILE;
if(!frs.readK(&chunk, sizeof(CHUNKHEADER)))
return SQE_R_BADFILE;
// prs32f("Read MAIN chunk: size: %d, type: %X\n", chunk.size, chunk.type);
if(chunk.type != CHUNK_PREFIX_TYPE &&
chunk.type != CHUNK_SCRIPT_CHUNK &&
chunk.type != CHUNK_FRAME_TYPE &&
chunk.type != CHUNK_SEGMENT_TABLE &&
chunk.type != CHUNK_HUFFMAN_TABLE)
return SQE_R_BADFILE;
if(chunk.type != CHUNK_FRAME_TYPE)
frs.seekg(chunk.size - sizeof(CHUNKHEADER), ios::cur);
else
{
if(!frs.readK(&subchunks, sizeof(u16)))
return SQE_R_BADFILE;
// prs32f("Chunk #%X has %d subchunks\n", chunk.type, subchunks);
frs.seekg(sizeof(u16) * 4, ios::cur);
break;
}
}
// prs32f("POS MAIN: %d\n", ftell(fptr));
// fsetpos(fptr, (fpos_t*)&pos);
// fseek(fptr, chunk.size, SEEK_CUR);
// prs32f("POS2 MAIN: %d\n", ftell(fptr));
while(subchunks--)
{
pos = frs.tellg();
if(!frs.readK(&subchunk, sizeof(CHUNKHEADER)))
return SQE_R_BADFILE;
// prs32f("*** Subchunk: %d\n", subchunk.type);
switch(subchunk.type)
{
case CHUNK_COLOR_64:
case CHUNK_COLOR_256:
{
// prs32f("*** Palette64 CHUNK\n");
u8 skip, count;
u16 packets;
RGB e;
if(!frs.readK(&packets, sizeof(u16)))
return SQE_R_BADFILE;
// prs32f("COLOR_64 packets: %d\n", packets);
for(s32 i = 0;i < packets;i++)
{
if(!frs.readK(&skip, 1)) return SQE_R_BADFILE;
if(!frs.readK(&count, 1)) return SQE_R_BADFILE;
// prs32f("COLOR64 skip: %d, count: %d\n", skip, count);
if(count)
{
for(s32 j = 0;j < count;j++)
{
if(!frs.readK(&e, sizeof(RGB))) return SQE_R_BADFILE;
// prs32f("COLOR_64 PALLETTE CHANGE %d,%d,%d\n", e.r, e.g, e.b);
}
}
else
{
// prs32f("Reading pallette...\n");
if(!frs.readK(pal, sizeof(RGB) * 256)) return SQE_R_BADFILE;
u8 *pp = (u8 *)pal;
if(subchunk.type == CHUNK_COLOR_64)
for(s32 j = 0;j < 768;j++)
pp[j] <<= 2;
// for(s32 j = 0;j < 256;j++)
// prs32f("COLOR_64 PALLETTE %d,%d,%d\n", pal[j].r, pal[j].g, pal[j].b);
// prs32f("\n");
}
}
}
break;
case CHUNK_RLE:
{
// prs32f("*** RLE DATA CHUNK\n");
u8 value;
s8 c;
s32 count;
for(s32 j = 0;j < image.h;j++)
{
s32 index = 0;
count = 0;
if(!frs.readK(&c, 1)) return SQE_R_BADFILE;
while(count < image.w)
{
if(!frs.readK(&c, 1)) return SQE_R_BADFILE;
if(c < 0)
{
c = -c;
for(s32 i = 0;i < c;i++)
{
if(!frs.readK(&value, 1)) return SQE_R_BADFILE;
buf[j][index] = value;
index++;
}
count += c;
}
else
{
if(!frs.readK(&value, 1)) return SQE_R_BADFILE;
for(s32 i = 0;i < c;i++)
{
buf[j][index] = value;
index++;
}
count += c;
}
}
}
}
break;
case CHUNK_DELTA_FLI:
{
u16 starty, totaly, ally, index;
u8 packets, skip, byte;
s8 size;
s32 count;
if(!frs.readK(&starty, 2)) return SQE_R_BADFILE;
if(!frs.readK(&totaly, 2)) return SQE_R_BADFILE;
ally = starty + totaly;
// prs32f("Y: %d, Total: %d\n", starty, totaly);
for(s32 j = starty;j < ally;j++)
{
count = 0;
index = 0;
if(!frs.readK(&packets, 1)) return SQE_R_BADFILE;
while(count < image.w)
{
for(s32 k = 0;k < packets;k++)
{
// prs32f("LINE %d\n", j);
if(!frs.readK(&skip, 1)) return SQE_R_BADFILE;
if(!frs.readK(&size, 1)) return SQE_R_BADFILE;
index += skip;
// prs32f("SKIP: %d, SIZE: %d\n", skip, size);
if(size > 0)
{
if(!frs.readK(buf[j]+index, size)) return SQE_R_BADFILE;
}
else if(size < 0)
{
size = -size;
if(!frs.readK(&byte, 1)) return SQE_R_BADFILE;
memset(buf[j]+index, byte, size);
}
index += size;
count += size;
}
break;
}
}
}
break;
case CHUNK_BLACK:
break;
case CHUNK_COPY:
{
// prs32f("*** COPY DATA CHUNK\n");
for(s32 j = 0;j < image.h;j++)
{
if(!frs.readK(buf[j], image.w)) return SQE_R_BADFILE;
}
}
break;
default:
// prs32f("*** UNKNOWN CHUNK! SEEKING ANYWAY\n");
frs.seekg(pos);
frs.seekg(subchunk.size, ios::cur);
}
// prs32f("POS: %d\n", ftell(fptr));
// prs32f("POS2: %d\n", ftell(fptr));
}
image.compression = "RLE/DELTA_FLI";
image.colorspace = "Color indexed";
finfo.image.push_back(image);
return SQE_OK;
}
s32 fmt_codec::read_next_pass()
{
line = -1;
return SQE_OK;
}
s32 fmt_codec::read_scanline(RGBA *scan)
{
line++;
fmt_image *im = image(currentImage);
fmt_utils::fillAlpha(scan, im->w);
for(s32 i = 0;i < im->w;i++)
{
memcpy(scan+i, pal+buf[line][i], sizeof(RGB));
}
return SQE_OK;
}
void fmt_codec::read_close()
{
if(buf)
{
for(s32 i = 0;i < flic.Height;i++)
if(buf[i])
free(buf[i]);
free(buf);
}
frs.close();
finfo.meta.clear();
finfo.image.clear();
}
bool find_chunk_type(const u16 type)
{
static const u16 A[] =
{
CHUNK_PREFIX_TYPE,
CHUNK_SCRIPT_CHUNK,
CHUNK_FRAME_TYPE,
CHUNK_SEGMENT_TABLE,
CHUNK_HUFFMAN_TABLE
};
static const s32 S = 5;
for(s32 i = 0;i < S;i++)
if(type == A[i])
return true;
return false;
}
bool fmt_codec::skip_flood(ifstreamK &s)
{
u8 _f[4];
u16 b;
fstream::pos_type _pos;
// prs32f("SKIP_FLOOD pos: %d\n", ftell(f));
if(!s.readK(_f, 4)) return false;
do
{
_pos = s.tellg();
if(!s.readK(&b, 2)) return false;
// prs32f("SKIP_FLOOD b: %X\n", b);
s.seekg(-1, ios::cur);
}while(!find_chunk_type(b));
_pos -= 4;
s.seekg(_pos);
return true;
// prs32f("SKIP_FLOOD pos2: %d\n", ftell(f));
}
#include "fmt_codec_cd_func.h"