Support retextured images.

Code based on www.quakewiki.net/quakesrc/39.html
Code ignores skin images, and is disabled by default.
This commit is contained in:
Denis Pauk 2018-11-12 23:02:23 +02:00
parent 0307361101
commit 25498be7ca
2 changed files with 227 additions and 70 deletions

View file

@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "header/local.h"
extern cvar_t *sw_retexturing;
#define MAX_RIMAGES 1024
static image_t r_images[MAX_RIMAGES];
@ -96,7 +97,7 @@ R_FindFreeImage (void)
if (i == numr_images)
{
if (numr_images == MAX_RIMAGES)
ri.Sys_Error (ERR_DROP, "MAX_RIMAGES");
ri.Sys_Error(ERR_DROP, "MAX_RIMAGES");
numr_images++;
}
image = &r_images[i];
@ -104,6 +105,25 @@ R_FindFreeImage (void)
return image;
}
static void
R_ImageShrink(const unsigned char* src, unsigned char *dst, int width, int realwidth, int height, int realheight)
{
int x, y;
float xstep, ystep;
xstep = (float)height / realheight;
ystep = (float)width / realwidth;
for (y=0; y<realheight; y++)
{
for (x=0; x<realwidth; x++)
{
// inplace update
dst[x + y * realwidth] = src[(int)(x * xstep) + (int)(y * ystep) * width];
}
}
}
/*
================
R_LoadPic
@ -114,9 +134,9 @@ static image_t *
R_LoadPic (char *name, byte *pic, int width, int height, imagetype_t type)
{
image_t *image;
size_t i, size;
size_t i, size, full_size;
image = R_FindFreeImage ();
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);
@ -126,8 +146,9 @@ R_LoadPic (char *name, byte *pic, int width, int height, imagetype_t type)
image->height = height;
image->type = type;
size = width*height;
image->pixels[0] = malloc (size);
size = width * height;
full_size = size * (256+64+16+4)/256;
image->pixels[0] = malloc(full_size);
image->transparent = false;
for (i=0 ; i<size ; i++)
{
@ -139,22 +160,23 @@ R_LoadPic (char *name, byte *pic, int width, int height, imagetype_t type)
}
memcpy(image->pixels[0], pic, size);
// restore mips
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;
// restore everything from first image
R_ImageShrink(image->pixels[0], image->pixels[1],
image->height, image->height/2,
image->width, image->width/2);
R_ImageShrink(image->pixels[1], image->pixels[2],
image->height/2, image->height/4,
image->width/2, image->width/4);
R_ImageShrink(image->pixels[2], image->pixels[3],
image->height/4, image->height/8,
image->width/4, image->width/8);
return image;
}
static void
R_Restore_Mip(unsigned char* src, unsigned char *dst, int height, int width)
{
int x, y;
for (y=0; y<height; y++)
{
for (x=0; x<width; x++)
{
dst[x + y * width] = src[(x + y * width)*2];
}
}
}
/*
================
R_LoadWal
@ -178,7 +200,7 @@ R_LoadWal (char *name, imagetype_t type)
if (file_size < sizeof(miptex_t))
{
R_Printf(PRINT_ALL, "R_LoadWal: can't load %s, small header\n", name);
ri.FS_FreeFile ((void *)mt);
ri.FS_FreeFile((void *)mt);
return r_notexture_mip;
}
@ -188,7 +210,7 @@ R_LoadWal (char *name, imagetype_t type)
image->height = LittleLong (mt->height);
image->type = type;
image->registration_sequence = registration_sequence;
ofs = LittleLong (mt->offsets[0]);
ofs = LittleLong(mt->offsets[0]);
size = image->width * image->height * (256+64+16+4)/256;
if ((ofs <= 0) || (image->width <= 0) || (image->height <= 0) ||
@ -206,22 +228,147 @@ R_LoadWal (char *name, imagetype_t type)
if (size > (file_size - ofs))
{
memcpy ( image->pixels[0], (byte *)mt + ofs, file_size - ofs);
// looks to short restore everything from first image
R_Restore_Mip(image->pixels[0], image->pixels[1], image->height/2, image->width/2);
R_Restore_Mip(image->pixels[1], image->pixels[2], image->height/4, image->width/4);
R_Restore_Mip(image->pixels[2], image->pixels[3], image->height/8, image->width/8);
memcpy(image->pixels[0], (byte *)mt + ofs, file_size - ofs);
// looks short, restore everything from first image
R_ImageShrink(image->pixels[0], image->pixels[1],
image->height, image->height/2,
image->width, image->width/2);
R_ImageShrink(image->pixels[1], image->pixels[2],
image->height/2, image->height/4,
image->width/2, image->width/4);
R_ImageShrink(image->pixels[2], image->pixels[3],
image->height/4, image->height/8,
image->width/4, image->width/8);
}
else
{
memcpy ( image->pixels[0], (byte *)mt + ofs, size);
memcpy(image->pixels[0], (byte *)mt + ofs, size);
}
ri.FS_FreeFile ((void *)mt);
ri.FS_FreeFile((void *)mt);
return image;
}
static unsigned char *d_16to8table; // 16 to 8 bit conversion table
static void
R_Convert32To8bit(unsigned char* pic_in, unsigned char* pic_out, size_t size)
{
size_t i;
if (!d_16to8table)
return;
for(i=0; i<size; i++)
{
unsigned int r, g, b, c;
r = ( pic_in[i * 4 + 0] >> 3 ) & 31;
g = ( pic_in[i * 4 + 1] >> 2 ) & 63;
b = ( pic_in[i * 4 + 2] >> 3 ) & 31;
c = r | ( g << 5 ) | ( b << 11 );
pic_out[i] = d_16to8table[c & 0xFFFF];
}
}
static image_t *
R_LoadHiColorImage(char *name, const char* namewe, const char *ext, imagetype_t type)
{
image_t *image = NULL;
byte *pic = NULL;
int realwidth = 0, realheight = 0;
int width = 0, height = 0;
if (strcmp(ext, "pcx") == 0)
{
/* Get size of the original texture */
GetPCXInfo(name, &realwidth, &realheight);
}
else if (strcmp(ext, "wal") == 0)
{
/* Get size of the original texture */
GetWalInfo(name, &realwidth, &realheight);
}
/* try to load a tga, png or jpg (in that order/priority) */
if ( LoadSTB(namewe, "tga", &pic, &width, &height)
|| LoadSTB(namewe, "png", &pic, &width, &height)
|| LoadSTB(namewe, "jpg", &pic, &width, &height) )
{
if (width >= realwidth && height >= realheight)
{
byte* pic8 = NULL;
int size;
if (realheight == 0 || realwidth == 0)
{
realheight = height;
realwidth = width;
}
size = width * height * (256+64+16+4)/256;
pic8 = malloc(size);
R_Convert32To8bit(pic, pic8, width * height);
if (width != realwidth || height != realheight)
{
R_ImageShrink(pic8, pic8, width, realwidth, height, realheight);
}
image = R_LoadPic(name, pic8, realwidth, realheight, type);
free(pic8);
}
}
if (!pic)
{
free(pic);
}
return image;
}
static image_t *
R_LoadImage(char *name, const char* namewe, const char *ext, imagetype_t type)
{
image_t *image = NULL;
// with retexturing and not skin
if (sw_retexturing->value && type != it_skin)
{
image = R_LoadHiColorImage(name, namewe, ext, type);
}
if (!image)
{
if (strcmp(ext, "pcx") == 0)
{
byte *pic = NULL;
byte *palette = NULL;
int width = 0, height = 0;
LoadPCX (name, &pic, &palette, &width, &height);
if (!pic)
return NULL;
image = R_LoadPic(name, pic, width, height, type);
if (palette)
{
free(palette);
}
if (!pic)
{
free(pic);
}
}
else if (strcmp(ext, "wal") == 0)
{
image = R_LoadWal(name, type);
}
}
return image;
}
/*
===============
@ -231,27 +378,42 @@ Finds or loads the given image
===============
*/
image_t *
R_FindImage (char *name, imagetype_t type)
R_FindImage(char *name, imagetype_t type)
{
image_t *image;
int i, len;
byte *pic, *palette;
int width, height;
int i, len;
char *ptr;
char namewe[256];
const char* ext;
if (!name)
return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: NULL name");
{
return NULL;
}
ext = COM_FileExtension(name);
if(!ext[0])
{
/* file has no extension */
return NULL;
}
len = strlen(name);
if (len<5)
return NULL; // ri.Sys_Error (ERR_DROP, "R_FindImage: bad name: %s", name);
#ifndef _WIN32
char *ptr;
/* Remove the extension */
memset(namewe, 0, 256);
memcpy(namewe, name, len - (strlen(ext) + 1));
// fix backslashes
while ((ptr=strchr(name,'\\'))) {
if (len < 5)
{
return NULL;
}
/* fix backslashes */
while ((ptr = strchr(name, '\\')))
{
*ptr = '/';
}
#endif
// look for it
for (i=0, image=r_images ; i<numr_images ; i++,image++)
@ -266,30 +428,7 @@ R_FindImage (char *name, imagetype_t type)
//
// 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 = R_LoadPic (name, pic, width, height, type);
}
else if (!strcmp(name+len-4, ".wal"))
{
image = R_LoadWal (name, type);
}
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;
return R_LoadImage(name, namewe, ext, type);
}
/*
@ -318,12 +457,10 @@ R_FreeUnusedImages (void)
continue; // don't free pics
// free it
free (image->pixels[0]); // the other mip levels just follow
memset (image, 0, sizeof(*image));
memset(image, 0, sizeof(*image));
}
}
/*
===============
R_InitImages
@ -332,7 +469,19 @@ R_InitImages
void
R_InitImages (void)
{
unsigned char * table16to8;
registration_sequence = 1;
d_16to8table = NULL;
ri.FS_LoadFile("pics/16to8.dat", (void **)&table16to8);
if ( !table16to8 )
{
ri.Sys_Error(ERR_FATAL, "Couldn't load pics/16to8.dat");
}
d_16to8table = malloc(0x10000);
memcpy(d_16to8table, table16to8, 0x10000);
ri.FS_FreeFile((void *)table16to8);
}
/*
@ -350,8 +499,14 @@ R_ShutdownImages (void)
{
if (!image->registration_sequence)
continue; // free texture
// free it
free (image->pixels[0]); // the other mip levels just follow
memset (image, 0, sizeof(*image));
if (image->pixels[0])
free(image->pixels[0]); // the other mip levels just follow
memset(image, 0, sizeof(*image));
}
if (d_16to8table)
free(d_16to8table);
}

View file

@ -129,6 +129,7 @@ cvar_t *sw_waterwarp;
static cvar_t *sw_overbrightbits;
cvar_t *sw_custom_particles;
cvar_t *sw_texture_filtering;
cvar_t *sw_retexturing;
cvar_t *r_drawworld;
static cvar_t *r_drawentities;
@ -259,7 +260,7 @@ void R_ImageList_f(void);
static void R_ScreenShot_f(void);
static void
R_Register (void)
R_RegisterVariables (void)
{
sw_aliasstats = ri.Cvar_Get ("sw_polymodelstats", "0", 0);
sw_clearcolor = ri.Cvar_Get ("sw_clearcolor", "2", 0);
@ -273,6 +274,7 @@ R_Register (void)
sw_overbrightbits = ri.Cvar_Get("sw_overbrightbits", "1.0", CVAR_ARCHIVE);
sw_custom_particles = ri.Cvar_Get("sw_custom_particles", "0", CVAR_ARCHIVE);
sw_texture_filtering = ri.Cvar_Get("sw_texture_filtering", "0", CVAR_ARCHIVE);
sw_retexturing = ri.Cvar_Get("sw_retexturing", "0", CVAR_ARCHIVE);
r_mode = ri.Cvar_Get( "r_mode", "0", CVAR_ARCHIVE );
r_lefthand = ri.Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE );
@ -326,6 +328,7 @@ R_Init
static qboolean
RE_Init(void)
{
R_RegisterVariables ();
R_InitImages ();
Mod_Init ();
Draw_InitLocal ();
@ -343,7 +346,6 @@ RE_Init(void)
r_aliasuvscale = 1.0;
R_Register ();
Draw_GetPalette ();
// create the window