diff options
Diffstat (limited to 'src/load_gif.c')
-rw-r--r-- | src/load_gif.c | 384 |
1 files changed, 384 insertions, 0 deletions
diff --git a/src/load_gif.c b/src/load_gif.c new file mode 100644 index 00000000..a8cb6cc0 --- /dev/null +++ b/src/load_gif.c @@ -0,0 +1,384 @@ +/* + * GIF Loader + * by Paul Bartrum + * + * Comment by Eric Stevens (tome@eastevens.com): + * + * This file has been modified to work with Allegro 4.0.3 that comes with + * DJGPP 2.0.3 for the use in compiling for ToME 2.2.7. This modification + * changes a variable name to one that is not in conflict with Allegro + * variable name. The variable 'empty_string' was changed to 'empty_str'. + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <allegro.h> +#include <string.h> + +int _color_load_depth(int depth); + +struct LZW_STRING +{ + short base; + char new; + short length; +}; + +PACKFILE *f; +int empty_str, curr_bit_size, bit_overflow; +int bit_pos, data_pos, data_len, entire, code; +int cc, string_length, i, bit_size; +unsigned char string[4096]; +struct LZW_STRING str[4096]; +BITMAP *bmp; +int image_x, image_y, image_w, image_h, x, y; +int interlace; + + +void clear_table(void) +{ + empty_str = cc + 2; + curr_bit_size = bit_size + 1; + bit_overflow = 0; +} + + +void get_code(void) +{ + if (bit_pos + curr_bit_size > 8) + { + if (data_pos >= data_len) + { + data_len = pack_getc(f); + data_pos = 0; + } + entire = (pack_getc(f) << 8) + entire; + data_pos ++; + } + if (bit_pos + curr_bit_size > 16) + { + if (data_pos >= data_len) + { + data_len = pack_getc(f); + data_pos = 0; + } + entire = (pack_getc(f) << 16) + entire; + data_pos ++; + } + code = (entire >> bit_pos) & ((1 << curr_bit_size) - 1); + if (bit_pos + curr_bit_size > 8) + entire >>= 8; + if (bit_pos + curr_bit_size > 16) + entire >>= 8; + bit_pos = (bit_pos + curr_bit_size) % 8; + if (bit_pos == 0) + { + if (data_pos >= data_len) + { + data_len = pack_getc(f); + data_pos = 0; + } + entire = pack_getc(f); + data_pos ++; + } +} + + +void input_string(int num) +{ + if (num < cc) + { + string_length = 1; + string[0] = str[num].new; + } + else + { + i = str[num].length; + string_length = i; + while (i > 0) + { + i --; + string[i] = str[num].new; + num = str[num].base; + } + /* if(num != -1) **-{[ERROR]}-** */ + } +} + + +void output_string(void) +{ + for (i = 0; i < string_length; i ++) + { + putpixel(bmp, x, y, string[i]); + x ++; + if (x >= image_x + image_w) + { + x = image_x; + y += interlace; + if (interlace) + { + if (y >= image_y + image_h) + { + if (interlace == 8 && (y - image_y) % 8 == 0) + { + interlace = 8; + y = image_y + 4; + } + else if (interlace == 8 && (y - image_y) % 8 == 4) + { + interlace = 4; + y = image_y + 2; + } + else if (interlace == 4) + { + interlace = 2; + y = image_y + 1; + } + } + } + } + } +} + + +/* load_gif: + * Loads a 2-256 colour GIF file onto a bitmap, returning the bitmap + * structure and storing the pallete data in the specified pallete (this + * should be an array of at least 256 RGB structures). + */ +BITMAP *load_gif (char *filename, RGB *pal) +{ + int width, height, depth; + int old; + BITMAP *bmp2; + int dest_depth; + + f = pack_fopen(filename, F_READ); + if (!f) /* can't open file */ + return NULL; + + i = pack_mgetw(f) << 8; + i += pack_getc(f); + if (i != 0x474946) /* is it really a GIF? */ + { + pack_fclose(f); + return NULL; + } + pack_fseek(f, 3); /* skip version */ + + width = pack_igetw(f); + height = pack_igetw(f); + + bmp = create_bitmap_ex(8, width, height); + if (bmp == NULL) + { + pack_fclose(f); + return NULL; + } + clear(bmp); + + i = pack_getc(f); + if (i & 128) /* no global colour table? */ + depth = (i & 7) + 1; + else + depth = 0; + + pack_fseek(f, 2); /* skip background colour and aspect ratio */ + + if (pal && depth) /* only read palette if pal and depth are not 0 */ + { + for (i = 0; i < (1 << depth); i ++) + { + pal[i].r = pack_getc(f) / 4; + pal[i].g = pack_getc(f) / 4; + pal[i].b = pack_getc(f) / 4; + } + } + else + if (depth) + pack_fseek(f, (1 << depth) * 3); + + do + { + i = pack_getc(f); + switch (i) + { + case 0x2C: /* Image Descriptor */ + image_x = pack_igetw(f); + image_y = pack_igetw(f); /* individual image dimensions */ + image_w = pack_igetw(f); + image_h = pack_igetw(f); + + i = pack_getc(f); + if (i & 64) + interlace = 8; + else + interlace = 1; + + if (i & 128) + { + depth = (i & 7) + 1; + if (pal) + { + for (i = 0; i < (1 << depth); i ++) + { + pal[i].r = pack_getc(f) / 4; + pal[i].g = pack_getc(f) / 4; + pal[i].b = pack_getc(f) / 4; + } + } + else + pack_fseek(f, (1 << depth) * 3); + } + + /* lzw stream starts now */ + bit_size = pack_getc(f); + cc = 1 << bit_size; + + /* initialise string table */ + for (i = 0; i < cc; i ++) + { + str[i].base = -1; + str[i].new = i; + str[i].length = 1; + } + + /* initialise the variables */ + bit_pos = 0; + data_len = pack_getc(f); + data_pos = 0; + entire = pack_getc(f); + data_pos ++; + string_length = 0; + x = image_x; + y = image_y; + + /* starting code */ + clear_table(); + get_code(); + if (code == cc) + get_code(); + input_string(code); + output_string(); + old = code; + + while (TRUE) + { + get_code(); + + if (code == cc) + { + /* starting code */ + clear_table(); + get_code(); + input_string(code); + output_string(); + old = code; + } + else if (code == cc + 1) + { + break; + } + else if (code < empty_str) + { + input_string(code); + output_string(); + + if (bit_overflow == 0) + { + str[empty_str].base = old; + str[empty_str].new = string[0]; + str[empty_str].length = str[old].length + 1; + empty_str ++; + if (empty_str == (1 << curr_bit_size)) + curr_bit_size ++; + if (curr_bit_size == 13) + { + curr_bit_size = 12; + bit_overflow = 1; + } + } + + old = code; + } + else + { + input_string(old); + string[str[old].length] = string[0]; + string_length ++; + + if (bit_overflow == 0) + { + str[empty_str].base = old; + str[empty_str].new = string[0]; + str[empty_str].length = str[old].length + 1; + empty_str ++; + if (empty_str == (1 << curr_bit_size)) + curr_bit_size ++; + if (curr_bit_size == 13) + { + curr_bit_size = 12; + bit_overflow = 1; + } + } + + output_string(); + old = code; + } + } + break; + case 0x21: /* Extension Introducer */ + i = pack_getc(f); + if (i == 0xF9) /* Graphic Control Extension */ + { + pack_fseek(f, 1); /* skip size (it's 4) */ + i = pack_getc(f); + if (i & 1) /* is transparency enabled? */ + { + pack_fseek(f, 2); + pack_getc(f); /* transparent colour */ + } + else + pack_fseek(f, 3); + } + i = pack_getc(f); + while (i) /* skip Data Sub-blocks */ + { + pack_fseek(f, i); + i = pack_getc(f); + } + break; + case 0x3B: /* Trailer - end of data */ + pack_fclose(f); + + /* convert to correct colour depth */ + dest_depth = _color_load_depth(8); + + if (dest_depth != 8) + { + bmp2 = create_bitmap_ex(dest_depth, bmp->w, bmp->h); + if (!bmp2) + { + destroy_bitmap(bmp); + return NULL; + } + + select_palette(pal); + blit(bmp, bmp2, 0, 0, 0, 0, bmp->w, bmp->h); + unselect_palette(); + + destroy_bitmap(bmp); + bmp = bmp2; + } + + return bmp; + } + } + while (TRUE); + + /* this is never executed but DJGPP complains if you leave it out */ + return NULL; +} |