mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2024-12-11 13:11:47 +00:00
830 lines
21 KiB
C++
830 lines
21 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
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.
|
|
|
|
===========================================================================
|
|
*/
|
|
/*
|
|
================================================================================================
|
|
Contains the DxtDecoder implementation.
|
|
================================================================================================
|
|
*/
|
|
|
|
#pragma hdrstop
|
|
#include "DXTCodec_local.h"
|
|
#include "DXTCodec.h"
|
|
|
|
/*
|
|
========================
|
|
idDxtDecoder::EmitBlock
|
|
========================
|
|
*/
|
|
void idDxtDecoder::EmitBlock( byte* outPtr, int x, int y, const byte* colorBlock )
|
|
{
|
|
outPtr += ( y * width + x ) * 4;
|
|
for( int j = 0; j < 4; j++ )
|
|
{
|
|
memcpy( outPtr, &colorBlock[j * 4 * 4], 4 * 4 );
|
|
outPtr += width * 4;
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idDxtDecoder::DecodeAlphaValues
|
|
========================
|
|
*/
|
|
void idDxtDecoder::DecodeAlphaValues( byte* colorBlock, const int offset )
|
|
{
|
|
int i;
|
|
unsigned int indexes;
|
|
byte alphas[8];
|
|
|
|
alphas[0] = ReadByte();
|
|
alphas[1] = ReadByte();
|
|
|
|
if( alphas[0] > alphas[1] )
|
|
{
|
|
alphas[2] = ( 6 * alphas[0] + 1 * alphas[1] ) / 7;
|
|
alphas[3] = ( 5 * alphas[0] + 2 * alphas[1] ) / 7;
|
|
alphas[4] = ( 4 * alphas[0] + 3 * alphas[1] ) / 7;
|
|
alphas[5] = ( 3 * alphas[0] + 4 * alphas[1] ) / 7;
|
|
alphas[6] = ( 2 * alphas[0] + 5 * alphas[1] ) / 7;
|
|
alphas[7] = ( 1 * alphas[0] + 6 * alphas[1] ) / 7;
|
|
}
|
|
else
|
|
{
|
|
alphas[2] = ( 4 * alphas[0] + 1 * alphas[1] ) / 5;
|
|
alphas[3] = ( 3 * alphas[0] + 2 * alphas[1] ) / 5;
|
|
alphas[4] = ( 2 * alphas[0] + 3 * alphas[1] ) / 5;
|
|
alphas[5] = ( 1 * alphas[0] + 4 * alphas[1] ) / 5;
|
|
alphas[6] = 0;
|
|
alphas[7] = 255;
|
|
}
|
|
|
|
colorBlock += offset;
|
|
|
|
indexes = ( int )ReadByte() | ( ( int )ReadByte() << 8 ) | ( ( int )ReadByte() << 16 );
|
|
for( i = 0; i < 8; i++ )
|
|
{
|
|
colorBlock[i * 4] = alphas[indexes & 7];
|
|
indexes >>= 3;
|
|
}
|
|
|
|
indexes = ( int )ReadByte() | ( ( int )ReadByte() << 8 ) | ( ( int )ReadByte() << 16 );
|
|
for( i = 8; i < 16; i++ )
|
|
{
|
|
colorBlock[i * 4] = alphas[indexes & 7];
|
|
indexes >>= 3;
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idDxtDecoder::DecodeColorValues
|
|
========================
|
|
*/
|
|
void idDxtDecoder::DecodeColorValues( byte* colorBlock, bool noBlack, bool writeAlpha )
|
|
{
|
|
byte colors[4][4];
|
|
|
|
unsigned short color0 = ReadUShort();
|
|
unsigned short color1 = ReadUShort();
|
|
|
|
ColorFrom565( color0, colors[0] );
|
|
ColorFrom565( color1, colors[1] );
|
|
|
|
colors[0][3] = 255;
|
|
colors[1][3] = 255;
|
|
|
|
if( noBlack || color0 > color1 )
|
|
{
|
|
colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
|
|
colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
|
|
colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3;
|
|
colors[2][3] = 255;
|
|
|
|
colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
|
|
colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
|
|
colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3;
|
|
colors[3][3] = 255;
|
|
}
|
|
else
|
|
{
|
|
colors[2][0] = ( 1 * colors[0][0] + 1 * colors[1][0] ) / 2;
|
|
colors[2][1] = ( 1 * colors[0][1] + 1 * colors[1][1] ) / 2;
|
|
colors[2][2] = ( 1 * colors[0][2] + 1 * colors[1][2] ) / 2;
|
|
colors[2][3] = 255;
|
|
|
|
colors[3][0] = 0;
|
|
colors[3][1] = 0;
|
|
colors[3][2] = 0;
|
|
colors[3][3] = 0;
|
|
}
|
|
|
|
unsigned int indexes = ReadUInt();
|
|
for( int i = 0; i < 16; i++ )
|
|
{
|
|
colorBlock[i * 4 + 0] = colors[indexes & 3][0];
|
|
colorBlock[i * 4 + 1] = colors[indexes & 3][1];
|
|
colorBlock[i * 4 + 2] = colors[indexes & 3][2];
|
|
if( writeAlpha )
|
|
{
|
|
colorBlock[i * 4 + 3] = colors[indexes & 3][3];
|
|
}
|
|
indexes >>= 2;
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idDxtDecoder::DecodeCTX1Values
|
|
========================
|
|
*/
|
|
void idDxtDecoder::DecodeCTX1Values( byte* colorBlock )
|
|
{
|
|
byte colors[4][2];
|
|
|
|
colors[0][0] = ReadByte();
|
|
colors[0][1] = ReadByte();
|
|
colors[1][0] = ReadByte();
|
|
colors[1][1] = ReadByte();
|
|
|
|
colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3;
|
|
colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3;
|
|
colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3;
|
|
colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3;
|
|
|
|
unsigned int indexes = ReadUInt();
|
|
for( int i = 0; i < 16; i++ )
|
|
{
|
|
colorBlock[i * 4 + 0] = colors[indexes & 3][0];
|
|
colorBlock[i * 4 + 1] = colors[indexes & 3][1];
|
|
indexes >>= 2;
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idDxtDecoder::DecompressImageDXT1
|
|
========================
|
|
*/
|
|
void idDxtDecoder::DecompressImageDXT1( const byte* inBuf, byte* outBuf, int width, int height )
|
|
{
|
|
byte block[64];
|
|
|
|
this->width = width;
|
|
this->height = height;
|
|
this->inData = inBuf;
|
|
|
|
for( int j = 0; j < height; j += 4 )
|
|
{
|
|
for( int i = 0; i < width; i += 4 )
|
|
{
|
|
DecodeColorValues( block, false, true );
|
|
EmitBlock( outBuf, i, j, block );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idDxtDecoder::DecompressImageDXT5
|
|
========================
|
|
*/
|
|
void idDxtDecoder::DecompressImageDXT5( const byte* inBuf, byte* outBuf, int width, int height )
|
|
{
|
|
byte block[64];
|
|
|
|
this->width = width;
|
|
this->height = height;
|
|
this->inData = inBuf;
|
|
|
|
for( int j = 0; j < height; j += 4 )
|
|
{
|
|
for( int i = 0; i < width; i += 4 )
|
|
{
|
|
DecodeAlphaValues( block, 3 );
|
|
DecodeColorValues( block, true, false );
|
|
EmitBlock( outBuf, i, j, block );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idDxtDecoder::DecompressImageDXT5_nVidia7x
|
|
========================
|
|
*/
|
|
void idDxtDecoder::DecompressImageDXT5_nVidia7x( const byte* inBuf, byte* outBuf, int width, int height )
|
|
{
|
|
byte block[64];
|
|
|
|
this->width = width;
|
|
this->height = height;
|
|
this->inData = inBuf;
|
|
|
|
for( int j = 0; j < height; j += 4 )
|
|
{
|
|
for( int i = 0; i < width; i += 4 )
|
|
{
|
|
DecodeAlphaValues( block, 3 );
|
|
DecodeColorValues( block, false, false );
|
|
EmitBlock( outBuf, i, j, block );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idDxtDecoder::DecompressYCoCgDXT5
|
|
========================
|
|
*/
|
|
void idDxtDecoder::DecompressYCoCgDXT5( const byte* inBuf, byte* outBuf, int width, int height )
|
|
{
|
|
DecompressImageDXT5_nVidia7x( inBuf, outBuf, width, height );
|
|
// descale the CoCg values and set the scale factor effectively to 1
|
|
for( int i = 0; i < width * height; i++ )
|
|
{
|
|
int scale = ( outBuf[i * 4 + 2] >> 3 ) + 1;
|
|
outBuf[i * 4 + 0] = byte( ( outBuf[i * 4 + 0] - 128 ) / scale + 128 );
|
|
outBuf[i * 4 + 1] = byte( ( outBuf[i * 4 + 1] - 128 ) / scale + 128 );
|
|
outBuf[i * 4 + 2] = 0; // this translates to a scale factor of 1 for uncompressed
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
========================
|
|
idDxtDecoder::DecompressYCoCgCTX1DXT5A
|
|
========================
|
|
*/
|
|
void idDxtDecoder::DecompressYCoCgCTX1DXT5A( const byte* inBuf, byte* outBuf, int width, int height )
|
|
{
|
|
byte block[64];
|
|
|
|
this->width = width;
|
|
this->height = height;
|
|
this->inData = inBuf;
|
|
|
|
for( int j = 0; j < height; j += 4 )
|
|
{
|
|
for( int i = 0; i < width; i += 4 )
|
|
{
|
|
DecodeAlphaValues( block, 3 );
|
|
DecodeCTX1Values( block );
|
|
EmitBlock( outBuf, i, j, block );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idDxtDecoder::DecodeNormalYValues
|
|
========================
|
|
*/
|
|
void idDxtDecoder::DecodeNormalYValues( byte* normalBlock, const int offsetY, byte& c0, byte& c1 )
|
|
{
|
|
int i;
|
|
unsigned int indexes;
|
|
unsigned short normal0, normal1;
|
|
byte normalsY[4];
|
|
|
|
normal0 = ReadUShort();
|
|
normal1 = ReadUShort();
|
|
|
|
assert( normal0 >= normal1 );
|
|
|
|
normalsY[0] = NormalYFrom565( normal0 );
|
|
normalsY[1] = NormalYFrom565( normal1 );
|
|
normalsY[2] = ( 2 * normalsY[0] + 1 * normalsY[1] ) / 3;
|
|
normalsY[3] = ( 1 * normalsY[0] + 2 * normalsY[1] ) / 3;
|
|
|
|
c0 = NormalBiasFrom565( normal0 );
|
|
c1 = NormalScaleFrom565( normal0 );
|
|
|
|
byte* normalYPtr = normalBlock + offsetY;
|
|
|
|
indexes = ReadUInt();
|
|
for( i = 0; i < 16; i++ )
|
|
{
|
|
normalYPtr[i * 4] = normalsY[indexes & 3];
|
|
indexes >>= 2;
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
UShortSqrt
|
|
========================
|
|
*/
|
|
byte UShortSqrt( unsigned short s )
|
|
{
|
|
#if 1
|
|
int t, b, r, x;
|
|
|
|
r = 0;
|
|
for( b = 0x10000000; b != 0; b >>= 2 )
|
|
{
|
|
t = r + b;
|
|
r >>= 1;
|
|
x = -( t <= s );
|
|
s = s - ( unsigned short )( t & x );
|
|
r += b & x;
|
|
}
|
|
return byte( r );
|
|
#else
|
|
int t, b, r;
|
|
|
|
r = 0;
|
|
for( b = 0x10000000; b != 0; b >>= 2 )
|
|
{
|
|
t = r + b;
|
|
r >>= 1;
|
|
if( t <= s )
|
|
{
|
|
s -= t;
|
|
r += b;
|
|
}
|
|
}
|
|
return r;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idDxtDecoder::DeriveNormalZValues
|
|
========================
|
|
*/
|
|
void idDxtDecoder::DeriveNormalZValues( byte* normalBlock )
|
|
{
|
|
int i;
|
|
|
|
for( i = 0; i < 16; i++ )
|
|
{
|
|
int x = normalBlock[i * 4 + 0] - 127;
|
|
int y = normalBlock[i * 4 + 1] - 127;
|
|
normalBlock[i * 4 + 2] = 128 + UShortSqrt( ( unsigned short )( 16383 - x * x - y * y ) );
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idDxtDecoder::UnRotateNormals
|
|
========================
|
|
*/
|
|
void UnRotateNormals( const byte* block, float* normals, byte c0, byte c1 )
|
|
{
|
|
int rotation = c0;
|
|
float angle = -( rotation / 255.0f ) * idMath::PI;
|
|
float s = sin( angle );
|
|
float c = cos( angle );
|
|
|
|
int scale = ( c1 >> 3 ) + 1;
|
|
for( int i = 0; i < 16; i++ )
|
|
{
|
|
float x = block[i * 4 + 0] / 255.0f * 2.0f - 1.0f;
|
|
float y = ( ( block[i * 4 + 1] - 128 ) / scale + 128 ) / 255.0f * 2.0f - 1.0f;
|
|
float rx = c * x - s * y;
|
|
float ry = s * x + c * y;
|
|
normals[i * 4 + 0] = rx;
|
|
normals[i * 4 + 1] = ry;
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idDxtDecoder::DecompressNormalMapDXT1
|
|
========================
|
|
*/
|
|
void idDxtDecoder::DecompressNormalMapDXT1( const byte* inBuf, byte* outBuf, int width, int height )
|
|
{
|
|
byte block[64];
|
|
|
|
this->width = width;
|
|
this->height = height;
|
|
this->inData = inBuf;
|
|
|
|
for( int j = 0; j < height; j += 4 )
|
|
{
|
|
for( int i = 0; i < width; i += 4 )
|
|
{
|
|
DecodeColorValues( block, false, true );
|
|
#if 1
|
|
float normals[16 * 4];
|
|
/*
|
|
for ( int k = 0; k < 16; k++ ) {
|
|
normals[k*4+0] = block[k*4+0] / 255.0f * 2.0f - 1.0f;
|
|
normals[k*4+1] = block[k*4+1] / 255.0f * 2.0f - 1.0f;
|
|
}
|
|
*/
|
|
UnRotateNormals( block, normals, block[0 * 4 + 2], 0 );
|
|
for( int k = 0; k < 16; k++ )
|
|
{
|
|
float x = normals[k * 4 + 0];
|
|
float y = normals[k * 4 + 1];
|
|
float z = 1.0f - x * x - y * y;
|
|
if( z < 0.0f ) z = 0.0f;
|
|
normals[k * 4 + 2] = sqrt( z );
|
|
}
|
|
for( int k = 0; k < 16; k++ )
|
|
{
|
|
block[k * 4 + 0] = idMath::Ftob( ( normals[k * 4 + 0] + 1.0f ) / 2.0f * 255.0f );
|
|
block[k * 4 + 1] = idMath::Ftob( ( normals[k * 4 + 1] + 1.0f ) / 2.0f * 255.0f );
|
|
block[k * 4 + 2] = idMath::Ftob( ( normals[k * 4 + 2] + 1.0f ) / 2.0f * 255.0f );
|
|
}
|
|
#else
|
|
DeriveNormalZValues( block );
|
|
#endif
|
|
EmitBlock( outBuf, i, j, block );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idDxtDecoder::DecompressNormalMapDXT1Renormalize
|
|
========================
|
|
*/
|
|
void idDxtDecoder::DecompressNormalMapDXT1Renormalize( const byte* inBuf, byte* outBuf, int width, int height )
|
|
{
|
|
byte block[64];
|
|
|
|
this->width = width;
|
|
this->height = height;
|
|
this->inData = inBuf;
|
|
|
|
for( int j = 0; j < height; j += 4 )
|
|
{
|
|
for( int i = 0; i < width; i += 4 )
|
|
{
|
|
DecodeColorValues( block, false, true );
|
|
|
|
for( int k = 0; k < 16; k++ )
|
|
{
|
|
float normal[3];
|
|
normal[0] = block[k * 4 + 0] / 255.0f * 2.0f - 1.0f;
|
|
normal[1] = block[k * 4 + 1] / 255.0f * 2.0f - 1.0f;
|
|
normal[2] = block[k * 4 + 2] / 255.0f * 2.0f - 1.0f;
|
|
float rsq = idMath::InvSqrt( normal[0] * normal[0] + normal[1] * normal[1] + normal[2] * normal[2] );
|
|
normal[0] *= rsq;
|
|
normal[1] *= rsq;
|
|
normal[2] *= rsq;
|
|
block[k * 4 + 0] = idMath::Ftob( ( normal[0] + 1.0f ) / 2.0f * 255.0f + 0.5f );
|
|
block[k * 4 + 1] = idMath::Ftob( ( normal[1] + 1.0f ) / 2.0f * 255.0f + 0.5f );
|
|
block[k * 4 + 2] = idMath::Ftob( ( normal[2] + 1.0f ) / 2.0f * 255.0f + 0.5f );
|
|
}
|
|
|
|
EmitBlock( outBuf, i, j, block );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idDxtDecoder::DecompressNormalMapDXT5Renormalize
|
|
========================
|
|
*/
|
|
void idDxtDecoder::DecompressNormalMapDXT5Renormalize( const byte* inBuf, byte* outBuf, int width, int height )
|
|
{
|
|
byte block[64];
|
|
|
|
this->width = width;
|
|
this->height = height;
|
|
this->inData = inBuf;
|
|
|
|
for( int j = 0; j < height; j += 4 )
|
|
{
|
|
for( int i = 0; i < width; i += 4 )
|
|
{
|
|
DecodeAlphaValues( block, 3 );
|
|
DecodeColorValues( block, false, false );
|
|
|
|
for( int k = 0; k < 16; k++ )
|
|
{
|
|
float normal[3];
|
|
#if 0 // object-space
|
|
normal[0] = block[k * 4 + 0] / 255.0f * 2.0f - 1.0f;
|
|
normal[1] = block[k * 4 + 1] / 255.0f * 2.0f - 1.0f;
|
|
normal[2] = block[k * 4 + 3] / 255.0f * 2.0f - 1.0f;
|
|
#else
|
|
normal[0] = block[k * 4 + 3] / 255.0f * 2.0f - 1.0f;
|
|
normal[1] = block[k * 4 + 1] / 255.0f * 2.0f - 1.0f;
|
|
normal[2] = block[k * 4 + 2] / 255.0f * 2.0f - 1.0f;
|
|
#endif
|
|
float rsq = idMath::InvSqrt( normal[0] * normal[0] + normal[1] * normal[1] + normal[2] * normal[2] );
|
|
normal[0] *= rsq;
|
|
normal[1] *= rsq;
|
|
normal[2] *= rsq;
|
|
block[k * 4 + 0] = idMath::Ftob( ( normal[0] + 1.0f ) / 2.0f * 255.0f + 0.5f );
|
|
block[k * 4 + 1] = idMath::Ftob( ( normal[1] + 1.0f ) / 2.0f * 255.0f + 0.5f );
|
|
block[k * 4 + 2] = idMath::Ftob( ( normal[2] + 1.0f ) / 2.0f * 255.0f + 0.5f );
|
|
}
|
|
|
|
EmitBlock( outBuf, i, j, block );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idDxtDecoder::BiasScaleNormalY
|
|
========================
|
|
*/
|
|
void BiasScaleNormalY( byte* normals, const int offsetY, const byte c0, const byte c1 )
|
|
{
|
|
int bias = c0 - 4;
|
|
int scale = ( c1 >> 3 ) + 1;
|
|
for( int i = 0; i < 16; i++ )
|
|
{
|
|
normals[i * 4 + offsetY] = byte( ( normals[i * 4 + offsetY] - 128 ) / scale + bias );
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idDxtDecoder::BiasScaleNormals
|
|
========================
|
|
*/
|
|
void BiasScaleNormals( const byte* block, float* normals, const byte c0, const byte c1 )
|
|
{
|
|
int bias = c0 - 4;
|
|
int scale = ( c1 >> 3 ) + 1;
|
|
for( int i = 0; i < 16; i++ )
|
|
{
|
|
normals[i * 4 + 0] = block[i * 4 + 0] / 255.0f * 2.0f - 1.0f;
|
|
normals[i * 4 + 1] = ( ( block[i * 4 + 1] - 128.0f ) / scale + bias ) / 255.0f * 2.0f - 1.0f;
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idDxtDecoder::DecompressNormalMapDXT5
|
|
========================
|
|
*/
|
|
void idDxtDecoder::DecompressNormalMapDXT5( const byte* inBuf, byte* outBuf, int width, int height )
|
|
{
|
|
byte block[64];
|
|
byte c0, c1;
|
|
|
|
this->width = width;
|
|
this->height = height;
|
|
this->inData = inBuf;
|
|
|
|
for( int j = 0; j < height; j += 4 )
|
|
{
|
|
for( int i = 0; i < width; i += 4 )
|
|
{
|
|
DecodeAlphaValues( block, 0 );
|
|
DecodeNormalYValues( block, 1, c0, c1 );
|
|
#if 1
|
|
float normals[16 * 4];
|
|
//BiasScaleNormals( block, normals, c0, c1 );
|
|
UnRotateNormals( block, normals, c0, c1 );
|
|
for( int k = 0; k < 16; k++ )
|
|
{
|
|
float x = normals[k * 4 + 0];
|
|
float y = normals[k * 4 + 1];
|
|
float z = 1.0f - x * x - y * y;
|
|
if( z < 0.0f ) z = 0.0f;
|
|
normals[k * 4 + 2] = sqrt( z );
|
|
}
|
|
for( int k = 0; k < 16; k++ )
|
|
{
|
|
block[k * 4 + 0] = idMath::Ftob( ( normals[k * 4 + 0] + 1.0f ) / 2.0f * 255.0f );
|
|
block[k * 4 + 1] = idMath::Ftob( ( normals[k * 4 + 1] + 1.0f ) / 2.0f * 255.0f );
|
|
block[k * 4 + 2] = idMath::Ftob( ( normals[k * 4 + 2] + 1.0f ) / 2.0f * 255.0f );
|
|
}
|
|
#else
|
|
BiasScaleNormalY( block, 1, c0, c1 );
|
|
DeriveNormalZValues( block );
|
|
#endif
|
|
|
|
EmitBlock( outBuf, i, j, block );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idDxtDecoder::DecompressNormalMapDXN2
|
|
========================
|
|
*/
|
|
void idDxtDecoder::DecompressNormalMapDXN2( const byte* inBuf, byte* outBuf, int width, int height )
|
|
{
|
|
byte block[64];
|
|
|
|
this->width = width;
|
|
this->height = height;
|
|
this->inData = inBuf;
|
|
|
|
for( int j = 0; j < height; j += 4 )
|
|
{
|
|
for( int i = 0; i < width; i += 4 )
|
|
{
|
|
DecodeAlphaValues( block, 0 );
|
|
DecodeAlphaValues( block, 1 );
|
|
#if 1
|
|
float normals[16 * 4];
|
|
for( int k = 0; k < 16; k++ )
|
|
{
|
|
normals[k * 4 + 0] = block[k * 4 + 0] / 255.0f * 2.0f - 1.0f;
|
|
normals[k * 4 + 1] = block[k * 4 + 1] / 255.0f * 2.0f - 1.0f;
|
|
}
|
|
for( int k = 0; k < 16; k++ )
|
|
{
|
|
float x = normals[k * 4 + 0];
|
|
float y = normals[k * 4 + 1];
|
|
float z = 1.0f - x * x - y * y;
|
|
if( z < 0.0f ) z = 0.0f;
|
|
normals[k * 4 + 2] = sqrt( z );
|
|
}
|
|
for( int k = 0; k < 16; k++ )
|
|
{
|
|
block[k * 4 + 0] = idMath::Ftob( ( normals[k * 4 + 0] + 1.0f ) / 2.0f * 255.0f );
|
|
block[k * 4 + 1] = idMath::Ftob( ( normals[k * 4 + 1] + 1.0f ) / 2.0f * 255.0f );
|
|
block[k * 4 + 2] = idMath::Ftob( ( normals[k * 4 + 2] + 1.0f ) / 2.0f * 255.0f );
|
|
}
|
|
#else
|
|
DeriveNormalZValues( block );
|
|
#endif
|
|
EmitBlock( outBuf, i, j, block );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idDxtDecoder::DecomposeColorBlock
|
|
========================
|
|
*/
|
|
void idDxtDecoder::DecomposeColorBlock( byte colors[2][4], byte colorIndices[16], bool noBlack )
|
|
{
|
|
int i;
|
|
unsigned int indices;
|
|
unsigned short color0, color1;
|
|
int colorRemap1[] = { 3, 0, 2, 1 };
|
|
int colorRemap2[] = { 1, 3, 2, 0 };
|
|
int* crm;
|
|
|
|
color0 = ReadUShort();
|
|
color1 = ReadUShort();
|
|
|
|
ColorFrom565( color0, colors[0] );
|
|
ColorFrom565( color1, colors[1] );
|
|
|
|
if( noBlack || color0 > color1 )
|
|
{
|
|
crm = colorRemap1;
|
|
}
|
|
else
|
|
{
|
|
crm = colorRemap2;
|
|
}
|
|
|
|
indices = ReadUInt();
|
|
for( i = 0; i < 16; i++ )
|
|
{
|
|
colorIndices[i] = ( byte )crm[ indices & 3 ];
|
|
indices >>= 2;
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idDxtDecoder::DecomposeAlphaBlock
|
|
========================
|
|
*/
|
|
void idDxtDecoder::DecomposeAlphaBlock( byte colors[2][4], byte alphaIndices[16] )
|
|
{
|
|
int i;
|
|
unsigned char alpha0, alpha1;
|
|
unsigned int indices;
|
|
int alphaRemap1[] = { 7, 0, 6, 5, 4, 3, 2, 1 };
|
|
int alphaRemap2[] = { 1, 6, 2, 3, 4, 5, 0, 7 };
|
|
int* arm;
|
|
|
|
alpha0 = ReadByte();
|
|
alpha1 = ReadByte();
|
|
|
|
colors[0][3] = alpha0;
|
|
colors[1][3] = alpha1;
|
|
|
|
if( alpha0 > alpha1 )
|
|
{
|
|
arm = alphaRemap1;
|
|
}
|
|
else
|
|
{
|
|
arm = alphaRemap2;
|
|
}
|
|
|
|
indices = ( int )ReadByte() | ( ( int )ReadByte() << 8 ) | ( ( int )ReadByte() << 16 );
|
|
for( i = 0; i < 8; i++ )
|
|
{
|
|
alphaIndices[i] = ( byte )arm[ indices & 7 ];
|
|
indices >>= 3;
|
|
}
|
|
|
|
indices = ( int )ReadByte() | ( ( int )ReadByte() << 8 ) | ( ( int )ReadByte() << 16 );
|
|
for( i = 8; i < 16; i++ )
|
|
{
|
|
alphaIndices[i] = ( byte )arm[ indices & 7 ];
|
|
indices >>= 3;
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idDxtDecoder::DecomposeImageDXT1
|
|
========================
|
|
*/
|
|
void idDxtDecoder::DecomposeImageDXT1( const byte* inBuf, byte* colorIndices, byte* pic1, byte* pic2, int width, int height )
|
|
{
|
|
byte colors[2][4];
|
|
byte indices[16];
|
|
|
|
this->width = width;
|
|
this->height = height;
|
|
this->inData = inBuf;
|
|
|
|
// extract the colors from the DXT
|
|
for( int j = 0; j < height; j += 4 )
|
|
{
|
|
for( int i = 0; i < width; i += 4 )
|
|
{
|
|
DecomposeColorBlock( colors, indices, false );
|
|
|
|
memcpy( colorIndices + ( j + 0 ) * width + i, indices + 0, 4 );
|
|
memcpy( colorIndices + ( j + 1 ) * width + i, indices + 4, 4 );
|
|
memcpy( colorIndices + ( j + 2 ) * width + i, indices + 8, 4 );
|
|
memcpy( colorIndices + ( j + 3 ) * width + i, indices + 12, 4 );
|
|
|
|
memcpy( pic1 + j * width / 4 + i, colors[0], 4 );
|
|
|
|
memcpy( pic2 + j * width / 4 + i, colors[1], 4 );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
========================
|
|
idDxtDecoder::DecomposeImageDXT5
|
|
========================
|
|
*/
|
|
void idDxtDecoder::DecomposeImageDXT5( const byte* inBuf, byte* colorIndices, byte* alphaIndices, byte* pic1, byte* pic2, int width, int height )
|
|
{
|
|
byte colors[2][4];
|
|
byte colorInd[16];
|
|
byte alphaInd[16];
|
|
|
|
this->width = width;
|
|
this->height = height;
|
|
this->inData = inBuf;
|
|
|
|
// extract the colors from the DXT
|
|
for( int j = 0; j < height; j += 4 )
|
|
{
|
|
for( int i = 0; i < width; i += 4 )
|
|
{
|
|
DecomposeAlphaBlock( colors, alphaInd );
|
|
DecomposeColorBlock( colors, colorInd, true );
|
|
|
|
memcpy( colorIndices + ( j + 0 ) * width + i, colorInd + 0, 4 );
|
|
memcpy( colorIndices + ( j + 1 ) * width + i, colorInd + 4, 4 );
|
|
memcpy( colorIndices + ( j + 2 ) * width + i, colorInd + 8, 4 );
|
|
memcpy( colorIndices + ( j + 3 ) * width + i, colorInd + 12, 4 );
|
|
|
|
memcpy( colorIndices + ( j + 0 ) * width + i, alphaInd + 0, 4 );
|
|
memcpy( colorIndices + ( j + 1 ) * width + i, alphaInd + 4, 4 );
|
|
memcpy( colorIndices + ( j + 2 ) * width + i, alphaInd + 8, 4 );
|
|
memcpy( colorIndices + ( j + 3 ) * width + i, alphaInd + 12, 4 );
|
|
|
|
memcpy( pic1 + j * width / 4 + i, colors[0], 4 );
|
|
|
|
memcpy( pic2 + j * width / 4 + i, colors[1], 4 );
|
|
}
|
|
}
|
|
}
|
|
|