diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index fb8c59ef..51eecb58 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -27,9 +27,11 @@ _______________________________ * Added console command convertMapToValve220 `` -[MISCELLANEOUS] +* Added console command exportImagesToTrenchBroom which decompresses and saves all .bimage images to _tb/*.png files -* Added CMake options STANDALONE and DOOM_CLASSIC +* Added console command exportModelsToTrenchBroom which saves all .base|.blwo|.bmd5mesh models to _tb/*.obj files + +[MISCELLANEOUS] * Added CMake options STANDALONE and DOOM_CLASSIC diff --git a/neo/framework/Common_mapconvert.cpp b/neo/framework/Common_mapconvert.cpp index 6260579f..90784c1c 100644 --- a/neo/framework/Common_mapconvert.cpp +++ b/neo/framework/Common_mapconvert.cpp @@ -715,8 +715,13 @@ CONSOLE_COMMAND( convertMapToValve220, "Convert .map file to the Valve 220 map f idMapFile map; if( map.Parse( mapName, true, false ) ) { + // make sure we have access to all .bimage files for that map + fileSystem->BeginLevelLoad( filename, NULL, 0 ); + map.ConvertToValve220Format(); + fileSystem->EndLevelLoad(); + idStrStatic< MAX_OSPATH > canonical = mapName; canonical.ToLower(); diff --git a/neo/framework/DeclManager.cpp b/neo/framework/DeclManager.cpp index 2d9f4026..bd76ae46 100644 --- a/neo/framework/DeclManager.cpp +++ b/neo/framework/DeclManager.cpp @@ -29,6 +29,9 @@ If you have questions concerning this license or the applicable additional terms #include "precompiled.h" #pragma hdrstop +#include "../renderer/Image.h" +#include "../renderer/DXT/DXTCodec.h" +#include "../renderer/Color/ColorSpace.h" /* @@ -264,6 +267,7 @@ private: static void ExportDeclsToBlender_f( const idCmdArgs& args ); static void ExportDeclsToTrenchBroom_f( const idCmdArgs& args ); static void ExportModelsToTrenchBroom_f( const idCmdArgs& args ); + static void ExportImagesToTrenchBroom_f( const idCmdArgs& args ); // RB end }; @@ -962,6 +966,7 @@ void idDeclManagerLocal::Init() cmdSystem->AddCommand( "exportEntityDefsToBlender", ExportDeclsToBlender_f, CMD_FL_SYSTEM, "exports all entity and model defs to exported/entities.json" ); cmdSystem->AddCommand( "exportFGD", ExportDeclsToTrenchBroom_f, CMD_FL_SYSTEM, "exports all entity and model defs to exported/_tb/Doom3.fgd" ); cmdSystem->AddCommand( "exportModelsToTrenchBroom", ExportModelsToTrenchBroom_f, CMD_FL_SYSTEM, "exports all generated models like blwo, base .. to _tb/*.obj" ); + cmdSystem->AddCommand( "exportImagesToTrenchBroom", ExportImagesToTrenchBroom_f, CMD_FL_SYSTEM, "exports all generated bimages to _tb/*.png" ); // RB end common->Printf( "------------------------------\n" ); @@ -2811,6 +2816,186 @@ void idDeclManagerLocal::ExportModelsToTrenchBroom_f( const idCmdArgs& args ) common->FatalError( "Exporting successful, need to restart manually" ); } + +void idDeclManagerLocal::ExportImagesToTrenchBroom_f( const idCmdArgs& args ) +{ + int totalImagesCount = 0; + + idFileList* files = fileSystem->ListFilesTree( "generated", ".bimage", true, true ); + + int totalStart = Sys_Milliseconds(); + + for( int f = 0; f < files->GetList().Num(); f++ ) + { + idStr imageName = files->GetList()[ f ]; + + if( idStr::Icmpn( imageName, "generated/images/env/maps/game/", 31 ) == 0 ) + { + // skip HDR cache data + continue; + } + + if( idStr::FindText( imageName, "addnormals", false ) != -1 ) + { + continue; + } + + if( idStr::FindText( imageName, "heightmap", false ) != -1 ) + { + continue; + } + + if( idStr::FindText( imageName, "makealpha", false ) != -1 ) + { + continue; + } + + if( idStr::FindText( imageName, "makeintensity", false ) != -1 ) + { + continue; + } + +#if 0 + // only export decals for testing + if( idStr::Icmpn( imageName, "generated/images/textures/decals/", 33 ) != 0 ) + { + continue; + } + + if( idStr::FindText( imageName, "a_pipecap2a_d", false ) != -1 ) + { + totalImagesCount++; + } +#endif + + + idFileLocal bFile = fileSystem->OpenFileRead( imageName ); + if( bFile == NULL ) + { + continue; + } + + idBinaryImage im( imageName ); + ID_TIME_T binaryFileTime = im.LoadFromGeneratedFile( bFile, FILE_NOT_FOUND_TIMESTAMP ); + + if( binaryFileTime != FILE_NOT_FOUND_TIMESTAMP ) + { + const bimageFile_t& imgHeader = im.GetFileHeader(); + const bimageImage_t& img = im.GetImageHeader( 0 ); + + const byte* data = im.GetImageData( 0 ); + + if( ( imgHeader.format == FMT_DXT5 || imgHeader.format == FMT_DXT1 ) && ( imgHeader.colorFormat != CFM_GREEN_ALPHA ) ) + { + idLib::Printf( "Exporting image '%s'\n", imageName.c_str() ); + + // RB: Images that are were DXT compressed and aren't multiples of 4 were padded out before compressing + // however the idBinaryImageData stores the original input width and height. + // We need multiples of 4 for the decompression routines + + int dxtWidth = 0; + int dxtHeight = 0; + if( imgHeader.format == FMT_DXT5 || imgHeader.format == FMT_DXT1 ) + { + if( ( img.width & 3 ) || ( img.height & 3 ) ) + { + dxtWidth = ( img.width + 3 ) & ~3; + dxtHeight = ( img.height + 3 ) & ~3; + } + else + { + dxtWidth = img.width; + dxtHeight = img.height; + } + } + + idTempArray rgba( dxtWidth * dxtHeight * 4 ); + memset( rgba.Ptr(), 255, rgba.Size() ); + + if( imgHeader.format == FMT_DXT1 ) + { + idDxtDecoder dxt; + dxt.DecompressImageDXT1( data, rgba.Ptr(), dxtWidth, dxtHeight ); + } + else if( imgHeader.format == FMT_DXT5 ) + { + idDxtDecoder dxt; + + if( imgHeader.colorFormat == CFM_NORMAL_DXT5 ) + { + dxt.DecompressNormalMapDXT5( data, rgba.Ptr(), dxtWidth, dxtHeight ); + } + else if( imgHeader.colorFormat == CFM_YCOCG_DXT5 ) + { + dxt.DecompressYCoCgDXT5( data, rgba.Ptr(), dxtWidth, dxtHeight ); + idColorSpace::ConvertCoCg_YToRGB( rgba.Ptr(), rgba.Ptr(), dxtWidth, dxtHeight ); + + for( int i = 0; i < ( dxtWidth * dxtHeight ); i++ ) + { + rgba[i * 4 + 3] = 255; + } + } + else + { + dxt.DecompressImageDXT5( data, rgba.Ptr(), dxtWidth, dxtHeight ); + } + } + + + imageName.StripLeadingOnce( "generated/images/" ); + + idStrStatic< MAX_OSPATH > exportName = "exported/_tb/"; + exportName += imageName; + int idx = exportName.Find( '#' ); + exportName.CapLength( idx ); + + exportName.SetFileExtension( ".png" ); + + if( dxtWidth != img.width || dxtHeight != img.height ) + { + // scale DXT sized images back to the original size + byte* scaled = R_Dropsample( rgba.Ptr(), dxtWidth, dxtHeight, img.width, img.height ); + +#if 1 + if( img.width > 16 && img.height > 16 ) + { + R_WritePNG( exportName, scaled, 4, img.width, img.height, true, "fs_basepath" ); + } + else +#endif + { + exportName.SetFileExtension( ".tga" ); + R_WriteTGA( exportName, scaled, img.width, img.height, false, "fs_basepath" ); + } + + Mem_Free( scaled ); + } + else + { +#if 1 + if( img.width > 16 && img.height > 16 ) + { + R_WritePNG( exportName, rgba.Ptr(), 4, img.width, img.height, true, "fs_basepath" ); + } + else +#endif + { + exportName.SetFileExtension( ".tga" ); + R_WriteTGA( exportName, rgba.Ptr(), img.width, img.height, false, "fs_basepath" ); + } + } + } + } + + totalImagesCount++; + } + fileSystem->FreeFileList( files ); + + int totalEnd = Sys_Milliseconds(); + + common->Printf( "----------------------------\n" ); + common->Printf( "Exported and decompressed %d images in %5.1f minutes.\n", totalImagesCount, ( totalEnd - totalStart ) / ( 1000.0f * 60 ) ); +} // RB end /* diff --git a/neo/renderer/BinaryImage.h b/neo/renderer/BinaryImage.h index 027af41b..fb00f47e 100644 --- a/neo/renderer/BinaryImage.h +++ b/neo/renderer/BinaryImage.h @@ -56,6 +56,7 @@ public: void Load2DAtlasMipchainFromMemory( int width, int height, const byte* pic_const, int numLevels, textureFormat_t& textureFormat, textureColor_t& colorFormat ); void LoadCubeFromMemory( int width, const byte* pics[6], int numLevels, textureFormat_t& textureFormat, bool gammaMips ); + bool LoadFromGeneratedFile( idFile* f, ID_TIME_T sourceFileTime ); ID_TIME_T LoadFromGeneratedFile( ID_TIME_T sourceFileTime ); ID_TIME_T WriteGeneratedFile( ID_TIME_T sourceFileTime ); @@ -123,7 +124,6 @@ private: private: void MakeGeneratedFileName( idStr& gfn ); - bool LoadFromGeneratedFile( idFile* f, ID_TIME_T sourceFileTime ); }; #endif // __BINARYIMAGE_H__ diff --git a/neo/renderer/DXT/DXTDecoder.cpp b/neo/renderer/DXT/DXTDecoder.cpp index afb89fa4..2db1320d 100644 --- a/neo/renderer/DXT/DXTDecoder.cpp +++ b/neo/renderer/DXT/DXTDecoder.cpp @@ -398,8 +398,8 @@ 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 ); + float s = idMath::Sin( angle ); + float c = idMath::Cos( angle ); int scale = ( c1 >> 3 ) + 1; for( int i = 0; i < 16; i++ ) @@ -614,7 +614,7 @@ void idDxtDecoder::DecompressNormalMapDXT5( const byte* inBuf, byte* outBuf, int { z = 0.0f; } - normals[k * 4 + 2] = sqrt( z ); + normals[k * 4 + 2] = idMath::Sqrt( z ); } for( int k = 0; k < 16; k++ ) { diff --git a/neo/swf/SWF_Main.cpp b/neo/swf/SWF_Main.cpp index 067e0e1b..d8001afd 100644 --- a/neo/swf/SWF_Main.cpp +++ b/neo/swf/SWF_Main.cpp @@ -29,7 +29,7 @@ If you have questions concerning this license or the applicable additional terms #include "precompiled.h" #pragma hdrstop #include "../renderer/Image.h" -#include "../renderer/DXT//DXTCodec.h" +#include "../renderer/DXT/DXTCodec.h" #pragma warning(disable: 4355) // 'this' : used in base member initializer list