387 lines
11 KiB
C++
387 lines
11 KiB
C++
/*
|
|
** Command & Conquer Renegade(tm)
|
|
** Copyright 2025 Electronic Arts Inc.
|
|
**
|
|
** This program is free software: you can redistribute it and/or modify
|
|
** it under the terms of the GNU General Public License as published by
|
|
** the Free Software Foundation, either version 3 of the License, or
|
|
** (at your option) any later version.
|
|
**
|
|
** This program is distributed in the hope that it will be useful,
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
** GNU General Public License for more details.
|
|
**
|
|
** You should have received a copy of the GNU General Public License
|
|
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/***********************************************************************************************
|
|
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
|
|
***********************************************************************************************
|
|
* *
|
|
* Project Name : WW3D *
|
|
* *
|
|
* $Archive:: /Commando/Code/ww3d2/ww3dformat.cpp $*
|
|
* *
|
|
* Original Author:: Hector Yee *
|
|
* *
|
|
* $Author:: Jani_p $*
|
|
* *
|
|
* $Modtime:: 12/10/01 3:16p $*
|
|
* *
|
|
* $Revision:: 13 $*
|
|
* *
|
|
*---------------------------------------------------------------------------------------------*
|
|
* Functions: *
|
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
#include "ww3dformat.h"
|
|
#include "vector4.h"
|
|
#include "wwdebug.h"
|
|
#include "targa.h"
|
|
#include "dx8wrapper.h"
|
|
#include "dx8caps.h"
|
|
#include <d3d8.h>
|
|
|
|
/*
|
|
WW3D_FORMAT_UNKNOWN=0,
|
|
WW3D_FORMAT_R8G8B8,
|
|
WW3D_FORMAT_A8R8G8B8,
|
|
WW3D_FORMAT_X8R8G8B8,
|
|
WW3D_FORMAT_R5G6B5,
|
|
WW3D_FORMAT_X1R5G5B5,
|
|
WW3D_FORMAT_A1R5G5B5,
|
|
WW3D_FORMAT_A4R4G4B4,
|
|
WW3D_FORMAT_R3G3B2,
|
|
WW3D_FORMAT_A8,
|
|
WW3D_FORMAT_A8R3G3B2,
|
|
WW3D_FORMAT_X4R4G4B4,
|
|
WW3D_FORMAT_A8P8,
|
|
WW3D_FORMAT_P8,
|
|
WW3D_FORMAT_L8,
|
|
WW3D_FORMAT_A8L8,
|
|
WW3D_FORMAT_A4L4,
|
|
WW3D_FORMAT_COUNT // Used only to determine number of surface formats
|
|
*/
|
|
|
|
void Get_WW3D_Format_Name(WW3DFormat format, StringClass& name)
|
|
{
|
|
switch (format) {
|
|
default:
|
|
case WW3D_FORMAT_UNKNOWN: name="Unknown"; break;
|
|
case WW3D_FORMAT_R8G8B8: name="R8G8B8"; break;
|
|
case WW3D_FORMAT_A8R8G8B8: name="A8R8G8B8"; break;
|
|
case WW3D_FORMAT_X8R8G8B8: name="X8R8G8B8"; break;
|
|
case WW3D_FORMAT_R5G6B5: name="R5G6B5"; break;
|
|
case WW3D_FORMAT_X1R5G5B5: name="X1R5G5B5"; break;
|
|
case WW3D_FORMAT_A1R5G5B5: name="A1R5G5B5"; break;
|
|
case WW3D_FORMAT_A4R4G4B4: name="A4R4G4B4"; break;
|
|
case WW3D_FORMAT_R3G3B2: name="R3G3B2"; break;
|
|
case WW3D_FORMAT_A8: name="A8"; break;
|
|
case WW3D_FORMAT_A8R3G3B2: name="A8R3G3B2"; break;
|
|
case WW3D_FORMAT_X4R4G4B4: name="X4R4G4B4"; break;
|
|
case WW3D_FORMAT_A8P8: name="A8P8"; break;
|
|
case WW3D_FORMAT_P8: name="P8"; break;
|
|
case WW3D_FORMAT_L8: name="L8"; break;
|
|
case WW3D_FORMAT_A8L8: name="A8L8"; break;
|
|
case WW3D_FORMAT_A4L4: name="A4L4"; break;
|
|
case WW3D_FORMAT_U8V8: name="U8V8"; break; // Bumpmap
|
|
case WW3D_FORMAT_L6V5U5: name="L6V5U5"; break; // Bumpmap
|
|
case WW3D_FORMAT_X8L8V8U8: name="X8L8V8U8"; break; // Bumpmap
|
|
case WW3D_FORMAT_DXT1: name="DXT1"; break;
|
|
case WW3D_FORMAT_DXT2: name="DXT2"; break;
|
|
case WW3D_FORMAT_DXT3: name="DXT3"; break;
|
|
case WW3D_FORMAT_DXT4: name="DXT4"; break;
|
|
case WW3D_FORMAT_DXT5: name="DXT5"; break;
|
|
}
|
|
}
|
|
|
|
|
|
// extract the luminance from the RGB using the CIE 709 standard
|
|
unsigned char RGB_to_CIEY(Vector4 color)
|
|
{
|
|
float lum=0.2126f*color.X + 0.7152f*color.Y + 0.0722f*color.Z;
|
|
return (unsigned char) (255.0f*lum);
|
|
}
|
|
|
|
void Vector4_to_Color(unsigned int *outc,const Vector4 &inc,const WW3DFormat format)
|
|
{
|
|
// convert to ARGB 32-bit
|
|
unsigned int color=DX8Wrapper::Convert_Color(inc);
|
|
unsigned char *argb=(unsigned char*) &color;
|
|
unsigned char r,g,b,a,lum;
|
|
|
|
switch (format)
|
|
{
|
|
case WW3D_FORMAT_R8G8B8:
|
|
case WW3D_FORMAT_A8R8G8B8:
|
|
case WW3D_FORMAT_X8R8G8B8:
|
|
*outc=color;
|
|
break;
|
|
case WW3D_FORMAT_R5G6B5:
|
|
r=argb[1] >> 3;
|
|
g=argb[2] >> 2;
|
|
b=argb[3] >> 3;
|
|
*outc=(r << 11) | (g<<5) | b;
|
|
break;
|
|
case WW3D_FORMAT_X1R5G5B5:
|
|
case WW3D_FORMAT_A1R5G5B5:
|
|
a=argb[0] >> 7;
|
|
r=argb[1] >> 3;
|
|
g=argb[2] >> 3;
|
|
b=argb[3] >> 3;
|
|
*outc=(a<<15) | (r<<10) | (g<<5) | b;
|
|
break;
|
|
|
|
case WW3D_FORMAT_A4R4G4B4:
|
|
case WW3D_FORMAT_X4R4G4B4:
|
|
a=argb[0] >> 4;
|
|
r=argb[1] >> 4;
|
|
g=argb[2] >> 4;
|
|
b=argb[3] >> 4;
|
|
*outc=(a<<12) | (r<<8) | (g<<4) | b;
|
|
break;
|
|
case WW3D_FORMAT_R3G3B2:
|
|
case WW3D_FORMAT_A8R3G3B2:
|
|
a=argb[0];
|
|
r=argb[1] >> 5;
|
|
g=argb[2] >> 5;
|
|
b=argb[3] >> 6;
|
|
*outc=(a<<8) | (r<<5) | (g<<2) | b;
|
|
break;
|
|
case WW3D_FORMAT_A8:
|
|
*outc=argb[0];
|
|
break;
|
|
case WW3D_FORMAT_L8:
|
|
lum=RGB_to_CIEY(inc);
|
|
*outc=lum;
|
|
break;
|
|
case WW3D_FORMAT_A8L8:
|
|
a=argb[0];
|
|
lum=RGB_to_CIEY(inc);
|
|
*outc=(a<<8) | lum;
|
|
break;
|
|
case WW3D_FORMAT_A4L4:
|
|
a=argb[0] >> 4;
|
|
lum=RGB_to_CIEY(inc);
|
|
lum=lum>>4;
|
|
*outc=(a<<4) | lum;
|
|
break;
|
|
default:
|
|
WWASSERT(0);
|
|
}
|
|
}
|
|
|
|
void Color_to_Vector4(Vector4* outc,const unsigned int inc,const WW3DFormat format)
|
|
{
|
|
WWASSERT(outc);
|
|
|
|
unsigned char *argb=(unsigned char*) &inc;
|
|
unsigned char a,r,g,b;
|
|
a=r=g=b=0;
|
|
|
|
switch (format)
|
|
{
|
|
case WW3D_FORMAT_R8G8B8:
|
|
case WW3D_FORMAT_A8R8G8B8:
|
|
case WW3D_FORMAT_X8R8G8B8:
|
|
a=argb[0];
|
|
r=argb[1];
|
|
g=argb[2];
|
|
b=argb[3];
|
|
break;
|
|
case WW3D_FORMAT_R5G6B5:
|
|
r=argb[1]<<3;
|
|
g=argb[2]<<2;
|
|
b=argb[3]<<3;
|
|
break;
|
|
case WW3D_FORMAT_X1R5G5B5:
|
|
case WW3D_FORMAT_A1R5G5B5:
|
|
a=argb[0]<<7;
|
|
r=argb[1]<<3;
|
|
g=argb[2]<<3;
|
|
b=argb[3]<<3;
|
|
break;
|
|
case WW3D_FORMAT_A4R4G4B4:
|
|
a=argb[0]<<4;
|
|
r=argb[1]<<4;
|
|
g=argb[2]<<4;
|
|
b=argb[3]<<4;
|
|
break;
|
|
case WW3D_FORMAT_R3G3B2:
|
|
r=argb[1]<<5;
|
|
g=argb[2]<<5;
|
|
b=argb[3]<<6;
|
|
break;
|
|
case WW3D_FORMAT_A8:
|
|
a=argb[0];
|
|
break;
|
|
case WW3D_FORMAT_A8R3G3B2:
|
|
a=argb[0];
|
|
r=argb[1]<<5;
|
|
g=argb[2]<<5;
|
|
b=argb[3]<<6;
|
|
break;
|
|
case WW3D_FORMAT_X4R4G4B4:
|
|
r=argb[1]<<4;
|
|
g=argb[2]<<4;
|
|
b=argb[3]<<4;
|
|
break;
|
|
default:
|
|
WWASSERT(0);
|
|
}
|
|
outc->X=r/255.0f;
|
|
outc->Y=g/255.0f;
|
|
outc->Z=b/255.0f;
|
|
outc->W=a/255.0f;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
//
|
|
// Utility function for determining WW3D format from TGA file header.
|
|
//
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void Get_WW3D_Format(WW3DFormat& dest_format,WW3DFormat& src_format,unsigned& src_bpp,const Targa& targa)
|
|
{
|
|
Get_WW3D_Format(src_format,src_bpp,targa);
|
|
dest_format=src_format;
|
|
if ((dest_format==WW3D_FORMAT_P8) || (dest_format==WW3D_FORMAT_L8)) {
|
|
dest_format=WW3D_FORMAT_X8R8G8B8;
|
|
}
|
|
dest_format=Get_Valid_Texture_Format(dest_format,false); // No compressed destination format if reading from targa...
|
|
|
|
}
|
|
|
|
void Get_WW3D_Format(WW3DFormat& src_format,unsigned& src_bpp,const Targa& targa)
|
|
{
|
|
// Guess the format from the TGA Header bits:
|
|
src_format = WW3D_FORMAT_UNKNOWN;
|
|
src_bpp=0;
|
|
switch (targa.Header.PixelDepth) {
|
|
case 32: src_format = WW3D_FORMAT_A8R8G8B8; src_bpp=4; break;
|
|
case 24: src_format = WW3D_FORMAT_R8G8B8; src_bpp=3; break;
|
|
case 16: src_format = WW3D_FORMAT_A1R5G5B5; src_bpp=2; break;
|
|
case 8:
|
|
src_bpp=1;
|
|
if (targa.Header.ColorMapType == 1) src_format = WW3D_FORMAT_P8;
|
|
else if (targa.Header.ImageType == TGA_MONO) src_format = WW3D_FORMAT_L8;
|
|
else src_format = WW3D_FORMAT_A8;
|
|
break;
|
|
default:
|
|
WWDEBUG_SAY(("TextureClass: Targa has unsupported bitdepth(%i)\n",targa.Header.PixelDepth));
|
|
// WWASSERT(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
//
|
|
// Utility function for determining valid WW3D format
|
|
//
|
|
// ----------------------------------------------------------------------------
|
|
|
|
WW3DFormat Get_Valid_Texture_Format(WW3DFormat format, bool is_compression_allowed)
|
|
{
|
|
int w,h,bits;
|
|
bool windowed;
|
|
|
|
if (!DX8Wrapper::Get_Current_Caps()->Support_DXTC() ||
|
|
!is_compression_allowed) {
|
|
switch (format) {
|
|
case WW3D_FORMAT_DXT1: format=WW3D_FORMAT_R8G8B8; break;
|
|
case WW3D_FORMAT_DXT2:
|
|
case WW3D_FORMAT_DXT3:
|
|
case WW3D_FORMAT_DXT4:
|
|
case WW3D_FORMAT_DXT5: format=WW3D_FORMAT_A8R8G8B8; break;
|
|
default: break;
|
|
}
|
|
}
|
|
else {
|
|
switch (format) {
|
|
case WW3D_FORMAT_DXT1:
|
|
// NVidia hack - switch to DXT2 is there is no DXT1 support (which is disabled on NVidia cards)
|
|
if (!DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(WW3D_FORMAT_DXT1) &&
|
|
DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(WW3D_FORMAT_DXT2)) {
|
|
format=WW3D_FORMAT_DXT2;
|
|
}
|
|
break;
|
|
case WW3D_FORMAT_DXT2:
|
|
case WW3D_FORMAT_DXT3:
|
|
case WW3D_FORMAT_DXT4:
|
|
case WW3D_FORMAT_DXT5:
|
|
if (!DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(format)) format=WW3D_FORMAT_A8R8G8B8;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (format==WW3D_FORMAT_R8G8B8) {
|
|
format=WW3D_FORMAT_X8R8G8B8;
|
|
}
|
|
|
|
WW3D::Get_Device_Resolution(w,h,bits,windowed);
|
|
if (WW3D::Get_Texture_Bitdepth()==16) bits=16;
|
|
|
|
// if the device bitdepth is 16, don't allow 32 bit textures
|
|
if (bits<=16) {
|
|
switch (format) {
|
|
case WW3D_FORMAT_A8R8G8B8: return WW3D_FORMAT_A4R4G4B4;
|
|
case WW3D_FORMAT_X8R8G8B8:
|
|
case WW3D_FORMAT_R8G8B8: return WW3D_FORMAT_R5G6B5;
|
|
case WW3D_FORMAT_A4R4G4B4:
|
|
case WW3D_FORMAT_A1R5G5B5:
|
|
case WW3D_FORMAT_R5G6B5:
|
|
case WW3D_FORMAT_L8:
|
|
case WW3D_FORMAT_A8:
|
|
case WW3D_FORMAT_P8:
|
|
default:
|
|
// Basically, anything goes here (just make sure the most common 32 bit formats are converted to 16 bit
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
// Fallback if the hardware doesn't support the texture format
|
|
if (!DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(format)) {
|
|
format=WW3D_FORMAT_A8R8G8B8;
|
|
if (!DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(format)) {
|
|
format=WW3D_FORMAT_A4R4G4B4;
|
|
if (!DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(format)) {
|
|
// If still no luck, try non-alpha formats
|
|
|
|
format=WW3D_FORMAT_X8R8G8B8;
|
|
if (!DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(format)) {
|
|
format=WW3D_FORMAT_R5G6B5;
|
|
if (!DX8Wrapper::Get_Current_Caps()->Support_Texture_Format(format)) {
|
|
WWASSERT_PRINT(0,("No valid texture format found"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return format;
|
|
}
|
|
|
|
unsigned Get_Bytes_Per_Pixel(WW3DFormat format)
|
|
{
|
|
switch (format) {
|
|
case WW3D_FORMAT_X8R8G8B8:
|
|
case WW3D_FORMAT_X8L8V8U8:
|
|
case WW3D_FORMAT_A8R8G8B8: return 4;
|
|
case WW3D_FORMAT_R8G8B8: return 3;
|
|
case WW3D_FORMAT_A1R5G5B5:
|
|
case WW3D_FORMAT_A4R4G4B4:
|
|
case WW3D_FORMAT_U8V8:
|
|
case WW3D_FORMAT_L6V5U5:
|
|
case WW3D_FORMAT_R5G6B5: return 2;
|
|
case WW3D_FORMAT_R3G3B2:
|
|
case WW3D_FORMAT_L8:
|
|
case WW3D_FORMAT_A8:
|
|
case WW3D_FORMAT_P8: return 1;
|
|
|
|
default: WWASSERT(0); break;
|
|
}
|
|
return 0;
|
|
}
|