You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
617 lines
13 KiB
617 lines
13 KiB
/* |
|
Copyright (C) 1997-2001 Id Software, Inc. |
|
|
|
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 "r_local.h" |
|
|
|
|
|
#define MAX_RIMAGES 1024 |
|
image_t r_images[MAX_RIMAGES]; |
|
int numr_images; |
|
|
|
|
|
/* |
|
=============== |
|
R_ImageList_f |
|
=============== |
|
*/ |
|
void R_ImageList_f (void) |
|
{ |
|
int i; |
|
image_t *image; |
|
int texels; |
|
|
|
ri.Con_Printf (PRINT_ALL, "------------------\n"); |
|
texels = 0; |
|
|
|
for (i=0, image=r_images ; i<numr_images ; i++, image++) |
|
{ |
|
if (image->registration_sequence <= 0) |
|
continue; |
|
texels += image->width*image->height; |
|
switch (image->type) |
|
{ |
|
case it_skin: |
|
ri.Con_Printf (PRINT_ALL, "M"); |
|
break; |
|
case it_sprite: |
|
ri.Con_Printf (PRINT_ALL, "S"); |
|
break; |
|
case it_wall: |
|
ri.Con_Printf (PRINT_ALL, "W"); |
|
break; |
|
case it_pic: |
|
ri.Con_Printf (PRINT_ALL, "P"); |
|
break; |
|
default: |
|
ri.Con_Printf (PRINT_ALL, " "); |
|
break; |
|
} |
|
|
|
ri.Con_Printf (PRINT_ALL, " %3i %3i : %s\n", |
|
image->width, image->height, image->name); |
|
} |
|
ri.Con_Printf (PRINT_ALL, "Total texel count: %i\n", texels); |
|
} |
|
|
|
|
|
/* |
|
================================================================= |
|
|
|
PCX LOADING |
|
|
|
================================================================= |
|
*/ |
|
|
|
/* |
|
============== |
|
LoadPCX |
|
============== |
|
*/ |
|
void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height) |
|
{ |
|
byte *raw; |
|
pcx_t *pcx; |
|
int x, y; |
|
int len; |
|
int dataByte, runLength; |
|
byte *out, *pix; |
|
|
|
*pic = NULL; |
|
|
|
// |
|
// load the file |
|
// |
|
len = ri.FS_LoadFile (filename, (void **)&raw); |
|
if (!raw) |
|
{ |
|
ri.Con_Printf (PRINT_DEVELOPER, "Bad pcx file %s\n", filename); |
|
return; |
|
} |
|
|
|
// |
|
// parse the PCX file |
|
// |
|
pcx = (pcx_t *)raw; |
|
|
|
pcx->xmin = LittleShort(pcx->xmin); |
|
pcx->ymin = LittleShort(pcx->ymin); |
|
pcx->xmax = LittleShort(pcx->xmax); |
|
pcx->ymax = LittleShort(pcx->ymax); |
|
pcx->hres = LittleShort(pcx->hres); |
|
pcx->vres = LittleShort(pcx->vres); |
|
pcx->bytes_per_line = LittleShort(pcx->bytes_per_line); |
|
pcx->palette_type = LittleShort(pcx->palette_type); |
|
|
|
raw = &pcx->data; |
|
|
|
if (pcx->manufacturer != 0x0a |
|
|| pcx->version != 5 |
|
|| pcx->encoding != 1 |
|
|| pcx->bits_per_pixel != 8 |
|
|| pcx->xmax >= 640 |
|
|| pcx->ymax >= 480) |
|
{ |
|
ri.Con_Printf (PRINT_ALL, "Bad pcx file %s\n", filename); |
|
return; |
|
} |
|
|
|
out = malloc ( (pcx->ymax+1) * (pcx->xmax+1) ); |
|
|
|
*pic = out; |
|
|
|
pix = out; |
|
|
|
if (palette) |
|
{ |
|
*palette = malloc(768); |
|
memcpy (*palette, (byte *)pcx + len - 768, 768); |
|
} |
|
|
|
if (width) |
|
*width = pcx->xmax+1; |
|
if (height) |
|
*height = pcx->ymax+1; |
|
|
|
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 *)pcx > len) |
|
{ |
|
ri.Con_Printf (PRINT_DEVELOPER, "PCX file %s was malformed", filename); |
|
free (*pic); |
|
*pic = NULL; |
|
} |
|
|
|
ri.FS_FreeFile (pcx); |
|
} |
|
|
|
/* |
|
========================================================= |
|
|
|
TARGA LOADING |
|
|
|
========================================================= |
|
*/ |
|
|
|
typedef struct _TargaHeader { |
|
unsigned char id_length, colormap_type, image_type; |
|
unsigned short colormap_index, colormap_length; |
|
unsigned char colormap_size; |
|
unsigned short x_origin, y_origin, width, height; |
|
unsigned char pixel_size, attributes; |
|
} TargaHeader; |
|
|
|
|
|
/* |
|
============= |
|
LoadTGA |
|
============= |
|
*/ |
|
void LoadTGA (char *name, byte **pic, int *width, int *height) |
|
{ |
|
int columns, rows, numPixels; |
|
byte *pixbuf; |
|
int row, column; |
|
byte *buf_p; |
|
byte *buffer; |
|
int length; |
|
TargaHeader targa_header; |
|
byte *targa_rgba; |
|
|
|
*pic = NULL; |
|
|
|
// |
|
// load the file |
|
// |
|
length = ri.FS_LoadFile (name, (void **)&buffer); |
|
if (!buffer) |
|
{ |
|
ri.Con_Printf (PRINT_DEVELOPER, "Bad tga file %s\n", name); |
|
return; |
|
} |
|
|
|
buf_p = buffer; |
|
|
|
targa_header.id_length = *buf_p++; |
|
targa_header.colormap_type = *buf_p++; |
|
targa_header.image_type = *buf_p++; |
|
|
|
targa_header.colormap_index = LittleShort ( *((short *)buf_p) ); |
|
buf_p+=2; |
|
targa_header.colormap_length = LittleShort ( *((short *)buf_p) ); |
|
buf_p+=2; |
|
targa_header.colormap_size = *buf_p++; |
|
targa_header.x_origin = LittleShort ( *((short *)buf_p) ); |
|
buf_p+=2; |
|
targa_header.y_origin = LittleShort ( *((short *)buf_p) ); |
|
buf_p+=2; |
|
targa_header.width = LittleShort ( *((short *)buf_p) ); |
|
buf_p+=2; |
|
targa_header.height = LittleShort ( *((short *)buf_p) ); |
|
buf_p+=2; |
|
targa_header.pixel_size = *buf_p++; |
|
targa_header.attributes = *buf_p++; |
|
|
|
if (targa_header.image_type!=2 |
|
&& targa_header.image_type!=10) |
|
ri.Sys_Error (ERR_DROP, "LoadTGA: Only type 2 and 10 targa RGB images supported\n"); |
|
|
|
if (targa_header.colormap_type !=0 |
|
|| (targa_header.pixel_size!=32 && targa_header.pixel_size!=24)) |
|
ri.Sys_Error (ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); |
|
|
|
columns = targa_header.width; |
|
rows = targa_header.height; |
|
numPixels = columns * rows; |
|
|
|
if (width) |
|
*width = columns; |
|
if (height) |
|
*height = rows; |
|
|
|
targa_rgba = malloc (numPixels*4); |
|
*pic = targa_rgba; |
|
|
|
if (targa_header.id_length != 0) |
|
buf_p += targa_header.id_length; // skip TARGA image comment |
|
|
|
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++) { |
|
unsigned char red,green,blue,alphabyte; |
|
switch (targa_header.pixel_size) { |
|
case 24: |
|
|
|
blue = *buf_p++; |
|
green = *buf_p++; |
|
red = *buf_p++; |
|
*pixbuf++ = red; |
|
*pixbuf++ = green; |
|
*pixbuf++ = blue; |
|
*pixbuf++ = 255; |
|
break; |
|
case 32: |
|
blue = *buf_p++; |
|
green = *buf_p++; |
|
red = *buf_p++; |
|
alphabyte = *buf_p++; |
|
*pixbuf++ = red; |
|
*pixbuf++ = green; |
|
*pixbuf++ = blue; |
|
*pixbuf++ = alphabyte; |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
else if (targa_header.image_type==10) { // Runlength encoded RGB images |
|
unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j; |
|
for(row=rows-1; row>=0; row--) { |
|
pixbuf = targa_rgba + row*columns*4; |
|
for(column=0; column<columns; ) { |
|
packetHeader= *buf_p++; |
|
packetSize = 1 + (packetHeader & 0x7f); |
|
if (packetHeader & 0x80) { // run-length packet |
|
switch (targa_header.pixel_size) { |
|
case 24: |
|
blue = *buf_p++; |
|
green = *buf_p++; |
|
red = *buf_p++; |
|
alphabyte = 255; |
|
break; |
|
case 32: |
|
blue = *buf_p++; |
|
green = *buf_p++; |
|
red = *buf_p++; |
|
alphabyte = *buf_p++; |
|
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 = *buf_p++; |
|
green = *buf_p++; |
|
red = *buf_p++; |
|
*pixbuf++ = red; |
|
*pixbuf++ = green; |
|
*pixbuf++ = blue; |
|
*pixbuf++ = 255; |
|
break; |
|
case 32: |
|
blue = *buf_p++; |
|
green = *buf_p++; |
|
red = *buf_p++; |
|
alphabyte = *buf_p++; |
|
*pixbuf++ = red; |
|
*pixbuf++ = green; |
|
*pixbuf++ = blue; |
|
*pixbuf++ = alphabyte; |
|
break; |
|
} |
|
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:; |
|
} |
|
} |
|
|
|
ri.FS_FreeFile (buffer); |
|
} |
|
|
|
|
|
//======================================================= |
|
|
|
image_t *R_FindFreeImage (void) |
|
{ |
|
image_t *image; |
|
int i; |
|
|
|
// find a free image_t |
|
for (i=0, image=r_images ; i<numr_images ; i++,image++) |
|
{ |
|
if (!image->registration_sequence) |
|
break; |
|
} |
|
if (i == numr_images) |
|
{ |
|
if (numr_images == MAX_RIMAGES) |
|
ri.Sys_Error (ERR_DROP, "MAX_RIMAGES"); |
|
numr_images++; |
|
} |
|
image = &r_images[i]; |
|
|
|
return image; |
|
} |
|
|
|
/* |
|
================ |
|
GL_LoadPic |
|
|
|
================ |
|
*/ |
|
image_t *GL_LoadPic (char *name, byte *pic, int width, int height, imagetype_t type) |
|
{ |
|
image_t *image; |
|
int i, c, b; |
|
|
|
image = R_FindFreeImage (); |
|
if (strlen(name) >= sizeof(image->name)) |
|
ri.Sys_Error (ERR_DROP, "Draw_LoadPic: \"%s\" is too long", name); |
|
strcpy (image->name, name); |
|
image->registration_sequence = registration_sequence; |
|
|
|
image->width = width; |
|
image->height = height; |
|
image->type = type; |
|
|
|
c = width*height; |
|
image->pixels[0] = malloc (c); |
|
image->transparent = false; |
|
for (i=0 ; i<c ; i++) |
|
{ |
|
b = pic[i]; |
|
if (b == 255) |
|
image->transparent = true; |
|
image->pixels[0][i] = b; |
|
} |
|
|
|
return image; |
|
} |
|
|
|
/* |
|
================ |
|
R_LoadWal |
|
================ |
|
*/ |
|
image_t *R_LoadWal (char *name) |
|
{ |
|
miptex_t *mt; |
|
int ofs; |
|
image_t *image; |
|
int size; |
|
|
|
ri.FS_LoadFile (name, (void **)&mt); |
|
if (!mt) |
|
{ |
|
ri.Con_Printf (PRINT_ALL, "R_LoadWal: can't load %s\n", name); |
|
return r_notexture_mip; |
|
} |
|
|
|
image = R_FindFreeImage (); |
|
strcpy (image->name, name); |
|
image->width = LittleLong (mt->width); |
|
image->height = LittleLong (mt->height); |
|
image->type = it_wall; |
|
image->registration_sequence = registration_sequence; |
|
|
|
size = image->width*image->height * (256+64+16+4)/256; |
|
image->pixels[0] = malloc (size); |
|
image->pixels[1] = image->pixels[0] + image->width*image->height; |
|
image->pixels[2] = image->pixels[1] + image->width*image->height/4; |
|
image->pixels[3] = image->pixels[2] + image->width*image->height/16; |
|
|
|
ofs = LittleLong (mt->offsets[0]); |
|
memcpy ( image->pixels[0], (byte *)mt + ofs, size); |
|
|
|
ri.FS_FreeFile ((void *)mt); |
|
|
|
return image; |
|
} |
|
|
|
|
|
/* |
|
=============== |
|
R_FindImage |
|
|
|
Finds or loads the given image |
|
=============== |
|
*/ |
|
image_t *R_FindImage (char *name, imagetype_t type) |
|
{ |
|
image_t *image; |
|
int i, len; |
|
byte *pic, *palette; |
|
int width, height; |
|
|
|
if (!name) |
|
return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: NULL name"); |
|
len = strlen(name); |
|
if (len<5) |
|
return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: bad name: %s", name); |
|
|
|
// look for it |
|
for (i=0, image=r_images ; i<numr_images ; i++,image++) |
|
{ |
|
if (!strcmp(name, image->name)) |
|
{ |
|
image->registration_sequence = registration_sequence; |
|
return image; |
|
} |
|
} |
|
|
|
// |
|
// load the pic from disk |
|
// |
|
pic = NULL; |
|
palette = NULL; |
|
if (!strcmp(name+len-4, ".pcx")) |
|
{ |
|
LoadPCX (name, &pic, &palette, &width, &height); |
|
if (!pic) |
|
return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: can't load %s", name); |
|
image = GL_LoadPic (name, pic, width, height, type); |
|
} |
|
else if (!strcmp(name+len-4, ".wal")) |
|
{ |
|
image = R_LoadWal (name); |
|
} |
|
else if (!strcmp(name+len-4, ".tga")) |
|
return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: can't load %s in software renderer", name); |
|
else |
|
return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: bad extension on: %s", name); |
|
|
|
if (pic) |
|
free(pic); |
|
if (palette) |
|
free(palette); |
|
|
|
return image; |
|
} |
|
|
|
|
|
|
|
/* |
|
=============== |
|
R_RegisterSkin |
|
=============== |
|
*/ |
|
struct image_s *R_RegisterSkin (char *name) |
|
{ |
|
return R_FindImage (name, it_skin); |
|
} |
|
|
|
|
|
/* |
|
================ |
|
R_FreeUnusedImages |
|
|
|
Any image that was not touched on this registration sequence |
|
will be freed. |
|
================ |
|
*/ |
|
void R_FreeUnusedImages (void) |
|
{ |
|
int i; |
|
image_t *image; |
|
|
|
for (i=0, image=r_images ; i<numr_images ; i++, image++) |
|
{ |
|
if (image->registration_sequence == registration_sequence) |
|
{ |
|
Com_PageInMemory ((byte *)image->pixels[0], image->width*image->height); |
|
continue; // used this sequence |
|
} |
|
if (!image->registration_sequence) |
|
continue; // free texture |
|
if (image->type == it_pic) |
|
continue; // don't free pics |
|
// free it |
|
free (image->pixels[0]); // the other mip levels just follow |
|
memset (image, 0, sizeof(*image)); |
|
} |
|
} |
|
|
|
|
|
|
|
/* |
|
=============== |
|
R_InitImages |
|
=============== |
|
*/ |
|
void R_InitImages (void) |
|
{ |
|
registration_sequence = 1; |
|
} |
|
|
|
/* |
|
=============== |
|
R_ShutdownImages |
|
=============== |
|
*/ |
|
void R_ShutdownImages (void) |
|
{ |
|
int i; |
|
image_t *image; |
|
|
|
for (i=0, image=r_images ; i<numr_images ; i++, image++) |
|
{ |
|
if (!image->registration_sequence) |
|
continue; // free texture |
|
// free it |
|
free (image->pixels[0]); // the other mip levels just follow |
|
memset (image, 0, sizeof(*image)); |
|
} |
|
} |
|
|
|
|