/* ** 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 : LevelEdit * * * * $Archive:: /Commando/Code/Tools/LevelEdit/TGAToDXT.cpp $* * * * Author:: Ian Leslie * * * * $Modtime:: 8/29/01 5:35p $* * * * $Revision:: 4 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "StdAfx.h" #include "NvDXTLib.h" #include "Targa.h" #include "TGAToDXT.H" #include #include // Singletons. TGAToDXTClass _TGAToDXTConverter; /////////////////////////////////////////////////////////////////////////////// // // TGAToDXTClass // /////////////////////////////////////////////////////////////////////////////// TGAToDXTClass::TGAToDXTClass() : WriteTimePtr (NULL), BufferSize (1024), BufferCount (0) { Buffer = new unsigned char [BufferSize]; ASSERT (Buffer != NULL); } /////////////////////////////////////////////////////////////////////////////// // // ~TGAToDXTClass // /////////////////////////////////////////////////////////////////////////////// TGAToDXTClass::~TGAToDXTClass() { // Clean-up. delete [] Buffer; } /////////////////////////////////////////////////////////////////////////////// // // Convert // /////////////////////////////////////////////////////////////////////////////// bool TGAToDXTClass::Convert (const char *inputpathname, const char *outputpathname, FILETIME *writetimeptr, bool &redundantalpha) { bool success; Targa targa; long error; WriteTimePtr = writetimeptr; redundantalpha = false; success = false; error = targa.Load (inputpathname, TGAF_IMAGE, false); if (error == 0) { bool validbitdepth, validsize, validaspect; // Check that the targa is in the right format. // In order to be valid it must adhere to the following: // 1. Pixel depth must be 24 or 32 (compressor has no support for lower bit depths). // 2. Dimensions >= 4 (DDS block size is 4x4). // 3. Aspect ratio <= 1:8 (some H/W will not render textures above this ratio). // 4. Dimensions must be power of 2 (see below). validbitdepth = ((targa.Header.PixelDepth == 24) || (targa.Header.PixelDepth == 32)); validsize = (targa.Header.Width >= 4) && (targa.Header.Height >= 4); validaspect = ((float) MAX (targa.Header.Width, targa.Header.Height)) / ((float) MIN (targa.Header.Width, targa.Header.Height)) <= 8.0f; if (validbitdepth && validsize && validaspect) { unsigned char *byte; HRESULT errorcode; targa.YFlip(); // If TGA has an alpha channel... if (targa.Header.PixelDepth == 32) { // Analyse the alpha channel and ignore it if it contains redundant data (ie. is either all black or all white). byte = (unsigned char*) targa.GetImage(); if ((*(byte + 3) == 0x00) || (*(byte + 3) == 0xff)) { const unsigned char alpha = *(byte + 3); redundantalpha = true; for (unsigned p = 0; p < ((unsigned) targa.Header.Width) * ((unsigned) targa.Header.Height); p++) { redundantalpha &= (*(byte + 3) == alpha); byte += 4; } } if (!redundantalpha) { errorcode = ::nvDXTcompress ((unsigned char*) targa.GetImage(), targa.Header.Width, targa.Header.Height, TF_DXT5, true, false, 4); } else { unsigned char *nonalphaimage, *nonalphabyte; // Remove the alpha channel and swizel the pixel data. nonalphaimage = new unsigned char [3 * ((unsigned) targa.Header.Width) * ((unsigned) targa.Header.Height)]; nonalphabyte = nonalphaimage; byte = (unsigned char*) targa.GetImage(); for (unsigned p = 0; p < ((unsigned) targa.Header.Width) * ((unsigned) targa.Header.Height); p++) { *(nonalphabyte + 0) = *(byte + 0); *(nonalphabyte + 1) = *(byte + 1); *(nonalphabyte + 2) = *(byte + 2); nonalphabyte += 3; byte += 4; } errorcode = ::nvDXTcompress (nonalphaimage, targa.Header.Width, targa.Header.Height, TF_DXT1, true, false, 3); delete [] nonalphaimage; } } else { errorcode = ::nvDXTcompress ((unsigned char*) targa.GetImage(), targa.Header.Width, targa.Header.Height, TF_DXT1, true, false, 3); } // Was the image compressed successfully? // NOTE: Any image that does not have power of 2 dimensions will not be compressed. if (errorcode >= 0) { Write (outputpathname); success = true; } } } return (success); } /////////////////////////////////////////////////////////////////////////////// // // Write // /////////////////////////////////////////////////////////////////////////////// void TGAToDXTClass::Write (const char *outputpathname) { HANDLE hfile; DWORD bytecountwritten; hfile = ::CreateFile (outputpathname, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0L, NULL); if (hfile != INVALID_HANDLE_VALUE) { LockFile (hfile, 0, 0, BufferCount, 0); WriteFile (hfile, Buffer, BufferCount, &bytecountwritten, NULL); UnlockFile (hfile, 0, 0, BufferCount, 0); // Stamp the write time (if one has been supplied). if (WriteTimePtr != NULL) { SetFileTime (hfile, NULL, NULL, WriteTimePtr); } CloseHandle (hfile); } // Reset buffer. BufferCount = 0; } /////////////////////////////////////////////////////////////////////////////// // // ReadDTXnFile // /////////////////////////////////////////////////////////////////////////////// void ReadDTXnFile (DWORD datacount, void *data) { // Not implemented. ASSERT (false); } /////////////////////////////////////////////////////////////////////////////// // // WriteDTXnFile // /////////////////////////////////////////////////////////////////////////////// void WriteDTXnFile (DWORD datacount, void *data) { // Ensure that the buffer is large enough. if (_TGAToDXTConverter.BufferSize < _TGAToDXTConverter.BufferCount + datacount) { unsigned newbuffersize; unsigned char *newbuffer; newbuffersize = MAX (_TGAToDXTConverter.BufferSize * 2, _TGAToDXTConverter.BufferCount + datacount); newbuffer = new unsigned char [newbuffersize]; ASSERT (newbuffer != NULL); memcpy (newbuffer, _TGAToDXTConverter.Buffer, _TGAToDXTConverter.BufferCount); delete [] _TGAToDXTConverter.Buffer; _TGAToDXTConverter.Buffer = newbuffer; _TGAToDXTConverter.BufferSize = newbuffersize; } // Write new data to buffer. memcpy (_TGAToDXTConverter.Buffer + _TGAToDXTConverter.BufferCount, data, datacount); _TGAToDXTConverter.BufferCount += datacount; }