/* * Copyright(c) 1997-2001 Id Software, Inc. * Copyright(c) 2002 The Quakeforge Project. * Copyright(c) 2006 Quetoo. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or(at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "tga.h" #include "video.h" extern cvar_t *gl_loadtga; /* * LoadTGA */ void LoadTGA(char *name, byte **pic, int *width, int *height){ int cols, rows, pixels; int row, col, length; targa_header_t targa_header; byte *b, *buffer, *pixbuf; byte *targa_rgba; byte tmp[2]; *pic = NULL; if(!strstr(name, "env/") && !gl_loadtga->value) return; // possibly disabled for world textures length = FS_LoadFile(name, (void **)(char *)&buffer); if(!buffer) // unable to open file return; b = buffer; targa_header.id_length = *buffer++; targa_header.colormap_type = *buffer++; targa_header.image_type = *buffer++; tmp[0] = buffer[0]; tmp[1] = buffer[1]; targa_header.colormap_index = LittleShort(*((short *)tmp)); buffer += 2; tmp[0] = buffer[0]; tmp[1] = buffer[1]; targa_header.colormap_length = LittleShort(*((short *)tmp)); buffer += 2; targa_header.colormap_size = *buffer++; targa_header.x_origin = LittleShort(*((short *)buffer)); buffer += 2; targa_header.y_origin = LittleShort(*((short *)buffer)); buffer += 2; targa_header.width = LittleShort(*((short *)buffer)); buffer += 2; targa_header.height = LittleShort(*((short *)buffer)); buffer += 2; targa_header.pixel_size = *buffer++; targa_header.attributes = *buffer++; if(targa_header.image_type != 2 && targa_header.image_type != 10) return; //uncompressed rgb[a] and runlength compression only if(targa_header.pixel_size != 32 && targa_header.pixel_size != 24) return; //24 and 32bpp only cols = targa_header.width; rows = targa_header.height; pixels = cols * rows; if(width) *width = cols; if(height) *height = rows; targa_rgba = malloc(pixels * 4); *pic = targa_rgba; if(targa_header.id_length != 0) // skip header comment buffer += targa_header.id_length; byte red, green, blue, alpha; byte packet_header, packet_size, j; red = green = blue = alpha = 0; packet_header = packet_size = j = 0; if(targa_header.image_type == 2){ // uncompressed rgb for(row = rows - 1; row >= 0; row--){ pixbuf = targa_rgba + row * cols * 4; for(col = 0; col < cols; col++){ switch(targa_header.pixel_size){ case 24: blue = *buffer++; green = *buffer++; red = *buffer++; *pixbuf++ = red; *pixbuf++ = green; *pixbuf++ = blue; *pixbuf++ = 255; break; case 32: blue = *buffer++; green = *buffer++; red = *buffer++; alpha = *buffer++; *pixbuf++ = red; *pixbuf++ = green; *pixbuf++ = blue; *pixbuf++ = alpha; break; } } } } else if(targa_header.image_type == 10){ // runlength encoded for(row = rows - 1; row >= 0; row--){ pixbuf = targa_rgba + row * cols * 4; for(col = 0; col < cols;){ packet_header = *buffer++; packet_size = 1 + (packet_header & 0x7f); if(packet_header & 0x80){ // runlength packet switch(targa_header.pixel_size){ case 24: blue = *buffer++; green = *buffer++; red = *buffer++; alpha = 255; break; case 32: blue = *buffer++; green = *buffer++; red = *buffer++; alpha = *buffer++; break; } for(j = 0; j < packet_size; j++){ *pixbuf++ = red; *pixbuf++ = green; *pixbuf++ = blue; *pixbuf++ = alpha; col++; if(col == cols){ // run spans across rows col = 0; if(row > 0) row--; else goto breakOut; pixbuf = targa_rgba + row * cols * 4; } } } else { // non runlength packet for(j = 0; j < packet_size; j++){ switch(targa_header.pixel_size){ case 24: blue = *buffer++; green = *buffer++; red = *buffer++; *pixbuf++ = red; *pixbuf++ = green; *pixbuf++ = blue; *pixbuf++ = 255; break; case 32: blue = *buffer++; green = *buffer++; red = *buffer++; alpha = *buffer++; *pixbuf++ = red; *pixbuf++ = green; *pixbuf++ = blue; *pixbuf++ = alpha; break; } col++; if(col == cols){ // pixel packet run spans across rows col = 0; if(row > 0) row--; else goto breakOut; pixbuf = targa_rgba + row * cols * 4; } } } } breakOut: ; } } FS_FreeFile(b); } /* * WriteTGA */ void WriteTGA(char *name, byte *data, int width, int height){ int length; byte header[18]; FILE *f; memset(header, 0, sizeof(header)); // clear header header[2] = 2; // uncompressed rgb header[12] = width & 255; // width header[13] = width >> 8; header[14] = height & 255; // height header[15] = height >> 8; header[16] = 24; // pixel size length = width * height * 3; // rgb data length if(!(f = fopen(name, "wb"))){ // failed to open Com_Printf( "Failed to open to %s\n", name); } else { // write file fwrite(header, 1, sizeof(header), f); fwrite(data, 1, length, f); fclose(f); } }