Assets - Converting BLK Files to Bitmaps
Traffic Department 2192 comes with 3 files with the BLK extension identifying the episode just like the NEWFACES files. Also, the lengths differ because they are also packed files. As usual, we need to get these files in to BMP format.
BLK File Format
The BLKs share several points in common with both the Faces and SCR files, but this time there's one important difference: There isn't any palette data embedded with the color indices. However, these clearly are still indices so we have to find another palette. The original game comes with a default palette in the file TD.PAL which is conventiently 768 bytes. Using a hex editor on the BLK files, we can see that there are clear breaks and they happen every 1,024 bytes. This number happens to have a convenient root in 32x32. We can make an educated guess that if we process these files with dimension 32x32 using the default palette, we'll arrive at the target sprite strip. Let's do it.
Conversion Process
Read in the default palette from TD.PAL. Scan through each 32x32 image (each 1,024 block). Match each index to an RGB triple in the palette. Write the resulting set colors to the output container to build a horizontal sprite strip. Just like with the Faces file, we have to calculate the proper position in the output surface to correctly form the strip. This is done in lines 72-75 of the source code below.
C Source Code
We'll make a small C program that turns a BLK file in to a bitmap. Run the application with the BLK file as the first argument.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
/* BLK to BMP file converter designed for use with Traffic Department 2192 .BLK files * argv[1] points to Face data file * * Issues: * 1) This program is a security nightmare - don't compile and store * 2) No trapping, feedback, instructions, or any output whatsoever * 3) SDL_Surface normally needs to be locked due to concurrency * 4) Free the SDL surface - in this case, the OS does it * 5) Void pointer implicit cast (not portable to C++) * 6) IMAGE_SIZE is truncated */ #include <stdio.h> /* Opening Files */ #include <string.h> /* Manipulating File Names */ #include <stdint.h> /* Fixed-width data types (C99) */ #include <SDL.H> /* Using SDL data structure */ int main(int argc, char* argv[]) { FILE *fin, *fpal; /* Input File and palette file pointers */ uint32_t FILE_SIZE; /* Get file size */ uint16_t IMAGE_WIDTH; /* Pixel width of a single frame*/ uint16_t IMAGE_HEIGHT; /* Pixel height of a single frame*/ uint8_t IMAGE_COUNT; /* Number of packed images */ uint16_t SURFACE_WIDTH; /* Width of the output surface */ SDL_Surface *surface; /* SDL Surface struct */ uint8_t *dst_byte; /* Pointer to surface struct Pixels */ uint16_t current_byte; /* Named iterator */ uint8_t current_image; /* Named iterator */ uint8_t palette[768]; /* Palette array: 3 x 8-bit*/ uint8_t src_byte; /* Single byte read from input */ uint8_t red_p, green_p, blue_p; /* Palette lookup bytes by color */ uint8_t image_row, image_col; /* Current image pixel location */ uint32_t surface_offset; /* Byte offset in surface */ uint8_t FILENAME_LEN; /* File Name length*/ char fout[12]; /* New filename container */ /* Open BLK and PAL File and find file size*/ fin = fopen(argv[1],"rb"); fpal = fopen("TD.PAL","rb"); /* Find File Size */ fseek(fin, 0, SEEK_END); FILE_SIZE = ftell(fin); rewind(fin); /* Calculate File Metrics */ IMAGE_WIDTH = 32; IMAGE_HEIGHT = 32; IMAGE_COUNT = FILE_SIZE / (IMAGE_WIDTH * IMAGE_HEIGHT); /* Make surface strip and pixel data pointer. Each Image is 160x100 */ SURFACE_WIDTH = IMAGE_COUNT * IMAGE_WIDTH; surface = SDL_CreateRGBSurface(0, SURFACE_WIDTH, IMAGE_HEIGHT, 32, 0,0,0,0); dst_byte = surface->pixels; /* Extract image palette - 768 bytes*/ for (current_byte=0; current_byte<768; current_byte++) palette[current_byte] = fgetc(fpal) << 2; /* Reranging values 63 -> 255 */ fclose(fpal); /* Process each image in file sequentially */ for(current_image=0; current_image < IMAGE_COUNT; current_image++) { /* Extract 1k of image data, match to palette, write to surface */ for (current_byte=0; current_byte<(IMAGE_WIDTH*IMAGE_HEIGHT); current_byte++) { src_byte = fgetc(fin); /* Read Byte From File */ red_p = palette[src_byte*3]; /* Lookup Red Channel */ green_p = palette[src_byte*3+1]; /* Lookup Green Channel */ blue_p = palette[src_byte*3+2]; /* Lookup Blue Channel */ image_row = current_byte / IMAGE_WIDTH; /* Int type clips fractions*/ image_col = current_byte % IMAGE_WIDTH; surface_offset = (current_image*IMAGE_WIDTH + image_row*SURFACE_WIDTH +image_col)*4; dst_byte[surface_offset] = blue_p; /* Set Blue channel pixel */ dst_byte[surface_offset+1] = green_p; /* Set Green channel pixel */ dst_byte[surface_offset+2] = red_p; /* Set Red channel pixel */ dst_byte[surface_offset+3] = 0xff; /* Set Alpha channel pixel */ } } fclose(fin); /* New output filename with .BMP extension */ FILENAME_LEN = strlen(argv[1]); /* Length of input file name */ strncpy(fout,argv[1],FILENAME_LEN-3); /* Chop off extension */ fout[FILENAME_LEN-3]='\0'; /* Nullterm it */ strncat(fout,"BMP",3); /* Attach BMP extension */ /* Save BMP*/ SDL_SaveBMP(surface, fout); return 0; } |