forked from opencode.energia.arti.ee/vt1200
195 lines
5.4 KiB
C
195 lines
5.4 KiB
C
/* movie.c -- pure decoder for the BAPL tile-delta movie format.
|
|
*
|
|
* K&R C: the 1987 TMS34010 compiler has no const, no ANSI prototypes and no
|
|
* stdint.h. The host test compiles this same file with gcc -std=c99.
|
|
*/
|
|
#include "movie.h"
|
|
|
|
#define HEADER_SIZE 36
|
|
#define INDEX_ENTRY_SIZE 6
|
|
|
|
static unsigned int rd16(p)
|
|
unsigned char *p;
|
|
{
|
|
return (unsigned int)p[0] | ((unsigned int)p[1] << 8);
|
|
}
|
|
|
|
static unsigned long rd32(p)
|
|
unsigned char *p;
|
|
{
|
|
return (unsigned long)p[0] | ((unsigned long)p[1] << 8)
|
|
| ((unsigned long)p[2] << 16) | ((unsigned long)p[3] << 24);
|
|
}
|
|
|
|
int movie_open(data, len, header)
|
|
unsigned char *data;
|
|
unsigned long len;
|
|
struct movie_header *header;
|
|
{
|
|
unsigned int version;
|
|
|
|
if (data == 0 || header == 0 || len < HEADER_SIZE) {
|
|
return -1;
|
|
}
|
|
if (data[0] != 'B' || data[1] != 'A' || data[2] != 'P' || data[3] != 'L') {
|
|
return -1;
|
|
}
|
|
version = rd16(data + 4);
|
|
if (version != 1) {
|
|
return -1;
|
|
}
|
|
header->width = rd16(data + 6);
|
|
header->height = rd16(data + 8);
|
|
header->scale = rd16(data + 10);
|
|
header->tile = rd16(data + 12);
|
|
header->tiles_x = rd16(data + 14);
|
|
header->tiles_y = rd16(data + 16);
|
|
header->frame_count = (unsigned int)rd32(data + 18);
|
|
header->index_offset = (unsigned int)rd32(data + 22);
|
|
header->data_offset = (unsigned int)rd32(data + 26);
|
|
header->source_fps = rd16(data + 30);
|
|
header->display_hz = rd16(data + 32);
|
|
if (header->scale == 0 || header->scale > 4 || header->tile == 0
|
|
|| header->tile > 32 || header->tiles_x == 0
|
|
|| header->tiles_y == 0) {
|
|
return -1;
|
|
}
|
|
if (header->width != header->tiles_x * header->tile
|
|
|| header->height != header->tiles_y * header->tile
|
|
|| header->width * header->scale > 1280
|
|
|| header->height * header->scale > 1024) {
|
|
return -1;
|
|
}
|
|
if ((unsigned long)header->index_offset
|
|
+ (unsigned long)header->frame_count * INDEX_ENTRY_SIZE > len) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
unsigned int movie_frame_ticks(data, len, frame, header)
|
|
unsigned char *data;
|
|
unsigned long len;
|
|
unsigned int frame;
|
|
struct movie_header *header;
|
|
{
|
|
unsigned long index_off;
|
|
|
|
if (data == 0 || header == 0 || frame >= header->frame_count) {
|
|
return 1;
|
|
}
|
|
index_off = (unsigned long)header->index_offset
|
|
+ (unsigned long)frame * INDEX_ENTRY_SIZE;
|
|
if (index_off + INDEX_ENTRY_SIZE > len) {
|
|
return 1;
|
|
}
|
|
return (unsigned int)data[index_off + 4];
|
|
}
|
|
|
|
int movie_decode_frame(data, len, frame, header, fill, ctx)
|
|
unsigned char *data;
|
|
unsigned long len;
|
|
unsigned int frame;
|
|
struct movie_header *header;
|
|
movie_fill_fn fill;
|
|
void *ctx;
|
|
{
|
|
unsigned long index_off;
|
|
unsigned long off;
|
|
unsigned int count;
|
|
unsigned int i;
|
|
unsigned int j;
|
|
unsigned int tile_index;
|
|
unsigned int packed;
|
|
unsigned int bg;
|
|
unsigned int rects;
|
|
unsigned int tx;
|
|
unsigned int ty;
|
|
unsigned int value;
|
|
unsigned int x0;
|
|
unsigned int y0;
|
|
unsigned int w;
|
|
unsigned int h;
|
|
int sx;
|
|
int sy;
|
|
|
|
if (data == 0 || header == 0 || fill == 0) {
|
|
return -1;
|
|
}
|
|
if (frame >= header->frame_count) {
|
|
return -1;
|
|
}
|
|
index_off = (unsigned long)header->index_offset
|
|
+ (unsigned long)frame * INDEX_ENTRY_SIZE;
|
|
if (index_off + INDEX_ENTRY_SIZE > len) {
|
|
return -1;
|
|
}
|
|
off = rd32(data + index_off);
|
|
if (off + 2 > len) {
|
|
return -1;
|
|
}
|
|
count = rd16(data + off);
|
|
off += 2;
|
|
|
|
for (i = 0; i < count; i++) {
|
|
if (off + 4 > len) {
|
|
return -1;
|
|
}
|
|
tile_index = rd16(data + off);
|
|
packed = rd16(data + off + 2);
|
|
off += 4;
|
|
if (tile_index >= header->tiles_x * header->tiles_y) {
|
|
return -1;
|
|
}
|
|
bg = packed >> 15;
|
|
rects = packed & 0x7FFF;
|
|
if (off + (unsigned long)rects * 3 > len) {
|
|
return -1;
|
|
}
|
|
tx = tile_index % header->tiles_x;
|
|
ty = tile_index / header->tiles_x;
|
|
|
|
/* The whole tile first: the old pixels outside every new rect must
|
|
* go away. The C test skips this first call per tile. */
|
|
sx = (int)(tx * header->tile * header->scale);
|
|
sy = (int)(ty * header->tile * header->scale);
|
|
fill(sx, sy, (int)(header->tile * header->scale),
|
|
(int)(header->tile * header->scale), (int)bg, ctx);
|
|
|
|
for (j = 0; j < rects; j++) {
|
|
value = (unsigned int)data[off]
|
|
| ((unsigned int)data[off + 1] << 8)
|
|
| ((unsigned int)data[off + 2] << 16);
|
|
off += 3;
|
|
x0 = value & 0x1F;
|
|
y0 = (value >> 5) & 0x1F;
|
|
w = ((value >> 10) & 0x1F) + 1;
|
|
h = ((value >> 15) & 0x1F) + 1;
|
|
if (x0 + w > header->tile || y0 + h > header->tile) {
|
|
return -1;
|
|
}
|
|
sx = (int)((tx * header->tile + x0) * header->scale);
|
|
sy = (int)((ty * header->tile + y0) * header->scale);
|
|
fill(sx, sy, (int)(w * header->scale),
|
|
(int)(h * header->scale), (int)(1 - bg), ctx);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
unsigned int movie_checksum(data, len)
|
|
unsigned char *data;
|
|
unsigned long len;
|
|
{
|
|
unsigned long sum = 0;
|
|
unsigned long i;
|
|
|
|
if (data == 0) {
|
|
return 0;
|
|
}
|
|
for (i = 0; i < len; i++) {
|
|
sum = (sum + data[i]) & 0xFFFFFFFF;
|
|
}
|
|
return (unsigned int)sum;
|
|
}
|