This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/ww3d2/ww3dformat.cpp

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;
}