/* Standard C Includes */ #include <stdlib.h> #include <stdio.h> #include <conio.h> #include <string.h> #include <ctype.h> /* User Defined Includes */ #include "genutil.h" #include "fileutil.h" #include "dagputil.h" /* Various Error Codes/Messages */ int dag_error_code = 0; char *dag_error_msgs[] = { "No Error Code Generated", "Unknown File Format", "Failed to Open File", "Short Count Received on File Read/Write", "Invalid Image Size Received", "Invalid Number of Images Received" }; /*========== Class DAGPIC_ARRAY Constructor ===============================*/ void DAGPIC_ARRAY::DAGPIC_ARRAY (void) { int i; /* Loop counter */ for (i = 0; i < MAX_IMAGES; i++) pics[i] = NULL; num_pics = 0; } /*========== End Class DAGPIC_ARRAY Constructor ===========================*/ /*========== Class DAGPIC_ARRAY Destructor ================================*/ void DAGPIC_ARRAY::~DAGPIC_ARRAY (void) { destroy(); } /*========== End Class DAGPIC_ARRAY Destructor ============================*/ /*========== Destroys an Array of Pictures ================================*/ void DAGPIC_ARRAY::destroy(void) { int i; /* Loop counter */ for (i = 0; i < MAX_IMAGES; i++) if (pics[i]) { delete pics[i]; pics[i] = NULL; } num_pics = 0; } /*========== End of Procedure DAGPIC_ARRAY::destroy() =====================*/ /*========== Loads an Arbitrary File Type into Picture Array ==============*/ boolean DAGPIC_ARRAY::load_pic (const char *filename, unsigned char *pal, const int index) { char buffer[4]; /* Temp buffer */ int i; /* Copy last 3 characters of filename into buffer */ i = strlen(filename) - 3; if (i < 0) i = 0; strcpy (buffer, filename + i); /* Determine the file type by the filename extension */ if (stricmp(buffer, "IMG") == 0) { /* Allocate the first picture if not already allocated */ if (!pics[index]) { if (!(pics[index] = new DAG_PICTURE)) bug (MEM_ERR_MSG, "*pics[0] (%d)", sizeof(DAG_PICTURE)); if (index >= num_pics) num_pics++; } return (pics[index]->load_img(filename, pal)); } else if (stricmp(buffer, "CIF") == 0) return (load_cif(filename)); else if (istexture (filename)) { TEXTURE_TYPE texture; /* Load the File */ if (!texture.load_texture (filename)) return (FALSE); /* Copy to the Pictures */ destroy(); for (i = 0; i < texture.num_images && i < MAX_IMAGES; i++) { /* Allocate New Object */ if (!(pics[i] = new DAG_PICTURE)) bug (MEM_ERR_MSG, "DAGPIC_ARRAY::load_pic() - *pics[i] (%d)", sizeof(DAG_PICTURE)); /* Copy Values */ pics[i]->x_offset = texture.pics[i]->x_offset; pics[i]->y_offset = texture.pics[i]->y_offset; pics[i]->width = texture.pics[i]->width; pics[i]->height = texture.pics[i]->height; pics[i]->null_bytes = texture.pics[i]->null_bytes; pics[i]->image_size = texture.pics[i]->image_size; pics[i]->data = texture.pics[i]->data; texture.pics[i]->data = NULL; } num_pics = texture.num_images; return (TRUE); } dag_error_code = DAG_ERR_FILEUNKNOWN; return (FALSE); } /*========== End of Function DAGPIC_ARRAY::load_pic() =====================*/ /*========== Loads a CIF Into Memory ======================================*/ boolean DAGPIC_ARRAY::load_cif (const char *filename) { FILE *f; /* File pointer */ DAG_PICTURE *pic_ptr; /* Temp pointer */ long current_fpos; /* Current position in file */ long file_size; int ch; /* Input buffer */ int count, i; /* Loop counters */ unsigned char *temp_ptr; /* Temp pointer */ /* Attempt to open the file */ if (!(f = openfile(filename, "rb"))) { dag_error_code = DAG_ERR_FILEOPEN; return (FALSE); } /* Get file size */ file_size = get_filesize (f); do { /* Load multiple images in CIF/IMG file */ /* Attempt to allocate the picture, if not already allocated */ if (!pics[num_pics]) { if (!(pics[num_pics] = new DAG_PICTURE)) bug (MEM_ERR_MSG, "load_cif(%s) - *pics[] (%d)", filename, sizeof(DAG_PICTURE)); } pic_ptr = pics[num_pics]; /* Get current fileposition */ current_fpos = ftell(f); pic_ptr->x_offset = read_int (f); pic_ptr->y_offset = read_int (f); pic_ptr->width = read_int (f); pic_ptr->height = read_int (f); pic_ptr->null_bytes = read_int(f); pic_ptr->image_size = read_int(f); /* Check for weapon/alternate type RLE CIF file */ if (pic_ptr->height * pic_ptr->width != pic_ptr->image_size) pic_ptr->rle = TRUE; else pic_ptr->rle = FALSE; // write_log_entry ("Cif Image #%d: (%d/%d) %d, Offset = %lX", num_pics, pic_ptr->width, pic_ptr->height, pic_ptr->image_size, ftell(f)); /* Check image size....make sure its a valid one */ if (pic_ptr->image_size > 65000l || pic_ptr->width > 340 || pic_ptr->height > 220) { write_log_entry ("ERROR: Cif Image #%d too Large (%d/%d) %d, Offset = %lX", num_pics, pic_ptr->width, pic_ptr->height, pic_ptr->image_size, ftell(f)); dag_error_code = DAG_ERR_IMAGESIZE; fclose (f); return (FALSE); } /* Allocate picture buffer */ if (pic_ptr->data) delete pic_ptr->data; pic_ptr->data = (unsigned char *) create_ptr (pic_ptr->height * pic_ptr->width + 1); temp_ptr = pic_ptr->data; /* For a Non-RLE encoded picture */ if (!pic_ptr->rle) { if (fread (pic_ptr->data, sizeof(char), pic_ptr->image_size, f) != pic_ptr->image_size) { dag_error_code = DAG_ERR_FILEREAD; fclose (f); return (FALSE); } } else { /* Must decode picture data */ fseek (f, 64, SEEK_CUR); /* Skip header_info? */ for (count = 1; count <= pic_ptr->image_size && count <= current_fpos + file_size; temp_ptr++, count++) { ch = fgetc(f); if (ch >= RLE_BYTE) { /* Is encoded bit */ for (i = 2*RLE_BYTE - ch, ch = fgetc(f); i < RLE_BYTE; i++, temp_ptr++, count++) *temp_ptr = ch; } else /* Regular byte */ *temp_ptr = ch; } /* End of for loop */ pic_ptr->image_size = pic_ptr->height * pic_ptr->width; /* Set proper size */ num_pics++; break; } num_pics++; /* Increase number of pictures loaded */ } while (ftell(f) + 10 < file_size && num_pics < MAX_IMAGES); return (TRUE); } /*========== End of Function DAGPIC_ARRAY::load_cif() =====================*/ /*========== Saves a Multiple Image File ==================================*/ boolean DAGPIC_ARRAY::save_cif (const char *filename) { FILE *f; /* File pointer */ int i; /* Loop counter */ if (!(f = openfile (filename, "wb"))) { dag_error_code = DAG_ERR_FILEOPEN; return (FALSE); } for (i = 0; i < num_pics; i++) { if (pics[i]) { write_int (f, pics[i]->x_offset); write_int (f, pics[i]->y_offset); write_int (f, pics[i]->width); write_int (f, pics[i]->height); write_int (f, pics[i]->null_bytes); write_int (f, pics[i]->image_size); /* Write in the important data */ if (fwrite (pics[i]->data, sizeof(char), pics[i]->image_size, f) != pics[i]->image_size) { dag_error_code = DAG_ERR_FILEREAD; fclose (f); return (FALSE); } } } fclose (f); return (TRUE); } /*========== End of Function DAGPIC_ARRAY::save_cif() =====================*/ /*========== Saves an Arbitrary File Type into Picture Array ==============*/ boolean DAGPIC_ARRAY::save_pic (const char *filename, const int index) { char buffer[4]; /* Temp buffer */ int i; /* Copy last 3 characters of filename into buffer */ i = strlen(filename) - 3; if (i < 0) i = 0; strcpy (buffer, filename + i); /* Determine the file type by the filename extension */ if (stricmp(buffer, "IMG") == 0) { return (pics[index]->save_img(filename)); } else if (stricmp(buffer, "CIF") == 0) { return (save_cif (filename)); } else dag_error_code = DAG_ERR_FILEUNKNOWN; return (FALSE); } /*========== End of Function DAGPIC_ARRAY::save_pic() =====================*/ /*========== Class DAG_PICTURE Constructor ================================*/ void DAG_PICTURE::DAG_PICTURE (void) { x_offset = y_offset = 0; width = height = 0; image_size = 0; null_bytes = 0; data = NULL; rle = FALSE; } /*========== End of Class DAG_PICTURE Constructor =========================*/ /*========== Class DAG_PICTURE Destructor =================================*/ void DAG_PICTURE::~DAG_PICTURE(void) { destroy(); } /*========== End of Class DAG_PICTURE Destructor ==========================*/ /*========== Deletes the Current Picture ==================================*/ void DAG_PICTURE::destroy (void) { if (data) delete data; data = NULL; image_size = 0; width = height = 0; x_offset = y_offset = 0; rle = FALSE; } /*========== End of Procedure DAG_PICTURE::destroy() ======================*/ /*========= Loads a picture named *file_ptr into picture_ptr ==============*/ boolean DAG_PICTURE::load_img (const char *filename, unsigned char *pal) { FILE *f; /* File Pointer */ unsigned long file_size; /* Attempt to open the file */ if (!(f = openfile (filename, "rb"))) { dag_error_code = DAG_ERR_FILEOPEN; return(FALSE); } file_size = get_filesize (f); /* Get file size */ /* Special file format for image size of 64kb */ if (file_size == 64000l && strstr(filename, ".IMG")) { y_offset = 0; x_offset = 0; width = 320; height = 200; null_bytes = 0; image_size = (unsigned int) 64000l; /* Attempt to allocate space for the picture */ if (data) delete data; data = (unsigned char *) create_ptr (image_size + 1); /* Read in image data */ if (fread (data, sizeof(char), image_size, f) != image_size) { dag_error_code = DAG_ERR_FILEREAD; fclose (f); return (FALSE); } } /* End of loading file_size = 64768b */ /* 320x200 image with attached palette */ else if (file_size == 64768l && strstr(filename, ".IMG")) { y_offset = 0; x_offset = 0; width = 320; height = 200; image_size = 64000u; null_bytes = 0; /* Attempt to allocate space */ if (data) delete data; data = (unsigned char *) create_ptr (image_size + 1); /* Read in image data */ if (fread (data, sizeof(char), image_size, f) != image_size) { dag_error_code = DAG_ERR_FILEREAD; fclose (f); return (FALSE); } /* Load palette contained in file */ if (fread(pal, sizeof(char), 768, f) != 768) { dag_error_code = DAG_ERR_FILEREAD; fclose (f); return (FALSE); } } /* End of load 320x200 image with attached palette */ else { /* Load regular IMG */ x_offset = read_int (f); y_offset = read_int (f); width = read_int (f); height = read_int (f); null_bytes = read_int (f); /* Skip 00's */ /* Read 11th and 12th bytes...image size */ image_size = read_int (f); rle = FALSE; /* Check image size....make sure its a valid one */ if (image_size > 65000u || width > 340 || height > 220) { dag_error_code = DAG_ERR_IMAGESIZE; fclose (f); return(FALSE); } /* Allocate the image data */ if (data) delete data; data = (unsigned char *) create_ptr (image_size + 1); /* Read in file */ if (fread (data, sizeof(char), image_size, f) != image_size) { dag_error_code = DAG_ERR_FILEREAD; fclose (f); return (FALSE); } } fclose(f); return (TRUE); } /*========== End of Function DAG_PICTURE::load_img() ======================*/ /*========== Saves a Regular IMG File =====================================*/ boolean DAG_PICTURE::save_img (const char *filename) { FILE *f; /* File pointer */ if (!(f = openfile(filename, "wb"))) { dag_error_code = DAG_ERR_FILEOPEN; return (FALSE); } write_int (f, x_offset); write_int (f, y_offset); write_int (f, width); write_int (f, height); write_int (f, null_bytes); write_int (f, image_size); /* Write in the important data */ if (fwrite (data, sizeof(char), image_size, f) != image_size) { dag_error_code = DAG_ERR_FILEREAD; fclose (f); return (FALSE); } fclose (f); return (TRUE); } /*========== End of Function DAG_PICTRE::save_img() =======================*/ /*========== Class TEXTURE_HEADER Constructor =============================*/ void TEXTURE_HEADER::TEXTURE_HEADER (void) { type1 = 0; offset = 0; type2 = 0; } /*========== End of Class TEXTURE_HEADER Constructor ======================*/ /*========= CLASS TEXTURE_PIC PROCEDURE/FUNCTIONS =========================*/ void TEXTURE_PIC::~TEXTURE_PIC (void) { memset(extra_header, 0, 16); destroy (); } /*========= END CLASS TEXTURE_PIC PROCEDURE/FUNCTIONS =====================*/ /*========= CLASS TEXTURE_TYPE PROCEDURE/FUNCTIONS ========================*/ void TEXTURE_TYPE::TEXTURE_TYPE (void) { int i; /* Loop Counter */ /* Set all pointers to initially NULL */ for (i = 0; i < MAX_IMAGES; i++) { header[i] = NULL; pics[i] = NULL; } extra_file = NULL; num_images = 0; text[0] = 0; extra_file_length = 0; } void TEXTURE_TYPE::~TEXTURE_TYPE (void) { destroy(); } void TEXTURE_TYPE::destroy (void) { int i; /* Loop Counter */ for (i = 0; i < MAX_IMAGES; i++) { if (pics[i]) delete pics[i]; if (header[i]) delete header[i]; header[i] = NULL; pics[i] = NULL; } if (extra_file) delete extra_file; extra_file = NULL; } /*========== END CLASS TEXTURE_TYPE PROCEDURE/FUNCTIONS ===================*/ /*========== Loads a Texture File Into Memory =============================*/ boolean TEXTURE_TYPE::load_texture (const char *filename) { TEXTURE_PIC *temp_pic; /* Temp Pointer */ FILE *f; short ch, ch1, c1; long size = 0, l = 0, offset; unsigned int bytes_read[MAX_IMAGES]; int texture_groups[MAX_GROUPS][MAX_SUBGROUPS]; int i, j, k, dx, count, c; /* Loop Counters */ /* Attempt to Open File For Reading */ if (!(f = openfile (filename, "rb"))) { dag_error_code = DAG_ERR_FILEOPEN; return (FALSE); } /* Clear the Array */ destroy (); /* Read in the Number of Textures */ num_images = read_int(f); /* Make sure the Number of Images is a Valid Number */ if (num_images <= 0) { dag_error_code = DAG_ERR_NUMIMAGES; fclose (f); return (FALSE); } /* Read in the Text Title of Texture */ if (fread (text, sizeof(char), 24, f) != 24) { dag_error_code = DAG_ERR_FILEREAD; fclose (f); return (FALSE); } /* Read in the Header Offset Section */ for (i = 0; i < num_images && i < MAX_IMAGES; i++) { /* Allocate new header object */ if (!(header[i] = new TEXTURE_HEADER)) bug (MEM_ERR_MSG, "TEXTURE_TYPE::load_texture() - header[] (%d)", sizeof(TEXTURE_HEADER)); header[i]->type1 = read_int (f); header[i]->offset = read_long(f); header[i]->type2 = read_int(f); if (fread (header[i]->extra_header, sizeof(char), 12, f) != 12) { dag_error_code = DAG_ERR_FILEREAD; fclose (f); return (FALSE); } write_log_entry ("Texture Offset: %ld", header[i]->offset); } /* Read in All the Picture Headers... */ for (i = 0; i < num_images && i < MAX_IMAGES; i++) { /* Allocate New Picture */ if (!(pics[i] = new TEXTURE_PIC)) bug (MEM_ERR_MSG, "TEXTURE_TYPE::load_texture() - pics[] (%d)", sizeof(TEXTURE_PIC)); /* Move to the Appropiate Offset */ fseek (f, header[i]->offset, SEEK_SET); /* Read in the Picture Header Information */ pics[i]->x_offset = read_int(f); pics[i]->y_offset = read_int(f); pics[i]->width = read_int (f); pics[i]->height = read_int (f); pics[i]->null_bytes = read_int (f); pics[i]->image_size = read_int (f); if (fread (pics[i]->extra_header, sizeof(char), 16, f) != 16) { dag_error_code = DAG_ERR_FILEREAD; fclose (f); return (FALSE); } /* Check to Make Sure Valid Width/Height Received */ if (pics[i]->width * pics[i]->height > 65000u || pics[i]->image_size > 65000u) { dag_error_code = DAG_ERR_IMAGESIZE; fclose (f); return (FALSE); } /* Create the Picture Pointer */ pics[i]->data = (unsigned char *) create_ptr (pics[i]->image_size + 1 - 28); } /* End of for read in pictures */ /* Init the groupings */ for (i = 0; i < MAX_GROUPS; i++) { texture_groups[i][0] = -1; } /* Create the Groupings */ for (i = 0; i < num_images; i++) { /* Find the proper group to add current image, or create new */ for (j = 0; j < MAX_GROUPS && texture_groups[j][0] != -1; j++) { offset = labs (header[texture_groups[j][0]]->offset - header[i]->offset); /* Successful match found */ if (offset % 28 == 0 && offset/28 <= 10) break; // pics[texture_groups[j][0]]->width == pics[i]->width && // pics[texture_groups[j][0]]->height == pics[i]->height) break; } /* End of for j loop... */ /* Too many groups, do nothing */ if (j >= MAX_GROUPS) { write_log_entry ("ERROR: Maximum number of texture groups exceeded (%d)", MAX_GROUPS); } /* Create new group */ else if (texture_groups[j][0] == -1) { texture_groups[j][0] = i; texture_groups[j][1] = -1; write_log_entry ("Created new texture group for pic #%d", i); } /* Add to existing group */ else { for (k = 0; k < MAX_SUBGROUPS && texture_groups[j][k] != -1; k++); /* Add to end of group */ if (k < MAX_SUBGROUPS) { texture_groups[j][k] = i; if (k + 1 != MAX_SUBGROUPS) texture_groups[j][k + 1] = -1; write_log_entry ("Added pic #%d to texture group %d", i, j); } /* Too Many Subgroups */ else { write_log_entry ("ERROR: Maximum number of texture sub-groups exceeded (%d)", MAX_SUBGROUPS); } } } /* End of for i loop (create groupings) */ offset = 0; /* Read in All the Picture Data by Groups */ for (i = 0; i < MAX_GROUPS && texture_groups[i][0] != -1; i++) { /* Find the Last Image in the Group */ for (j = 0, size = 0, k = 0; j < MAX_SUBGROUPS && texture_groups[i][j] != -1; j++) { if (header[k]->offset < header[texture_groups[i][j]]->offset) k = texture_groups[i][j]; bytes_read[j] = 0; //size += pics[texture_groups[i][j]]->image_size - 28 - 20; size += pics[texture_groups[i][j]]->width * pics[texture_groups[i][j]]->height; } /* Jump to Start of Image Data, hopefully */ fseek (f, header[k]->offset + 28 + 20, SEEK_SET); write_log_entry ("Jumped to Offset %ld (#%d)", ftell(f), k); l = 0; k = 0; dx = 1; j = 0; /* Read this group of images */ while (l < size && k < 32000) { k++; if (j >= MAX_SUBGROUPS || (texture_groups[i][j] == -1 && j > 0)) { dx = -1; j--; } else if (j < 0) { j = 0; dx = 1; } temp_pic = pics[texture_groups[i][j]]; /* Make sure we don't read more than we allocated */ if (bytes_read[j] + temp_pic->width <= temp_pic->image_size - 28) { /* Read one line */ c1 = bytes_read[j]; count = 0; while (count < temp_pic->width) { ch = fgetc(f); ch1 = fgetc(f); for (c = 0; c < ch; c++) temp_pic->data[c1 + c] = 0; c1 += ch; count += ch; for (c = 0; c < ch1; c++) { temp_pic->data[c1 + c] = fgetc(f); } count += ch1; c1 += ch1; } l += temp_pic->width; bytes_read[j] += temp_pic->width; } j += dx; } // return (TRUE); write_log_entry ("Offset = %ld, l = %ld, Lines Read = %d", ftell(f), l, k); } /* Close File And Return Success */ fclose (f); return (TRUE); } /*========== End of Function TEXTURE_TYPE::load_texture() =================*/ /*========== Returns TRUE if filename is a Valid Texture Name =============*/ boolean istexture (const char *filename) { if (strlen(filename) != 11 || strnicmp (filename, "TEXTURE", 7) != 0) return (FALSE); /* Make sure the Extension is Purely Numerical */ if (!isdigit(filename[8]) || !isdigit(filename[9]) || !isdigit(filename[10])) return (FALSE); return (TRUE); } /*========== End of function istexture() ==================================*/ /*========== Loads a DF game palette into memory ==========================*/ boolean load_dagpal (const char *filename, unsigned char *pal) { int count, ch; FILE *f; /* Attempt and open the file */ if (!(f = openfile(filename, "rb"))) { dag_error_code = DAG_ERR_FILEOPEN; return (FALSE); } /* If palette is a COL file skip header information */ if (get_filesize (f) == 776) fseek (f, 8, SEEK_SET); /* Read in the colour values */ for (count = 0; count < 768; count++) { if ((ch = fgetc(f)) == EOF) break; *pal = ch; pal++; } fclose (f); if (count != 768) { dag_error_code = DAG_ERR_FILEREAD; return (FALSE); } return (TRUE); } /*========= End of procedure load_dagpal() ================================*/ /*========== Saves a DF game palette to file ==============================*/ boolean save_dagpal (const char *filename, unsigned char *pal) { int count; FILE *f; /* Attempt and open the file */ if (!(f = openfile(filename, "rb"))) { dag_error_code = DAG_ERR_FILEOPEN; return (FALSE); } /* Write the colour values */ for (count = 0; count < 768; count++) { fputc (*pal, f); pal++; } fclose (f); return (TRUE); } /*========= End of procedure save_dagpal() ================================*/