/* Residual - Virtual machine to run LucasArts' 3D adventure games * * Residual is the legal property of its developers, whose names * are too numerous to list here. Please refer to the AUTHORS * file distributed with this source distribution. * 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 * Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * * $URL$ * $Id$ * */ #include #include #include #include #include #include int32_t read_LEint32(FILE *f) { unsigned char c[4]; fread(c, 1, 4, f); return (c[0]) | (c[1] << 8) | (c[2] << 16) | (c[3] << 24); } void read_header(FILE *in, int *codec, int *num_images, int *format) { char magic[8]; fread(magic, 1, 8, in); if (memcmp(magic, "BM F\0\0\0", 8) != 0) { fprintf(stderr, "not a bitmap file\n"); exit(1); } *codec = read_LEint32(in); read_LEint32(in); *num_images = read_LEint32(in); read_LEint32(in); /* ignore x offset */ read_LEint32(in); /* ignore y offset */ read_LEint32(in); *format = read_LEint32(in); fseek(in, 128, SEEK_SET); } void read_data_codec0(FILE *in, int width, int height, unsigned char *result) { fread(result, 1, width * height * 2, in); } void read_data_codec3(FILE *in, int size, unsigned char *result) { unsigned char *data; const unsigned char *data_ptr; int bitstr_val, bitstr_len; int offset, len; data = malloc(size); fread(data, 1, size, in); bitstr_val = data[0] | (data[1] << 8); bitstr_len = 16; data_ptr = data + 2; #define GET_BIT ({ \ int bit_result = bitstr_val & 1; \ bitstr_val >>= 1; \ bitstr_len--; \ if (bitstr_len == 0) { \ bitstr_val = data_ptr[0] | (data_ptr[1] << 8); \ bitstr_len = 16; \ data_ptr += 2; \ } \ bit_result; \ }) for (;;) { if (GET_BIT == 1) *result++ = *data_ptr++; else { if (GET_BIT == 0) { len = GET_BIT * 2; len += GET_BIT; len += 3; offset = *data_ptr - 0x100; data_ptr++; } else { offset = data_ptr[0] | ((data_ptr[1] & 0xf0) << 4); offset -= 0x1000; len = (data_ptr[1] & 0xf) + 3; data_ptr += 2; if (len == 3) { len = *data_ptr++; len++; if (len == 1) { free(data); return; } } } while (len > 0) { *result = result[offset]; result++; len--; } } } } void write_img(pixel **img, const char *fname, int img_num, int width, int height, int maxval) { const char *basename; char newname[1024]; FILE *out; basename = strrchr(fname, '/'); if (basename != NULL) basename++; else basename = fname; strcpy(newname, basename); if (strlen(newname) > 3 && strcasecmp(newname + strlen(newname) - 3, ".bm") == 0) newname[strlen(newname) - 3] = '\0'; else if (strlen(newname) > 4 && strcasecmp(newname + strlen(newname) - 4, ".zbm") == 0) { newname[strlen(newname) - 4] = '\0'; strcat(newname, "_z"); } sprintf(newname + strlen(newname), "_%d.ppm", img_num); out = fopen(newname, "wb"); if (out == NULL) { perror(newname); exit(1); } ppm_writeppm(out, img, width, height, maxval, 0); fclose(out); } pixel **toimg_fmt1(const unsigned char *data, int width, int height) { pixel **result; int x, y; int r, g, b; result = ppm_allocarray(width, height); for (y = 0; y < height; y++) for (x = 0; x < width; x++) { r = data[1] >> 3; r = (r << 3) | (r >> 2); g = ((data[1] & 7) << 3) | (data[0] >> 5); g = (g << 2) | (g >> 4); b = data[0] & 0x1f; b = (b << 3) | (b >> 2); PPM_ASSIGN(result[y][x], r, g, b); data += 2; } return result; } pixel **toimg_fmt5(const unsigned char *data, int width, int height) { pixel **result; int x, y; unsigned short gray; result = ppm_allocarray(width, height); for (y = 0; y < height; y++) for (x = 0; x < width; x++) { /* gray = data[0] | (data[1] << 8); */ gray = data[1]; PPM_ASSIGN(result[y][x], gray, gray, gray); data += 2; } return result; } void process_file(const char *fname) { FILE *in; int codec, num_images, format; int i; int width, height, size, maxval; unsigned char *data; pixel **img; in = fopen(fname, "rb"); if (in == NULL) { perror(fname); exit(1); } read_header(in, &codec, &num_images, &format); for (i = 0; i < num_images; i++) { width = read_LEint32(in); height = read_LEint32(in); data = malloc(width * height * 2); if (codec == 0) read_data_codec0(in, width, height, data); else if (codec == 3) { size = read_LEint32(in); read_data_codec3(in, size, data); } else { fprintf(stderr, "%s: unsupported codec %d\n", fname, codec); exit(1); } if (format == 1) { img = toimg_fmt1(data, width, height); maxval = 255; } else if (format == 5) { img = toimg_fmt5(data, width, height); maxval = 255; } else { fprintf(stderr, "%s: unsupported format %d\n", fname, format); exit(1); } write_img(img, fname, i, width, height, maxval); free(data); ppm_freearray(img, height); } fclose(in); } int main(int argc, char **argv) { int i; ppm_init(&argc, argv); for (i = 1; i < argc; i++) process_file(argv[i]); return 0; }