From b9892a853bc82b79e3838b147d94b1f7b3a4a3cf Mon Sep 17 00:00:00 2001 From: Aerik72 Date: Sat, 7 Aug 2021 20:39:34 -0500 Subject: [PATCH 1/5] tr1pc_replace_textile function set up --- Source/tr1pc.c | 34 +++++++++++++++++++++++++++++++--- Source/tr1pc.h | 5 ++++- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/Source/tr1pc.c b/Source/tr1pc.c index d7871ee..d35770f 100644 --- a/Source/tr1pc.c +++ b/Source/tr1pc.c @@ -250,6 +250,14 @@ void tr1pc_main(int argc, char *args[], char *bytelist, unsigned fsize){ if (!_strnicmp(args[2],"get",3)&&!_strnicmp(args[3],"offset",6)) tr1pc_get_offset(bytelist, args, argc, p_NumVertices, p_NumSprites, p_NumLights, p_NumZSector, p_NumStaticMeshes, p_AlternateRoom, p_NumFloorData, p_NumItems, p_NumSpriteSequences, p_NumCameras, p_NumDemoData, p_NumBoxes, p_NumOverlaps, p_NumSoundDetails, p_NumSamples, p_NumSampleIndices, p_NumSoundSources, fsize); if (!_strnicmp(args[2],"extract",7)&&!strnicmp(args[3],"textile",7)) tr1pc_extract_textile(bytelist, args, numTexTiles, p_TexTiles, palette, !strnicmp(args[4],"all",3) ? -1 : atoi(args[4])); + if (!_strnicmp(args[2], "replace", 7)) + { + if (!strnicmp(args[3], "textile", 7)) + { + tr1pc_replace_textile(bytelist, args, numTexTiles, p_TexTiles, palette); + } + } + free(p_TexTiles); free(roomX); free(roomY); @@ -3152,8 +3160,9 @@ void tr1pc_get_offset(char *bytelist, char *args[], unsigned argc, unsigned p_Nu if (!_strnicmp(args[4],"numsampleindices",16)) printf("%X\n",p_NumSampleIndices); } +// This function extracts a texture tile from the level into a bitmap file. The syntax is "trmod [FILE] EXTRACT TEXTILE [#/All]". // int selection // -1 for all, 0 - (numTexTiles-1) for an individual texture tile -void tr1pc_extract_textile(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles, unsigned char* palette, int selection) +void tr1pc_extract_textile(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles, BYTE* palette, int selection) { if (selection < -1 || selection >= (int)numTexTiles) { @@ -3162,7 +3171,6 @@ void tr1pc_extract_textile(char* bytelist, char* args[], unsigned numTexTiles, u } printf("Extracting textile %d...\n", selection); - // This function extracts a texture tile from the level into a bitmap file. The syntax is "trmod [FILE] EXTRACT TEXTILE [#/All]". printf("Writing \"palette.bmp\"...\n"); writeBitmap(palette, "palette.bmp", 16, 16); @@ -3170,7 +3178,7 @@ void tr1pc_extract_textile(char* bytelist, char* args[], unsigned numTexTiles, u const unsigned w = 256; const unsigned h = 256; - for (int t = (selection == -1 ? 0 : selection); t <= (selection == -1 ? numTexTiles-1 : selection); ++t) + for (int t = (selection == -1 ? 0 : selection); t <= (selection == -1 ? numTexTiles - 1 : selection); ++t) { unsigned char* img = (char*)malloc(3 * w * h); memset(img, 0, 3 * w * h); // Fill the whole image with 0s @@ -3215,4 +3223,24 @@ void tr1pc_extract_textile(char* bytelist, char* args[], unsigned numTexTiles, u free(img); free(filename); } +} + +// This function replaces a texture tile in the level from a bitmap file. The syntax is "trmod [FILE] REPLACE TEXTILE [#] [FILENAME.BMP]". +void tr1pc_replace_textile(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles, BYTE * palette) +{ + int selection = atoi(args[4]); + char* filename = args[5]; + + if (selection < 0 || selection >= (int)numTexTiles) + { + printf("ERROR: Textile selection must be between \"0\" and \"%d\", argument was \"%d\"", numTexTiles - 1, selection); + return 0; + } + + printf("Replacing textile %d...\n", selection); + + const unsigned w = 256; + const unsigned h = 256; + + // todo } \ No newline at end of file diff --git a/Source/tr1pc.h b/Source/tr1pc.h index fde23aa..b131adc 100644 --- a/Source/tr1pc.h +++ b/Source/tr1pc.h @@ -1,6 +1,8 @@ #ifndef TR1PC_H_INCLUDED #define TR1PC_H_INCLUDED +typedef unsigned char BYTE; + void tr1pc_main(int argc, char *args[], char *bytelist, unsigned fsize); void tr1pc_list(char *bytelist, char *args[], unsigned roomX[], int roomY[], unsigned roomZ[], unsigned p_NumVertices[], unsigned p_NumSprites[], unsigned p_NumLights[], unsigned p_NumZSector[], unsigned p_NumStaticMeshes[], unsigned p_AlternateRoom[], unsigned p_NumFloorData, unsigned p_NumSpriteSequences, unsigned p_NumCameras, unsigned p_NumBoxes, unsigned p_NumSoundSources, unsigned p_NumItems, unsigned short numRooms, unsigned fsize); void tr1pc_add_item(char *bytelist, char *args[], unsigned roomX[], int roomY[], unsigned roomZ[], unsigned p_NumItems, unsigned fsize); @@ -59,6 +61,7 @@ void tr1pc_replace_zone(char *bytelist, char *args[], unsigned p_NumBoxes, unsig void tr1pc_add_overlap(char *bytelist, char *args[], unsigned argc, unsigned p_NumOverlaps, unsigned fsize); void tr1pc_overwrite_overlap(char *bytelist, char *args[], unsigned argc, unsigned p_NumOverlaps, unsigned fsize); void tr1pc_get_offset(char *bytelist, char *args[], unsigned argc, unsigned p_NumVertices[], unsigned p_NumSprites[], unsigned p_NumLights[], unsigned p_NumZSector[], unsigned p_NumStaticMeshes[], unsigned p_AlternateRoom[], unsigned p_NumFloorData, unsigned p_NumItems, unsigned p_NumSpriteSequences, unsigned p_NumCameras, unsigned p_NumDemoData, unsigned p_NumBoxes, unsigned p_NumOverlaps, unsigned p_NumSoundDetails, unsigned p_NumSamples, unsigned p_NumSampleIndices, unsigned p_NumSoundSources, unsigned fsize); -void tr1pc_extract_textile(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles, unsigned char* palette, int selection); +void tr1pc_extract_textile(char *bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles, BYTE* palette, int selection); +void tr1pc_replace_textile(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles, BYTE* palette); #endif From 6e7f7b3d1ba5e9c89c5b9ab6dbf2d1b663a51f61 Mon Sep 17 00:00:00 2001 From: Aerik72 Date: Sun, 8 Aug 2021 16:34:06 -0500 Subject: [PATCH 2/5] TR1PC replace textile working --- Source/functions.c | 135 +++++++++++++++++++++++++++++++++++++++++++++ Source/functions.h | 4 ++ Source/tr1pc.c | 52 ++++++++++++++--- Source/tr1pc.h | 2 +- 4 files changed, 185 insertions(+), 8 deletions(-) diff --git a/Source/functions.c b/Source/functions.c index e6723d6..04f7e91 100644 --- a/Source/functions.c +++ b/Source/functions.c @@ -2,6 +2,8 @@ #include #include #include +#include "functions.h" + char* readFile(char *inputFile){ // This function reads a file into memory, and returns a pointer printf("Reading binary file %s...\n", inputFile); @@ -22,6 +24,86 @@ char* readFile(char *inputFile){ fclose(levelFile); // Closes file return bytelist; } + +// This function requires a 24-bit bitmap with no compression +// The caller of the function is responsible for freeing the returned BYTE* memory +// Returns the pixel array in 3-byte RGB pixels, with rows bottom-to-top +BYTE* readBitmapFile(char* inputFilename) +{ + char* image = readFile(inputFilename); + + // Check bitmap integrity + BYTE bmpIntegrityA; + BYTE bmpIntegrityB; + memcpy(&bmpIntegrityA, image + 0, 1); + memcpy(&bmpIntegrityB, image + 1, 1); + //printf("Bitmap integrity: %c%c\n", bmpIntegrityA, bmpIntegrityB); + if (!(bmpIntegrityA == 'B' && bmpIntegrityB == 'M')) + { + printf("ERROR: File must be BM for Windows 3.1x, 95, NT, etc.\n"); + free(image); + return NULL; + } + + // Verify that the bitmap is 24 bits per pixel + unsigned short bitsPerPixel; + memcpy(&bitsPerPixel, image + 28, 2); + //printf("Bitmap bpp: %d", bitsPerPixel); + if (!bitsPerPixel == 24) + { + printf("ERROR: Bitmap must be 24 bits per pixel.\n"); + free(image); + return NULL; + } + + // Verify image is uncompressed + signed int compression; + memcpy(&compression, image + 30, 4); + //printf("Compression method: %d", compression); + if (compression != 0) + { + printf("ERROR: Bitmap must be uncompressed (found compression method %d, must be 0 a.k.a. BI_RGB).\n", compression); + free(image); + return NULL; + } + + // Read width and height + signed int width; + signed int height; + memcpy(&width, image + 18, 4); + memcpy(&height, image + 22, 4); + //printf("Width x height: %d x %d\n", width, height); + + // Read image size + signed int imageSize; + memcpy(&imageSize, image + 34, 4); + if (imageSize == 0) + { + // For BI_RGB, a dummy 0 may indicate bpp x w x h + imageSize = bitsPerPixel * width * height; + } + printf("Image size: %d\n", imageSize); + + // Allocate memory for result + BYTE* result = malloc(imageSize * sizeof(BYTE)); + if (result == 0) + { + printf("ERROR: Could not allocate memory to read bmp! (error code: %d)\n", errno); + return NULL; + } + + // Determine the offset of the pixel array + signed int offset; + memcpy(&offset, image + 10, 4); + //printf("Bitmap pixel array offset: %d", offset); + + memcpy(result, image + offset, imageSize); + + free(image); + + return result; +} + void writeFile(char *outputFile, char *bytelist, unsigned fsize){ // This function writes bytelist to the level file. FILE *File = fopen(outputFile,"wb"); @@ -118,3 +200,56 @@ void writeBitmap(char* img, char* filename, const unsigned w, const unsigned h) fclose(f); } + +BYTE findPixelKey(BYTE* palette, BYTE r, BYTE g, BYTE b) +{ + BYTE pr, pg, pb; + BYTE result; + short closestMatch = 255 * 3; + short diff; + BYTE isExactMatch = 0; + BYTE rpr, rpg, rpb; + for (int i = 0; i < 256; i++) + { + short curpos = i * 3; + memcpy(&pr, palette + curpos + 2, 1); + memcpy(&pg, palette + curpos + 1, 1); + memcpy(&pb, palette + curpos + 0, 1); + + if (pr == r && + pg == g && + pb == b) + { + result = i; + isExactMatch = 1; + break; + } + + diff = abs(pr - r) + + abs(pg - g) + + abs(pb - b); + + if (diff < closestMatch) + { + closestMatch = diff; + result = i; + rpr = pr; + rpg = pg; + rpb = pb; + isExactMatch = 0; + } + } + + /* + if (isExactMatch == 1) + { + printf("Exact match: %d, %d, %d matches palette %d\n", r, g, b, result); + } + else + { + printf("No match: %d, %d, %d is closest to palette %d (%d, %d, %d)\n", r, g, b, result, rpr, rpg, rpb); + } + */ + + return result; +} diff --git a/Source/functions.h b/Source/functions.h index ca2f3ac..871e932 100644 --- a/Source/functions.h +++ b/Source/functions.h @@ -1,7 +1,10 @@ #ifndef FUNCTIONS_H_INCLUDED #define FUNCTIONS_H_INCLUDED +typedef unsigned char BYTE; + char* readFile(char *inputFile); +BYTE* readBitmapFile(char* inputFilename); void writeFile(char *outputFile, char *bytelist, unsigned fsize); unsigned filesize(char *inputFile); char* substring(char *string, unsigned offset, unsigned length); @@ -10,5 +13,6 @@ unsigned countchar(char *instring, char countChar); char* insertrange(char *bytelist, unsigned offset, unsigned length, char *insertme, unsigned fsize); unsigned removerange(char *bytelist, unsigned offset, unsigned length, unsigned fsize); void writeBitmap(char* img, char* filename, const unsigned w, const unsigned h); +BYTE findPixelKey(BYTE* palette, BYTE r, BYTE g, BYTE b); #endif \ No newline at end of file diff --git a/Source/tr1pc.c b/Source/tr1pc.c index d35770f..b6d8a71 100644 --- a/Source/tr1pc.c +++ b/Source/tr1pc.c @@ -254,7 +254,7 @@ void tr1pc_main(int argc, char *args[], char *bytelist, unsigned fsize){ { if (!strnicmp(args[3], "textile", 7)) { - tr1pc_replace_textile(bytelist, args, numTexTiles, p_TexTiles, palette); + tr1pc_replace_textile(bytelist, args, numTexTiles, p_TexTiles, palette, fsize); } } @@ -3226,12 +3226,12 @@ void tr1pc_extract_textile(char* bytelist, char* args[], unsigned numTexTiles, u } // This function replaces a texture tile in the level from a bitmap file. The syntax is "trmod [FILE] REPLACE TEXTILE [#] [FILENAME.BMP]". -void tr1pc_replace_textile(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles, BYTE * palette) +void tr1pc_replace_textile(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles, BYTE * palette, unsigned fsize) { - int selection = atoi(args[4]); + unsigned int selection = atoi(args[4]); char* filename = args[5]; - if (selection < 0 || selection >= (int)numTexTiles) + if (selection < 0 || selection >= numTexTiles) { printf("ERROR: Textile selection must be between \"0\" and \"%d\", argument was \"%d\"", numTexTiles - 1, selection); return 0; @@ -3239,8 +3239,46 @@ void tr1pc_replace_textile(char* bytelist, char* args[], unsigned numTexTiles, u printf("Replacing textile %d...\n", selection); - const unsigned w = 256; - const unsigned h = 256; + const short w = 256; + const short h = 256; + unsigned memorySize = 3 * w * h; + + BYTE* bitmapImage = readBitmapFile(filename); + if (bitmapImage == NULL) + { + printf("ERROR: Could not read bitmap.\n"); + return 0; + } + + for (int j = 0; j < h; j++) + { + for (int i = 0; i < w; i++) + { + unsigned int curpos = j * w + i; + BYTE r; + BYTE g; + BYTE b; + BYTE pixelKey; + + memcpy(&r, bitmapImage + curpos * 3 + 2, 1); + memcpy(&g, bitmapImage + curpos * 3 + 1, 1); + memcpy(&b, bitmapImage + curpos * 3 + 0, 1); + + if (r == 0 && g == 0 && b == 0) + { + pixelKey = 0; // Reserved for pure-black aka transparent + } + else + { + pixelKey = findPixelKey(palette, r, g, b); + } + + unsigned int curposFlip = ((h - 1 - j) * w) + i; // Bitmap rows are stored bottom-up + memcpy(bytelist + p_TexTiles[selection] + curposFlip, &pixelKey, 1); + } + } + + writeFile(args[1], bytelist, fsize); - // todo + free(bitmapImage); } \ No newline at end of file diff --git a/Source/tr1pc.h b/Source/tr1pc.h index b131adc..fe761a1 100644 --- a/Source/tr1pc.h +++ b/Source/tr1pc.h @@ -62,6 +62,6 @@ void tr1pc_add_overlap(char *bytelist, char *args[], unsigned argc, unsigned p_N void tr1pc_overwrite_overlap(char *bytelist, char *args[], unsigned argc, unsigned p_NumOverlaps, unsigned fsize); void tr1pc_get_offset(char *bytelist, char *args[], unsigned argc, unsigned p_NumVertices[], unsigned p_NumSprites[], unsigned p_NumLights[], unsigned p_NumZSector[], unsigned p_NumStaticMeshes[], unsigned p_AlternateRoom[], unsigned p_NumFloorData, unsigned p_NumItems, unsigned p_NumSpriteSequences, unsigned p_NumCameras, unsigned p_NumDemoData, unsigned p_NumBoxes, unsigned p_NumOverlaps, unsigned p_NumSoundDetails, unsigned p_NumSamples, unsigned p_NumSampleIndices, unsigned p_NumSoundSources, unsigned fsize); void tr1pc_extract_textile(char *bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles, BYTE* palette, int selection); -void tr1pc_replace_textile(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles, BYTE* palette); +void tr1pc_replace_textile(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles, BYTE* palette, unsigned fsize); #endif From 5e0507b64af90c15613a5eee9439386e62ad9cf3 Mon Sep 17 00:00:00 2001 From: Aerik72 Date: Mon, 9 Aug 2021 22:55:49 -0500 Subject: [PATCH 3/5] TR2PC replace textile working --- Source/tr1pc.c | 2 +- Source/tr2pc.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++ Source/tr2pc.h | 1 + 3 files changed, 68 insertions(+), 1 deletion(-) diff --git a/Source/tr1pc.c b/Source/tr1pc.c index b6d8a71..8f42d89 100644 --- a/Source/tr1pc.c +++ b/Source/tr1pc.c @@ -3180,7 +3180,7 @@ void tr1pc_extract_textile(char* bytelist, char* args[], unsigned numTexTiles, u for (int t = (selection == -1 ? 0 : selection); t <= (selection == -1 ? numTexTiles - 1 : selection); ++t) { - unsigned char* img = (char*)malloc(3 * w * h); + BYTE* img = malloc(3 * w * h); memset(img, 0, 3 * w * h); // Fill the whole image with 0s for (int j = 0; j < h; j++) diff --git a/Source/tr2pc.c b/Source/tr2pc.c index 8b54515..43588e4 100644 --- a/Source/tr2pc.c +++ b/Source/tr2pc.c @@ -250,6 +250,14 @@ void tr2pc_main(int argc, char *args[], char *bytelist, unsigned fsize){ if (!_strnicmp(args[2],"get",3)&&!_strnicmp(args[3],"offset",6)) tr2pc_get_offset(bytelist, args, argc, p_NumVertices, p_NumSprites, p_NumLights, p_NumZSector, p_NumStaticMeshes, p_AlternateRoom, p_NumFloorData, p_NumItems, p_NumSpriteSequences, p_NumCameras, p_NumDemoData, p_NumBoxes, p_NumOverlaps, p_NumSoundSources, fsize); if (!_strnicmp(args[2], "extract", 7) && !strnicmp(args[3], "textile", 7)) tr2pc_extract_textile(bytelist, args, numTexTiles, p_TexTiles8, palette8, !strnicmp(args[4], "all", 3) ? -1 : atoi(args[4])); + if (!_strnicmp(args[2], "replace", 7)) + { + if (!strnicmp(args[3], "textile", 7)) + { + tr2pc_replace_textile(bytelist, args, numTexTiles, p_TexTiles8, palette8, fsize); + } + } + free(palette8); free(palette16); free(p_TexTiles8); @@ -2964,3 +2972,61 @@ void tr2pc_extract_textile(char* bytelist, char* args[], unsigned numTexTiles, u free(filename); } } + +// This function replaces a texture tile in the level from a bitmap file. The syntax is "trmod [FILE] REPLACE TEXTILE [#] [FILENAME.BMP]". +void tr2pc_replace_textile(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles, BYTE* palette8, unsigned fsize) +{ + unsigned int selection = atoi(args[4]); + char* filename = args[5]; + + if (selection < 0 || selection >= numTexTiles) + { + printf("ERROR: Textile selection must be between \"0\" and \"%d\", argument was \"%d\"", numTexTiles - 1, selection); + return 0; + } + + printf("Replacing 8-bit textile %d...\n", selection); + + const short w = 256; + const short h = 256; + unsigned memorySize = 3 * w * h; + + BYTE* bitmapImage = readBitmapFile(filename); + if (bitmapImage == NULL) + { + printf("ERROR: Could not read bitmap.\n"); + return 0; + } + + for (int j = 0; j < h; j++) + { + for (int i = 0; i < w; i++) + { + unsigned int curpos = j * w + i; + BYTE r; + BYTE g; + BYTE b; + BYTE pixelKey; + + memcpy(&r, bitmapImage + curpos * 3 + 2, 1); + memcpy(&g, bitmapImage + curpos * 3 + 1, 1); + memcpy(&b, bitmapImage + curpos * 3 + 0, 1); + + if (r == 255 && g == 0 && b == 255) + { + pixelKey = 0; // Reserved for pure-magenta aka transparent + } + else + { + pixelKey = findPixelKey(palette8, r, g, b); + } + + unsigned int curposFlip = ((h - 1 - j) * w) + i; // Bitmap rows are stored bottom-up + memcpy(bytelist + p_TexTiles[selection] + curposFlip, &pixelKey, 1); + } + } + + writeFile(args[1], bytelist, fsize); + + free(bitmapImage); +} diff --git a/Source/tr2pc.h b/Source/tr2pc.h index 67bd27f..d15872a 100644 --- a/Source/tr2pc.h +++ b/Source/tr2pc.h @@ -40,5 +40,6 @@ void tr2pc_add_zone(char *bytelist, char *args[], unsigned p_NumBoxes, unsigned void tr2pc_replace_zone(char *bytelist, char *args[], unsigned p_NumBoxes, unsigned p_NumOverlaps, unsigned fsize); void tr2pc_get_offset(char *bytelist, char *args[], unsigned argc, unsigned p_NumVertices[], unsigned p_NumSprites[], unsigned p_NumLights[], unsigned p_NumZSector[], unsigned p_NumStaticMeshes[], unsigned p_AlternateRoom[], unsigned p_NumFloorData, unsigned p_NumItems, unsigned p_NumSpriteSequences, unsigned p_NumCameras, unsigned p_NumDemoData, unsigned p_NumBoxes, unsigned p_NumOverlaps, unsigned p_NumSoundSources, unsigned fsize); void tr2pc_extract_textile(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles, BYTE* palette8, int selection); +void tr2pc_replace_textile(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles, BYTE* palette8, unsigned fsize); #endif From d48ccd3d9cf9b03e36f4c4e1c0183d3eadfbfc4a Mon Sep 17 00:00:00 2001 From: Aerik72 Date: Tue, 10 Aug 2021 23:11:10 -0500 Subject: [PATCH 4/5] TR2 textile extract working tentatively --- Source/functions.c | 36 ++++++++++++++ Source/tr1psx.c | 8 ++++ Source/tr2pc.c | 115 ++++++++++++++++++++++++++++++++++++++++++--- Source/tr2pc.h | 5 +- 4 files changed, 155 insertions(+), 9 deletions(-) diff --git a/Source/functions.c b/Source/functions.c index 04f7e91..575d57e 100644 --- a/Source/functions.c +++ b/Source/functions.c @@ -166,6 +166,9 @@ unsigned removerange(char *bytelist, unsigned offset, unsigned length, unsigned return (fsize-length); } +// This function writes a 24-bit bitmap (R8 G8 B8) +// In TR1, full black (0, 0, 0) represents transparent +// In TR2, full magenta (255, 0, 255) represents transparent void writeBitmap(char* img, char* filename, const unsigned w, const unsigned h) { FILE* f; @@ -201,6 +204,39 @@ void writeBitmap(char* img, char* filename, const unsigned w, const unsigned h) fclose(f); } +void writeBitmap32(char* img, char* filename, const unsigned w, const unsigned h) +{ + FILE* f; + int bmpFileSize = 54 + 4 * w * h; + + unsigned char bmpfileheader[14] = { 'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0 }; + unsigned char bmpinfoheader[40] = { 40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 32,0 }; + + bmpfileheader[2] = (unsigned char)(bmpFileSize); + bmpfileheader[3] = (unsigned char)(bmpFileSize >> 8); + bmpfileheader[4] = (unsigned char)(bmpFileSize >> 16); + bmpfileheader[5] = (unsigned char)(bmpFileSize >> 24); + + bmpinfoheader[4] = (unsigned char)(w); + bmpinfoheader[5] = (unsigned char)(w >> 8); + bmpinfoheader[6] = (unsigned char)(w >> 16); + bmpinfoheader[7] = (unsigned char)(w >> 24); + bmpinfoheader[8] = (unsigned char)(h); + bmpinfoheader[9] = (unsigned char)(h >> 8); + bmpinfoheader[10] = (unsigned char)(h >> 16); + bmpinfoheader[11] = (unsigned char)(h >> 24); + + f = fopen(filename, "wb"); + fwrite(bmpfileheader, 1, 14, f); + fwrite(bmpinfoheader, 1, 40, f); + for (int i = 0; i < h; i++) + { + fwrite(img + (w * (h - i - 1) * 4), 4, w, f); + } + + fclose(f); +} + BYTE findPixelKey(BYTE* palette, BYTE r, BYTE g, BYTE b) { BYTE pr, pg, pb; diff --git a/Source/tr1psx.c b/Source/tr1psx.c index 545020c..1c3d032 100644 --- a/Source/tr1psx.c +++ b/Source/tr1psx.c @@ -178,6 +178,14 @@ void tr1psx_main(int argc, char *args[], char *bytelist, unsigned fsize){ if (!_strnicmp(args[2],"get",3)&&!_strnicmp(args[3],"offset",6)) tr1psx_get_offset(bytelist, args, argc, p_NumVertices, p_NumSprites, p_NumLights, p_NumZSector, p_NumStaticMeshes, p_AlternateRoom, p_NumFloorData, p_NumItems, p_NumSpriteSequences, p_NumCameras, p_NumBoxes, p_NumOverlaps, p_NumSoundSources, fsize); if (!_strnicmp(args[2], "extract", 7) && !strnicmp(args[3], "textile", 7)) printf("EXTRACT TEXTILE is not supported for PSX file format."); + if (!_strnicmp(args[2], "replace", 7)) + { + if (!strnicmp(args[3], "textile", 7)) + { + printf("REPLACE TEXTILE is not supported for PSX file format."); + } + } + free(roomX); free(roomY); free(roomZ); diff --git a/Source/tr2pc.c b/Source/tr2pc.c index 43588e4..c20eac1 100644 --- a/Source/tr2pc.c +++ b/Source/tr2pc.c @@ -49,6 +49,7 @@ void tr2pc_main(int argc, char *args[], char *bytelist, unsigned fsize){ // 16-bit palette // NOTE: There is no reason for us to store the unused byte, so we'll discard it for a smaller memory footprint. // tr_colour4 Palette16[256]; // 16-bit palette (1024 bytes) + // The 16-bit palette is used for identifying the colors of solid polygons, *not* textile colors. // struct tr_colour4 // 4 bytes // { // uint8_t Red; @@ -69,18 +70,23 @@ void tr2pc_main(int argc, char *args[], char *bytelist, unsigned fsize){ // Texture tiles // uint32_t NumTextiles; // number of texture tiles (4 bytes) - // tr2_textile8 Textile8[NumTextiles]; // 8-bit (palettized) textiles (NumTextiles * 65536 bytes) - // tr2_textile16 Textile16[NumTextiles]; // 16-bit (ARGB) textiles (NumTextiles * 131072 bytes) memcpy(&freeuint1, bytelist + curpos, 4); // Number of Texture Tiles numTexTiles = freeuint1; curpos += 4; + // tr2_textile8 Textile8[NumTextiles]; // 8-bit (palettized) textiles (NumTextiles * 65536 bytes) p_TexTiles8 = malloc(numTexTiles * sizeof(unsigned)); // Offsets of 8-bit TexTiles for (int i = 0; i < numTexTiles; i++) { p_TexTiles8[i] = curpos; curpos += (1 << 16); // Each texture is 8 bits in a 256 x 256 grid a.k.a. 2^16 } + + // tr2_textile16 Textile16[NumTextiles]; // 16-bit (ARGB) textiles (NumTextiles * 131072 bytes) + // The 16-bit textile array, which contains[tr_textile16] structures, specifies colours using 16 - bit ARGB, + // where the highest bit (0x8000) is a crude alpha channel (really just a simple transparency: 0==transparent, 1==opaque). + // The next 5 bits(0x7C00) specify the red channel, the next 5 bits(0x03E0) specify the green channel, + // and the last 5 bits(0x001F) specify the blue channel, each on a scale from 0..31. p_TexTiles16 = malloc(numTexTiles * sizeof(unsigned)); // Offsets of 16-bit TexTiles for (int i = 0; i < numTexTiles; i++) { @@ -248,13 +254,26 @@ void tr2pc_main(int argc, char *args[], char *bytelist, unsigned fsize){ if (!_strnicmp(args[2],"add",3)&&!_strnicmp(args[3],"overlap",7)) tr1pc_add_overlap(bytelist, args, argc, p_NumOverlaps, fsize); if (!_strnicmp(args[2],"overwrite",7)&&!_strnicmp(args[3],"overlap",7)) tr1pc_overwrite_overlap(bytelist, args, argc, p_NumOverlaps, fsize); if (!_strnicmp(args[2],"get",3)&&!_strnicmp(args[3],"offset",6)) tr2pc_get_offset(bytelist, args, argc, p_NumVertices, p_NumSprites, p_NumLights, p_NumZSector, p_NumStaticMeshes, p_AlternateRoom, p_NumFloorData, p_NumItems, p_NumSpriteSequences, p_NumCameras, p_NumDemoData, p_NumBoxes, p_NumOverlaps, p_NumSoundSources, fsize); - if (!_strnicmp(args[2], "extract", 7) && !strnicmp(args[3], "textile", 7)) tr2pc_extract_textile(bytelist, args, numTexTiles, p_TexTiles8, palette8, !strnicmp(args[4], "all", 3) ? -1 : atoi(args[4])); + + if (!_strnicmp(args[2], "extract", 7)) + { + if (!strnicmp(args[3], "textile", 9)) + { + tr2pc_extract_textile16(bytelist, args, numTexTiles, p_TexTiles16, !strnicmp(args[4], "all", 3) ? -1 : atoi(args[4])); + } + else if (!strnicmp(args[3], "textile8", 7)) + { + printf("WARNING: 8-bit textures are a legacy feature, and will probably not render on a modern PC.\n"); + tr2pc_extract_textile8(bytelist, args, numTexTiles, p_TexTiles8, palette8, !strnicmp(args[4], "all", 3) ? -1 : atoi(args[4])); + } + } if (!_strnicmp(args[2], "replace", 7)) { - if (!strnicmp(args[3], "textile", 7)) + if (!strnicmp(args[3], "textile8", 7)) { - tr2pc_replace_textile(bytelist, args, numTexTiles, p_TexTiles8, palette8, fsize); + printf("WARNING: 8-bit textures are a legacy feature, and will probably not render on a modern PC.\n"); + tr2pc_replace_textile8(bytelist, args, numTexTiles, p_TexTiles8, palette8, fsize); } } @@ -2909,7 +2928,7 @@ void tr2pc_get_offset(char *bytelist, char *args[], unsigned argc, unsigned p_Nu } // int selection // -1 for all, 0 - (numTexTiles-1) for an individual texture tile -void tr2pc_extract_textile(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles8, BYTE* palette8, int selection) +void tr2pc_extract_textile8(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles8, BYTE* palette8, int selection) { if (selection < -1 || selection >= (int)numTexTiles) { @@ -2973,8 +2992,90 @@ void tr2pc_extract_textile(char* bytelist, char* args[], unsigned numTexTiles, u } } +// tr2_textile16 Textile16[NumTextiles]; // 16-bit (ARGB) textiles (NumTextiles * 131072 bytes) +// The 16-bit textile array, which contains[tr_textile16] structures, specifies colours using 16 - bit ARGB, +// where the highest bit (0x8000) is a crude alpha channel (really just a simple transparency: 0==transparent, 1==opaque). +// The next 5 bits(0x7C00) specify the red channel, the next 5 bits(0x03E0) specify the green channel, +// and the last 5 bits(0x001F) specify the blue channel, each on a scale from 0..31. +void tr2pc_extract_textile16(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles16, int selection) +{ + if (selection < -1 || selection >= (int)numTexTiles) + { + printf("ERROR: Textile selection must be between \"0\" and \"%d\" or \"all\", argument was \"%d\"", numTexTiles - 1, selection); + return 0; + } + + // todo UM, ACTUALLY should just do 24-bit BMP. + // since we're not using the alpha channel, it's a waste of HDD space + + if (selection == -1) + { + printf("Extracting all 16-bit textiles to 32-bit bitmap (BMP)..."); + } + { + printf("Extracting 16-bit textile %d to 32-bit bitmap (BMP)...\n", selection); + } + + // This function extracts a texture tile from the level into a bitmap file. The syntax is "trmod [FILE] EXTRACT TEXTILE [#/All]". + + const unsigned w = 256; + const unsigned h = 256; + + for (int t = (selection == -1 ? 0 : selection); t <= (selection == -1 ? numTexTiles - 1 : selection); ++t) + { + BYTE* img = malloc(4 * w * h); + //memset(img, 0, 4 * w * h); // Fill the whole image with 0s + + for (int j = 0; j < h; j++) + { + for (int i = 0; i < w; i++) + { + unsigned int curpos = (j * w + i) * 2; + unsigned short pixel16; + BYTE a; + BYTE r; + BYTE g; + BYTE b; + + memcpy(&pixel16, bytelist + p_TexTiles16[t] + curpos, 2); + + a = pixel16 >> 15 == 1 ? 255 : 0; + r = (pixel16 >> 10) & 0b11111; // 5-bit red channel + g = (pixel16 >> 5) & 0b11111; // 5-bit green channel + b = pixel16 & 0b11111; // 5-bit blue channel + + if (a == 0) + { + // TR2 transparency - full magenta + img[i * 4 + j * w * 4 + 2] = 255; // 8-bit red + img[i * 4 + j * w * 4 + 1] = 0; // 8-bit green + img[i * 4 + j * w * 4 + 0] = 255; // 8-bit blue + img[i * 4 + j * w * 4 + 3] = 255; // Opaque (according to BMP) + } + else + { + // Full color / full opaque + img[i * 4 + j * w * 4 + 2] = r * 255 / 31; // Convert to 8-bit red + img[i * 4 + j * w * 4 + 1] = g * 255 / 31; // Convert to 8-bit green + img[i * 4 + j * w * 4 + 0] = b * 255 / 31; // Convert to 8-bit blue + img[i * 4 + j * w * 4 + 3] = 255; // Opaque + } + } + } + + unsigned fnameLen = 12 + (t < 10 ? 1 : 2); + char* filename = malloc(fnameLen); + snprintf(filename, fnameLen, "textile%u.bmp", t); + printf("Writing \"%s\"...\n", filename); + writeBitmap32(img, filename, 256, 256); + + free(img); + free(filename); + } +} + // This function replaces a texture tile in the level from a bitmap file. The syntax is "trmod [FILE] REPLACE TEXTILE [#] [FILENAME.BMP]". -void tr2pc_replace_textile(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles, BYTE* palette8, unsigned fsize) +void tr2pc_replace_textile8(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles, BYTE* palette8, unsigned fsize) { unsigned int selection = atoi(args[4]); char* filename = args[5]; diff --git a/Source/tr2pc.h b/Source/tr2pc.h index d15872a..8b26505 100644 --- a/Source/tr2pc.h +++ b/Source/tr2pc.h @@ -39,7 +39,8 @@ void tr2pc_get_zones(char *bytelist, char *args[], unsigned p_NumBoxes, unsigned void tr2pc_add_zone(char *bytelist, char *args[], unsigned p_NumBoxes, unsigned p_NumOverlaps, unsigned fsize); void tr2pc_replace_zone(char *bytelist, char *args[], unsigned p_NumBoxes, unsigned p_NumOverlaps, unsigned fsize); void tr2pc_get_offset(char *bytelist, char *args[], unsigned argc, unsigned p_NumVertices[], unsigned p_NumSprites[], unsigned p_NumLights[], unsigned p_NumZSector[], unsigned p_NumStaticMeshes[], unsigned p_AlternateRoom[], unsigned p_NumFloorData, unsigned p_NumItems, unsigned p_NumSpriteSequences, unsigned p_NumCameras, unsigned p_NumDemoData, unsigned p_NumBoxes, unsigned p_NumOverlaps, unsigned p_NumSoundSources, unsigned fsize); -void tr2pc_extract_textile(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles, BYTE* palette8, int selection); -void tr2pc_replace_textile(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles, BYTE* palette8, unsigned fsize); +void tr2pc_extract_textile8(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles, BYTE* palette8, int selection); +void tr2pc_extract_textile16(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles16, int selection); +void tr2pc_replace_textile8(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles, BYTE* palette8, unsigned fsize); #endif From 500a0ffb1779327da255bf2613547402d36d0cf8 Mon Sep 17 00:00:00 2001 From: Aerik72 Date: Fri, 13 Aug 2021 00:41:01 -0500 Subject: [PATCH 5/5] TR2 texture replace working --- Source/tr1pc.c | 1 - Source/tr2pc.c | 131 +++++++++++++++++++++++++++++++++++++------------ Source/tr2pc.h | 3 +- 3 files changed, 101 insertions(+), 34 deletions(-) diff --git a/Source/tr1pc.c b/Source/tr1pc.c index 8f42d89..ea83356 100644 --- a/Source/tr1pc.c +++ b/Source/tr1pc.c @@ -3241,7 +3241,6 @@ void tr1pc_replace_textile(char* bytelist, char* args[], unsigned numTexTiles, u const short w = 256; const short h = 256; - unsigned memorySize = 3 * w * h; BYTE* bitmapImage = readBitmapFile(filename); if (bitmapImage == NULL) diff --git a/Source/tr2pc.c b/Source/tr2pc.c index c20eac1..806333d 100644 --- a/Source/tr2pc.c +++ b/Source/tr2pc.c @@ -259,7 +259,7 @@ void tr2pc_main(int argc, char *args[], char *bytelist, unsigned fsize){ { if (!strnicmp(args[3], "textile", 9)) { - tr2pc_extract_textile16(bytelist, args, numTexTiles, p_TexTiles16, !strnicmp(args[4], "all", 3) ? -1 : atoi(args[4])); + tr2pc_extract_textile(bytelist, args, numTexTiles, p_TexTiles16, !strnicmp(args[4], "all", 3) ? -1 : atoi(args[4])); } else if (!strnicmp(args[3], "textile8", 7)) { @@ -270,7 +270,11 @@ void tr2pc_main(int argc, char *args[], char *bytelist, unsigned fsize){ if (!_strnicmp(args[2], "replace", 7)) { - if (!strnicmp(args[3], "textile8", 7)) + if (!strnicmp(args[3], "textile", 9)) + { + tr2pc_replace_textile(bytelist, args, numTexTiles, p_TexTiles16, fsize); + } + else if (!strnicmp(args[3], "textile8", 7)) { printf("WARNING: 8-bit textures are a legacy feature, and will probably not render on a modern PC.\n"); tr2pc_replace_textile8(bytelist, args, numTexTiles, p_TexTiles8, palette8, fsize); @@ -2992,12 +2996,70 @@ void tr2pc_extract_textile8(char* bytelist, char* args[], unsigned numTexTiles, } } +// This function replaces a texture tile in the level from a bitmap file. The syntax is "trmod [FILE] REPLACE TEXTILE [#] [FILENAME.BMP]". +void tr2pc_replace_textile8(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles, BYTE* palette8, unsigned fsize) +{ + unsigned int selection = atoi(args[4]); + char* filename = args[5]; + + if (selection < 0 || selection >= numTexTiles) + { + printf("ERROR: Textile selection must be between \"0\" and \"%d\", argument was \"%d\"", numTexTiles - 1, selection); + return 0; + } + + printf("Replacing 8-bit textile %d...\n", selection); + + const short w = 256; + const short h = 256; + unsigned memorySize = 3 * w * h; + + BYTE* bitmapImage = readBitmapFile(filename); + if (bitmapImage == NULL) + { + printf("ERROR: Could not read bitmap.\n"); + return 0; + } + + for (int j = 0; j < h; j++) + { + for (int i = 0; i < w; i++) + { + unsigned int curpos = j * w + i; + BYTE r; + BYTE g; + BYTE b; + BYTE pixelKey; + + memcpy(&r, bitmapImage + curpos * 3 + 2, 1); + memcpy(&g, bitmapImage + curpos * 3 + 1, 1); + memcpy(&b, bitmapImage + curpos * 3 + 0, 1); + + if (r == 255 && g == 0 && b == 255) + { + pixelKey = 0; // Reserved for pure-magenta aka transparent + } + else + { + pixelKey = findPixelKey(palette8, r, g, b); + } + + unsigned int curposFlip = ((h - 1 - j) * w) + i; // Bitmap rows are stored bottom-up + memcpy(bytelist + p_TexTiles[selection] + curposFlip, &pixelKey, 1); + } + } + + writeFile(args[1], bytelist, fsize); + + free(bitmapImage); +} + // tr2_textile16 Textile16[NumTextiles]; // 16-bit (ARGB) textiles (NumTextiles * 131072 bytes) // The 16-bit textile array, which contains[tr_textile16] structures, specifies colours using 16 - bit ARGB, // where the highest bit (0x8000) is a crude alpha channel (really just a simple transparency: 0==transparent, 1==opaque). // The next 5 bits(0x7C00) specify the red channel, the next 5 bits(0x03E0) specify the green channel, // and the last 5 bits(0x001F) specify the blue channel, each on a scale from 0..31. -void tr2pc_extract_textile16(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles16, int selection) +void tr2pc_extract_textile(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles16, int selection) { if (selection < -1 || selection >= (int)numTexTiles) { @@ -3005,26 +3067,22 @@ void tr2pc_extract_textile16(char* bytelist, char* args[], unsigned numTexTiles, return 0; } - // todo UM, ACTUALLY should just do 24-bit BMP. - // since we're not using the alpha channel, it's a waste of HDD space - if (selection == -1) { - printf("Extracting all 16-bit textiles to 32-bit bitmap (BMP)..."); + printf("Extracting all 16-bit textiles to 24-bit bitmap (BMP)..."); } { - printf("Extracting 16-bit textile %d to 32-bit bitmap (BMP)...\n", selection); + printf("Extracting 16-bit textile %d to 24-bit bitmap (BMP)...\n", selection); } // This function extracts a texture tile from the level into a bitmap file. The syntax is "trmod [FILE] EXTRACT TEXTILE [#/All]". - const unsigned w = 256; - const unsigned h = 256; + const unsigned short w = 256; + const unsigned short h = 256; for (int t = (selection == -1 ? 0 : selection); t <= (selection == -1 ? numTexTiles - 1 : selection); ++t) { - BYTE* img = malloc(4 * w * h); - //memset(img, 0, 4 * w * h); // Fill the whole image with 0s + BYTE* img = malloc(3 * w * h); for (int j = 0; j < h; j++) { @@ -3039,7 +3097,8 @@ void tr2pc_extract_textile16(char* bytelist, char* args[], unsigned numTexTiles, memcpy(&pixel16, bytelist + p_TexTiles16[t] + curpos, 2); - a = pixel16 >> 15 == 1 ? 255 : 0; + // Crack it + a = pixel16 >> 15; r = (pixel16 >> 10) & 0b11111; // 5-bit red channel g = (pixel16 >> 5) & 0b11111; // 5-bit green channel b = pixel16 & 0b11111; // 5-bit blue channel @@ -3047,18 +3106,16 @@ void tr2pc_extract_textile16(char* bytelist, char* args[], unsigned numTexTiles, if (a == 0) { // TR2 transparency - full magenta - img[i * 4 + j * w * 4 + 2] = 255; // 8-bit red - img[i * 4 + j * w * 4 + 1] = 0; // 8-bit green - img[i * 4 + j * w * 4 + 0] = 255; // 8-bit blue - img[i * 4 + j * w * 4 + 3] = 255; // Opaque (according to BMP) + img[i * 3 + j * w * 3 + 2] = 255; // 8-bit red + img[i * 3 + j * w * 3 + 1] = 0; // 8-bit green + img[i * 3 + j * w * 3 + 0] = 255; // 8-bit blue } else { // Full color / full opaque - img[i * 4 + j * w * 4 + 2] = r * 255 / 31; // Convert to 8-bit red - img[i * 4 + j * w * 4 + 1] = g * 255 / 31; // Convert to 8-bit green - img[i * 4 + j * w * 4 + 0] = b * 255 / 31; // Convert to 8-bit blue - img[i * 4 + j * w * 4 + 3] = 255; // Opaque + img[i * 3 + j * w * 3 + 2] = r * 255 / 31; // Convert to 8-bit red + img[i * 3 + j * w * 3 + 1] = g * 255 / 31; // Convert to 8-bit green + img[i * 3 + j * w * 3 + 0] = b * 255 / 31; // Convert to 8-bit blue } } } @@ -3067,7 +3124,7 @@ void tr2pc_extract_textile16(char* bytelist, char* args[], unsigned numTexTiles, char* filename = malloc(fnameLen); snprintf(filename, fnameLen, "textile%u.bmp", t); printf("Writing \"%s\"...\n", filename); - writeBitmap32(img, filename, 256, 256); + writeBitmap(img, filename, 256, 256); free(img); free(filename); @@ -3075,7 +3132,11 @@ void tr2pc_extract_textile16(char* bytelist, char* args[], unsigned numTexTiles, } // This function replaces a texture tile in the level from a bitmap file. The syntax is "trmod [FILE] REPLACE TEXTILE [#] [FILENAME.BMP]". -void tr2pc_replace_textile8(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles, BYTE* palette8, unsigned fsize) +// The 16-bit textile array, which contains[tr_textile16] structures, specifies colours using 16 - bit ARGB, +// where the highest bit (0x8000) is a crude alpha channel (really just a simple transparency: 0==transparent, 1==opaque). +// The next 5 bits(0x7C00) specify the red channel, the next 5 bits(0x03E0) specify the green channel, +// and the last 5 bits(0x001F) specify the blue channel, each on a scale from 0..31. +void tr2pc_replace_textile(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles, unsigned fsize) { unsigned int selection = atoi(args[4]); char* filename = args[5]; @@ -3086,16 +3147,15 @@ void tr2pc_replace_textile8(char* bytelist, char* args[], unsigned numTexTiles, return 0; } - printf("Replacing 8-bit textile %d...\n", selection); + printf("Replacing 16-bit textile %d with 24-bit bitmap (BMP)...\n", selection); const short w = 256; const short h = 256; - unsigned memorySize = 3 * w * h; BYTE* bitmapImage = readBitmapFile(filename); if (bitmapImage == NULL) { - printf("ERROR: Could not read bitmap.\n"); + printf("ERROR: Could not read 24-bit bitmap \"%s\".\n", filename); return 0; } @@ -3104,26 +3164,33 @@ void tr2pc_replace_textile8(char* bytelist, char* args[], unsigned numTexTiles, for (int i = 0; i < w; i++) { unsigned int curpos = j * w + i; + BYTE a; BYTE r; BYTE g; BYTE b; - BYTE pixelKey; - + unsigned short pixel16; + memcpy(&r, bitmapImage + curpos * 3 + 2, 1); memcpy(&g, bitmapImage + curpos * 3 + 1, 1); memcpy(&b, bitmapImage + curpos * 3 + 0, 1); if (r == 255 && g == 0 && b == 255) { - pixelKey = 0; // Reserved for pure-magenta aka transparent + pixel16 = 0; // Reserved for pure-magenta aka transparent } else { - pixelKey = findPixelKey(palette8, r, g, b); + a = 1; // Full color / full opaque + r = r * 31 / 255; // Convert to 5-bit red + g = g * 31 / 255; // Convert to 5-bit green + b = b * 31 / 255; // Convert to 5-bit blue + + // Pack it + pixel16 = (a << 15) | (r << 10) | (g << 5) | b; } - unsigned int curposFlip = ((h - 1 - j) * w) + i; // Bitmap rows are stored bottom-up - memcpy(bytelist + p_TexTiles[selection] + curposFlip, &pixelKey, 1); + unsigned int curposFlip = (((h - 1 - j) * w) + i) * 2; // Bitmap rows are stored bottom-up + memcpy(bytelist + p_TexTiles[selection] + curposFlip, &pixel16, 2); } } diff --git a/Source/tr2pc.h b/Source/tr2pc.h index 8b26505..2f207ed 100644 --- a/Source/tr2pc.h +++ b/Source/tr2pc.h @@ -40,7 +40,8 @@ void tr2pc_add_zone(char *bytelist, char *args[], unsigned p_NumBoxes, unsigned void tr2pc_replace_zone(char *bytelist, char *args[], unsigned p_NumBoxes, unsigned p_NumOverlaps, unsigned fsize); void tr2pc_get_offset(char *bytelist, char *args[], unsigned argc, unsigned p_NumVertices[], unsigned p_NumSprites[], unsigned p_NumLights[], unsigned p_NumZSector[], unsigned p_NumStaticMeshes[], unsigned p_AlternateRoom[], unsigned p_NumFloorData, unsigned p_NumItems, unsigned p_NumSpriteSequences, unsigned p_NumCameras, unsigned p_NumDemoData, unsigned p_NumBoxes, unsigned p_NumOverlaps, unsigned p_NumSoundSources, unsigned fsize); void tr2pc_extract_textile8(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles, BYTE* palette8, int selection); -void tr2pc_extract_textile16(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles16, int selection); +void tr2pc_extract_textile(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles16, int selection); void tr2pc_replace_textile8(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles, BYTE* palette8, unsigned fsize); +void tr2pc_replace_textile(char* bytelist, char* args[], unsigned numTexTiles, unsigned* p_TexTiles, unsigned fsize); #endif