#include "toollib.h" #include "piclib.h" byte_t* g_tgabuffer; byte_t* g_tgabuffptr; /***************************************************************************** TL_LoadPCX *****************************************************************************/ void TL_LoadPCX(char* filename, byte_t** pic, byte_t** palette, int* width, int* height) { byte_t* raw; pcx_t* pcx; int x; int y; int len; int databyte; int runlength; byte_t* out; byte_t* pix; // load the file len = TL_LoadFile(filename,(void **)&raw); // parse the PCX file pcx = (pcx_t*)raw; raw = &pcx->data; pcx->xmin = TL_LittleShort(pcx->xmin); pcx->ymin = TL_LittleShort(pcx->ymin); pcx->xmax = TL_LittleShort(pcx->xmax); pcx->ymax = TL_LittleShort(pcx->ymax); pcx->hres = TL_LittleShort(pcx->hres); pcx->vres = TL_LittleShort(pcx->vres); pcx->bytes_per_line = TL_LittleShort(pcx->bytes_per_line); pcx->palette_type = TL_LittleShort(pcx->palette_type); if (pcx->manufacturer != 0x0a || pcx->version != 5 || pcx->encoding != 1 || pcx->bits_per_pixel != 8 || pcx->xmax >= 640 || pcx->ymax >= 480) TL_Error("Bad pcx file %s",filename); if (palette) { *palette = (byte_t*)TL_Malloc(768); memcpy(*palette,(byte_t*)pcx + len - 768,768); } if (width) *width = pcx->xmax+1; if (height) *height = pcx->ymax+1; if (!pic) return; out = (byte_t*)TL_Malloc((pcx->ymax+1)*(pcx->xmax+1)); *pic = out; pix = out; for (y=0; y<=pcx->ymax; y++, pix += pcx->xmax+1) { for (x=0; x<=pcx->xmax; ) { databyte = *raw++; if((databyte & 0xC0) == 0xC0) { runlength = databyte & 0x3F; databyte = *raw++; } else runlength = 1; while (runlength-- > 0) pix[x++] = databyte; } } if (raw - (byte_t *)pcx > len) TL_Error("PCX file %s was malformed",filename); TL_Free(pcx); } /***************************************************************************** TL_SavePCX *****************************************************************************/ void TL_SavePCX(char* filename, byte_t* data, int width, int height, byte_t* palette) { int i; int j; int length; pcx_t* pcx; byte_t* pack; pcx = (pcx_t*)TL_Malloc(width*height*2+1000); pcx->manufacturer = 0x0A; // PCX id pcx->version = 5; // 256 color pcx->encoding = 1; // uncompressed pcx->bits_per_pixel = 8; // 256 color pcx->xmin = 0; pcx->ymin = 0; pcx->xmax = TL_LittleShort((short)(width-1)); pcx->ymax = TL_LittleShort((short)(height-1)); pcx->hres = TL_LittleShort((short)width); pcx->vres = TL_LittleShort((short)height); pcx->color_planes = 1; // chunky image pcx->bytes_per_line = TL_LittleShort((short)width); pcx->palette_type = TL_LittleShort(2); // not a grey scale // pack the image pack = &pcx->data; for (i=0; i<height; i++) { for (j=0; j<width; j++) { if ((*data & 0xc0) != 0xC0) *pack++ = *data++; else { *pack++ = 0xC1; *pack++ = *data++; } } } // write the palette *pack++ = 0x0C; for (i=0; i<768; i++) *pack++ = *palette++; // write output file length = pack - (byte_t*)pcx; TL_SaveFile(filename,pcx,length); TL_Free(pcx); } /***************************************************************************** TGA_GetByte *****************************************************************************/ byte_t TGA_GetByte(void) { return (*g_tgabuffptr++); } /***************************************************************************** TGA_GetShort *****************************************************************************/ short TGA_GetShort(void) { byte_t msb; byte_t lsb; lsb = g_tgabuffptr[0]; msb = g_tgabuffptr[1]; g_tgabuffptr += 2; return ((msb<<8)|lsb); } /***************************************************************************** TL_LoadTGA *****************************************************************************/ void TL_LoadTGA(char* name, byte_t** pixels, int* width, int* height) { int columns; int rows; int numPixels; byte_t* pixbuf; int row; int column; byte_t* targa_rgba; tga_t targa_header; byte_t red; byte_t green; byte_t blue; byte_t alphabyte; byte_t packetHeader; byte_t packetSize; byte_t j; TL_LoadFile(name,(void**)&g_tgabuffer); g_tgabuffptr = g_tgabuffer; /* load unaligned tga data */ targa_header.id_length = TGA_GetByte(); targa_header.colormap_type = TGA_GetByte(); targa_header.image_type = TGA_GetByte(); targa_header.colormap_index = TGA_GetShort(); targa_header.colormap_length = TGA_GetShort(); targa_header.colormap_size = TGA_GetByte(); targa_header.x_origin = TGA_GetShort(); targa_header.y_origin = TGA_GetShort(); targa_header.width = TGA_GetShort(); targa_header.height = TGA_GetShort(); targa_header.pixel_size = TGA_GetByte(); targa_header.attributes = TGA_GetByte(); if (targa_header.image_type != 2 && targa_header.image_type != 10) TL_Error("TL_LoadTGA: %s - Only type 2 and 10 targa RGB images supported",name); if ((targa_header.colormap_type != 0) || (targa_header.pixel_size != 32 && targa_header.pixel_size != 24)) TL_Error("TL_LoadTGA: %s - Only 32 or 24 bit images supported (no colormaps)",name); columns = targa_header.width; rows = targa_header.height; numPixels = columns * rows; if (width) *width = columns; if (height) *height = rows; targa_rgba = (byte_t*)TL_Malloc(numPixels*4); *pixels = targa_rgba; if (targa_header.id_length != 0) { // skip TARGA image comment g_tgabuffptr += targa_header.id_length; } if (targa_header.image_type==2) { // Uncompressed, RGB images for (row=rows-1; row>=0; row--) { pixbuf = targa_rgba + row*columns*4; for(column=0; column<columns; column++) { switch (targa_header.pixel_size) { case 24: blue = TGA_GetByte(); green = TGA_GetByte(); red = TGA_GetByte(); alphabyte = 255; break; case 32: blue = TGA_GetByte(); green = TGA_GetByte(); red = TGA_GetByte(); alphabyte = TGA_GetByte(); break; } *pixbuf++ = red; *pixbuf++ = green; *pixbuf++ = blue; *pixbuf++ = alphabyte; } } } else if (targa_header.image_type==10) { // Runlength encoded RGB images for (row=rows-1; row>=0; row--) { pixbuf = targa_rgba + row*columns*4; for(column=0; column<columns; ) { packetHeader = TGA_GetByte(); packetSize = 1 + (packetHeader & 0x7f); if (packetHeader & 0x80) { // run-length packet switch (targa_header.pixel_size) { case 24: blue = TGA_GetByte(); green = TGA_GetByte(); red = TGA_GetByte(); alphabyte = 255; break; case 32: blue = TGA_GetByte(); green = TGA_GetByte(); red = TGA_GetByte(); alphabyte = TGA_GetByte(); break; } for(j=0; j<packetSize; j++) { *pixbuf++ = red; *pixbuf++ = green; *pixbuf++ = blue; *pixbuf++ = alphabyte; column++; if (column==columns) { // run spans across rows column=0; if (row>0) row--; else goto breakOut; pixbuf = targa_rgba + row*columns*4; } } } else { // non run-length packet for(j=0; j<packetSize; j++) { switch (targa_header.pixel_size) { case 24: blue = TGA_GetByte(); green = TGA_GetByte(); red = TGA_GetByte(); alphabyte = 255; break; case 32: blue = TGA_GetByte(); green = TGA_GetByte(); red = TGA_GetByte(); alphabyte = TGA_GetByte(); break; } *pixbuf++ = red; *pixbuf++ = green; *pixbuf++ = blue; *pixbuf++ = alphabyte; column++; if (column == columns) { // pixel packet run spans across rows column=0; if (row>0) row--; else goto breakOut; pixbuf = targa_rgba + row*columns*4; } } } } breakOut:; } } TL_Free(g_tgabuffer); } /***************************************************************************** TL_SaveTGA Saves TGA. Supports r/w 16/24/32 bpp. *****************************************************************************/ void TL_SaveTGA(char* filename, byte_t* pixels, int width, int height, int sbpp, int tbpp) { int handle; tga_t tga; unsigned short rgba5551; unsigned long rgba8888; int r; int g; int b; int x; int y; int a; byte_t* tgabuffer; byte_t* tgabufferptr; byte_t* rawbufferptr; byte_t* tempbuffer; byte_t* tempbufferptr; int bytesperpixel; // all source is upsampled into easy 32 bit rgba8888 // and downsampled into tga buffer tempbuffer = (byte_t*)TL_Malloc(width*height*4); if (sbpp == 16) { /* source is 16 bit rgba */ rawbufferptr = pixels; for (y=0; y<height; y++) { tempbufferptr = tempbuffer + y*width*4; for (x=0; x<width; x++) { rgba5551 = *(unsigned short*)rawbufferptr; r = (rgba5551 & 0xF800)>>11; g = (rgba5551 & 0x07C0)>>6; b = (rgba5551 & 0x003E)>>1; a = (rgba5551 & 0x01); tempbufferptr[0] = (byte_t)(b * (255.0/31.0)); tempbufferptr[1] = (byte_t)(g * (255.0/31.0)); tempbufferptr[2] = (byte_t)(r * (255.0/31.0)); tempbufferptr[3] = (byte_t)(a * 255.0); rawbufferptr += sizeof(unsigned short); tempbufferptr += 4; } } } else if (sbpp == 24) { /* source is 24 bit rgba */ rawbufferptr = pixels; for (y=0; y<height; y++) { tempbufferptr = tempbuffer + y*width*4; for (x=0; x<width; x++) { tempbufferptr[0] = rawbufferptr[0]; tempbufferptr[1] = rawbufferptr[1]; tempbufferptr[2] = rawbufferptr[2]; tempbufferptr[3] = 255; rawbufferptr += 3; tempbufferptr += 4; } } } else if (sbpp == 32) { /* source is 32 bit rgba */ memcpy(tempbuffer,pixels,width*height*4); } else TL_Error("TL_SaveTGA: cannot handle source %d bits per pixel",sbpp); if (tbpp == 16) bytesperpixel = 2; else if (tbpp == 24) bytesperpixel = 3; else if (tbpp == 32) bytesperpixel = 4; else TL_Error("TL_SaveTGA: cannot handle target %d bits per pixel",tbpp); handle = TL_SafeOpenWrite(filename); /* write the targa header */ tga.id_length = 0; tga.colormap_type = 0; tga.image_type = 2; tga.colormap_index = 0; tga.colormap_length = 0; tga.colormap_size = 0; tga.x_origin = 0; tga.y_origin = 0; tga.width = width; tga.height = height; tga.pixel_size = tbpp; tga.attributes = 0; TL_SafeWrite(handle,&tga.id_length,sizeof(tga.id_length)); TL_SafeWrite(handle,&tga.colormap_type,sizeof(tga.colormap_type)); TL_SafeWrite(handle,&tga.image_type,sizeof(tga.image_type)); TL_SafeWrite(handle,&tga.colormap_index,sizeof(tga.colormap_index)); TL_SafeWrite(handle,&tga.colormap_length,sizeof(tga.colormap_length)); TL_SafeWrite(handle,&tga.colormap_size,sizeof(tga.colormap_size)); TL_SafeWrite(handle,&tga.x_origin,sizeof(tga.x_origin)); TL_SafeWrite(handle,&tga.y_origin,sizeof(tga.y_origin)); TL_SafeWrite(handle,&tga.width,sizeof(tga.width)); TL_SafeWrite(handle,&tga.height,sizeof(tga.height)); TL_SafeWrite(handle,&tga.pixel_size,sizeof(tga.pixel_size)); TL_SafeWrite(handle,&tga.attributes,sizeof(tga.attributes)); /* tga images are upside down left to right - !@#$% */ tgabuffer = (byte_t*)TL_Malloc(width*height*bytesperpixel); /* source is 32 bit rgba */ rawbufferptr = tempbuffer; for (y=height-1; y>=0; y--) { tgabufferptr = tgabuffer + y*width*bytesperpixel; for (x=0; x<width; x++) { switch (bytesperpixel) { case 2: break; case 3: rgba8888 = TL_BigLong(*(unsigned long*)rawbufferptr); r = (rgba8888 & 0xFF000000)>>24; g = (rgba8888 & 0x00FF0000)>>16; b = (rgba8888 & 0x0000FF00)>>8; tgabufferptr[0] = b; tgabufferptr[1] = g; tgabufferptr[2] = r; break; case 4: rgba8888 = TL_BigLong(*(unsigned long*)rawbufferptr); r = (rgba8888 & 0xFF000000)>>24; g = (rgba8888 & 0x00FF0000)>>16; b = (rgba8888 & 0x0000FF00)>>8; a = rgba8888 & 0xFF; tgabufferptr[0] = b; tgabufferptr[1] = g; tgabufferptr[2] = r; tgabufferptr[3] = a; break; } rawbufferptr += 4; tgabufferptr += bytesperpixel; } } TL_SafeWrite(handle,tgabuffer,width*height*bytesperpixel); close(handle); TL_Free(tempbuffer); TL_Free(tgabuffer); } /***************************************************************************** TL_LoadImage Loads an image based on extension. *****************************************************************************/ void TL_LoadImage(char* name, byte_t** pixels, byte_t** palette, int* width, int* height) { char ext[16]; TL_GetExtension(name,ext); if (!stricmp(ext,"pcx")) TL_LoadPCX(name,pixels,palette,width,height); else if (!stricmp(ext,"tga")) { TL_LoadTGA(name,pixels,width,height); *palette = NULL; } else TL_Error("TL_LoadImage: unknown image extension %s",ext); }