From 1639c37ca5922e086cd0edc0b486965e3698a6a0 Mon Sep 17 00:00:00 2001 From: Robert Beckebans Date: Mon, 1 Jul 2024 22:35:27 +0200 Subject: [PATCH] Fixed a couple of bugs regarding Flash JSON reimport --- README.md | 3 - neo/framework/Common_dialog.cpp | 4 +- neo/swf/SWF.h | 2 +- neo/swf/SWF_Load.cpp | 3 +- neo/swf/SWF_Main.cpp | 114 +++++++++++++++++++++++++++----- neo/swf/SWF_SpriteInstance.cpp | 2 +- neo/swf/SWF_Sprites.cpp | 4 +- 7 files changed, 105 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index eb1ba180..a4eb7b88 100644 --- a/README.md +++ b/README.md @@ -662,9 +662,6 @@ convertMapQuakeToDoom `` | Command: Expects a Quake 1 .map in the makeZooMapForModels | Command: Makes a Source engine style zoo map with mapobject/models like .blwo, .base et cetera and saves it to maps/zoomaps/zoo_models.map. This helps mappers to get a good overview of the trememdous amount of custom models available in Doom 3 BFG by sorting them into categories and arranging them in 3D. It also filters models so that only modular models are picked that can be reused in new maps. exportEntityDefsToBlender | Command: Exports all entity and model defs to base/_bl/entities.json for usage in Blender before loading a map. exportMapToOBJ | Command: Convert .map file to .obj/.mtl -postLoadExportFlashAtlas | Cvar: Set to 1 at startup to dump the Flash images to exported/swf/ -postLoadExportFlashToSWF | Cvar: Set to 1 at startup to dump the Flash .bswf files as .swf (WIP) -postLoadExportFlashToJSON | Cvar: Set to 1 at startup to dump the Flash .bswf files as .json. Can be reimported into the engine and imported into Blender for inspection swf_show | Cvar: Draws the bounding box of instanced Flash sprites in red and their names makeMaterials `` | Command: Make a .mtr file based on PBR naming conventions diff --git a/neo/framework/Common_dialog.cpp b/neo/framework/Common_dialog.cpp index d40d9918..723986bd 100644 --- a/neo/framework/Common_dialog.cpp +++ b/neo/framework/Common_dialog.cpp @@ -811,8 +811,8 @@ void idCommonDialog::Init() Shutdown(); - dialog = new( TAG_SWF ) idSWF( "dialog" ); - saveIndicator = new( TAG_SWF ) idSWF( "save_indicator" ); + dialog = new( TAG_SWF ) idSWF( "dialog", NULL ); + saveIndicator = new( TAG_SWF ) idSWF( "save_indicator", NULL ); #define BIND_DIALOG_CONSTANT( x ) dialog->SetGlobal( #x, x ) if( dialog != NULL ) diff --git a/neo/swf/SWF.h b/neo/swf/SWF.h index 8339c871..260f84c0 100644 --- a/neo/swf/SWF.h +++ b/neo/swf/SWF.h @@ -86,7 +86,7 @@ This class handles loading and rendering SWF files class idSWF { public: - idSWF( const char* filename, idSoundWorld* soundWorld = NULL ); + idSWF( const char* filename, idSoundWorld* soundWorld, bool exportJSON = false, bool exportSWF = false ); ~idSWF(); bool IsLoaded() diff --git a/neo/swf/SWF_Load.cpp b/neo/swf/SWF_Load.cpp index c58cee72..935476cd 100644 --- a/neo/swf/SWF_Load.cpp +++ b/neo/swf/SWF_Load.cpp @@ -1154,7 +1154,7 @@ bool idSWF::LoadJSON( const char* filename ) for( int d = 0; d < shape->lineDraws.Num(); d++ ) { idSWFShapeDrawLine& lineDraw = shape->lineDraws[d]; - Value& jsonDraw = entry["lineDraw"][d]; + Value& jsonDraw = entry["lineDraws"][d]; Value& style = jsonDraw["style"]; lineDraw.style.startWidth = style["startWidth"].GetUint(); @@ -1808,4 +1808,5 @@ void idSWF::WriteJSON( const char* jsonFilename ) file->WriteFloatString( "\t]\n" ); file->WriteFloatString( "}\n" ); } + // RB end diff --git a/neo/swf/SWF_Main.cpp b/neo/swf/SWF_Main.cpp index 2bf9a358..f425e306 100644 --- a/neo/swf/SWF_Main.cpp +++ b/neo/swf/SWF_Main.cpp @@ -34,11 +34,6 @@ If you have questions concerning this license or the applicable additional terms #pragma warning(disable: 4355) // 'this' : used in base member initializer list idCVar swf_loadBinary( "swf_loadBinary", "1", CVAR_INTEGER, "used to set whether to load binary swf from generated" ); -// RB begin -idCVar postLoadExportFlashAtlas( "postLoadExportFlashAtlas", "0", CVAR_INTEGER, "" ); -idCVar postLoadExportFlashToSWF( "postLoadExportFlashToSWF", "0", CVAR_INTEGER, "" ); -idCVar postLoadExportFlashToJSON( "postLoadExportFlashToJSON", "0", CVAR_INTEGER, "" ); -// RB end int idSWF::mouseX = -1; int idSWF::mouseY = -1; @@ -53,7 +48,7 @@ extern idCVar in_useJoystick; idSWF::idSWF =================== */ -idSWF::idSWF( const char* filename_, idSoundWorld* soundWorld_ ) +idSWF::idSWF( const char* filename_, idSoundWorld* soundWorld_, bool exportJSON, bool exportSWF ) { atlasMaterial = NULL; @@ -179,7 +174,7 @@ idSWF::idSWF( const char* filename_, idSoundWorld* soundWorld_ ) } } - if( postLoadExportFlashToJSON.GetBool() ) + if( exportJSON ) { idStr jsonFileName = "exported/"; jsonFileName += filename; @@ -196,7 +191,7 @@ idSWF::idSWF( const char* filename_, idSoundWorld* soundWorld_ ) int atlasExportImageWidth = 0; int atlasExportImageHeight = 0; - if( /*!loadedFromJSON &&*/ ( postLoadExportFlashToJSON.GetBool() || postLoadExportFlashAtlas.GetBool() || postLoadExportFlashToSWF.GetBool() ) ) + if( /*!loadedFromJSON &&*/ ( exportJSON || exportSWF ) ) { // try loading the TGA first ID_TIME_T timestamp; @@ -205,7 +200,7 @@ idSWF::idSWF( const char* filename_, idSoundWorld* soundWorld_ ) if( ( atlasExportImageRGBA == NULL ) || ( timestamp == FILE_NOT_FOUND_TIMESTAMP ) ) { - idLib::Warning( "failed to load atlas '%s'", atlasFileName.c_str() ); + //idLib::Warning( "failed to load atlas '%s'", atlasFileName.c_str() ); idStrStatic< MAX_OSPATH > generatedName = atlasFileName; generatedName.StripFileExtension(); @@ -221,15 +216,33 @@ idSWF::idSWF( const char* filename_, idSoundWorld* soundWorld_ ) const byte* data = im.GetImageData( 0 ); - //( img.level, 0, 0, img.destZ, img.width, img.height, data ); + // 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 - idTempArray rgba( img.width * img.height * 4 ); + int dxtWidth = img.width; + int dxtHeight = img.height; + 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; + } + } + + idTempArray rgba( dxtWidth * dxtHeight * 4 ); memset( rgba.Ptr(), 255, rgba.Size() ); if( imgHeader.format == FMT_DXT1 ) { idDxtDecoder dxt; - dxt.DecompressImageDXT1( data, rgba.Ptr(), img.width, img.height ); + dxt.DecompressImageDXT1( data, rgba.Ptr(), dxtWidth, dxtHeight ); + + for( int i = 0; i < ( dxtWidth * dxtHeight ); i++ ) + { + rgba[i * 4 + 3] = 255; + } } else if( imgHeader.format == FMT_DXT5 ) { @@ -237,16 +250,33 @@ idSWF::idSWF( const char* filename_, idSoundWorld* soundWorld_ ) if( imgHeader.colorFormat == CFM_NORMAL_DXT5 ) { - dxt.DecompressNormalMapDXT5( data, rgba.Ptr(), img.width, img.height ); + dxt.DecompressNormalMapDXT5( data, rgba.Ptr(), dxtWidth, dxtHeight ); + + for( int i = 0; i < ( dxtWidth * dxtHeight ); i++ ) + { + rgba[i * 4 + 3] = 255; + } } + /* else if( imgHeader.colorFormat == CFM_YCOCG_DXT5 ) { - dxt.DecompressYCoCgDXT5( data, rgba.Ptr(), img.width, img.height ); + 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 ); - dxt.DecompressImageDXT5( data, rgba.Ptr(), img.width, img.height ); + for( int i = 0; i < ( dxtWidth * dxtHeight ); i++ ) + { + rgba[i * 4 + 3] = 255; + } } } else if( imgHeader.format == FMT_LUM8 || imgHeader.format == FMT_INT8 ) @@ -303,9 +333,11 @@ idSWF::idSWF( const char* filename_, idSoundWorld* soundWorld_ ) atlasFileNameExport.Replace( "generated/", "exported/" ); atlasFileNameExport.SetFileExtension( ".png" ); + idLib::Printf( "Exporting image '%s'\n", atlasFileNameExport.c_str() ); + R_WritePNG( atlasFileNameExport, rgba.Ptr(), 4, img.width, img.height, "fs_basepath" ); - if( postLoadExportFlashToSWF.GetBool() ) + if( exportSWF ) { atlasExportImageWidth = img.width; atlasExportImageHeight = img.height; @@ -317,7 +349,7 @@ idSWF::idSWF( const char* filename_, idSoundWorld* soundWorld_ ) } - if( postLoadExportFlashToSWF.GetBool() ) + if( exportSWF ) { idStr swfFileName = "exported/"; swfFileName += filename; @@ -974,3 +1006,51 @@ void idSWF::idSWFScriptNativeVar_crop::Set( idSWFScriptObject* object, const idS { pThis->crop = value.ToBool(); } + +// RB begin +CONSOLE_COMMAND_SHIP( exportFlash, "Export all .bswf files to the exported/swf/ folder", NULL ) +{ + bool exportSWF = false; + + for( int i = 1; i < args.Argc(); i++ ) + { + idStr option = args.Argv( i ); + option.StripLeading( '-' ); + + if( option.Icmp( "swf" ) == 0 ) + { + exportSWF = true; + } + } + + idFileList* files = fileSystem->ListFilesTree( "generated", ".bswf", true, true ); + + for( int f = 0; f < files->GetList().Num(); f++ ) + { + idStr bswfName = files->GetList()[ f ]; + +#if 0 + // only export hud for testing + if( idStr::Icmp( bswfName, "generated/swf/hud.bswf" ) != 0 ) + { + continue; + } +#endif + + /* + idFileLocal bFile = fileSystem->OpenFileRead( bswfName ); + if( bFile == NULL ) + { + continue; + } + */ + + bswfName.StripLeadingOnce( "generated/" ); + + idSWF* swf = new idSWF( bswfName, NULL, true, true ); //exportSWF ); + delete swf; + } + + fileSystem->FreeFileList( files ); +} +// RB end \ No newline at end of file diff --git a/neo/swf/SWF_SpriteInstance.cpp b/neo/swf/SWF_SpriteInstance.cpp index 342751c2..5caaf0fd 100644 --- a/neo/swf/SWF_SpriteInstance.cpp +++ b/neo/swf/SWF_SpriteInstance.cpp @@ -427,7 +427,7 @@ void idSWFSpriteInstance::RunTo( int targetFrame ) targetFrame = sprite->frameOffsets.Num() - 1; } - // actions.Clear(); + //actions.Clear(); uint32 firstActionCommand = sprite->frameOffsets[ targetFrame - 1 ]; diff --git a/neo/swf/SWF_Sprites.cpp b/neo/swf/SWF_Sprites.cpp index 6f6559cf..563ad891 100644 --- a/neo/swf/SWF_Sprites.cpp +++ b/neo/swf/SWF_Sprites.cpp @@ -725,8 +725,8 @@ void idSWFSprite::WriteJSON_DoAction( idFile* file, idSWFBitStream& bitstream, i base64.Encode( bitstream.Ptr(), bitstream.Length() ); #if 1 - //file->WriteFloatString( "%s\t\t\t\t{\t\"type\": \"Tag_DoAction\", \"streamLength\": %i, \"stream\": \"%s\" }", ( commandID != 0 ) ? ",\n" : "", bitstream.Length(), base64.c_str() ); - file->WriteFloatString( "%s\t\t\t\t{\t\"type\": \"Tag_DoAction\", \"streamLength\": %i, \"stream\": \"FIXME\" }", ( commandID != 0 ) ? ",\n" : "", bitstream.Length() ); + file->WriteFloatString( "%s\t\t\t\t{\t\"type\": \"Tag_DoAction\", \"streamLength\": %i, \"stream\": \"%s\" }", ( commandID != 0 ) ? ",\n" : "", bitstream.Length(), base64.c_str() ); + //file->WriteFloatString( "%s\t\t\t\t{\t\"type\": \"Tag_DoAction\", \"streamLength\": %i, \"stream\": \"FIXME\" }", ( commandID != 0 ) ? ",\n" : "", bitstream.Length() ); #else idSWFScriptObject* scriptObject = idSWFScriptObject::Alloc(); scriptObject->SetPrototype( &spriteInstanceScriptObjectPrototype );