diff --git a/change.log b/change.log index 500f4b9b..b50f25b3 100644 --- a/change.log +++ b/change.log @@ -1,3 +1,6 @@ +build 3366 + + build 3224 Client: make players solid for prediction code diff --git a/common/render_api.h b/common/render_api.h index c454bc47..a8573094 100644 --- a/common/render_api.h +++ b/common/render_api.h @@ -47,6 +47,7 @@ GNU General Public License for more details. #define PARM_TEX_TYPE 11 #define PARM_TEX_CACHEFRAME 12 // compare with worldmodel->needload #define PARM_TEX_GLFORMAT 13 // get a texture GL-format +#define PARM_TEX_ENCODE 14 // custom encoding for DXT image // reserved #define PARM_WORLD_VERSION 16 // return the version of bsp #define PARM_SKY_SPHERE 17 // sky is quake sphere ? @@ -121,7 +122,7 @@ typedef enum TF_STATIC = (1<<21), // a marker for purge mechanism (not used by engine) TF_TEXTURE_RECTANGLE= (1<<22), // this is GL_TEXTURE_RECTANGLE TF_ALPHA_BORDER = (1<<23), // clamp to (0,0,0,255) (probably no difference) - TF_IMAGE_PROGRAM = (1<<24), // enable image program support like in Doom3 + TF_ALPHACONTRAST = (1<<25), // special texture flags for internal usage TF_FLOAT = (1<<26), // float textures TF_NOCOMPARE = (1<<27), // disable comparing for depth textures diff --git a/common/wadfile.h b/common/wadfile.h index 80d54a8f..f5d47ef5 100644 --- a/common/wadfile.h +++ b/common/wadfile.h @@ -35,19 +35,36 @@ infotable dlumpinfo_t[dwadinfo_t->numlumps] #define IDWAD3HEADER (('3'<<24)+('D'<<16)+('A'<<8)+'W') -// dlumpinfo_t->compression -#define CMP_NONE 0 // compression none -#define CMP_LZSS 1 // LZSS compression +// dlumpinfo_t->attribs +#define ATTR_NONE 0 // allow to read-write +#define ATTR_READONLY BIT( 0 ) // don't overwrite this lump in anyway +#define ATTR_COMPRESSED BIT( 1 ) // not used for now, just reserved +#define ATTR_HIDDEN BIT( 2 ) // not used for now, just reserved +#define ATTR_SYSTEM BIT( 3 ) // not used for now, just reserved // dlumpinfo_t->type -#define TYP_QPAL 64 // quake palette -#define TYP_QTEX 65 // probably was never used -#define TYP_QPIC 66 // quake1 and hl pic (lmp_t) -#define TYP_MIPTEX 67 // half-life (mip_t) previous was TYP_SOUND but never used in quake1 -#define TYP_QMIP 68 // quake1 (mip_t) (replaced with TYPE_MIPTEX while loading) -#define TYP_RAW 69 // raw data +#define TYP_ANY -1 // any type can be accepted +#define TYP_NONE 0 // unknown lump type +#define TYP_LABEL 1 // legacy from Doom1. Empty lump - label (like P_START, P_END etc) +#define TYP_PALETTE 64 // quake or half-life palette (768 bytes) +#define TYP_DDSTEX 65 // contain DDS texture +#define TYP_GFXPIC 66 // menu or hud image (not contain mip-levels) +#define TYP_MIPTEX 67 // quake1 and half-life in-game textures with four miplevels +#define TYP_RAWDATA 68 // never was used but may contain any data +#define TYP_COLORMAP2 69 // old stuff. build palette from LBM file (not used) #define TYP_QFONT 70 // half-life font (qfont_t) +// dlumpinfo_t->img_type +#define IMG_DIFFUSE 0 // same as default pad1 always equal 0 +#define IMG_ALPHAMASK 1 // alpha-channel that stored separate as luminance texture +#define IMG_NORMALMAP 2 // indexed normalmap +#define IMG_GLOSSMAP 3 // luminance or color specularity map +#define IMG_GLOSSPOWER 4 // gloss power map (each value is a specular pow) +#define IMG_HEIGHTMAP 5 // heightmap (for parallax occlusion mapping or source of normalmap) +#define IMG_LUMA 6 // luma or glow texture with self-illuminated parts +#define IMG_DECAL_ALPHA 7 // it's a decal texture (last color in palette is base color, and other colors his graduations) +#define IMG_DECAL_COLOR 8 // decal without alpha-channel uses base, like 127 127 127 as transparent color + /* ======================================================================== diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index eaae6fdb..e7ce6c82 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -357,8 +357,8 @@ void CL_CreateCmd( void ) pcmd->cmd.lerp_msec = cl_interp->value * 1000; pcmd->cmd.lerp_msec = bound( 0, cmd.lerp_msec, 250 ); - V_ProcessOverviewCmds( &cmd ); - V_ProcessShowTexturesCmds( &cmd ); + V_ProcessOverviewCmds( &pcmd->cmd ); + V_ProcessShowTexturesCmds( &pcmd->cmd ); if(( cl.background && !cls.demoplayback ) || gl_overview->integer || cls.changelevel ) { diff --git a/engine/client/client.h b/engine/client/client.h index 0b1f90c2..746a7dc1 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -36,7 +36,7 @@ GNU General Public License for more details. #define MAX_MOVIES 8 #define MAX_CDTRACKS 32 #define MAX_IMAGES 256 // SpriteTextures -#define MAX_EFRAGS 1024 +#define MAX_EFRAGS 4096 #define MAX_REQUESTS 32 // screenshot types diff --git a/engine/client/gl_image.c b/engine/client/gl_image.c index 02ae3236..46041441 100644 --- a/engine/client/gl_image.c +++ b/engine/client/gl_image.c @@ -20,7 +20,6 @@ GNU General Public License for more details. #define TEXTURES_HASH_SIZE 64 -static rgbdata_t *R_LoadImage( char **buffer, const char *name, const byte *buf, size_t size, int *samples, texFlags_t *flags ); static int r_textureMinFilter = GL_LINEAR_MIPMAP_LINEAR; static int r_textureMagFilter = GL_LINEAR; static gltexture_t r_textures[MAX_TEXTURES]; @@ -356,7 +355,7 @@ void R_TextureList_f( void ) int i, texCount, bytes = 0; Msg( "\n" ); - Msg(" -w-- -h-- -size- -fmt- type -filter -wrap-- -name--------\n" ); + Msg(" -w-- -h-- -size- -fmt- type -data-- -encode-- -wrap-- -name--------\n" ); for( i = texCount = 0, image = r_textures; i < r_numTextures; i++, image++ ) { @@ -498,20 +497,41 @@ void R_TextureList_f( void ) } if( image->flags & TF_NORMALMAP ) - Msg( "normal " ); - else if( image->flags & TF_NOMIPMAP ) - Msg( "linear " ); - if( image->flags & TF_NEAREST ) - Msg( "nearest" ); - else Msg( "default" ); + Msg( "normal " ); + else Msg( "diffuse " ); + + switch( image->encode ) + { + case DXT_ENCODE_COLOR_YCoCg: + Msg( "YCoCg " ); + break; + case DXT_ENCODE_NORMAL_AG_ORTHO: + Msg( "ortho " ); + break; + case DXT_ENCODE_NORMAL_AG_STEREO: + Msg( "stereo " ); + break; + case DXT_ENCODE_NORMAL_AG_PARABOLOID: + Msg( "parabolic " ); + break; + case DXT_ENCODE_NORMAL_AG_QUARTIC: + Msg( "quartic " ); + break; + case DXT_ENCODE_NORMAL_AG_AZIMUTHAL: + Msg( "azimuthal " ); + break; + default: + Msg( "default " ); + break; + } if( image->flags & TF_CLAMP ) - Msg( " clamp " ); + Msg( "clamp " ); else if( image->flags & TF_BORDER ) - Msg( " border " ); + Msg( "border " ); else if( image->flags & TF_ALPHA_BORDER ) - Msg( " aborder" ); - else Msg( " repeat " ); + Msg( "aborder" ); + else Msg( "repeat " ); Msg( " %s\n", image->name ); } @@ -1116,6 +1136,7 @@ static void GL_UploadTextureDXT( rgbdata_t *pic, gltexture_t *tex, qboolean subI tex->flags &= ~TF_KEEP_8BIT; tex->flags &= ~TF_KEEP_RGBDATA; tex->flags |= TF_NOPICMIP; + tex->encode = pic->encode; // share encode method samples = GL_CalcTextureSamples( pic->flags ); @@ -1196,12 +1217,13 @@ static void GL_UploadTextureDXT( rgbdata_t *pic, gltexture_t *tex, qboolean subI for( j = 0; j < numMips; j++ ) { + width = max( 1, ( pic->width >> j )); + height = max( 1, ( pic->height >> j )); texsize = Image_DXTGetLinearSize( pic->type, width, height, depth ); if( ImageDXT( pic->type )) GL_TextureImageDXT( inFormat, glTarget, i, j, width, height, depth, subImage, texsize, buf ); else GL_TextureImage( inFormat, tex->format, glTarget, i, j, width, height, depth, subImage, texsize, buf ); - width = (width+1)>>1, height = (height+1)>>1; buf += texsize; // move pointer // catch possible errors @@ -1470,38 +1492,12 @@ int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags, i // set some image flags Image_SetForceFlags( picFlags ); - if( flags & TF_IMAGE_PROGRAM ) - { - char buffer[256], token[256]; - char *script; - int samples; + // HACKHACK: get rid of black vertical line on a 'BlackMesa map' + if( !Q_strcmp( name, "#lab1_map1.mip" ) || !Q_strcmp( name, "#lab1_map2.mip" )) + flags |= TF_NEAREST; - // create quoted string on a spec symbols - if( name[0] == '#' || name[0] == '{' ) - Q_snprintf( buffer, sizeof( buffer ), "\"%s\"", name ); - else Q_strncpy( buffer, name, sizeof( buffer )); - script = &buffer[0]; - - if(( script = COM_ParseFile( script, token )) == NULL ) - return 0; - - // parse image program - pic = R_LoadImage( &script, token, buf, size, &samples, &flags ); - if( !pic ) return 0; // couldn't loading image - - // recalc image samples here - pic->flags &= ~(IMAGE_HAS_COLOR|IMAGE_HAS_ALPHA); - pic->flags |= GL_ImageFlagsFromSamples( samples ); - } - else - { - // HACKHACK: get rid of black vertical line on a 'BlackMesa map' - if( !Q_strcmp( name, "#lab1_map1.mip" ) || !Q_strcmp( name, "#lab1_map2.mip" )) - flags |= TF_NEAREST; - - pic = FS_LoadImage( name, buf, size ); - if( !pic ) return 0; // couldn't loading image - } + pic = FS_LoadImage( name, buf, size ); + if( !pic ) return 0; // couldn't loading image // force upload texture as RGB or RGBA (detail textures requires this) if( flags & TF_FORCE_COLOR ) pic->flags |= IMAGE_HAS_COLOR; @@ -1813,1959 +1809,6 @@ void GL_FreeTexture( GLenum texnum ) R_FreeImage( &r_textures[texnum] ); } -/* -======================================================================= - - IMAGE PROGRAM FUNCTIONS - -======================================================================= -*/ -/* -================= -R_ForceImageToRGBA - -Unpack any image to RGBA buffer -================= -*/ -_inline static rgbdata_t *R_ForceImageToRGBA( rgbdata_t *pic ) -{ - // don't need additional checks - image lib do it himself - Image_Process( &pic, 0, 0, 0, IMAGE_FORCE_RGBA, NULL ); - - return pic; -} - -/* -================= -R_AddImages - -Adds the given images together -================= -*/ -static rgbdata_t *R_AddImages( rgbdata_t *in1, rgbdata_t *in2 ) -{ - rgbdata_t *out; - int width, height; - int r, g, b, a; - int x, y; - - // make sure what we processing RGBA images - in1 = R_ForceImageToRGBA( in1 ); - in2 = R_ForceImageToRGBA( in2 ); - width = in1->width, height = in1->height; - out = in1; - - for( y = 0; y < height; y++ ) - { - for( x = 0; x < width; x++ ) - { - r = in1->buffer[4*(y*width+x)+0] + in2->buffer[4*(y*width+x)+0]; - g = in1->buffer[4*(y*width+x)+1] + in2->buffer[4*(y*width+x)+1]; - b = in1->buffer[4*(y*width+x)+2] + in2->buffer[4*(y*width+x)+2]; - a = in1->buffer[4*(y*width+x)+3] + in2->buffer[4*(y*width+x)+3]; - out->buffer[4*(y*width+x)+0] = bound( 0, r, 255 ); - out->buffer[4*(y*width+x)+1] = bound( 0, g, 255 ); - out->buffer[4*(y*width+x)+2] = bound( 0, b, 255 ); - out->buffer[4*(y*width+x)+3] = bound( 0, a, 255 ); - } - } - - FS_FreeImage( in2 ); - - return out; -} - -/* -================= -R_MultiplyImages - -Multiplies the given images -================= -*/ -static rgbdata_t *R_MultiplyImages( rgbdata_t *in1, rgbdata_t *in2 ) -{ - rgbdata_t *out; - int width, height; - int r, g, b, a; - int x, y; - - // make sure what we processing RGBA images - in1 = R_ForceImageToRGBA( in1 ); - in2 = R_ForceImageToRGBA( in2 ); - width = in1->width, height = in1->height; - out = in1; - - for( y = 0; y < height; y++ ) - { - for( x = 0; x < width; x++ ) - { - r = in1->buffer[4*(y*width+x)+0] * (in2->buffer[4*(y*width+x)+0] * (1.0f/255)); - g = in1->buffer[4*(y*width+x)+1] * (in2->buffer[4*(y*width+x)+1] * (1.0f/255)); - b = in1->buffer[4*(y*width+x)+2] * (in2->buffer[4*(y*width+x)+2] * (1.0f/255)); - a = in1->buffer[4*(y*width+x)+3] * (in2->buffer[4*(y*width+x)+3] * (1.0f/255)); - out->buffer[4*(y*width+x)+0] = bound( 0, r, 255 ); - out->buffer[4*(y*width+x)+1] = bound( 0, g, 255 ); - out->buffer[4*(y*width+x)+2] = bound( 0, b, 255 ); - out->buffer[4*(y*width+x)+3] = bound( 0, a, 255 ); - } - } - FS_FreeImage( in2 ); - - return out; -} - -/* -================= -R_BiasImage - -Biases the given image -================= -*/ -static rgbdata_t *R_BiasImage( rgbdata_t *in, const vec4_t bias ) -{ - rgbdata_t *out; - int width, height; - int r, g, b, a; - int x, y; - - // make sure what we processing RGBA image - in = R_ForceImageToRGBA( in ); - width = in->width, height = in->height; - out = in; - - for( y = 0; y < height; y++ ) - { - for( x = 0; x < width; x++ ) - { - r = in->buffer[4*(y*width+x)+0] + (255 * bias[0]); - g = in->buffer[4*(y*width+x)+1] + (255 * bias[1]); - b = in->buffer[4*(y*width+x)+2] + (255 * bias[2]); - a = in->buffer[4*(y*width+x)+3] + (255 * bias[3]); - out->buffer[4*(y*width+x)+0] = bound( 0, r, 255 ); - out->buffer[4*(y*width+x)+1] = bound( 0, g, 255 ); - out->buffer[4*(y*width+x)+2] = bound( 0, b, 255 ); - out->buffer[4*(y*width+x)+3] = bound( 0, a, 255 ); - } - } - - return out; -} - -/* -================= -R_ScaleImage - -Scales the given image -================= -*/ -static rgbdata_t *R_ScaleImage( rgbdata_t *in, const vec4_t scale ) -{ - rgbdata_t *out; - int width, height; - int r, g, b, a; - int x, y; - - // make sure what we processing RGBA image - in = R_ForceImageToRGBA( in ); - width = in->width, height = in->height; - out = in; - - for( y = 0; y < height; y++ ) - { - for( x = 0; x < width; x++ ) - { - r = in->buffer[4*(y*width+x)+0] * scale[0]; - g = in->buffer[4*(y*width+x)+1] * scale[1]; - b = in->buffer[4*(y*width+x)+2] * scale[2]; - a = in->buffer[4*(y*width+x)+3] * scale[3]; - out->buffer[4*(y*width+x)+0] = bound( 0, r, 255 ); - out->buffer[4*(y*width+x)+1] = bound( 0, g, 255 ); - out->buffer[4*(y*width+x)+2] = bound( 0, b, 255 ); - out->buffer[4*(y*width+x)+3] = bound( 0, a, 255 ); - } - } - - return out; -} - -/* -================= -R_InvertColor - -Inverts the color channels of the given image -================= -*/ -static rgbdata_t *R_InvertColor( rgbdata_t *in ) -{ - rgbdata_t *out; - int width, height; - int x, y; - - // make sure what we processing RGBA image - in = R_ForceImageToRGBA( in ); - width = in->width, height = in->height; - out = in; - - for( y = 0; y < height; y++ ) - { - for( x = 0; x < width; x++ ) - { - out->buffer[4*(y*width+x)+0] = 255 - in->buffer[4*(y*width+x)+0]; - out->buffer[4*(y*width+x)+1] = 255 - in->buffer[4*(y*width+x)+1]; - out->buffer[4*(y*width+x)+2] = 255 - in->buffer[4*(y*width+x)+2]; - } - } - - return out; -} - -/* -================= -R_InvertAlpha - -Inverts the alpha channel of the given image -================= -*/ -static rgbdata_t *R_InvertAlpha( rgbdata_t *in ) -{ - rgbdata_t *out; - int width, height; - int x, y; - - // make sure what we processing RGBA image - in = R_ForceImageToRGBA( in ); - width = in->width, height = in->height; - out = in; - - for( y = 0; y < height; y++ ) - { - for( x = 0; x < width; x++ ) - out->buffer[4*(y*width+x)+3] = 255 - in->buffer[4*(y*width+x)+3]; - } - - return out; -} - -/* -================= -R_MakeIntensity - -Converts the given image to intensity -================= -*/ -static rgbdata_t *R_MakeIntensity( rgbdata_t *in ) -{ - rgbdata_t *out; - int width, height; - byte intensity; - float r, g, b; - int x, y; - - // make sure what we processing RGBA image - in = R_ForceImageToRGBA( in ); - width = in->width, height = in->height; - out = in; - - for( y = 0; y < height; y++ ) - { - for( x = 0; x < width; x++ ) - { - r = r_luminanceTable[in->buffer[4*(y*width+x)+0]][0]; - g = r_luminanceTable[in->buffer[4*(y*width+x)+1]][1]; - b = r_luminanceTable[in->buffer[4*(y*width+x)+2]][2]; - - intensity = (byte)(r + g + b); - - out->buffer[4*(y*width+x)+0] = intensity; - out->buffer[4*(y*width+x)+1] = intensity; - out->buffer[4*(y*width+x)+2] = intensity; - out->buffer[4*(y*width+x)+3] = intensity; - } - } - - return out; -} - -/* -================= -R_MakeLuminance - -Converts the given image to luminance -================= -*/ -static rgbdata_t *R_MakeLuminance( rgbdata_t *in ) -{ - rgbdata_t *out; - int width, height; - byte luminance; - float r, g, b; - int x, y; - - // make sure what we processing RGBA image - in = R_ForceImageToRGBA( in ); - width = in->width, height = in->height; - out = in; - - for( y = 0; y < height; y++ ) - { - for( x = 0; x < width; x++ ) - { - r = r_luminanceTable[in->buffer[4*(y*width+x)+0]][0]; - g = r_luminanceTable[in->buffer[4*(y*width+x)+1]][1]; - b = r_luminanceTable[in->buffer[4*(y*width+x)+2]][2]; - - luminance = (byte)(r + g + b); - - out->buffer[4*(y*width+x)+0] = luminance; - out->buffer[4*(y*width+x)+1] = luminance; - out->buffer[4*(y*width+x)+2] = luminance; - out->buffer[4*(y*width+x)+3] = 255; - } - } - - return out; -} - -/* -================= -R_MakeLuma - -Converts the given image to glow (LUMA) -================= -*/ -static rgbdata_t *R_MakeLuma( rgbdata_t *in ) -{ - Image_Process( &in, 0, 0, 0, IMAGE_MAKE_LUMA|IMAGE_FORCE_RGBA, NULL ); - - return in; -} - -/* -================= -R_MakeImageBlock - -Scissor the specifed rectangle from image -================= -*/ -static rgbdata_t *R_MakeImageBlock( rgbdata_t *in, int block[4] ) -{ - byte *fin, *fout, *out; - int i, x, y, xl, yl, xh, yh, w, h; - int linedelta; - - // make sure what we processing RGBA image - in = R_ForceImageToRGBA( in ); - - xl = block[0]; - yl = block[1]; - w = block[2]; - h = block[3]; - xh = xl + w; - yh = yl + h; - - out = fout = Mem_Alloc( r_temppool, w * h * 4 ); - - fin = in->buffer + (yl * in->width + xl) * 4; - linedelta = (in->width - w) * 4; - - // cut block from source - for( y = yl; y < yh; y++ ) - { - for( x = xl; x < xh; x++ ) - for( i = 0; i < 4; i++ ) - *out++ = *fin++; - fin += linedelta; - } - - // update image size - in->width = w, in->height = h; - in->size = in->width * in->height * 4; - - // copy result back - in->buffer = Mem_Realloc( host.imagepool, in->buffer, in->size ); - Q_memcpy( in->buffer, fout, in->size ); - Mem_Free( fout ); // purge temp buffer - - return in; -} - -/* -================= -R_MakeAlpha - -Converts the given image to alpha -================= -*/ -static rgbdata_t *R_MakeAlpha( rgbdata_t *in ) -{ - rgbdata_t *out; - int width, height; - byte alpha; - float r, g, b; - int x, y; - - // make sure what we processing RGBA image - in = R_ForceImageToRGBA( in ); - width = in->width, height = in->height; - out = in; - - for( y = 0; y < height; y++ ) - { - for( x = 0; x < width; x++ ) - { - r = r_luminanceTable[in->buffer[4*(y*width+x)+0]][0]; - g = r_luminanceTable[in->buffer[4*(y*width+x)+1]][1]; - b = r_luminanceTable[in->buffer[4*(y*width+x)+2]][2]; - - alpha = (byte)(r + g + b); - - out->buffer[4*(y*width+x)+0] = 255; - out->buffer[4*(y*width+x)+1] = 255; - out->buffer[4*(y*width+x)+2] = 255; - out->buffer[4*(y*width+x)+3] = alpha; - } - } - - return out; -} - -/* -================= -R_HeightMap - -Converts the given height map to a normal map -================= -*/ -static rgbdata_t *R_HeightMap( rgbdata_t *in, float bumpScale ) -{ - byte *out; - int width, height; - vec3_t normal; - float r, g, b; - float c, cx, cy; - int x, y; - - // make sure what we processing RGBA image - in = R_ForceImageToRGBA( in ); - width = in->width, height = in->height; - out = Mem_Alloc( r_temppool, width * height * 4 ); - - if( !bumpScale ) bumpScale = 1.0f; - - for( y = 0; y < height; y++ ) - { - for( x = 0; x < width; x++ ) - { - r = r_luminanceTable[in->buffer[4*(y*width+x)+0]][0]; - g = r_luminanceTable[in->buffer[4*(y*width+x)+1]][1]; - b = r_luminanceTable[in->buffer[4*(y*width+x)+2]][2]; - - c = (r + g + b) * (1.0f/255); - - r = r_luminanceTable[in->buffer[4*(y*width+((x+1)%width))+0]][0]; - g = r_luminanceTable[in->buffer[4*(y*width+((x+1)%width))+1]][1]; - b = r_luminanceTable[in->buffer[4*(y*width+((x+1)%width))+2]][2]; - - cx = (r + g + b) * (1.0f/255); - - r = r_luminanceTable[in->buffer[4*(((y+1)%height)*width+x)+0]][0]; - g = r_luminanceTable[in->buffer[4*(((y+1)%height)*width+x)+1]][1]; - b = r_luminanceTable[in->buffer[4*(((y+1)%height)*width+x)+2]][2]; - - cy = (r + g + b) * (1.0f/255); - - normal[0] = (c - cx) * bumpScale; - normal[1] = (c - cy) * bumpScale; - normal[2] = 1.0f; - - if( !VectorNormalizeLength( normal )) - VectorSet( normal, 0.0f, 0.0f, 1.0f ); - - out[4*(y*width+x)+0] = (byte)(128 + 127 * normal[0]); - out[4*(y*width+x)+1] = (byte)(128 + 127 * normal[1]); - out[4*(y*width+x)+2] = (byte)(128 + 127 * normal[2]); - out[4*(y*width+x)+3] = 255; - } - } - - // copy result back - Q_memcpy( in->buffer, out, width * height * 4 ); - Mem_Free( out ); - - return in; -} - -/* -================= -R_AddNormals - -Adds the given normal maps together -================= -*/ -static rgbdata_t *R_AddNormals( rgbdata_t *in1, rgbdata_t *in2 ) -{ - byte *out; - int width, height; - vec3_t normal; - int x, y; - - // make sure what we processing RGBA images - in1 = R_ForceImageToRGBA( in1 ); - in2 = R_ForceImageToRGBA( in2 ); - width = in1->width, height = in1->height; - out = Mem_Alloc( r_temppool, in1->size ); - - for( y = 0; y < height; y++ ) - { - for( x = 0; x < width; x++ ) - { - normal[0] = (in1->buffer[4*(y*width+x)+0] * (1.0f/127) - 1.0f) + (in2->buffer[4*(y*width+x)+0] * (1.0f/127) - 1.0f); - normal[1] = (in1->buffer[4*(y*width+x)+1] * (1.0f/127) - 1.0f) + (in2->buffer[4*(y*width+x)+1] * (1.0f/127) - 1.0f); - normal[2] = (in1->buffer[4*(y*width+x)+2] * (1.0f/127) - 1.0f) + (in2->buffer[4*(y*width+x)+2] * (1.0f/127) - 1.0f); - - if( !VectorNormalizeLength( normal )) - VectorSet( normal, 0.0f, 0.0f, 1.0f ); - - out[4*(y*width+x)+0] = (byte)(128 + 127 * normal[0]); - out[4*(y*width+x)+1] = (byte)(128 + 127 * normal[1]); - out[4*(y*width+x)+2] = (byte)(128 + 127 * normal[2]); - out[4*(y*width+x)+3] = 255; - } - } - - // copy result back - Q_memcpy( in1->buffer, out, width * height * 4 ); - FS_FreeImage( in2 ); - Mem_Free( out ); - - return in1; -} - -/* -================= -R_SmoothNormals - -Smoothes the given normal map -================= -*/ -static rgbdata_t *R_SmoothNormals( rgbdata_t *in ) -{ - byte *out; - int width, height; - uint frac, fracStep; - uint p1[0x1000], p2[0x1000]; - byte *pix1, *pix2, *pix3, *pix4; - uint *inRow1, *inRow2; - vec3_t normal; - int i, x, y; - - // make sure what we processing RGBA image - in = R_ForceImageToRGBA( in ); - width = in->width, height = in->height; - out = Mem_Alloc( r_temppool, in->size ); - - fracStep = 0x10000; - frac = fracStep>>2; - for( i = 0; i < width; i++ ) - { - p1[i] = 4 * (frac>>16); - frac += fracStep; - } - - frac = (fracStep>>2) * 3; - for( i = 0; i < width; i++ ) - { - p2[i] = 4 * (frac>>16); - frac += fracStep; - } - - for( y = 0; y < height; y++ ) - { - inRow1 = (uint *)in->buffer + width * (int)((float)y + 0.25f); - inRow2 = (uint *)in->buffer + width * (int)((float)y + 0.75f); - - for( x = 0; x < width; x++ ) - { - pix1 = (byte *)inRow1 + p1[x]; - pix2 = (byte *)inRow1 + p2[x]; - pix3 = (byte *)inRow2 + p1[x]; - pix4 = (byte *)inRow2 + p2[x]; - - normal[0] = (pix1[0] * (1.0f/127) - 1.0f) + (pix2[0] * (1.0f/127) - 1.0f) + (pix3[0] * (1.0f/127) - 1.0f) + (pix4[0] * (1.0f/127) - 1.0f); - normal[1] = (pix1[1] * (1.0f/127) - 1.0f) + (pix2[1] * (1.0f/127) - 1.0f) + (pix3[1] * (1.0f/127) - 1.0f) + (pix4[1] * (1.0f/127) - 1.0f); - normal[2] = (pix1[2] * (1.0f/127) - 1.0f) + (pix2[2] * (1.0f/127) - 1.0f) + (pix3[2] * (1.0f/127) - 1.0f) + (pix4[2] * (1.0f/127) - 1.0f); - - if( !VectorNormalizeLength( normal )) - VectorSet( normal, 0.0f, 0.0f, 1.0f ); - - out[4*(y*width+x)+0] = (byte)(128 + 127 * normal[0]); - out[4*(y*width+x)+1] = (byte)(128 + 127 * normal[1]); - out[4*(y*width+x)+2] = (byte)(128 + 127 * normal[2]); - out[4*(y*width+x)+3] = 255; - } - } - - // copy result back - Q_memcpy( in->buffer, out, width * height * 4 ); - Mem_Free( out ); - - return in; -} - -/* -================ -R_IncludeDepthmap - -Write depthmap into alpha-channel the given normal map -================ -*/ -static rgbdata_t *R_IncludeDepthmap( rgbdata_t *in1, rgbdata_t *in2 ) -{ - int i; - byte *pic1, *pic2; - - // make sure what we processing RGBA images - in1 = R_ForceImageToRGBA( in1 ); - in2 = R_ForceImageToRGBA( in2 ); - - pic1 = in1->buffer; - pic2 = in2->buffer; - - for( i = (in1->width * in1->height) - 1; i > 0; i--, pic1 += 4, pic2 += 4 ) - { - if( in2->flags & IMAGE_HAS_COLOR ) - pic1[3] = ((int)pic2[0] + (int)pic2[1] + (int)pic2[2]) / 3; - else if( in2->flags & IMAGE_HAS_ALPHA ) - pic1[3] = pic2[3]; - else pic1[3] = pic2[0]; - } - - in1->flags |= (IMAGE_HAS_COLOR|IMAGE_HAS_ALPHA); - FS_FreeImage( in2 ); - - return in1; -} - -/* -================ -R_ClearPixels - -clear specified area: color or alpha -================ -*/ -static rgbdata_t *R_ClearPixels( rgbdata_t *in, qboolean clearAlpha ) -{ - byte *pic; - int i; - - // make sure what we processing RGBA images - in = R_ForceImageToRGBA( in ); - pic = in->buffer; - - if( clearAlpha ) - { - for( i = 0; ( i < in->width * in->height ) && ( in->flags & IMAGE_HAS_ALPHA ); i++ ) - pic[(i<<2)+3] = 0xFF; - } - else - { - // clear color or greyscale image otherwise - for( i = 0; i < in->width * in->height; i++ ) - pic[(i<<2)+0] = pic[(i<<2)+1] = pic[(i<<2)+2] = 0xFF; - } - - return in; -} - -/* -================ -R_MovePixels - -move alpha-channel into color or back -================ -*/ -static rgbdata_t *R_MovePixels( rgbdata_t *in, qboolean alphaToColor ) -{ - byte *pic; - int i; - - // make sure what we processing RGBA images - in = R_ForceImageToRGBA( in ); - pic = in->buffer; - - if( alphaToColor ) - { - for( i = 0; ( i < in->width * in->height ) && ( in->flags & IMAGE_HAS_ALPHA ); i++ ) - { - pic[(i<<2)+0] = pic[(i<<2)+1] = pic[(i<<2)+2] = pic[(i<<2)+3]; // move from alpha to color - pic[(i<<2)+3] = 0xFF; // clear alpha channel - } - } - else - { - // clear color or greyscale image otherwise - for( i = 0; i < in->width * in->height; i++ ) - { - // convert to grayscale - pic[(i<<2)+3] = (pic[(i<<2)+0] * 0.32f) + (pic[(i<<2)+0] * 0.59f) + (pic[(i<<2)+0] * 0.09f); - pic[(i<<2)+0] = pic[(i<<2)+1] = pic[(i<<2)+2] = 0x00; // clear RGB channels - } - } - - return in; -} - -/* -============================================================================== - -EXTENDED IMAGE INTERFACE - -============================================================================== -*/ -/* -================= -R_ParseAdd -================= -*/ -static rgbdata_t *R_ParseAdd( char **script, int *samples, texFlags_t *flags ) -{ - char token[256]; - rgbdata_t *pic1, *pic2; - int samples1, samples2; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "(" )) - { - MsgDev( D_WARN, "expected '(', found '%s' instead for 'add'\n", token ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'add'\n" ); - return NULL; - } - - pic1 = R_LoadImage( script, token, NULL, 0, &samples1, flags ); - if( !pic1 ) return NULL; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "," )) - { - MsgDev( D_WARN, "expected ',', found '%s' instead for 'add'\n", token ); - FS_FreeImage( pic1 ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'add'\n" ); - FS_FreeImage( pic1 ); - return NULL; - } - - pic2 = R_LoadImage( script, token, NULL, 0, &samples2, flags ); - if( !pic2 ) - { - FS_FreeImage( pic1 ); - return NULL; - } - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, ")" )) - { - MsgDev( D_WARN, "expected ')', found '%s' instead for 'add'\n", token ); - FS_FreeImage( pic1 ); - FS_FreeImage( pic2 ); - return NULL; - } - - if( pic1->width != pic2->width || pic1->height != pic2->height ) - { - MsgDev( D_WARN, "images for 'add' have mismatched dimensions [%ix%i] != [%ix%i]\n", - pic1->width, pic1->height, pic2->width, pic2->height ); - - FS_FreeImage( pic1 ); - FS_FreeImage( pic2 ); - return NULL; - } - - *samples = GL_CalcImageSamples( samples1, samples2 ); - if( *samples != 1 ) - { - *flags &= ~TF_INTENSITY; - *flags &= ~TF_LUMINANCE; - } - - return R_AddImages( pic1, pic2 ); -} - -/* -================= -R_ParseMultiply -================= -*/ -static rgbdata_t *R_ParseMultiply( char **script, int *samples, texFlags_t *flags ) -{ - char token[256]; - rgbdata_t *pic1, *pic2; - int samples1, samples2; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "(" )) - { - MsgDev( D_WARN, "expected '(', found '%s' instead for 'multiply'\n", token ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'multiply'\n" ); - return NULL; - } - - pic1 = R_LoadImage( script, token, NULL, 0, &samples1, flags ); - if( !pic1 ) return NULL; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "," )) - { - MsgDev( D_WARN, "expected ',', found '%s' instead for 'multiply'\n", token ); - FS_FreeImage( pic1 ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'multiply'\n" ); - FS_FreeImage( pic1 ); - return NULL; - } - - pic2 = R_LoadImage( script, token, NULL, 0, &samples2, flags ); - if( !pic2 ) - { - FS_FreeImage( pic1 ); - return NULL; - } - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, ")" )) - { - MsgDev( D_WARN, "expected ')', found '%s' instead for 'multiply'\n", token ); - - FS_FreeImage( pic1 ); - FS_FreeImage( pic2 ); - return NULL; - } - - if( pic1->width != pic2->width || pic1->height != pic2->height ) - { - MsgDev( D_WARN, "images for 'multiply' have mismatched dimensions [%ix%i] != [%ix%i]\n", - pic1->width, pic1->height, pic2->width, pic2->height ); - - FS_FreeImage( pic1 ); - FS_FreeImage( pic2 ); - return NULL; - } - - *samples = GL_CalcImageSamples( samples1, samples2 ); - - if( *samples != 1 ) - { - *flags &= ~TF_INTENSITY; - *flags &= ~TF_LUMINANCE; - } - - return R_MultiplyImages( pic1, pic2 ); -} - -/* -================= -R_ParseBias -================= -*/ -static rgbdata_t *R_ParseBias( char **script, int *samples, texFlags_t *flags ) -{ - char token[256]; - rgbdata_t *pic; - vec4_t bias; - int i; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "(" )) - { - MsgDev( D_WARN, "expected '(', found '%s' instead for 'bias'\n", token ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'bias'\n" ); - return NULL; - } - - pic = R_LoadImage( script, token, NULL, 0, samples, flags ); - if( !pic ) return NULL; - - for( i = 0; i < 4; i++ ) - { - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "," )) - { - MsgDev( D_WARN, "expected ',', found '%s' instead for 'bias'\n", token ); - FS_FreeImage( pic ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'bias'\n" ); - FS_FreeImage( pic ); - return NULL; - } - - bias[i] = Q_atof( token ); - } - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, ")" )) - { - MsgDev( D_WARN, "expected ')', found '%s' instead for 'bias'\n", token ); - FS_FreeImage( pic ); - return NULL; - } - - if( *samples < 3 ) *samples += 2; - *flags &= ~TF_INTENSITY; - *flags &= ~TF_LUMINANCE; - - return R_BiasImage( pic, bias ); -} - -/* -================= -R_ParseScale -================= -*/ -static rgbdata_t *R_ParseScale( char **script, int *samples, texFlags_t *flags ) -{ - char token[256]; - rgbdata_t *pic; - vec4_t scale; - int i; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "(" )) - { - MsgDev( D_WARN, "expected '(', found '%s' instead for 'scale'\n", token ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'scale'\n" ); - return NULL; - } - - pic = R_LoadImage( script, token, NULL, 0, samples, flags ); - if( !pic ) return NULL; - - for( i = 0; i < 4; i++ ) - { - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "," )) - { - MsgDev( D_WARN, "expected ',', found '%s' instead for 'scale'\n", token ); - FS_FreeImage( pic ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'scale'\n" ); - FS_FreeImage( pic ); - return NULL; - } - - scale[i] = Q_atof( token ); - } - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, ")" )) - { - MsgDev( D_WARN, "expected ')', found '%s' instead for 'scale'\n", token ); - FS_FreeImage( pic ); - return NULL; - } - - if( *samples < 3 ) *samples += 2; - *flags &= ~TF_INTENSITY; - *flags &= ~TF_LUMINANCE; - - return R_ScaleImage( pic, scale ); -} - -/* -================= -R_ParseInvertColor -================= -*/ -static rgbdata_t *R_ParseInvertColor( char **script, int *samples, texFlags_t *flags ) -{ - char token[256]; - rgbdata_t *pic; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "(" )) - { - MsgDev( D_WARN, "expected '(', found '%s' instead for 'invertColor'\n", token ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'invertColor'\n" ); - return NULL; - } - - pic = R_LoadImage( script, token, NULL, 0, samples, flags ); - if( !pic ) return NULL; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, ")" )) - { - MsgDev( D_WARN, "expected ')', found '%s' instead for 'invertColor'\n", token ); - FS_FreeImage( pic ); - return NULL; - } - - return R_InvertColor( pic ); -} - -/* -================= -R_ParseInvertAlpha -================= -*/ -static rgbdata_t *R_ParseInvertAlpha( char **script, int *samples, texFlags_t *flags ) -{ - char token[256]; - rgbdata_t *pic; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "(" )) - { - MsgDev( D_WARN, "expected '(', found '%s' instead for 'invertAlpha'\n", token ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'invertAlpha'\n" ); - return NULL; - } - - pic = R_LoadImage( script, token, NULL, 0, samples, flags ); - if( !pic ) return NULL; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, ")" )) - { - MsgDev( D_WARN, "expected ')', found '%s' instead for 'invertAlpha'\n", token ); - FS_FreeImage( pic ); - return NULL; - } - - return R_InvertAlpha( pic ); -} - -/* -================= -R_ParseMakeIntensity -================= -*/ -static rgbdata_t *R_ParseMakeIntensity( char **script, int *samples, texFlags_t *flags ) -{ - char token[256]; - rgbdata_t *pic; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "(" )) - { - MsgDev( D_WARN, "expected '(', found '%s' instead for 'makeIntensity'\n", token ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'makeIntensity'\n" ); - return NULL; - } - - pic = R_LoadImage( script, token, NULL, 0, samples, flags ); - if( !pic ) return NULL; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, ")" )) - { - MsgDev( D_WARN, "expected ')', found '%s' instead for 'makeIntensity'\n", token ); - FS_FreeImage( pic ); - return NULL; - } - - *samples = 1; - *flags |= TF_INTENSITY; - *flags &= ~TF_LUMINANCE; - *flags &= ~TF_NORMALMAP; - - return R_MakeIntensity( pic ); -} - -/* -================= -R_ParseMakeLuminance -================= -*/ -static rgbdata_t *R_ParseMakeLuminance( char **script, int *samples, texFlags_t *flags ) -{ - char token[256]; - rgbdata_t *pic; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "(" )) - { - MsgDev( D_WARN, "expected '(', found '%s' instead for 'makeLuminance'\n", token ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'makeLuminance'\n" ); - return NULL; - } - - pic = R_LoadImage( script, token, NULL, 0, samples, flags ); - if( !pic ) return NULL; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, ")" )) - { - MsgDev( D_WARN, "expected ')', found '%s' instead for 'makeLuminance'\n", token ); - FS_FreeImage( pic ); - return NULL; - } - - *samples = 1; - *flags |= TF_LUMINANCE; - *flags &= ~TF_INTENSITY; - *flags &= ~TF_NORMALMAP; - - return R_MakeIntensity( pic ); -} - -/* -================= -R_ParseMakeAlpha -================= -*/ -static rgbdata_t *R_ParseMakeAlpha( char **script, int *samples, texFlags_t *flags ) -{ - char token[256]; - rgbdata_t *pic; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "(" )) - { - MsgDev( D_WARN, "expected '(', found '%s' instead for 'makeAlpha'\n", token ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'makeAlpha'\n" ); - return NULL; - } - - pic = R_LoadImage( script, token, NULL, 0, samples, flags ); - if( !pic ) return NULL; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, ")" )) - { - MsgDev( D_WARN, "expected ')', found '%s' instead for 'makeAlpha'\n", token ); - FS_FreeImage( pic ); - return NULL; - } - - *samples = 1; - *flags &= ~TF_INTENSITY; - *flags |= TF_HAS_ALPHA; - *flags &= ~TF_NORMALMAP; - - return R_MakeAlpha( pic ); -} - -/* -================= -R_ParseMakeLuma -================= -*/ -static rgbdata_t *R_ParseMakeLuma( char **script, int *samples, texFlags_t *flags ) -{ - char token[256]; - rgbdata_t *pic; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "(" )) - { - MsgDev( D_WARN, "expected '(', found '%s' instead for 'makeLuma'\n", token ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'makeLuma'\n" ); - return NULL; - } - - pic = R_LoadImage( script, token, NULL, 0, samples, flags ); - if( !pic ) return NULL; - - if( !( pic->flags & IMAGE_HAS_LUMA )) - { - MsgDev( D_WARN, "%s doesn't contain a luma-pixels for 'makeLuma'\n", token ); - FS_FreeImage( pic ); - return NULL; - } - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, ")" )) - { - MsgDev( D_WARN, "expected ')', found '%s' instead for 'makeLuma'\n", token ); - FS_FreeImage( pic ); - return NULL; - } - - *samples = 3; - - return R_MakeLuma( pic ); -} - -/* -================= -R_ParseStudioSkin -================= -*/ -static rgbdata_t *R_ParseStudioSkin( char **script, const byte *buf, size_t size, int *samples, texFlags_t *flags ) -{ - char token[256]; - string model_path; - string modelT_path; - string skinname; - rgbdata_t *pic; - studiohdr_t hdr; - file_t *f; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "(" )) - { - MsgDev( D_WARN, "expected '(', found '%s' instead for 'Studio'\n", token ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'Studio'\n" ); - return NULL; - } - - // NOTE: studio skin show as 'models/props/flame1.mdl/flame2a.bmp' - FS_ExtractFilePath( token, model_path ); - FS_StripExtension( model_path ); - Q_snprintf( modelT_path, MAX_STRING, "%sT.mdl", model_path ); - FS_DefaultExtension( model_path, ".mdl" ); - FS_FileBase( token, skinname ); - - // load it in - if( buf && size ) - { - pic = R_LoadImage( script, va( "#%s.mdl", skinname ), buf, size, samples, flags ); - if( !pic ) return NULL; - goto studio_done; - } - - FS_DefaultExtension( skinname, ".bmp" ); - f = FS_Open( model_path, "rb", false ); - - if( !f ) - { - MsgDev( D_WARN, "'Studio' can't find studiomodel %s\n", model_path ); - return NULL; - } - - if( FS_Read( f, &hdr, sizeof( hdr )) != sizeof( hdr )) - { - MsgDev( D_WARN, "'Studio' %s probably corrupted\n", model_path ); - FS_Close( f ); - return NULL; - } - - if( hdr.numtextures == 0 ) - { - // textures are keep seperate - FS_Close( f ); - f = FS_Open( modelT_path, "rb", false ); - - if( !f ) - { - MsgDev( D_WARN, "'Studio' can't find studiotextures %s\n", modelT_path ); - return NULL; - } - - if( FS_Read( f, &hdr, sizeof( hdr )) != sizeof( hdr )) - { - MsgDev( D_WARN, "'Studio' %s probably corrupted\n", modelT_path ); - FS_Close( f ); - return NULL; - } - } - - if( hdr.textureindex > 0 && hdr.numtextures <= MAXSTUDIOSKINS ) - { - // all ok, can load model into memory - mstudiotexture_t *ptexture, *tex; - size_t mdl_size, tex_size; - byte *pin; - int i; - - FS_Seek( f, 0, SEEK_END ); - mdl_size = FS_Tell( f ); - FS_Seek( f, 0, SEEK_SET ); - - pin = Mem_Alloc( r_temppool, mdl_size ); - - if( FS_Read( f, pin, mdl_size ) != mdl_size ) - { - MsgDev( D_WARN, "'Studio' %s probably corrupted\n", model_path ); - Mem_Free( pin ); - FS_Close( f ); - return NULL; - } - - ptexture = (mstudiotexture_t *)(pin + hdr.textureindex); - - // find specified texture - for( i = 0; i < hdr.numtextures; i++ ) - { - if( !Q_stricmp( ptexture[i].name, skinname )) - break; // found - } - - if( i == hdr.numtextures ) - { - MsgDev( D_WARN, "'Studio' %s doesn't have skin %s\n", model_path, skinname ); - Mem_Free( pin ); - FS_Close( f ); - return NULL; - } - - tex = ptexture + i; - - // NOTE: replace index with pointer to start of imagebuffer, ImageLib expected it - tex->index = (int)pin + tex->index; - tex_size = sizeof( mstudiotexture_t ) + tex->width * tex->height + 768; - - // load studio texture and bind it - FS_FileBase( skinname, skinname ); - - // load it in - pic = R_LoadImage( script, va( "#%s.mdl", tex->name ), (byte *)tex, tex_size, samples, flags ); - - // shutdown operations - Mem_Free( pin ); - FS_Close( f ); - - if( !pic ) return NULL; - } - else - { - MsgDev( D_WARN, "'Studio' %s has invalid skin count\n", model_path ); - FS_Close( f ); - return NULL; - } - -studio_done: - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, ")" )) - { - MsgDev( D_WARN, "expected ')', found '%s' instead for 'Studio'\n", token ); - FS_FreeImage( pic ); - return NULL; - } - - return pic; -} - -/* -================= -R_ParseSpriteFrame -================= -*/ -static rgbdata_t *R_ParseSpriteFrame( char **script, const byte *buf, size_t size, int *samples, texFlags_t *flags ) -{ - char token[256]; - rgbdata_t *pic; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "(" )) - { - MsgDev( D_WARN, "expected '(', found '%s' instead for 'Sprite'\n", token ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'Sprite'\n" ); - return NULL; - } - - pic = R_LoadImage( script, va( "#%s.spr", token ), buf, size, samples, flags ); - if( !pic ) return NULL; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, ")" )) - { - MsgDev( D_WARN, "expected ')', found '%s' instead for 'Sprite'\n", token ); - FS_FreeImage( pic ); - return NULL; - } - - return pic; -} - -/* -================= -R_ParseScrapBlock -================= -*/ -static rgbdata_t *R_ParseScrapBlock( char **script, int *samples, texFlags_t *flags ) -{ - int i, block[4]; - char token[256]; - rgbdata_t *pic; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "(" )) - { - MsgDev( D_WARN, "expected '(', found '%s' instead for 'scrapBlock'\n", token ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'scrapBlock'\n" ); - return NULL; - } - - pic = R_LoadImage( script, token, NULL, 0, samples, flags ); - if( !pic ) return NULL; - - for( i = 0; i < 4; i++ ) - { - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "," )) - { - MsgDev( D_WARN, "expected ',', found '%s' instead for 'rect'\n", token ); - FS_FreeImage( pic ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'block'\n" ); - FS_FreeImage( pic ); - return NULL; - } - - block[i] = Q_atoi( token ); -#if 0 - if( block[i] < 0 ) - { - MsgDev( D_WARN, "invalid argument %i for 'block'\n", i + 1 ); - FS_FreeImage( pic ); - return NULL; - } - - if((( i + 1 ) & 1 ) && block[i] > pic->width ) - { - MsgDev( D_WARN, "invalid argument %i for 'block'\n", i + 1 ); - FS_FreeImage( pic ); - return NULL; - } - - if((( i + 1 ) & 2 ) && block[i] > pic->height ) - { - MsgDev( D_WARN, "invalid argument %i for 'block'\n", i + 1 ); - FS_FreeImage( pic ); - return NULL; - } -#endif - } - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, ")" )) - { - MsgDev( D_WARN, "expected ')', found '%s' instead for 'bias'\n", token ); - FS_FreeImage( pic ); - return NULL; - } - - // check bounds silently - if( block[0] < 0 || block[0] > pic->width ) block[0] = 0; - if( block[1] < 0 || block[1] > pic->height ) block[1] = 0; - if( block[2] < 0 || block[2] > pic->width ) block[2] = pic->width; - if( block[3] < 0 || block[3] > pic->height ) block[3] = pic->height; - - if(( block[0] + block[2] > pic->width ) || ( block[1] + block[3] > pic->height )) - { - MsgDev( D_WARN, "'ScrapBlock' image size out of bounds\n" ); - FS_FreeImage( pic ); - return NULL; - } - - return R_MakeImageBlock( pic, block ); -} - -/* -================= -R_ParseHeightMap -================= -*/ -static rgbdata_t *R_ParseHeightMap( char **script, const byte *buf, size_t size, int *samples, texFlags_t *flags ) -{ - char token[256]; - rgbdata_t *pic; - float scale; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "(" )) - { - MsgDev( D_WARN, "expected '(', found '%s' instead for 'heightMap'\n", token ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'heightMap'\n" ); - return NULL; - } - - pic = R_LoadImage( script, token, buf, size, samples, flags ); - if( !pic ) return NULL; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "," )) - { - MsgDev( D_WARN, "expected ',', found '%s' instead for 'heightMap'\n", token ); - FS_FreeImage( pic ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'heightMap'\n" ); - FS_FreeImage( pic ); - return NULL; - } - - scale = Q_atof( token ); - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, ")" )) - { - MsgDev( D_WARN, "expected ')', found '%s' instead for 'heightMap'\n", token ); - FS_FreeImage( pic ); - return NULL; - } - - *samples = 3; - *flags &= ~TF_INTENSITY; - *flags &= ~TF_LUMINANCE; - *flags |= TF_NORMALMAP; - - return R_HeightMap( pic, scale ); -} - -/* -================= -R_ParseAddNormals -================= -*/ -static rgbdata_t *R_ParseAddNormals( char **script, int *samples, texFlags_t *flags ) -{ - char token[256]; - rgbdata_t *pic1, *pic2; - int samples1, samples2; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "(" )) - { - MsgDev( D_WARN, "expected '(', found '%s' instead for 'addNormals'\n", token ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'addNormals'\n" ); - return NULL; - } - - pic1 = R_LoadImage( script, token, NULL, 0, &samples1, flags ); - if( !pic1 ) return NULL; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "," )) - { - MsgDev( D_WARN, "expected ',', found '%s' instead for 'addNormals'\n", token ); - FS_FreeImage( pic1 ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'addNormals'\n" ); - FS_FreeImage( pic1 ); - return NULL; - } - - pic2 = R_LoadImage( script, token, NULL, 0, &samples2, flags ); - if( !pic2 ) - { - FS_FreeImage( pic1 ); - return NULL; - } - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, ")" )) - { - MsgDev( D_WARN, "expected ')', found '%s' instead for 'addNormals'\n", token ); - FS_FreeImage( pic1 ); - FS_FreeImage( pic2 ); - return NULL; - } - - if( pic1->width != pic2->width || pic1->height != pic2->height ) - { - MsgDev( D_WARN, "images for 'addNormals' have mismatched dimensions [%ix%i] != [%ix%i]\n", - pic1->width, pic1->height, pic2->width, pic2->height ); - FS_FreeImage( pic1 ); - FS_FreeImage( pic2 ); - return NULL; - } - - *samples = 3; - *flags &= ~TF_INTENSITY; - *flags &= ~TF_LUMINANCE; - *flags |= TF_NORMALMAP; - - return R_AddNormals( pic1, pic2 ); -} - -/* -================= -R_ParseSmoothNormals -================= -*/ -static rgbdata_t *R_ParseSmoothNormals( char **script, int *samples, texFlags_t *flags ) -{ - char token[256]; - rgbdata_t *pic; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "(" )) - { - MsgDev( D_WARN, "expected '(', found '%s' instead for 'smoothNormals'\n", token ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'smoothNormals'\n" ); - return NULL; - } - - pic = R_LoadImage( script, token, NULL, 0, samples, flags ); - if( !pic ) return NULL; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, ")" )) - { - MsgDev( D_WARN, "expected ')', found '%s' instead for 'smoothNormals'\n", token ); - FS_FreeImage( pic ); - return NULL; - } - - *samples = 3; - *flags &= ~TF_INTENSITY; - *flags &= ~TF_LUMINANCE; - *flags |= TF_NORMALMAP; - - return R_SmoothNormals( pic ); -} - -/* -================= -R_ParseDepthmap -================= -*/ -static rgbdata_t *R_ParseDepthmap( char **script, const byte *buf, size_t size, int *samples, texFlags_t *flags ) -{ - char token[256]; - rgbdata_t *pic1, *pic2; - int samples1, samples2; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "(" )) - { - MsgDev( D_WARN, "expected '(', found '%s' instead for 'mergeDepthmap'\n", token ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'mergeDepthmap'\n" ); - return NULL; - } - - pic1 = R_LoadImage( script, token, buf, size, &samples1, flags ); - if( !pic1 ) return NULL; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "," )) - { - MsgDev( D_WARN, "expected ',', found '%s' instead for 'mergeDepthmap'\n", token ); - FS_FreeImage( pic1 ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'mergeDepthmap'\n" ); - FS_FreeImage( pic1 ); - return NULL; - } - - *samples = 3; - pic2 = R_LoadImage( script, token, buf, size, &samples2, flags ); - if( !pic2 ) return pic1; // don't free normalmap - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, ")" )) - { - MsgDev( D_WARN, "expected ')', found '%s' instead for 'mergeDepthmap'\n", token ); - - FS_FreeImage( pic1 ); - FS_FreeImage( pic2 ); - return NULL; - } - - if( pic1->width != pic2->width || pic1->height != pic2->height ) - { - MsgDev( D_WARN, "images for 'mergeDepthmap' have mismatched dimensions [%ix%i] != [%ix%i]\n", - pic1->width, pic1->height, pic2->width, pic2->height ); - - FS_FreeImage( pic2 ); - return pic1; // don't free normalmap - } - - *samples = 4; - *flags &= ~TF_INTENSITY; - - return R_IncludeDepthmap( pic1, pic2 ); -} - -/* -================= -R_ParseClearPixels -================= -*/ -static rgbdata_t *R_ParseClearPixels( char **script, int *samples, texFlags_t *flags ) -{ - char token[256]; - qboolean clearAlpha; - rgbdata_t *pic; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "(" )) - { - MsgDev( D_WARN, "expected '(', found '%s' instead for 'clearPixels'\n", token ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'clearPixels'\n" ); - return NULL; - } - - pic = R_LoadImage( script, token, NULL, 0, samples, flags ); - if( !pic ) return NULL; - - *script = COM_ParseFile( *script, token ); - if( !Q_stricmp( token, "alpha" )) - { - *script = COM_ParseFile( *script, token ); - clearAlpha = true; - } - else if( !Q_stricmp( token, "color" )) - { - *script = COM_ParseFile( *script, token ); - clearAlpha = false; - } - else if( !Q_stricmp( token, ")" )) - { - clearAlpha = false; // clear color as default - } - else *script = COM_ParseFile( *script, token ); // skip unknown token - - if( Q_stricmp( token, ")" )) - { - MsgDev( D_WARN, "expected ')', found '%s' instead for 'clearPixels'\n", token ); - FS_FreeImage( pic ); - return NULL; - } - - *samples = clearAlpha ? 3 : 1; - if( clearAlpha ) *flags &= ~TF_HAS_ALPHA; - *flags &= ~TF_INTENSITY; - - return R_ClearPixels( pic, clearAlpha ); -} - -/* -================= -R_ParseMovePixels -================= -*/ -static rgbdata_t *R_ParseMovePixels( char **script, int *samples, texFlags_t *flags ) -{ - char token[256]; - qboolean alphaToColor; - rgbdata_t *pic; - - *script = COM_ParseFile( *script, token ); - if( Q_stricmp( token, "(" )) - { - MsgDev( D_WARN, "expected '(', found '%s' instead for 'movePixels'\n", token ); - return NULL; - } - - if(( *script = COM_ParseFile( *script, token )) == NULL ) - { - MsgDev( D_WARN, "missing parameters for 'movePixels'\n" ); - return NULL; - } - - pic = R_LoadImage( script, token, NULL, 0, samples, flags ); - if( !pic ) return NULL; - - *script = COM_ParseFile( *script, token ); - if( !Q_stricmp( token, "AlphaToColor" )) - { - *script = COM_ParseFile( *script, token ); - alphaToColor = true; - } - else if( !Q_stricmp( token, "ColorToAlpha" )) - { - *script = COM_ParseFile( *script, token ); - alphaToColor = false; - } - else if( !Q_stricmp( token, ")" )) - { - alphaToColor = true; // move alpha to color as default - } - else *script = COM_ParseFile( *script, token ); // skip unknown token - - if( Q_stricmp( token, ")" )) - { - MsgDev( D_WARN, "expected ')', found '%s' instead for 'movePixels'\n", token ); - FS_FreeImage( pic ); - return NULL; - } - - *samples = alphaToColor ? 3 : 1; - if( alphaToColor ) *flags &= ~TF_HAS_ALPHA; - *flags &= ~TF_INTENSITY; - - return R_MovePixels( pic, alphaToColor ); -} - -/* -================= -R_LoadImage -================= -*/ -static rgbdata_t *R_LoadImage( char **script, const char *name, const byte *buf, size_t size, int *samples, texFlags_t *flags ) -{ - if( !Q_stricmp( name, "add" )) - return R_ParseAdd( script, samples, flags ); - else if( !Q_stricmp( name, "multiply" )) - return R_ParseMultiply( script, samples, flags ); - else if( !Q_stricmp( name, "bias" )) - return R_ParseBias( script, samples, flags ); - else if( !Q_stricmp( name, "scale")) - return R_ParseScale( script, samples, flags ); - else if( !Q_stricmp( name, "invertColor" )) - return R_ParseInvertColor( script, samples, flags ); - else if( !Q_stricmp( name, "invertAlpha" )) - return R_ParseInvertAlpha( script, samples, flags ); - else if( !Q_stricmp( name, "makeIntensity" )) - return R_ParseMakeIntensity( script, samples, flags ); - else if( !Q_stricmp( name, "makeLuminance" )) - return R_ParseMakeLuminance( script, samples, flags); - else if( !Q_stricmp( name, "makeAlpha" )) - return R_ParseMakeAlpha( script, samples, flags ); - else if( !Q_stricmp( name, "makeLuma" )) - return R_ParseMakeLuma( script, samples, flags ); - else if( !Q_stricmp( name, "heightMap" )) - return R_ParseHeightMap( script, buf, size, samples, flags ); - else if( !Q_stricmp( name, "ScrapBlock" )) - return R_ParseScrapBlock( script, samples, flags ); - else if( !Q_stricmp( name, "addNormals" )) - return R_ParseAddNormals( script, samples, flags ); - else if( !Q_stricmp( name, "smoothNormals" )) - return R_ParseSmoothNormals( script, samples, flags ); - else if( !Q_stricmp( name, "mergeDepthmap" )) - return R_ParseDepthmap( script, buf, size, samples, flags ); - else if( !Q_stricmp( name, "clearPixels" )) - return R_ParseClearPixels( script, samples, flags ); - else if( !Q_stricmp( name, "movePixels" )) - return R_ParseMovePixels( script, samples, flags ); - else if( !Q_stricmp( name, "Studio" )) - return R_ParseStudioSkin( script, buf, size, samples, flags ); - else if( !Q_stricmp( name, "Sprite" )) - return R_ParseSpriteFrame( script, buf, size, samples, flags ); - else - { - // loading form disk - rgbdata_t *image = FS_LoadImage( name, buf, size ); - - // we can't decompress DXT texture - if( image && ImageDXT( image->type )) - { - FS_FreeImage( image ); - return NULL; - } - - if( image ) *samples = GL_CalcTextureSamples( image->flags ); - - return image; - } - - return NULL; -} - /* ================ R_FreeImage diff --git a/engine/client/gl_local.h b/engine/client/gl_local.h index 0d26fc15..9283df74 100644 --- a/engine/client/gl_local.h +++ b/engine/client/gl_local.h @@ -70,6 +70,7 @@ typedef struct gltexture_s GLuint target; // glTarget GLuint texnum; // gl texture binding GLint format; // uploaded format + GLint encode; // using GLSL decoder texFlags_t flags; rgba_t fogParams; // some water textures diff --git a/engine/client/gl_rmain.c b/engine/client/gl_rmain.c index 83370794..ac49d123 100644 --- a/engine/client/gl_rmain.c +++ b/engine/client/gl_rmain.c @@ -1406,6 +1406,9 @@ static int GL_RenderGetParm( int parm, int arg ) case PARM_TEX_GLFORMAT: glt = R_GetTexture( arg ); return glt->format; + case PARM_TEX_ENCODE: + glt = R_GetTexture( arg ); + return glt->encode; case PARM_TEX_SKYBOX: ASSERT( arg >= 0 && arg < 6 ); return tr.skyboxTextures[arg]; diff --git a/engine/client/gl_studio.c b/engine/client/gl_studio.c index 33484637..52a77b94 100644 --- a/engine/client/gl_studio.c +++ b/engine/client/gl_studio.c @@ -3373,9 +3373,6 @@ static void R_StudioLoadTexture( model_t *mod, studiohdr_t *phdr, mstudiotexture imgfilter_t *filter = NULL; texture_t *tx = NULL; - if( ptexture->flags & STUDIO_NF_TRANSPARENT ) - flags |= (TF_CLAMP|TF_NOMIPMAP); - if( ptexture->flags & STUDIO_NF_NORMALMAP ) flags |= (TF_NORMALMAP); diff --git a/engine/common/build.c b/engine/common/build.c index ce9bc748..8822c162 100644 --- a/engine/common/build.c +++ b/engine/common/build.c @@ -23,7 +23,7 @@ static char mond[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; int Q_buildnum( void ) { // do not touch this! Only author of Xash3D can increase buildnumbers! -#if 1 +#if 0 int m = 0, d = 0, y = 0; static int b = 0; @@ -48,6 +48,6 @@ int Q_buildnum( void ) return b; #else - return 3308; + return 3366; #endif } \ No newline at end of file diff --git a/engine/common/common.h b/engine/common/common.h index db4ea639..2acfc5d3 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -85,7 +85,7 @@ typedef enum #include "com_model.h" #include "crtlib.h" -#define XASH_VERSION 0.97f // engine current version +#define XASH_VERSION 0.98f // engine current version // PERFORMANCE INFO #define MIN_FPS 15.0 // host minimum fps value for maxfps. @@ -459,6 +459,18 @@ typedef enum IL_DDS_HARDWARE = BIT(4), // DXT compression is support } ilFlags_t; +// goes into rgbdata_t->encode +#define DXT_ENCODE_DEFAULT 0 // don't use custom encoders +#define DXT_ENCODE_COLOR_YCoCg 0x1A01 // make sure that value dosn't collide with anything +#define DXT_ENCODE_ALPHA_1BIT 0x1A02 // normal 1-bit alpha +#define DXT_ENCODE_ALPHA_8BIT 0x1A03 // normal 8-bit alpha +#define DXT_ENCODE_ALPHA_SDF 0x1A04 // signed distance field +#define DXT_ENCODE_NORMAL_AG_ORTHO 0x1A05 // orthographic projection +#define DXT_ENCODE_NORMAL_AG_STEREO 0x1A06 // stereographic projection +#define DXT_ENCODE_NORMAL_AG_PARABOLOID 0x1A07 // paraboloid projection +#define DXT_ENCODE_NORMAL_AG_QUARTIC 0x1A08 // newton method +#define DXT_ENCODE_NORMAL_AG_AZIMUTHAL 0x1A09 // Lambert Azimuthal Equal-Area + // rgbdata output flags typedef enum { @@ -506,6 +518,7 @@ typedef struct rgbdata_s word depth; // image depth uint type; // compression type uint flags; // misc image flags + word encode; // DXT may have custom encoder, that will be decoded in GLSL-side byte numMips; // mipmap count byte *palette; // palette if present byte *buffer; // image buffer @@ -651,6 +664,7 @@ CLIENT / SERVER SYSTEMS void CL_Init( void ); void CL_Shutdown( void ); void Host_ClientFrame( void ); +void Host_RenderFrame( void ); qboolean CL_Active( void ); void SV_Init( void ); diff --git a/engine/common/filesystem.c b/engine/common/filesystem.c index 4565bf71..f0693ea2 100644 --- a/engine/common/filesystem.c +++ b/engine/common/filesystem.c @@ -2981,14 +2981,29 @@ WADSYSTEM PRIVATE COMMON FUNCTIONS ============================================================================= */ // associate extension with wad type -static const wadtype_t wad_types[] = +static const wadtype_t wad_types[6] = { -{ "pal", TYP_QPAL }, // palette -{ "lmp", TYP_QPIC }, // quake1, hl pic -{ "fnt", TYP_QFONT }, // hl qfonts -{ "mip", TYP_MIPTEX }, // hl/q1 mip -{ "raw", TYP_RAW }, // signed raw data -{ NULL, TYP_NONE } +{ "pal", TYP_PALETTE }, // palette +{ "dds", TYP_DDSTEX }, // DDS image +{ "lmp", TYP_GFXPIC }, // quake1, hl pic +{ "fnt", TYP_QFONT }, // hl qfonts +{ "mip", TYP_MIPTEX }, // hl/q1 mip +{ NULL, TYP_NONE } +}; + +// suffix converts to img_type and back +static const wadtype_t wad_hints[10] = +{ +{ "", IMG_DIFFUSE }, // no suffix +{ "_mask", IMG_ALPHAMASK }, // alpha-channel stored to another lump +{ "_norm", IMG_NORMALMAP }, // indexed normalmap +{ "_spec", IMG_GLOSSMAP }, // grayscale\color specular +{ "_gpow", IMG_GLOSSPOWER }, // grayscale gloss power +{ "_hmap", IMG_HEIGHTMAP }, // heightmap (can be converted to normalmap) +{ "_luma", IMG_LUMA }, // self-illuminate parts on the diffuse +{ "_adec", IMG_DECAL_ALPHA }, // classic HL-decal (with alpha-channel) +{ "_cdec", IMG_DECAL_COLOR }, // paranoia decal (base 127 127 127) +{ NULL, 0 } // terminator }; static char W_TypeFromExt( const char *lumpname ) @@ -3002,12 +3017,19 @@ static char W_TypeFromExt( const char *lumpname ) for( type = wad_types; type->ext; type++ ) { - if(!Q_stricmp( ext, type->ext )) + if( !Q_stricmp( ext, type->ext )) return type->type; } return TYP_NONE; } +/* +=========== +W_ExtFromType + +Convert type to extension +=========== +*/ static const char *W_ExtFromType( char lumptype ) { const wadtype_t *type; @@ -3024,35 +3046,87 @@ static const char *W_ExtFromType( char lumptype ) return ""; } +/* +=========== +W_HintFromSuf + +Convert name suffix into image type +=========== +*/ +char W_HintFromSuf( const char *lumpname ) +{ + char barename[64]; + char suffix[8]; + const wadtype_t *hint; + + // trying to extract hint from the name + FS_FileBase( lumpname, barename ); + Q_strncpy( suffix, barename + Q_strlen( barename ) - HINT_NAMELEN, sizeof( suffix )); + + // we not known about filetype, so match only by filename + for( hint = wad_hints; hint->ext; hint++ ) + { + if( !Q_stricmp( suffix, hint->ext )) + return hint->type; + } + + // no any special type was found + return IMG_DIFFUSE; +} + static dlumpinfo_t *W_FindLump( wfile_t *wad, const char *name, const char matchtype ) { - int left, right, middle; + char img_type = IMG_DIFFUSE; + char barename[64], suffix[8]; + int left, right; + const wadtype_t *hint; if( !wad || !wad->lumps || matchtype == TYP_NONE ) return NULL; + // trying to extract hint from the name + FS_FileBase( name, barename ); + Q_strncpy( suffix, barename + Q_strlen( barename ) - HINT_NAMELEN, sizeof( suffix )); + + // we not known about filetype, so match only by filename + for( hint = wad_hints; hint->ext; hint++ ) + { + if( !Q_stricmp( suffix, hint->ext )) + { + img_type = hint->type; + break; + } + } + + if( img_type != IMG_DIFFUSE ) + barename[Q_strlen( barename ) - HINT_NAMELEN] = '\0'; // kill the suffix + // look for the file (binary search) left = 0; right = wad->numlumps - 1; while( left <= right ) { - int diff; + int middle = (left + right) / 2; + int diff = Q_stricmp( wad->lumps[middle].name, barename ); - middle = (left + right) / 2; - diff = Q_stricmp( wad->lumps[middle].name, name ); - - // Found it if( !diff ) { - if( matchtype == TYP_ANY || matchtype == wad->lumps[middle].type ) + if( wad->lumps[middle].img_type > img_type ) + diff = 1; + else if( wad->lumps[middle].img_type < img_type ) + diff = -1; + else if(( matchtype == TYP_ANY ) || ( matchtype == wad->lumps[middle].type )) return &wad->lumps[middle]; // found - else break; + else if( wad->lumps[middle].type < matchtype ) + diff = 1; + else if( wad->lumps[middle].type > matchtype ) + diff = -1; + else break; // not found } // if we're too far in the list - if( diff > 0 ) - right = middle - 1; + if( diff > 0 ) right = middle - 1; else left = middle + 1; } @@ -3066,49 +3140,53 @@ FS_AddFileToWad Add a file to the list of files contained into a package ==================== */ -static dlumpinfo_t *W_AddFileToWad( const char *name, wfile_t *wad, int filepos, int packsize, int realsize, char type, char compression ) +static dlumpinfo_t *W_AddFileToWad( const char *name, wfile_t *wad, dlumpinfo_t *newlump ) { - int left, right, middle; + int left, right; dlumpinfo_t *plump; + // convert all qmip types to miptex + if( newlump->type == TYP_RAWDATA ) + newlump->type = TYP_MIPTEX; + + // check for Quake 'conchars' issues (only lmp loader supposed to read this lame pic) + if( !Q_stricmp( newlump->name, "conchars" ) && newlump->type == TYP_RAWDATA ) + newlump->type = TYP_GFXPIC; + // look for the slot we should put that file into (binary search) left = 0; right = wad->numlumps - 1; while( left <= right ) { - int diff; + int middle = ( left + right ) / 2; + int diff = Q_stricmp( wad->lumps[middle].name, name ); - middle = ( left + right ) / 2; - diff = Q_stricmp( wad->lumps[middle].name, name ); - - // If we found the file, there's a problem - if( !diff ) MsgDev( D_NOTE, "Wad %s contains the file %s several times\n", wad->filename, name ); + if( !diff ) + { + if( wad->lumps[middle].img_type > newlump->img_type ) + diff = 1; + else if( wad->lumps[middle].img_type < newlump->img_type ) + diff = -1; + else if( wad->lumps[middle].type < newlump->type ) + diff = 1; + else if( wad->lumps[middle].type > newlump->type ) + diff = -1; + else MsgDev( D_NOTE, "Wad %s contains the file %s several times\n", wad->filename, name ); + } // If we're too far in the list if( diff > 0 ) right = middle - 1; else left = middle + 1; } - // We have to move the right of the list by one slot to free the one we need + // we have to move the right of the list by one slot to free the one we need plump = &wad->lumps[left]; - Q_memmove( plump + 1, plump, ( wad->numlumps - left ) * sizeof( *plump )); + memmove( plump + 1, plump, ( wad->numlumps - left ) * sizeof( *plump )); wad->numlumps++; - Q_memcpy( plump->name, name, sizeof( plump->name )); - plump->filepos = filepos; - plump->disksize = realsize; - plump->size = packsize; - plump->compression = compression; - - // convert all qmip types to miptex - if( type == TYP_QMIP ) - plump->type = TYP_MIPTEX; - else plump->type = type; - - // check for Quake 'conchars' issues (only lmp loader supposed to read this lame pic) - if( !Q_stricmp( plump->name, "conchars" ) && plump->type == TYP_QMIP ) - plump->type = TYP_QPIC; + *plump = *newlump; + memcpy( plump->name, name, sizeof( plump->name )); return plump; } @@ -3147,7 +3225,7 @@ static qboolean W_ReadLumpTable( wfile_t *wad ) k = Q_strlen( Q_strrchr( name, '*' )); if( k ) name[Q_strlen( name ) - k] = '!'; // quake1 issues (can't save images that contain '*' symbol) - W_AddFileToWad( name, wad, srclumps[i].filepos, srclumps[i].size, srclumps[i].disksize, srclumps[i].type, srclumps[i].compression ); + W_AddFileToWad( name, wad, &srclumps[i] ); } // release source lumps diff --git a/engine/common/filesystem.h b/engine/common/filesystem.h index f5a6935e..54583ec9 100644 --- a/engine/common/filesystem.h +++ b/engine/common/filesystem.h @@ -62,7 +62,8 @@ infotable dlumpinfo_t[dwadinfo_t->numlumps] #define IDWAD3HEADER (('3'<<24)+('D'<<16)+('A'<<8)+'W') // little-endian "WAD3" half-life wads #define WAD3_NAMELEN 16 -#define MAX_FILES_IN_WAD 8192 +#define HINT_NAMELEN 5 // e.g. _mask, _norm +#define MAX_FILES_IN_WAD 65535 // real limit as above <2Gb size not a lumpcount // hidden virtual lump types #define TYP_ANY -1 // any type can be accepted @@ -79,14 +80,14 @@ typedef struct typedef struct { - int filepos; - int disksize; + int filepos; // file offset in WAD + int disksize; // compressed or uncompressed int size; // uncompressed - char type; - char compression; // probably not used - char pad1; - char pad2; - char name[16]; // must be null terminated + char type; // TYP_* + char attribs; // file attribs + char img_type; // IMG_* + char pad; + char name[WAD3_NAMELEN]; // must be null terminated } dlumpinfo_t; #include "custom.h" diff --git a/engine/common/imagelib/imagelib.h b/engine/common/imagelib/imagelib.h index 655cceae..3a8606af 100644 --- a/engine/common/imagelib/imagelib.h +++ b/engine/common/imagelib/imagelib.h @@ -68,6 +68,7 @@ typedef struct imglib_s word height; word depth; byte num_mips; // mipmap count + word encode; // custom encode type uint type; // main type switcher uint flags; // additional image flags size_t size; // image rgba size (for bounds checking) diff --git a/engine/common/imagelib/img_dds.c b/engine/common/imagelib/img_dds.c index 57559c77..dd6efdfc 100644 --- a/engine/common/imagelib/img_dds.c +++ b/engine/common/imagelib/img_dds.c @@ -102,14 +102,6 @@ void Image_DXTGetPixelFormat( dds_t *hdr ) if( !( hdr->dsCaps.dwCaps2 & DDS_VOLUME )) hdr->dwDepth = 1; - image.flags |= IMAGE_HAS_COLOR; // predict state - - if( hdr->dsPixelFormat.dwFlags & DDS_ALPHA ) - image.flags |= IMAGE_HAS_ALPHA; - - if( hdr->dsPixelFormat.dwFlags & DDS_LUMINANCE ) - image.flags &= ~IMAGE_HAS_COLOR; - if( hdr->dsPixelFormat.dwFlags & DDS_FOURCC ) { switch( hdr->dsPixelFormat.dwFourCC ) @@ -157,9 +149,6 @@ void Image_DXTGetPixelFormat( dds_t *hdr ) if( hdr->dsCaps.dwCaps1 & DDS_COMPLEX && hdr->dsCaps.dwCaps2 & DDS_CUBEMAP ) image.flags |= IMAGE_CUBEMAP; - if( hdr->dsPixelFormat.dwFlags & DDS_ALPHAPIXELS ) - image.flags |= IMAGE_HAS_ALPHA; - if( hdr->dwFlags & DDS_MIPMAPCOUNT ) image.num_mips = hdr->dwMipMapCount; // get actual mip count } @@ -180,18 +169,17 @@ size_t Image_DXTGetLinearSize( int type, int width, int height, int depth ) return 0; } -uint Image_DXTCalcMipmapSize( dds_t *hdr ) +size_t Image_DXTCalcMipmapSize( dds_t *hdr ) { - uint buffsize = 0; - int w = hdr->dwWidth; - int h = hdr->dwHeight; - int i, mipsize = 0; + size_t buffsize = 0; + int i, width, height; // now correct buffer size - for( i = 0; i < max( 1, image.num_mips ); i++, buffsize += mipsize ) + for( i = 0; i < hdr->dwMipMapCount; i++ ) { - mipsize = Image_DXTGetLinearSize( image.type, w, h, image.depth ); - w = (w+1)>>1, h = (h+1)>>1; + width = max( 1, ( hdr->dwWidth >> i )); + height = max( 1, ( hdr->dwHeight >> i )); + buffsize += Image_DXTGetLinearSize( image.type, width, height, image.depth ); } return buffsize; @@ -301,14 +289,28 @@ qboolean Image_LoadDDS( const char *name, const byte *buffer, size_t filesize ) if( image.size == 0 ) return false; // just in case fin = (byte *)(buffer + sizeof( dds_t )); - // check for real alpha-pixels - if( image.type == PF_DXT3 && Image_CheckDXT3Alpha( &header, fin )) + // copy an encode method + image.encode = (word)header.dwReserved1[0]; + + switch( image.encode ) { - image.flags |= IMAGE_HAS_ALPHA; - } - else if( image.type == PF_DXT5 && Image_CheckDXT5Alpha( &header, fin )) - { - image.flags |= IMAGE_HAS_ALPHA; + case DXT_ENCODE_COLOR_YCoCg: + image.flags |= IMAGE_HAS_COLOR; + break; + case DXT_ENCODE_NORMAL_AG_ORTHO: + case DXT_ENCODE_NORMAL_AG_STEREO: + case DXT_ENCODE_NORMAL_AG_PARABOLOID: + case DXT_ENCODE_NORMAL_AG_QUARTIC: + case DXT_ENCODE_NORMAL_AG_AZIMUTHAL: + image.flags |= IMAGE_HAS_COLOR; + break; + default: // check for real alpha-pixels + if( image.type == PF_DXT3 && Image_CheckDXT3Alpha( &header, fin )) + image.flags |= IMAGE_HAS_ALPHA; + else if( image.type == PF_DXT5 && Image_CheckDXT5Alpha( &header, fin )) + image.flags |= IMAGE_HAS_ALPHA; + image.flags |= IMAGE_HAS_COLOR; + break; } // dds files will be uncompressed on a render. requires minimal of info for set this diff --git a/engine/common/imagelib/img_main.c b/engine/common/imagelib/img_main.c index a10d1204..71d53b20 100644 --- a/engine/common/imagelib/img_main.c +++ b/engine/common/imagelib/img_main.c @@ -107,6 +107,7 @@ void Image_Reset( void ) image.fogParams[1] = 0; image.fogParams[2] = 0; image.fogParams[3] = 0; + image.encode = 0; // pointers will be saved with prevoius picture struct // don't care about it @@ -146,6 +147,7 @@ rgbdata_t *ImagePack( void ) pack->buffer = image.rgba; pack->width = image.width; pack->height = image.height; + pack->depth = image.depth; pack->type = image.type; pack->size = image.size; } @@ -159,7 +161,7 @@ rgbdata_t *ImagePack( void ) pack->flags = image.flags; pack->numMips = image.num_mips; pack->palette = image.palette; - pack->depth = image.depth; + pack->encode = image.encode; return pack; }