Assets - Converting SCR Files to Bitmaps
We will spend the next half-dozen videos pulling the graphics assets out of the original game archive. All the graphics are stored in a custom, but simple format that we can quickly extract by making small C utilities for each case. We'll begin with the most numerous of the assets: The SCR files.
Traffic Department 2192 comes with 44 files with the extension SCR. Each file is exactly 64,768. We can make an educated guess that SCR is related to the screen and the size is consistent with a graphics asset. The issue is that this is a custom format that isn't readily handled by any application. We need to get these data in to a common format, such as BMP, that we can easily handle with graphics libraries or a game engine.
SCR File Format
Reviewing several files in a hex editor, we see section break at offset (0x300). This means that we have two sections of size 768 bytes and 64k bytes. We know the screen resolution of the game is 320x200 which means that one screen has 64,000 pixels. If we suppose that each pixel is stored as 1 byte, then we know that we need to reference color values elsewhere. The top 768 bytes is probably the custom palette for each image, which is also consistent with the dithering we noted in the playthrough. We can store 1 byte for each channel (Red, green, and blue) for each of the 256 colors using exactly 768 bytes. Interestingly, these palette bytes in the SCR file only use the least-significant 6-bits of the byte to store values (range is 0 through 63 in decimal). Let's use this information to convert an SCR file to BMP with the SDL data structure, SDL_Surface and the function SDL_SaveBMP.
Conversion Process
Scan through each of the 64,000 color indices in row-major. Match each index to an RGB triple in the palette. Write the resulting set colors to the output container.
C Source Code
We'll make a small C program that performs the task on one SCR file provided as an argument. After testing the program one one file, run it against all the SCR files in the folder by redirecting the list of the names to the SCRtoBMP application. This program has several issues noted in the comments and in the videos, but it does the job.
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 |
/* SCR to BMP file converter designed for use with Traffic Department 2192.SCR files * * Code 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 (sorry C++) */ #include <stdio.h> /* Opening Files */ #include <string.h> /* Manipulating Strings */ #include <stdint.h> /* Fixed-width data types (C99) */ #include <SDL.h> /* Using SDL data structure */ int main(int argc, char* argv[]) { SDL_Surface *surface; /* Pointer to our output SDL_surface */ uint8_t *dst_byte; /* Pointer to the byte we're about to write */ FILE *fin; /* Pointer to our output file */ uint16_t current_byte; /* Number of the byte we're reading from the SCR */ uint8_t palette[768]; /* Sequential array holding our palette */ uint8_t src_byte; /* Value of the current byte we're reading */ uint8_t red_p, green_p, blue_p; /* RGB channel values that we're about to set */ uint8_t FILENAME_LEN; /* The length of the input file name */ char fout[12]; /* Output file name derived by input file name */ /* Make surface and point to pixel data */ surface = SDL_CreateRGBSurface(0, 320, 200, 32, 0, 0, 0 ,0); dst_byte = surface->pixels; /* Open SCR file passed at argument 1 */ fin = fopen(argv[1],"rb"); /* Extract Palette from first 768 bytes of SCR file */ for (current_byte=0; current_byte<768; current_byte++) palette[current_byte] = fgetc(fin) << 2; /* Reranging values 63->252 */ /* Extract 64kb of image data, match to palette, write to surface */ for (current_byte=0; current_byte<64000; current_byte++){ src_byte = fgetc(fin); /* Read current byte from file */ red_p = palette[src_byte*3]; /* Palette Red Channel */ green_p = palette[src_byte*3+1]; /* Palette Green Channel */ blue_p = palette[src_byte*3+2]; /* Palette Blue Channel */ dst_byte[current_byte*4] = blue_p; /* Set Blue Channel pixel */ dst_byte[current_byte*4+1]= green_p; /* Set Green channel pixel */ dst_byte[current_byte*4+2]= red_p; /* Set Red channel pixel */ dst_byte[current_byte*4+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 of SCR Extension */ fout[FILENAME_LEN-3]='\0'; /* Nullterm it */ strncat(fout, "BMP", 3); /* Attach BMP extension */ /* Save BMP */ SDL_SaveBMP(surface, fout); return 0; } |