This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/engine/client/cl_remap.c

433 lines
12 KiB
C
Raw Normal View History

2011-07-22 22:00:00 +02:00
/*
gl_remap.c - remap model textures
Copyright (C) 2011 Uncle Mike
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 3 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.
*/
#include "common.h"
#include "client.h"
#include "gl_local.h"
#include "studio.h"
/*
====================
CL_GetRemapInfoForEntity
Returns remapinfo slot for specified entity
====================
*/
remap_info_t *CL_GetRemapInfoForEntity( cl_entity_t *e )
{
if( !e ) return NULL;
if( e == &clgame.viewent )
return clgame.remap_info[clgame.maxEntities];
return clgame.remap_info[e->curstate.number];
}
2011-08-21 22:00:00 +02:00
/*
====================
CL_CmpStudioTextures
return true if equal
====================
*/
qboolean CL_CmpStudioTextures( int numtexs, mstudiotexture_t *p1, mstudiotexture_t *p2 )
{
int i;
if( !p1 || !p2 ) return false;
for( i = 0; i < numtexs; i++, p1++, p2++ )
{
if( p1->flags & STUDIO_NF_COLORMAP )
continue; // colormaps always has different indexes
if( p1->index != p2->index )
return false;
}
return true;
}
2011-07-22 22:00:00 +02:00
/*
====================
CL_CreateRawTextureFromPixels
Convert texture_t struct into mstudiotexture_t prototype
====================
*/
byte *CL_CreateRawTextureFromPixels( texture_t *tx, size_t *size, int topcolor, int bottomcolor )
{
static mstudiotexture_t pin;
byte *pal;
2018-02-12 22:00:00 +01:00
Assert( size != NULL );
2011-07-22 22:00:00 +02:00
*size = sizeof( pin ) + (tx->width * tx->height) + 768;
// fill header
if( !pin.name[0] ) Q_strncpy( pin.name, "#raw_remap_image.mdl", sizeof( pin.name ));
pin.flags = STUDIO_NF_COLORMAP; // just in case :-)
pin.index = (int)(tx + 1); // pointer to pixels
pin.width = tx->width;
pin.height = tx->height;
// update palette
pal = (byte *)(tx + 1) + (tx->width * tx->height);
2017-12-02 22:00:00 +01:00
Image_PaletteHueReplace( pal, topcolor, tx->anim_min, tx->anim_max, 3 );
Image_PaletteHueReplace( pal, bottomcolor, tx->anim_max + 1, tx->anim_total, 3 );
2011-07-22 22:00:00 +02:00
return (byte *)&pin;
}
/*
====================
CL_DuplicateTexture
Dupliacte texture with remap pixels
====================
*/
void CL_DuplicateTexture( mstudiotexture_t *ptexture, int topcolor, int bottomcolor )
{
2018-08-23 23:00:00 +02:00
gl_texture_t *glt;
2011-07-22 22:00:00 +02:00
texture_t *tx = NULL;
char texname[128];
int i, size, index;
2011-08-14 22:00:00 +02:00
byte paletteBackup[768];
byte *raw, *pal;
2011-07-22 22:00:00 +02:00
2013-02-24 21:00:00 +01:00
// save off the real texture index
2011-07-22 22:00:00 +02:00
index = ptexture->index;
glt = R_GetTexture( index );
Q_snprintf( texname, sizeof( texname ), "#%i_%s", RI.currententity->curstate.number, glt->name + 1 );
// search for pixels
for( i = 0; i < RI.currentmodel->numtextures; i++ )
{
tx = RI.currentmodel->textures[i];
if( tx->gl_texturenum == index )
break; // found
}
2018-02-12 22:00:00 +01:00
Assert( tx != NULL );
2011-07-22 22:00:00 +02:00
2011-08-14 22:00:00 +02:00
// backup original palette
pal = (byte *)(tx + 1) + (tx->width * tx->height);
2016-11-17 22:00:00 +01:00
memcpy( paletteBackup, pal, 768 );
2011-08-14 22:00:00 +02:00
2011-07-22 22:00:00 +02:00
raw = CL_CreateRawTextureFromPixels( tx, &size, topcolor, bottomcolor );
2018-10-17 23:00:00 +02:00
ptexture->index = GL_LoadTexture( texname, raw, size, TF_FORCE_COLOR ); // do copy
2011-08-14 22:00:00 +02:00
// restore original palette
2016-11-17 22:00:00 +01:00
memcpy( pal, paletteBackup, 768 );
2011-07-22 22:00:00 +02:00
}
/*
====================
2018-03-07 22:00:00 +01:00
CL_UpdateStudioTexture
2011-07-22 22:00:00 +02:00
Update texture top and bottom colors
====================
*/
2018-03-07 22:00:00 +01:00
void CL_UpdateStudioTexture( mstudiotexture_t *ptexture, int topcolor, int bottomcolor )
2011-07-22 22:00:00 +02:00
{
2018-08-23 23:00:00 +02:00
gl_texture_t *glt;
2011-07-22 22:00:00 +02:00
rgbdata_t *pic;
texture_t *tx = NULL;
2011-09-03 22:00:00 +02:00
char texname[128], name[128], mdlname[128];
2011-07-22 22:00:00 +02:00
int i, size, index;
byte paletteBackup[768];
byte *raw, *pal;
2018-03-06 22:00:00 +01:00
// save off the real texture index
2011-07-22 22:00:00 +02:00
glt = R_GetTexture( ptexture->index );
// build name of original texture
2011-09-03 22:00:00 +02:00
Q_strncpy( mdlname, RI.currentmodel->name, sizeof( mdlname ));
2018-02-28 22:00:00 +01:00
COM_FileBase( ptexture->name, name );
COM_StripExtension( mdlname );
2011-09-03 22:00:00 +02:00
Q_snprintf( texname, sizeof( texname ), "#%s/%s.mdl", mdlname, name );
2011-07-22 22:00:00 +02:00
index = GL_FindTexture( texname );
if( !index ) return; // couldn't find texture
// search for pixels
for( i = 0; i < RI.currentmodel->numtextures; i++ )
{
tx = RI.currentmodel->textures[i];
if( tx->gl_texturenum == index )
break; // found
}
2018-02-12 22:00:00 +01:00
Assert( tx != NULL );
2011-07-22 22:00:00 +02:00
// backup original palette
pal = (byte *)(tx + 1) + (tx->width * tx->height);
2016-11-17 22:00:00 +01:00
memcpy( paletteBackup, pal, 768 );
2011-07-22 22:00:00 +02:00
raw = CL_CreateRawTextureFromPixels( tx, &size, topcolor, bottomcolor );
pic = FS_LoadImage( glt->name, raw, size );
if( !pic )
{
2018-09-10 23:00:00 +02:00
Con_DPrintf( S_ERROR "Couldn't update texture %s\n", glt->name );
2011-07-22 22:00:00 +02:00
return;
}
2018-08-23 23:00:00 +02:00
index = GL_UpdateTextureInternal( glt->name, pic, 0 );
2011-07-22 22:00:00 +02:00
FS_FreeImage( pic );
// restore original palette
2016-11-17 22:00:00 +01:00
memcpy( pal, paletteBackup, 768 );
2011-07-22 22:00:00 +02:00
2018-02-12 22:00:00 +01:00
Assert( index == ptexture->index );
2011-07-22 22:00:00 +02:00
}
2018-03-07 22:00:00 +01:00
/*
====================
CL_UpdateAliasTexture
Update texture top and bottom colors
====================
*/
void CL_UpdateAliasTexture( unsigned short *texture, int skinnum, int topcolor, int bottomcolor )
{
char texname[MAX_QPATH];
rgbdata_t skin, *pic;
texture_t *tx;
if( !texture || !RI.currentmodel->textures )
return; // no remapinfo in model
tx = RI.currentmodel->textures[skinnum];
if( !tx ) return; // missing texture ?
if( *texture == 0 )
{
2018-10-05 23:00:00 +02:00
Q_snprintf( texname, sizeof( texname ), "%s:remap%i_%i", RI.currentmodel->name, skinnum, RI.currententity->index );
2018-03-07 22:00:00 +01:00
skin.width = tx->width;
skin.height = tx->height;
skin.depth = skin.numMips = 1;
skin.size = tx->width * tx->height;
skin.type = PF_INDEXED_24;
skin.flags = IMAGE_HAS_COLOR|IMAGE_QUAKEPAL;
skin.encode = DXT_ENCODE_DEFAULT;
skin.buffer = (byte *)(tx + 1);
skin.palette = skin.buffer + skin.size;
pic = FS_CopyImage( &skin ); // because GL_LoadTextureInternal will freed a rgbdata_t at end
2018-08-23 23:00:00 +02:00
*texture = GL_LoadTextureInternal( texname, pic, TF_KEEP_SOURCE );
2018-03-07 22:00:00 +01:00
}
// and now we can remap with internal routines
GL_ProcessTexture( *texture, -1.0f, topcolor, bottomcolor );
}
2011-07-22 22:00:00 +02:00
/*
====================
CL_AllocRemapInfo
Allocate new remap info per entity
and make copy of remap textures
====================
*/
void CL_AllocRemapInfo( int topcolor, int bottomcolor )
{
remap_info_t *info;
studiohdr_t *phdr;
2018-03-07 22:00:00 +01:00
aliashdr_t *ahdr;
2011-07-22 22:00:00 +02:00
mstudiotexture_t *src, *dst;
int i, size;
2011-10-02 22:00:00 +02:00
if( !RI.currententity ) return;
2011-07-22 22:00:00 +02:00
i = ( RI.currententity == &clgame.viewent ) ? clgame.maxEntities : RI.currententity->curstate.number;
2018-03-07 22:00:00 +01:00
if( !RI.currentmodel || ( RI.currentmodel->type != mod_alias && RI.currentmodel->type != mod_studio ))
2011-07-22 22:00:00 +02:00
{
// entity has changed model by another type, release remap info
if( clgame.remap_info[i] )
{
CL_FreeRemapInfo( clgame.remap_info[i] );
clgame.remap_info[i] = NULL;
}
2013-02-24 21:00:00 +01:00
return; // missed or hide model, ignore it
2011-07-22 22:00:00 +02:00
}
// model doesn't contains remap textures
if( RI.currentmodel->numtextures <= 0 )
{
// entity has changed model with no remap textures
if( clgame.remap_info[i] )
{
CL_FreeRemapInfo( clgame.remap_info[i] );
clgame.remap_info[i] = NULL;
}
return;
}
2018-03-07 22:00:00 +01:00
if( RI.currentmodel->type == mod_studio )
{
phdr = (studiohdr_t *)Mod_StudioExtradata( RI.currentmodel );
if( !phdr ) return; // bad model?
src = (mstudiotexture_t *)(((byte *)phdr) + phdr->textureindex);
dst = (clgame.remap_info[i] ? clgame.remap_info[i]->ptexture : NULL);
// NOTE: we must copy all the structures 'mstudiotexture_t' for easy access when model is rendering
if( !CL_CmpStudioTextures( phdr->numtextures, src, dst ) || clgame.remap_info[i]->model != RI.currentmodel )
{
// this code catches studiomodel change with another studiomodel with remap textures
// e.g. playermodel 'barney' with playermodel 'gordon'
if( clgame.remap_info[i] ) CL_FreeRemapInfo( clgame.remap_info[i] ); // free old info
size = sizeof( remap_info_t ) + ( sizeof( mstudiotexture_t ) * phdr->numtextures );
2018-05-26 23:00:00 +02:00
info = clgame.remap_info[i] = Mem_Calloc( clgame.mempool, size );
2018-03-07 22:00:00 +01:00
info->ptexture = (mstudiotexture_t *)(info + 1); // textures are immediately comes after remap_info
}
else
{
// studiomodel is valid, nothing to change
return;
}
info->numtextures = phdr->numtextures;
info->topcolor = topcolor;
info->bottomcolor = bottomcolor;
src = (mstudiotexture_t *)(((byte *)phdr) + phdr->textureindex);
dst = info->ptexture;
2011-07-22 22:00:00 +02:00
2018-03-07 22:00:00 +01:00
// copy unchanged first
memcpy( dst, src, sizeof( mstudiotexture_t ) * phdr->numtextures );
2011-08-21 22:00:00 +02:00
2018-03-07 22:00:00 +01:00
// make local copies for remap textures
for( i = 0; i < info->numtextures; i++ )
{
if( dst[i].flags & STUDIO_NF_COLORMAP )
CL_DuplicateTexture( &dst[i], topcolor, bottomcolor );
}
}
else if( RI.currentmodel->type == mod_alias )
2011-07-22 22:00:00 +02:00
{
2018-03-07 22:00:00 +01:00
ahdr = (aliashdr_t *)Mod_AliasExtradata( RI.currentmodel );
if( !ahdr ) return; // bad model?
// NOTE: we must copy all the structures 'mstudiotexture_t' for easy access when model is rendering
if( !clgame.remap_info[i] || clgame.remap_info[i]->model != RI.currentmodel )
{
// this code catches studiomodel change with another studiomodel with remap textures
// e.g. playermodel 'barney' with playermodel 'gordon'
if( clgame.remap_info[i] ) CL_FreeRemapInfo( clgame.remap_info[i] ); // free old info
2018-05-26 23:00:00 +02:00
info = clgame.remap_info[i] = Mem_Calloc( clgame.mempool, sizeof( remap_info_t ));
2018-03-07 22:00:00 +01:00
}
else
{
// aliasmodel is valid, nothing to change
return;
}
info->numtextures = RI.currentmodel->numtextures;
// alias remapping is easy
CL_UpdateRemapInfo( topcolor, bottomcolor );
2011-07-22 22:00:00 +02:00
}
else
{
2018-03-07 22:00:00 +01:00
// only alias & studio models are supposed for remapping
2011-07-22 22:00:00 +02:00
return;
}
info->model = RI.currentmodel;
}
/*
====================
CL_UpdateRemapInfo
Update all remaps per entity
====================
*/
void CL_UpdateRemapInfo( int topcolor, int bottomcolor )
{
remap_info_t *info;
int i;
i = ( RI.currententity == &clgame.viewent ) ? clgame.maxEntities : RI.currententity->curstate.number;
info = clgame.remap_info[i];
if( !info ) return; // no remap info
if( info->topcolor == topcolor && info->bottomcolor == bottomcolor )
return; // values is valid
for( i = 0; i < info->numtextures; i++ )
{
2018-03-07 22:00:00 +01:00
if( info->ptexture != NULL )
{
if( FBitSet( info->ptexture[i].flags, STUDIO_NF_COLORMAP ))
CL_UpdateStudioTexture( &info->ptexture[i], topcolor, bottomcolor );
}
else CL_UpdateAliasTexture( &info->textures[i], i, topcolor, bottomcolor );
2011-07-22 22:00:00 +02:00
}
info->topcolor = topcolor;
info->bottomcolor = bottomcolor;
}
/*
====================
CL_FreeRemapInfo
Release remap info per entity
====================
*/
void CL_FreeRemapInfo( remap_info_t *info )
{
int i;
2018-02-12 22:00:00 +01:00
Assert( info != NULL );
2011-07-22 22:00:00 +02:00
// release all colormap texture copies
for( i = 0; i < info->numtextures; i++ )
{
2018-03-07 22:00:00 +01:00
if( info->ptexture != NULL )
{
if( FBitSet( info->ptexture[i].flags, STUDIO_NF_COLORMAP ))
GL_FreeTexture( info->ptexture[i].index );
}
if( info->textures[i] != 0 )
GL_FreeTexture( info->textures[i] );
2011-07-22 22:00:00 +02:00
}
Mem_Free( info ); // release struct
}
/*
====================
CL_ClearAllRemaps
Release all remap infos
====================
*/
void CL_ClearAllRemaps( void )
{
int i;
if( clgame.remap_info )
{
for( i = 0; i < clgame.maxRemapInfos; i++ )
{
if( clgame.remap_info[i] )
CL_FreeRemapInfo( clgame.remap_info[i] );
}
Mem_Free( clgame.remap_info );
}
clgame.remap_info = NULL;
}