/* ** 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 . */ /*********************************************************************************************** *** 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 /* 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; }