/**************************************************************************** * iff.c * * This file implements a simple IFF format file reader. * * from Persistence of Vision Raytracer * Copyright 1993 Persistence of Vision Team *--------------------------------------------------------------------------- * NOTICE: This source code file is provided so that users may experiment * with enhancements to POV-Ray and to port the software to platforms other * than those supported by the POV-Ray Team. There are strict rules under * which you are permitted to use this file. The rules are in the file * named POVLEGAL.DOC which should be distributed with this file. If * POVLEGAL.DOC is not available or for more info please contact the POV-Ray * Team Coordinator by leaving a message in CompuServe's Graphics Developer's * Forum. The latest version of POV-Ray may be found there as well. * * This program is based on the popular DKB raytracer version 2.12. * DKBTrace was originally written by David K. Buck. * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins. * *****************************************************************************/ #include "frame.h" #include "povproto.h" static IMAGE_COLOUR *iff_colour_map; static int colourmap_size; static CHUNK_HEADER Chunk_Header; #define FORM 0x464f524dL #define ILBM 0x494c424dL #define BMHD 0x424d4844L #define CAMG 0x43414d47L #define CMAP 0x434d4150L #define BODY 0x424f4459L #define CMPNONE 0 #define HAM 0x800 void iff_error() { fprintf (stderr, "Invalid IFF file\n"); exit(1); } int read_byte(f) FILE *f; { int c; if ((c = getc(f)) == EOF) iff_error(); return (c); } int read_word(f) FILE *f; { int result; result = read_byte(f)*256; result += read_byte(f); return (result); } long read_long(f) FILE *f; { int i; long result; result = 0; for (i = 0 ; i < 4 ; i++) result = result * 256 + read_byte(f); return (result); } void Read_Chunk_Header (f, dest) FILE *f; CHUNK_HEADER *dest; { dest->name = read_long(f); dest->size = read_long(f); } void Read_Iff_Image(Image, filename) IMAGE *Image; char *filename; { FILE *f; unsigned char **row_bytes; int c, i, j, k, nBytes, nPlanes, compression, mask, byte_index, count, viewmodes; int Previous_Red, Previous_Green, Previous_Blue; struct Image_Line *line; unsigned long creg; if ((f = Locate_File(filename, READ_FILE_STRING)) == NULL) { fprintf (stderr, "Cannot open IFF file %s\n", filename); exit(1); } Previous_Red = Previous_Green = Previous_Blue = 0; viewmodes = 0; iff_colour_map = NULL; while (1) { Read_Chunk_Header(f, &Chunk_Header); switch ( IFF_SWITCH_CAST Chunk_Header.name) { case FORM: if (read_long(f) != ILBM) iff_error(); break; case BMHD: Image->iwidth = read_word(f); Image->width = (DBL)Image->iwidth; Image->iheight = read_word(f); Image->height = (DBL)Image->iheight; read_word(f); /* x position ignored */ read_word(f); /* y position ignored */ nPlanes = read_byte(f); colourmap_size = 1<Colour_Map_Size = 0; Image->Colour_Map = NULL; } else { Image->Colour_Map_Size = colourmap_size; Image->Colour_Map = iff_colour_map; } if ((row_bytes = (unsigned char **) malloc (4*nPlanes)) == NULL) { fprintf (stderr, "Cannot allocate memory for row bytes\n"); exit(1); } for (i = 0 ; i < nPlanes ; i++) if ((row_bytes[i] = (unsigned char *) malloc(((Image->iwidth+15)/16)*2)) == NULL) { fprintf (stderr, "Cannot allocate memory for row bytes\n"); exit(1); } if (Image->Colour_Map == NULL) { if ((Image->data.rgb_lines = (struct Image_Line *) malloc(Image->iheight * sizeof (struct Image_Line)))==NULL) { fprintf (stderr, "Cannot allocate memory for picture\n"); exit(1); } } else { if ((Image->data.map_lines = (unsigned char **) malloc(Image->iheight * sizeof (unsigned char *)))==NULL) { fprintf (stderr, "Cannot allocate memory for picture\n"); exit(1); } } for (i = 0 ; i < Image->iheight ; i++) { if (Image->Colour_Map == NULL) { if (((Image->data.rgb_lines[i].red = (unsigned char *) malloc(Image->iwidth))==NULL) || ((Image->data.rgb_lines[i].green = (unsigned char *) malloc(Image->iwidth))==NULL) || ((Image->data.rgb_lines[i].blue = (unsigned char *) malloc(Image->iwidth))==NULL)) { fprintf (stderr, "Cannot allocate memory for picture\n"); exit(1); } } else { if ((Image->data.map_lines[i] = (unsigned char *) malloc(Image->iwidth * sizeof(unsigned char))) == NULL) { fprintf (stderr, "Cannot allocate memory for picture\n"); exit(1); } } for (j = 0 ; j < nPlanes ; j++) if (compression == CMPNONE) { for (k = 0 ; k < (((Image->iwidth+15)/16)*2) ; k++) row_bytes[j][k] = (unsigned char)read_byte(f); if ((k & 1) != 0) read_byte(f); } else { nBytes = 0; while (nBytes != ((Image->iwidth+15)/16)*2) { c = read_byte(f); if ((c >= 0) && (c <= 127)) for (k = 0 ; k <= c ; k++) row_bytes[j][nBytes++] = (unsigned char)read_byte(f); else if ((c >= 129) && (c <= 255)) { count = 257-c; c = read_byte(f); for (k = 0 ; k < count ; k++) row_bytes[j][nBytes++] = (unsigned char)c; } } } mask = 0x80; byte_index = 0; for (j = 0 ; j < Image->iwidth ; j++) { creg = 0; for (k = nPlanes-1 ; k >= 0 ; k--) if (row_bytes[k][byte_index] & mask) creg = creg*2 + 1; else creg *= 2; if (viewmodes & HAM) { line = &Image->data.rgb_lines[i]; switch (creg >> 4) { case 0: Previous_Red = line->red[j] = (unsigned char)iff_colour_map[creg].Red; Previous_Green = line->green[j] = (unsigned char)iff_colour_map[creg].Green; Previous_Blue = line->blue[j] = (unsigned char)iff_colour_map[creg].Blue; break; case 1: line->red[j] = (unsigned char)Previous_Red; line->green[j] = (unsigned char)Previous_Green; line->blue[j] = (unsigned char)(((creg & 0xf)<<4) + (creg&0xf)); Previous_Blue = (int) line->blue[j]; break; case 2: line->red[j] = (unsigned char)(((creg & 0xf)<<4) + (creg&0xf)); Previous_Red = (int) line->red[j]; line->green[j] = (unsigned char)Previous_Green; line->blue[j] = (unsigned char)Previous_Blue; break; case 3: line->red[j] = (unsigned char)Previous_Red; line->green[j] = (unsigned char)(((creg & 0xf)<<4) + (creg&0xf)); Previous_Green = (int) line->green[j]; line->blue[j] = (unsigned char)Previous_Blue; break; } } else if (nPlanes == 24) { line = &Image->data.rgb_lines[i]; line->red[j] = (unsigned char)((creg >> 16) & 0xFF); line->green[j] = (unsigned char)((creg >> 8) & 0xFF); line->blue[j] = (unsigned char)(creg & 0xFF); } else { if (creg > (unsigned long)Image->Colour_Map_Size) { fprintf (stderr, "Error - IFF Image Map Colour out of range\n"); exit(1); } Image->data.map_lines[i][j] = (char)creg; } mask >>= 1; if (mask == 0) { mask = 0x80; byte_index++; } } } free (row_bytes); fclose (f); return; default: for (i = 0 ; (long) i < Chunk_Header.size ; i++) if (getc(f) == EOF) iff_error(); break; } } }