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/common/imagelib/img_wad.c

510 lines
13 KiB
C
Raw Normal View History

2011-05-09 22:00:00 +02:00
/*
img_mip.c - hl1 and q1 image mips
Copyright (C) 2007 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.
*/
2008-08-06 22:00:00 +02:00
2008-10-22 22:00:00 +02:00
#include "imagelib.h"
2011-10-09 22:00:00 +02:00
#include "mathlib.h"
2010-09-10 22:00:00 +02:00
#include "wadfile.h"
#include "studio.h"
#include "sprite.h"
#include "qfont.h"
2008-08-06 22:00:00 +02:00
/*
============
Image_LoadPAL
============
*/
2010-10-26 22:00:00 +02:00
qboolean Image_LoadPAL( const char *name, const byte *buffer, size_t filesize )
2008-08-06 22:00:00 +02:00
{
2008-10-19 22:00:00 +02:00
int rendermode = LUMP_NORMAL;
2008-08-06 22:00:00 +02:00
if( filesize != 768 )
{
2008-08-08 22:00:00 +02:00
MsgDev( D_ERROR, "Image_LoadPAL: (%s) have invalid size (%d should be %d)\n", name, filesize, 768 );
2008-08-06 22:00:00 +02:00
return false;
}
2008-10-19 22:00:00 +02:00
if( name[0] == '#' )
{
// using palette name as rendermode
2011-03-09 22:00:00 +01:00
if( Q_stristr( name, "normal" ))
2008-10-19 22:00:00 +02:00
rendermode = LUMP_NORMAL;
2017-03-11 22:00:00 +01:00
else if( Q_stristr( name, "masked" ))
rendermode = LUMP_MASKED;
else if( Q_stristr( name, "gradient" ))
rendermode = LUMP_GRADIENT;
2011-03-09 22:00:00 +01:00
else if( Q_stristr( name, "valve" ))
2017-03-14 22:00:00 +01:00
{
rendermode = LUMP_HALFLIFE;
2010-11-06 22:00:00 +01:00
buffer = NULL; // force to get HL palette
2017-03-14 22:00:00 +01:00
}
else if( Q_stristr( name, "id" ))
{
rendermode = LUMP_QUAKE1;
buffer = NULL; // force to get Q1 palette
}
2008-10-19 22:00:00 +02:00
}
// NOTE: image.d_currentpal not cleared with Image_Reset()
// and stay valid any time before new call of Image_SetPalette
Image_GetPaletteLMP( buffer, rendermode );
2008-08-07 22:00:00 +02:00
Image_CopyPalette32bit();
2008-10-19 22:00:00 +02:00
image.rgba = NULL; // only palette, not real image
image.size = 1024; // expanded palette
image.width = image.height = 0;
2016-09-20 23:00:00 +02:00
image.depth = 1;
2008-08-06 22:00:00 +02:00
return true;
}
2009-10-18 22:00:00 +02:00
/*
============
Image_LoadFNT
============
*/
2010-10-26 22:00:00 +02:00
qboolean Image_LoadFNT( const char *name, const byte *buffer, size_t filesize )
2009-10-18 22:00:00 +02:00
{
qfont_t font;
const byte *pal, *fin;
size_t size;
2010-11-21 22:00:00 +01:00
int numcolors;
2009-10-18 22:00:00 +02:00
if( image.hint == IL_HINT_Q1 )
return false; // Quake1 doesn't have qfonts
if( filesize < sizeof( font ))
return false;
2011-07-07 22:00:00 +02:00
2016-11-17 22:00:00 +01:00
memcpy( &font, buffer, sizeof( font ));
2009-10-18 22:00:00 +02:00
// last sixty four bytes - what the hell ????
2011-07-07 22:00:00 +02:00
size = sizeof( qfont_t ) - 4 + ( font.height * font.width * QCHAR_WIDTH ) + sizeof( short ) + 768 + 64;
2009-10-18 22:00:00 +02:00
if( size != filesize )
{
// oldstyle font: "conchars" or "creditsfont"
image.width = 256; // hardcoded
image.height = font.height;
}
else
{
// Half-Life 1.1.0.0 font style (qfont_t)
image.width = font.width * QCHAR_WIDTH;
image.height = font.height;
}
2011-07-07 22:00:00 +02:00
if( !Image_LumpValidSize( name ))
return false;
2009-10-18 22:00:00 +02:00
2011-07-07 22:00:00 +02:00
fin = buffer + sizeof( font ) - 4;
2010-07-08 22:00:00 +02:00
pal = fin + (image.width * image.height);
2010-11-21 22:00:00 +01:00
numcolors = *(short *)pal, pal += sizeof( short );
2009-10-18 22:00:00 +02:00
2011-10-15 22:00:00 +02:00
if( numcolors == 768 || numcolors == 256 )
2009-10-18 22:00:00 +02:00
{
2011-10-15 22:00:00 +02:00
// g-cont. make sure that is didn't hit anything
2017-03-11 22:00:00 +01:00
Image_GetPaletteLMP( pal, LUMP_MASKED );
2011-07-07 22:00:00 +02:00
image.flags |= IMAGE_HAS_ALPHA; // fonts always have transparency
2009-10-18 22:00:00 +02:00
}
else
{
if( image.hint == IL_HINT_NO )
MsgDev( D_ERROR, "Image_LoadFNT: (%s) have invalid palette size %d\n", name, numcolors );
return false;
}
2010-07-08 22:00:00 +02:00
image.type = PF_INDEXED_32; // 32-bit palette
2016-09-20 23:00:00 +02:00
image.depth = 1;
2010-07-08 22:00:00 +02:00
2010-11-29 22:00:00 +01:00
return Image_AddIndexedImageToPack( fin, image.width, image.height );
2009-10-18 22:00:00 +02:00
}
2008-10-19 22:00:00 +02:00
/*
============
Image_LoadMDL
============
*/
2010-10-26 22:00:00 +02:00
qboolean Image_LoadMDL( const char *name, const byte *buffer, size_t filesize )
2008-10-19 22:00:00 +02:00
{
byte *fin;
size_t pixels;
2010-07-08 22:00:00 +02:00
mstudiotexture_t *pin;
2014-01-02 21:00:00 +01:00
int flags;
2008-10-19 22:00:00 +02:00
2010-07-08 22:00:00 +02:00
pin = (mstudiotexture_t *)buffer;
2010-11-21 22:00:00 +01:00
flags = pin->flags;
2008-10-19 22:00:00 +02:00
2010-11-21 22:00:00 +01:00
image.width = pin->width;
image.height = pin->height;
2008-10-19 22:00:00 +02:00
pixels = image.width * image.height;
2009-08-25 22:00:00 +02:00
fin = (byte *)pin->index; // setup buffer
2008-10-19 22:00:00 +02:00
2012-07-20 22:00:00 +02:00
if( !Image_ValidSize( name )) return false;
2009-10-16 22:00:00 +02:00
2014-01-02 21:00:00 +01:00
if( image.hint == IL_HINT_HL )
2008-10-19 22:00:00 +02:00
{
2009-10-16 22:00:00 +02:00
if( filesize < ( sizeof( *pin ) + pixels + 768 ))
return false;
2017-03-11 22:00:00 +01:00
if( FBitSet( flags, STUDIO_NF_MASKED ))
2009-08-25 22:00:00 +02:00
{
2010-05-27 22:00:00 +02:00
byte *pal = fin + pixels;
2017-03-11 22:00:00 +01:00
Image_GetPaletteLMP( pal, LUMP_MASKED );
2009-08-25 22:00:00 +02:00
image.flags |= IMAGE_HAS_ALPHA;
}
2009-09-04 22:00:00 +02:00
else Image_GetPaletteLMP( fin + pixels, LUMP_NORMAL );
2008-10-19 22:00:00 +02:00
}
2009-08-25 22:00:00 +02:00
else
{
if( image.hint == IL_HINT_NO )
MsgDev( D_ERROR, "Image_LoadMDL: lump (%s) is corrupted\n", name );
return false; // unknown or unsupported mode rejected
2014-09-05 22:00:00 +02:00
}
2008-10-19 22:00:00 +02:00
image.type = PF_INDEXED_32; // 32-bit palete
2016-09-20 23:00:00 +02:00
image.depth = 1;
2008-10-19 22:00:00 +02:00
2010-11-29 22:00:00 +01:00
return Image_AddIndexedImageToPack( fin, image.width, image.height );
2008-10-19 22:00:00 +02:00
}
/*
============
Image_LoadSPR
============
*/
2010-10-26 22:00:00 +02:00
qboolean Image_LoadSPR( const char *name, const byte *buffer, size_t filesize )
2008-10-19 22:00:00 +02:00
{
2012-12-21 21:00:00 +01:00
dspriteframe_t *pin; // identical for q1\hl sprites
2017-07-20 23:00:00 +02:00
qboolean truecolor = false;
2008-11-03 22:00:00 +01:00
2008-10-19 22:00:00 +02:00
if( image.hint == IL_HINT_HL )
{
if( !image.d_currentpal )
{
MsgDev( D_ERROR, "Image_LoadSPR: (%s) palette not installed\n", name );
return false;
}
}
else if( image.hint == IL_HINT_Q1 )
{
Image_GetPaletteQ1();
}
2012-12-21 21:00:00 +01:00
else
{
// unknown mode rejected
return false;
}
2008-10-19 22:00:00 +02:00
2008-10-25 22:00:00 +02:00
pin = (dspriteframe_t *)buffer;
2010-11-21 22:00:00 +01:00
image.width = pin->width;
image.height = pin->height;
2008-10-19 22:00:00 +02:00
2008-10-20 22:00:00 +02:00
if( filesize < image.width * image.height )
{
MsgDev( D_ERROR, "Image_LoadSPR: file (%s) have invalid size\n", name );
return false;
}
2017-07-20 23:00:00 +02:00
if( filesize == ( image.width * image.height * 4 ))
truecolor = true;
2008-10-19 22:00:00 +02:00
// sorry, can't validate palette rendermode
2012-12-21 21:00:00 +01:00
if( !Image_LumpValidSize( name )) return false;
2017-07-20 23:00:00 +02:00
image.type = (truecolor) ? PF_RGBA_32 : PF_INDEXED_32; // 32-bit palete
2016-09-20 23:00:00 +02:00
image.depth = 1;
2008-10-19 22:00:00 +02:00
2008-10-20 22:00:00 +02:00
// detect alpha-channel by palette type
2011-01-02 22:00:00 +01:00
switch( image.d_rendermode )
{
2017-03-11 22:00:00 +01:00
case LUMP_GRADIENT:
case LUMP_MASKED:
2017-03-14 22:00:00 +01:00
case LUMP_QUAKE1:
2017-03-11 22:00:00 +01:00
SetBits( image.flags, IMAGE_HAS_ALPHA );
2011-01-02 22:00:00 +01:00
break;
}
2008-10-20 22:00:00 +02:00
2017-07-20 23:00:00 +02:00
if( truecolor )
{
// spr32 support
image.size = image.width * image.height * 4;
image.rgba = Mem_Alloc( host.imagepool, image.size );
memcpy( image.rgba, (byte *)(pin + 1), image.size );
SetBits( image.flags, IMAGE_HAS_COLOR ); // Color. True Color!
return true;
}
2010-11-29 22:00:00 +01:00
return Image_AddIndexedImageToPack( (byte *)(pin + 1), image.width, image.height );
2008-10-19 22:00:00 +02:00
}
2008-08-06 22:00:00 +02:00
/*
============
Image_LoadLMP
============
*/
2010-10-26 22:00:00 +02:00
qboolean Image_LoadLMP( const char *name, const byte *buffer, size_t filesize )
2008-08-06 22:00:00 +02:00
{
lmp_t lmp;
byte *fin, *pal;
2008-10-25 22:00:00 +02:00
int rendermode;
2017-07-05 23:00:00 +02:00
int i, pixels;
2008-08-06 22:00:00 +02:00
2008-10-25 22:00:00 +02:00
if( filesize < sizeof( lmp ))
2008-08-06 22:00:00 +02:00
{
MsgDev( D_ERROR, "Image_LoadLMP: file (%s) have invalid size\n", name );
return false;
}
2008-10-25 22:00:00 +02:00
2010-11-06 22:00:00 +01:00
// greatest hack from valve software (particle palette)
2011-03-09 22:00:00 +01:00
if( Q_stristr( name, "palette.lmp" ))
2010-11-06 22:00:00 +01:00
return Image_LoadPAL( name, buffer, filesize );
2017-07-05 23:00:00 +02:00
// greatest hack from id software (image without header)
if( image.hint != IL_HINT_HL && Q_stristr( name, "conchars" ))
{
image.width = image.height = 128;
2017-07-20 23:00:00 +02:00
rendermode = LUMP_QUAKE1;
2017-07-05 23:00:00 +02:00
filesize += sizeof( lmp );
fin = (byte *)buffer;
// need to remap transparent color from first to last entry
for( i = 0; i < 16384; i++ ) if( !fin[i] ) fin[i] = 0xFF;
}
else
{
fin = (byte *)buffer;
memcpy( &lmp, fin, sizeof( lmp ));
image.width = lmp.width;
image.height = lmp.height;
rendermode = LUMP_MASKED;
fin += sizeof( lmp );
}
2012-12-21 21:00:00 +01:00
2008-10-19 22:00:00 +02:00
pixels = image.width * image.height;
2008-08-06 22:00:00 +02:00
2008-10-25 22:00:00 +02:00
if( filesize < sizeof( lmp ) + pixels )
2008-08-06 22:00:00 +02:00
{
MsgDev( D_ERROR, "Image_LoadLMP: file (%s) have invalid size %d\n", name, filesize );
return false;
}
2010-11-21 22:00:00 +01:00
if( !Image_ValidSize( name ))
return false;
2008-10-19 22:00:00 +02:00
if( image.hint != IL_HINT_Q1 && filesize > (int)sizeof(lmp) + pixels )
2008-08-06 22:00:00 +02:00
{
2008-10-19 22:00:00 +02:00
int numcolors;
2008-08-06 22:00:00 +02:00
pal = fin + pixels;
2010-11-21 22:00:00 +01:00
numcolors = *(short *)pal;
2008-08-06 22:00:00 +02:00
if( numcolors != 256 ) pal = NULL; // corrupted lump ?
2008-10-19 22:00:00 +02:00
else pal += sizeof( short );
2008-08-06 22:00:00 +02:00
}
2012-12-21 21:00:00 +01:00
else if( image.hint != IL_HINT_HL )
{
2017-07-03 23:00:00 +02:00
rendermode = LUMP_QUAKE1;
2012-12-21 21:00:00 +01:00
pal = NULL;
}
else
{
// unknown mode rejected
return false;
}
2008-08-06 22:00:00 +02:00
2008-10-25 22:00:00 +02:00
Image_GetPaletteLMP( pal, rendermode );
2017-03-11 22:00:00 +01:00
image.flags |= IMAGE_HAS_ALPHA; // FIXME: detect it properly
2012-12-21 21:00:00 +01:00
image.type = PF_INDEXED_32; // 32-bit palete
2016-09-20 23:00:00 +02:00
image.depth = 1;
2012-12-21 21:00:00 +01:00
2010-11-29 22:00:00 +01:00
return Image_AddIndexedImageToPack( fin, image.width, image.height );
2008-08-06 22:00:00 +02:00
}
/*
=============
Image_LoadMIP
=============
*/
2010-10-26 22:00:00 +02:00
qboolean Image_LoadMIP( const char *name, const byte *buffer, size_t filesize )
2008-08-06 22:00:00 +02:00
{
mip_t mip;
2011-02-15 22:00:00 +01:00
qboolean hl_texture;
2008-08-06 22:00:00 +02:00
byte *fin, *pal;
int ofs[4], rendermode;
int i, pixels, numcolors;
2016-08-12 23:00:00 +02:00
int reflectivity[3] = { 0, 0, 0 };
2008-08-06 22:00:00 +02:00
2010-07-29 22:00:00 +02:00
if( filesize < sizeof( mip ))
2008-08-06 22:00:00 +02:00
{
MsgDev( D_ERROR, "Image_LoadMIP: file (%s) have invalid size\n", name );
return false;
}
2016-11-17 22:00:00 +01:00
memcpy( &mip, buffer, sizeof( mip ));
2010-11-21 22:00:00 +01:00
image.width = mip.width;
image.height = mip.height;
if( !Image_ValidSize( name ))
return false;
2016-11-17 22:00:00 +01:00
memcpy( ofs, mip.offsets, sizeof( ofs ));
2008-10-19 22:00:00 +02:00
pixels = image.width * image.height;
2008-08-06 22:00:00 +02:00
2008-10-27 22:00:00 +01:00
if( image.hint != IL_HINT_Q1 && filesize >= (int)sizeof(mip) + ((pixels * 85)>>6) + sizeof(short) + 768)
2008-08-06 22:00:00 +02:00
{
// half-life 1.0.0.1 mip version with palette
fin = (byte *)buffer + mip.offsets[0];
2008-10-19 22:00:00 +02:00
pal = (byte *)buffer + mip.offsets[0] + (((image.width * image.height) * 85)>>6);
2010-11-21 22:00:00 +01:00
numcolors = *(short *)pal;
2008-10-27 22:00:00 +01:00
if( numcolors != 256 ) pal = NULL; // corrupted mip ?
2010-05-24 22:00:00 +02:00
else pal += sizeof( short ); // skip colorsize
2011-02-15 22:00:00 +01:00
hl_texture = true;
2012-12-21 21:00:00 +01:00
// setup rendermode
2011-03-09 22:00:00 +01:00
if( Q_strrchr( name, '{' ))
2008-08-06 22:00:00 +02:00
{
2011-03-20 22:00:00 +01:00
if( !host.decal_loading )
2010-05-28 22:00:00 +02:00
{
2017-03-11 22:00:00 +01:00
rendermode = LUMP_MASKED;
2010-05-28 22:00:00 +02:00
}
else
2008-11-27 22:00:00 +01:00
{
2008-12-06 22:00:00 +01:00
// apply decal palette immediately
2008-11-27 22:00:00 +01:00
image.flags |= IMAGE_COLORINDEX;
2017-03-11 22:00:00 +01:00
rendermode = LUMP_GRADIENT;
2008-11-27 22:00:00 +01:00
}
2012-12-21 21:00:00 +01:00
2008-11-03 22:00:00 +01:00
image.flags |= IMAGE_HAS_ALPHA;
2008-08-06 22:00:00 +02:00
}
2010-06-06 22:00:00 +02:00
else
{
int pal_type;
2011-04-06 22:00:00 +02:00
// NOTE: we can have luma-pixels if quake1 texture
2010-06-06 22:00:00 +02:00
// converted into the hl texture but palette leave unchanged
// this is a good reason for using fullbright pixels
pal_type = Image_ComparePalette( pal );
2011-09-03 22:00:00 +02:00
// check for luma pixels (but ignore liquid textures, this a Xash3D limitation)
if( mip.name[0] != '!' && pal_type == PAL_QUAKE1 )
2010-06-06 22:00:00 +02:00
{
for( i = 0; i < image.width * image.height; i++ )
{
if( fin[i] > 224 )
{
2011-02-11 22:00:00 +01:00
image.flags |= IMAGE_HAS_LUMA;
2010-06-06 22:00:00 +02:00
break;
}
}
}
2012-12-21 21:00:00 +01:00
2010-06-06 22:00:00 +02:00
rendermode = LUMP_NORMAL;
}
2010-12-06 22:00:00 +01:00
Image_GetPaletteLMP( pal, rendermode );
2011-04-19 22:00:00 +02:00
image.d_currentpal[255] &= 0xFFFFFF;
2008-08-06 22:00:00 +02:00
}
2008-10-19 22:00:00 +02:00
else if( image.hint != IL_HINT_HL && filesize >= (int)sizeof(mip) + ((pixels * 85)>>6))
2008-08-06 22:00:00 +02:00
{
// quake1 1.01 mip version without palette
fin = (byte *)buffer + mip.offsets[0];
pal = NULL; // clear palette
rendermode = LUMP_NORMAL;
2008-11-13 22:00:00 +01:00
2011-02-15 22:00:00 +01:00
hl_texture = false;
2017-07-20 23:00:00 +02:00
// check for luma and alpha pixels
2008-11-13 22:00:00 +01:00
for( i = 0; i < image.width * image.height; i++ )
{
2017-07-20 23:00:00 +02:00
if( fin[i] > 224 && fin[i] != 255 )
2008-11-13 22:00:00 +01:00
{
2010-12-22 22:00:00 +01:00
// don't apply luma to water surfaces because
// we use glpoly->next for store luma chain each frame
// and can't modify glpoly_t because many-many HL mods
// expected unmodified glpoly_t and can crashes on changed struct
// water surfaces uses glpoly->next as pointer to subdivided surfaces (as q1)
if( mip.name[0] != '*' && mip.name[0] != '!' )
2011-02-11 22:00:00 +01:00
image.flags |= IMAGE_HAS_LUMA;
2008-11-13 22:00:00 +01:00
break;
}
}
2010-12-06 22:00:00 +01:00
2017-07-20 23:00:00 +02:00
// Arcane Dimensions has the transparent textures
if( Q_strrchr( name, '{' ))
{
for( i = 0; i < image.width * image.height; i++ )
{
if( fin[i] == 255 )
{
image.flags |= IMAGE_HAS_ALPHA;
break;
}
}
}
2010-12-06 22:00:00 +01:00
Image_GetPaletteQ1();
2008-08-06 22:00:00 +02:00
}
else
{
2008-10-19 22:00:00 +02:00
if( image.hint == IL_HINT_NO )
MsgDev( D_ERROR, "Image_LoadMIP: lump (%s) is corrupted\n", name );
return false; // unknown or unsupported mode rejected
2008-08-06 22:00:00 +02:00
}
2010-12-06 22:00:00 +01:00
// check for quake-sky texture
2011-03-09 22:00:00 +01:00
if( !Q_strncmp( mip.name, "sky", 3 ) && image.width == ( image.height * 2 ))
2010-12-06 22:00:00 +01:00
{
2011-02-11 22:00:00 +01:00
// g-cont: we need to run additional checks for palette type and colors ?
2010-12-06 22:00:00 +01:00
image.flags |= IMAGE_QUAKESKY;
}
2011-02-15 22:00:00 +01:00
// check for half-life water texture
2011-03-09 22:00:00 +01:00
if( hl_texture && ( mip.name[0] == '!' || !Q_strnicmp( mip.name, "water", 5 )))
2011-02-15 22:00:00 +01:00
{
// grab the fog color
image.fogParams[0] = pal[3*3+0];
image.fogParams[1] = pal[3*3+1];
image.fogParams[2] = pal[3*3+2];
// grab the fog density
image.fogParams[3] = pal[4*3+0];
}
2011-10-28 22:00:00 +02:00
else if( hl_texture && host.decal_loading )
2011-10-09 22:00:00 +02:00
{
// grab the decal color
image.fogParams[0] = pal[255*3+0];
image.fogParams[1] = pal[255*3+1];
image.fogParams[2] = pal[255*3+2];
// calc the decal reflectivity
image.fogParams[3] = VectorAvg( image.fogParams );
}
2016-08-12 23:00:00 +02:00
else if( pal != NULL )// calc texture reflectivity
{
for( i = 0; i < 256; i++ )
{
reflectivity[0] += pal[i*3+0];
reflectivity[1] += pal[i*3+1];
reflectivity[2] += pal[i*3+2];
}
VectorDivide( reflectivity, 256, image.fogParams );
}
2011-02-15 22:00:00 +01:00
2008-10-19 22:00:00 +02:00
image.type = PF_INDEXED_32; // 32-bit palete
2016-09-20 23:00:00 +02:00
image.depth = 1;
2010-11-29 22:00:00 +01:00
return Image_AddIndexedImageToPack( fin, image.width, image.height );
2008-08-06 22:00:00 +02:00
}