123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493 |
- /*
- ===========================================================================
- Doom 3 BFG Edition GPL Source Code
- Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
- Doom 3 BFG Edition Source Code 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.
- Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
- If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
- ===========================================================================
- */
- #pragma hdrstop
- #include "../idlib/precompiled.h"
- #include "tr_local.h"
- /*
- ================
- R_ResampleTexture
- Used to resample images in a more general than quartering fashion.
- This will only have filter coverage if the resampled size
- is greater than half the original size.
- If a larger shrinking is needed, use the mipmap function
- after resampling to the next lower power of two.
- ================
- */
- #define MAX_DIMENSION 4096
- byte *R_ResampleTexture( const byte *in, int inwidth, int inheight,
- int outwidth, int outheight ) {
- int i, j;
- const byte *inrow, *inrow2;
- unsigned int frac, fracstep;
- unsigned int p1[MAX_DIMENSION], p2[MAX_DIMENSION];
- const byte *pix1, *pix2, *pix3, *pix4;
- byte *out, *out_p;
- if ( outwidth > MAX_DIMENSION ) {
- outwidth = MAX_DIMENSION;
- }
- if ( outheight > MAX_DIMENSION ) {
- outheight = MAX_DIMENSION;
- }
- out = (byte *)R_StaticAlloc( outwidth * outheight * 4, TAG_IMAGE );
- out_p = out;
- fracstep = inwidth*0x10000/outwidth;
- frac = fracstep>>2;
- for ( i=0 ; i<outwidth ; i++ ) {
- p1[i] = 4*(frac>>16);
- frac += fracstep;
- }
- frac = 3*(fracstep>>2);
- for ( i=0 ; i<outwidth ; i++ ) {
- p2[i] = 4*(frac>>16);
- frac += fracstep;
- }
- for (i=0 ; i<outheight ; i++, out_p += outwidth*4 ) {
- inrow = in + 4 * inwidth * (int)( ( i + 0.25f ) * inheight / outheight );
- inrow2 = in + 4 * inwidth * (int)( ( i + 0.75f ) * inheight / outheight );
- frac = fracstep >> 1;
- for (j=0 ; j<outwidth ; j++) {
- pix1 = inrow + p1[j];
- pix2 = inrow + p2[j];
- pix3 = inrow2 + p1[j];
- pix4 = inrow2 + p2[j];
- out_p[j*4+0] = (pix1[0] + pix2[0] + pix3[0] + pix4[0])>>2;
- out_p[j*4+1] = (pix1[1] + pix2[1] + pix3[1] + pix4[1])>>2;
- out_p[j*4+2] = (pix1[2] + pix2[2] + pix3[2] + pix4[2])>>2;
- out_p[j*4+3] = (pix1[3] + pix2[3] + pix3[3] + pix4[3])>>2;
- }
- }
- return out;
- }
- /*
- ================
- R_Dropsample
- Used to resample images in a more general than quartering fashion.
- Normal maps and such should not be bilerped.
- ================
- */
- byte *R_Dropsample( const byte *in, int inwidth, int inheight,
- int outwidth, int outheight ) {
- int i, j, k;
- const byte *inrow;
- const byte *pix1;
- byte *out, *out_p;
- out = (byte *)R_StaticAlloc( outwidth * outheight * 4, TAG_IMAGE );
- out_p = out;
- for (i=0 ; i<outheight ; i++, out_p += outwidth*4 ) {
- inrow = in + 4*inwidth*(int)((i+0.25)*inheight/outheight);
- for (j=0 ; j<outwidth ; j++) {
- k = j * inwidth / outwidth;
- pix1 = inrow + k * 4;
- out_p[j*4+0] = pix1[0];
- out_p[j*4+1] = pix1[1];
- out_p[j*4+2] = pix1[2];
- out_p[j*4+3] = pix1[3];
- }
- }
- return out;
- }
- /*
- ================
- R_SetAlphaNormalDivergence
- If any of the angles inside the cone would directly reflect to the light, there will be
- a specular highlight. The intensity of the highlight is inversely proportional to the
- area of the spread.
- Light source area is important for the base size.
- area subtended in light is the divergence times the distance
- Shininess value is subtracted from the divergence
- Sets the alpha channel to the greatest divergence dot product of the surrounding texels.
- 1.0 = flat, 0.0 = turns a 90 degree angle
- Lower values give less shiny specular
- With mip maps, the lowest samnpled value will be retained
- Should we rewrite the normal as the centered average?
- ================
- */
- void R_SetAlphaNormalDivergence( byte *in, int width, int height ) {
- for ( int y = 0 ; y < height ; y++ ) {
- for ( int x = 0 ; x < width ; x++ ) {
- // the divergence is the smallest dot product of any of the eight surrounding texels
- byte *pic_p = in + ( y * width + x ) * 4;
- idVec3 center;
- center[0] = ( pic_p[0] - 128 ) / 127;
- center[1] = ( pic_p[1] - 128 ) / 127;
- center[2] = ( pic_p[2] - 128 ) / 127;
- center.Normalize();
- float maxDiverge = 1.0;
- // FIXME: this assumes wrap mode, but should handle clamp modes and border colors
- for ( int yy = -1 ; yy <= 1 ; yy++ ) {
- for ( int xx = -1 ; xx <= 1 ; xx++ ) {
- if ( yy == 0 && xx == 0 ) {
- continue;
- }
- byte *corner_p = in + ( ((y+yy)&(height-1)) * width + ((x+xx)&width-1) ) * 4;
- idVec3 corner;
- corner[0] = ( corner_p[0] - 128 ) / 127;
- corner[1] = ( corner_p[1] - 128 ) / 127;
- corner[2] = ( corner_p[2] - 128 ) / 127;
- corner.Normalize();
- float diverge = corner * center;
- if ( diverge < maxDiverge ) {
- maxDiverge = diverge;
- }
- }
- }
- // we can get a diverge < 0 in some extreme cases
- if ( maxDiverge < 0 ) {
- maxDiverge = 0;
- }
- pic_p[3] = maxDiverge * 255;
- }
- }
- }
- /*
- ================
- R_MipMapWithAlphaSpecularity
- Returns a new copy of the texture, quartered in size and filtered.
- The alpha channel is taken to be the minimum of the dots of all surrounding normals.
- ================
- */
- #define MIP_MIN(a,b) (a<b?a:b)
- byte *R_MipMapWithAlphaSpecularity( const byte *in, int width, int height ) {
- int i, j, c, x, y, sx, sy;
- const byte *in_p;
- byte *out, *out_p;
- int row;
- int newWidth, newHeight;
- float *fbuf, *fbuf_p;
- if ( width < 1 || height < 1 || ( width + height == 2 ) ) {
- common->FatalError( "R_MipMapWithAlphaMin called with size %i,%i", width, height );
- }
- // convert the incoming texture to centered floating point
- c = width * height;
- fbuf = (float *)_alloca( c * 4 * sizeof( *fbuf ) );
- in_p = in;
- fbuf_p = fbuf;
- for ( i = 0 ; i < c ; i++, in_p+=4, fbuf_p += 4 ) {
- fbuf_p[0] = ( in_p[0] / 255.0 ) * 2.0 - 1.0; // convert to a normal
- fbuf_p[1] = ( in_p[1] / 255.0 ) * 2.0 - 1.0;
- fbuf_p[2] = ( in_p[2] / 255.0 ) * 2.0 - 1.0;
- fbuf_p[3] = ( in_p[3] / 255.0 ); // filtered divegence / specularity
- }
- row = width * 4;
- newWidth = width >> 1;
- newHeight = height >> 1;
- if ( !newWidth ) {
- newWidth = 1;
- }
- if ( !newHeight ) {
- newHeight = 1;
- }
- out = (byte *)R_StaticAlloc( newWidth * newHeight * 4, TAG_IMAGE );
- out_p = out;
- in_p = in;
- for ( i=0 ; i<newHeight ; i++ ) {
- for ( j=0 ; j<newWidth ; j++, out_p+=4 ) {
- idVec3 total;
- float totalSpec;
- total.Zero();
- totalSpec = 0;
- // find the average normal
- for ( x = -1 ; x <= 1 ; x++ ) {
- sx = ( j * 2 + x ) & (width-1);
- for ( y = -1 ; y <= 1 ; y++ ) {
- sy = ( i * 2 + y ) & (height-1);
- fbuf_p = fbuf + ( sy * width + sx ) * 4;
- total[0] += fbuf_p[0];
- total[1] += fbuf_p[1];
- total[2] += fbuf_p[2];
- totalSpec += fbuf_p[3];
- }
- }
- total.Normalize();
- totalSpec /= 9.0;
- // find the maximum divergence
- for ( x = -1 ; x <= 1 ; x++ ) {
- for ( y = -1 ; y <= 1 ; y++ ) {
- }
- }
- // store the average normal and divergence
- }
- }
- return out;
- }
- float mip_gammaTable[256] = {
- 0.000000f, 0.000005f, 0.000023f, 0.000057f, 0.000107f, 0.000175f, 0.000262f, 0.000367f, 0.000493f, 0.000638f, 0.000805f, 0.000992f, 0.001202f, 0.001433f, 0.001687f, 0.001963f,
- 0.002263f, 0.002586f, 0.002932f, 0.003303f, 0.003697f, 0.004116f, 0.004560f, 0.005028f, 0.005522f, 0.006041f, 0.006585f, 0.007155f, 0.007751f, 0.008373f, 0.009021f, 0.009696f,
- 0.010398f, 0.011126f, 0.011881f, 0.012664f, 0.013473f, 0.014311f, 0.015175f, 0.016068f, 0.016988f, 0.017936f, 0.018913f, 0.019918f, 0.020951f, 0.022013f, 0.023104f, 0.024223f,
- 0.025371f, 0.026549f, 0.027755f, 0.028991f, 0.030257f, 0.031551f, 0.032876f, 0.034230f, 0.035614f, 0.037029f, 0.038473f, 0.039947f, 0.041452f, 0.042987f, 0.044553f, 0.046149f,
- 0.047776f, 0.049433f, 0.051122f, 0.052842f, 0.054592f, 0.056374f, 0.058187f, 0.060032f, 0.061907f, 0.063815f, 0.065754f, 0.067725f, 0.069727f, 0.071761f, 0.073828f, 0.075926f,
- 0.078057f, 0.080219f, 0.082414f, 0.084642f, 0.086901f, 0.089194f, 0.091518f, 0.093876f, 0.096266f, 0.098689f, 0.101145f, 0.103634f, 0.106156f, 0.108711f, 0.111299f, 0.113921f,
- 0.116576f, 0.119264f, 0.121986f, 0.124741f, 0.127530f, 0.130352f, 0.133209f, 0.136099f, 0.139022f, 0.141980f, 0.144972f, 0.147998f, 0.151058f, 0.154152f, 0.157281f, 0.160444f,
- 0.163641f, 0.166872f, 0.170138f, 0.173439f, 0.176774f, 0.180144f, 0.183549f, 0.186989f, 0.190463f, 0.193972f, 0.197516f, 0.201096f, 0.204710f, 0.208360f, 0.212044f, 0.215764f,
- 0.219520f, 0.223310f, 0.227137f, 0.230998f, 0.234895f, 0.238828f, 0.242796f, 0.246800f, 0.250840f, 0.254916f, 0.259027f, 0.263175f, 0.267358f, 0.271577f, 0.275833f, 0.280124f,
- 0.284452f, 0.288816f, 0.293216f, 0.297653f, 0.302126f, 0.306635f, 0.311181f, 0.315763f, 0.320382f, 0.325037f, 0.329729f, 0.334458f, 0.339223f, 0.344026f, 0.348865f, 0.353741f,
- 0.358654f, 0.363604f, 0.368591f, 0.373615f, 0.378676f, 0.383775f, 0.388910f, 0.394083f, 0.399293f, 0.404541f, 0.409826f, 0.415148f, 0.420508f, 0.425905f, 0.431340f, 0.436813f,
- 0.442323f, 0.447871f, 0.453456f, 0.459080f, 0.464741f, 0.470440f, 0.476177f, 0.481952f, 0.487765f, 0.493616f, 0.499505f, 0.505432f, 0.511398f, 0.517401f, 0.523443f, 0.529523f,
- 0.535642f, 0.541798f, 0.547994f, 0.554227f, 0.560499f, 0.566810f, 0.573159f, 0.579547f, 0.585973f, 0.592438f, 0.598942f, 0.605484f, 0.612066f, 0.618686f, 0.625345f, 0.632043f,
- 0.638779f, 0.645555f, 0.652370f, 0.659224f, 0.666117f, 0.673049f, 0.680020f, 0.687031f, 0.694081f, 0.701169f, 0.708298f, 0.715465f, 0.722672f, 0.729919f, 0.737205f, 0.744530f,
- 0.751895f, 0.759300f, 0.766744f, 0.774227f, 0.781751f, 0.789314f, 0.796917f, 0.804559f, 0.812241f, 0.819964f, 0.827726f, 0.835528f, 0.843370f, 0.851252f, 0.859174f, 0.867136f,
- 0.875138f, 0.883180f, 0.891262f, 0.899384f, 0.907547f, 0.915750f, 0.923993f, 0.932277f, 0.940601f, 0.948965f, 0.957370f, 0.965815f, 0.974300f, 0.982826f, 0.991393f, 1.000000f
- };
- /*
- ================
- R_MipMapGamma
- Returns a new copy of the texture, quartered in size with gamma correction.
- ================
- */
- byte * R_MipMapWithGamma( const byte *in, int width, int height ) {
- int i, j;
- const byte *in_p;
- byte *out, *out_p;
- int row;
- int newWidth, newHeight;
- if ( width < 1 || height < 1 || ( width + height == 2 ) ) {
- return NULL;
- }
- row = width * 4;
- newWidth = width >> 1;
- newHeight = height >> 1;
- if ( !newWidth ) {
- newWidth = 1;
- }
- if ( !newHeight ) {
- newHeight = 1;
- }
- out = (byte *)R_StaticAlloc( newWidth * newHeight * 4, TAG_IMAGE );
- out_p = out;
- in_p = in;
- width >>= 1;
- height >>= 1;
- if ( width == 0 || height == 0 ) {
- width += height; // get largest
- for (i=0 ; i<width ; i++, out_p+=4, in_p+=8 ) {
- out_p[0] = idMath::Ftob( 255.0f * idMath::Pow( 0.5f * ( mip_gammaTable[in_p[0]] + mip_gammaTable[in_p[4]] ), 1.0f / 2.2f ) );
- out_p[1] = idMath::Ftob( 255.0f * idMath::Pow( 0.5f * ( mip_gammaTable[in_p[1]] + mip_gammaTable[in_p[5]] ), 1.0f / 2.2f ) );
- out_p[2] = idMath::Ftob( 255.0f * idMath::Pow( 0.5f * ( mip_gammaTable[in_p[2]] + mip_gammaTable[in_p[6]] ), 1.0f / 2.2f ) );
- out_p[3] = idMath::Ftob( 255.0f * idMath::Pow( 0.5f * ( mip_gammaTable[in_p[3]] + mip_gammaTable[in_p[7]] ), 1.0f / 2.2f ) );
- }
- return out;
- }
- for (i=0 ; i<height ; i++, in_p+=row) {
- for (j=0 ; j<width ; j++, out_p+=4, in_p+=8) {
- out_p[0] = idMath::Ftob( 255.0f * idMath::Pow( 0.25f * ( mip_gammaTable[in_p[0]] + mip_gammaTable[in_p[4]] + mip_gammaTable[in_p[row+0]] + mip_gammaTable[in_p[row+4]] ), 1.0f / 2.2f ) );
- out_p[1] = idMath::Ftob( 255.0f * idMath::Pow( 0.25f * ( mip_gammaTable[in_p[1]] + mip_gammaTable[in_p[5]] + mip_gammaTable[in_p[row+1]] + mip_gammaTable[in_p[row+5]] ), 1.0f / 2.2f ) );
- out_p[2] = idMath::Ftob( 255.0f * idMath::Pow( 0.25f * ( mip_gammaTable[in_p[2]] + mip_gammaTable[in_p[6]] + mip_gammaTable[in_p[row+2]] + mip_gammaTable[in_p[row+6]] ), 1.0f / 2.2f ) );
- out_p[3] = idMath::Ftob( 255.0f * idMath::Pow( 0.25f * ( mip_gammaTable[in_p[3]] + mip_gammaTable[in_p[7]] + mip_gammaTable[in_p[row+3]] + mip_gammaTable[in_p[row+7]] ), 1.0f / 2.2f ) );
- }
- }
- return out;
- }
- /*
- ================
- R_MipMap
- Returns a new copy of the texture, quartered in size and filtered.
- ================
- */
- byte * R_MipMap( const byte *in, int width, int height ) {
- int i, j;
- const byte *in_p;
- byte *out, *out_p;
- int row;
- int newWidth, newHeight;
- if ( width < 1 || height < 1 || ( width + height == 2 ) ) {
- return NULL;
- }
- row = width * 4;
- newWidth = width >> 1;
- newHeight = height >> 1;
- if ( !newWidth ) {
- newWidth = 1;
- }
- if ( !newHeight ) {
- newHeight = 1;
- }
- out = (byte *)R_StaticAlloc( newWidth * newHeight * 4, TAG_IMAGE );
- out_p = out;
- in_p = in;
- width >>= 1;
- height >>= 1;
- if ( width == 0 || height == 0 ) {
- width += height; // get largest
- for (i=0 ; i<width ; i++, out_p+=4, in_p+=8 ) {
- out_p[0] = ( in_p[0] + in_p[4] )>>1;
- out_p[1] = ( in_p[1] + in_p[5] )>>1;
- out_p[2] = ( in_p[2] + in_p[6] )>>1;
- out_p[3] = ( in_p[3] + in_p[7] )>>1;
- }
- return out;
- }
- for (i=0 ; i<height ; i++, in_p+=row) {
- for (j=0 ; j<width ; j++, out_p+=4, in_p+=8) {
- out_p[0] = (in_p[0] + in_p[4] + in_p[row+0] + in_p[row+4])>>2;
- out_p[1] = (in_p[1] + in_p[5] + in_p[row+1] + in_p[row+5])>>2;
- out_p[2] = (in_p[2] + in_p[6] + in_p[row+2] + in_p[row+6])>>2;
- out_p[3] = (in_p[3] + in_p[7] + in_p[row+3] + in_p[row+7])>>2;
- }
- }
- return out;
- }
- /*
- ==================
- R_BlendOverTexture
- Apply a color blend over a set of pixels
- ==================
- */
- void R_BlendOverTexture( byte *data, int pixelCount, const byte blend[4] ) {
- int i;
- int inverseAlpha;
- int premult[3];
- inverseAlpha = 255 - blend[3];
- premult[0] = blend[0] * blend[3];
- premult[1] = blend[1] * blend[3];
- premult[2] = blend[2] * blend[3];
- for ( i = 0 ; i < pixelCount ; i++, data+=4 ) {
- data[0] = ( data[0] * inverseAlpha + premult[0] ) >> 9;
- data[1] = ( data[1] * inverseAlpha + premult[1] ) >> 9;
- data[2] = ( data[2] * inverseAlpha + premult[2] ) >> 9;
- }
- }
- /*
- ==================
- R_HorizontalFlip
- Flip the image in place
- ==================
- */
- void R_HorizontalFlip( byte *data, int width, int height ) {
- int i, j;
- int temp;
- for ( i = 0 ; i < height ; i++ ) {
- for ( j = 0 ; j < width / 2 ; j++ ) {
- temp = *( (int *)data + i * width + j );
- *( (int *)data + i * width + j ) = *( (int *)data + i * width + width - 1 - j );
- *( (int *)data + i * width + width - 1 - j ) = temp;
- }
- }
- }
- void R_VerticalFlip( byte *data, int width, int height ) {
- int i, j;
- int temp;
- for ( i = 0 ; i < width ; i++ ) {
- for ( j = 0 ; j < height / 2 ; j++ ) {
- temp = *( (int *)data + j * width + i );
- *( (int *)data + j * width + i ) = *( (int *)data + ( height - 1 - j ) * width + i );
- *( (int *)data + ( height - 1 - j ) * width + i ) = temp;
- }
- }
- }
- void R_RotatePic( byte *data, int width ) {
- int i, j;
- int *temp;
- temp = (int *)R_StaticAlloc( width * width * 4, TAG_IMAGE );
- for ( i = 0 ; i < width ; i++ ) {
- for ( j = 0 ; j < width ; j++ ) {
- *( temp + i * width + j ) = *( (int *)data + j * width + i );
- }
- }
- memcpy( data, temp, width * width * 4 );
- R_StaticFree( temp );
- }
|