diff --git a/neo/d3xp/menus/MenuHandler_Shell.cpp b/neo/d3xp/menus/MenuHandler_Shell.cpp
index 40010ed841..630cc4bf93 100644
--- a/neo/d3xp/menus/MenuHandler_Shell.cpp
+++ b/neo/d3xp/menus/MenuHandler_Shell.cpp
@@ -60,7 +60,7 @@ void idMenuHandler_Shell::Update()
ClearWidgetActionRepeater();
}
- if( nextState != state )
+ if( nextState != state && gui->IsContructed() )
{
if( introGui != NULL && introGui->IsActive() )
@@ -162,7 +162,7 @@ void idMenuHandler_Shell::Update()
}
}
- if( activeScreen != nextScreen )
+ if( activeScreen != nextScreen && gui->IsContructed() )
{
ClearWidgetActionRepeater();
diff --git a/neo/swf/SWF.h b/neo/swf/SWF.h
index 260f84c096..bb53487c55 100644
--- a/neo/swf/SWF.h
+++ b/neo/swf/SWF.h
@@ -4,6 +4,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2013 Robert Beckebans
+Copyright (C) 2023 Harrie van Ginneken
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@@ -41,8 +42,10 @@ If you have questions concerning this license or the applicable additional terms
#include "SWF_ParmList.h"
#include "SWF_ScriptFunction.h"
#include "SWF_SpriteInstance.h"
+#include "SWF_EventDispatcher.h"
#include "SWF_ShapeParser.h"
#include "SWF_TextInstance.h"
+#include "SWF_Abc.h"
class idSWFDictionaryEntry
{
@@ -65,6 +68,9 @@ class idSWFDictionaryEntry
// the compressed images are normalize to reduce compression artifacts,
// color must be scaled down by this
idVec4 channelScale;
+ idSWFScriptVar scriptClass;
+ bool resolved;
+ idStrPtr name;
};
struct purgableSwfImage_t
@@ -153,6 +159,11 @@ class idSWF
return *( mainspriteInstance->GetScriptObject() );
}
+ bool IsContructed()
+ {
+ return mainspriteInstance->constructed;
+ }
+
void Invoke( const char* functionName, const idSWFParmList& parms );
void Invoke( const char* functionName, const idSWFParmList& parms, idSWFScriptVar& scriptVar );
void Invoke( const char* functionName, const idSWFParmList& parms, bool& functionExists );
@@ -215,6 +226,8 @@ class idSWF
idSWFScriptObject* HitTest( idSWFSpriteInstance* spriteInstance, const swfRenderState_t& renderState, int x, int y, idSWFScriptObject* parentObject );
+ SWF_AbcFile abcFile;
+ static bool isMouseInClientArea;
private:
idStr filename;
ID_TIME_T timestamp;
@@ -251,7 +264,7 @@ class idSWF
static int mouseX; // mouse x coord for all flash files
static int mouseY; // mouse y coord for all flash files
- static bool isMouseInClientArea;
+
idSWFScriptObject* mouseObject;
idSWFScriptObject* hoverObject;
@@ -269,44 +282,75 @@ class idSWF
idBlockAlloc< idSWFSpriteInstance, 16 > spriteInstanceAllocator;
idBlockAlloc< idSWFTextInstance, 16 > textInstanceAllocator;
+#define SWF_NATIVE_FUNCTION_SWF_NOASAPI_DECLARE( x ) \
+ class idSWFScriptFunction_##x : public idSWFScriptFunction_Nested< idSWF > { \
+ public: \
+ idSWFScriptVar Call( idSWFScriptObject * thisObject, const idSWFParmList & parms ); \
+ } scriptFunction_##x;
+
+#define SWF_NATIVE_FUNCTION_SWF_ASAPI_DECLARE( x ) \
+ class idSWFScriptFunction_##x : public idSWFScriptFunction_Nested< idSWF > { \
+ public: \
+ idSWFScriptFunction_##x(){ static bool once = false; if (!once) {idSwfActionScriptAPI::actionScriptAPIs.Alloc() = this; once = true;}}\
+ idSWFScriptVar Call( idSWFScriptObject * thisObject, const idSWFParmList & parms ); \
+ const char * GetActionScriptAPI( idStr & out ) ;\
+ } scriptFunction_##x;
+
+#define SWF_NATIVE_FUNCTION_SWF_ASAPI_RETURNVAL_DECLARE( x, type, val ) \
+ class idSWFScriptFunction_##x : public idSWFScriptFunction_Nested< idSWF > { \
+ public: \
+ idSWFScriptFunction_##x(){ static bool once = false; if (!once) {idSwfActionScriptAPI::actionScriptAPIs.Alloc() = this; once = true;}}\
+ idSWFScriptVar Call( idSWFScriptObject * thisObject, const idSWFParmList & parms ); \
+ const char * GetActionScriptAPI( idStr & out ) { out = "/** \n * Generated by RBDoom3BFG \n*/\npackage{\n\tpublic function "; out+= #x;out+= +"( ... parms) : ";out+=#type;out+=" { trace(\""; out+= #x; out+="( \" + parms + \" )\");return ";out+= #val;out+=";};\n}"; return #x;} \
+ } scriptFunction_##x;
+
#define SWF_NATIVE_FUNCTION_SWF_DECLARE( x ) \
class idSWFScriptFunction_##x : public idSWFScriptFunction_Nested< idSWF > { \
public: \
+ idSWFScriptFunction_##x(){ static bool once = false; if (!once) {idSwfActionScriptAPI::actionScriptAPIs.Alloc() = this; once = true;}}\
idSWFScriptVar Call( idSWFScriptObject * thisObject, const idSWFParmList & parms ); \
+ const char * GetActionScriptAPI( idStr & out ) { out = "/** \n * Generated by RBDoom3BFG \n*/\npackage{\n\tpublic function "; out+= #x;out+= +"( ... parms) :void { trace(\""; out+= #x; out+="( \" + parms + \" )\")};\n}"; return #x;} \
} scriptFunction_##x;
SWF_NATIVE_FUNCTION_SWF_DECLARE( shortcutKeys_clear );
SWF_NATIVE_FUNCTION_SWF_DECLARE( deactivate );
SWF_NATIVE_FUNCTION_SWF_DECLARE( inhibitControl );
SWF_NATIVE_FUNCTION_SWF_DECLARE( useInhibit );
- SWF_NATIVE_FUNCTION_SWF_DECLARE( precacheSound );
+ SWF_NATIVE_FUNCTION_SWF_ASAPI_RETURNVAL_DECLARE( precacheSound, String, parms[0] );
SWF_NATIVE_FUNCTION_SWF_DECLARE( playSound );
SWF_NATIVE_FUNCTION_SWF_DECLARE( stopSounds );
- SWF_NATIVE_FUNCTION_SWF_DECLARE( getPlatform );
- SWF_NATIVE_FUNCTION_SWF_DECLARE( getTruePlatform );
- SWF_NATIVE_FUNCTION_SWF_DECLARE( getLocalString );
- SWF_NATIVE_FUNCTION_SWF_DECLARE( swapPS3Buttons );
- SWF_NATIVE_FUNCTION_SWF_DECLARE( getCVarInteger );
- SWF_NATIVE_FUNCTION_SWF_DECLARE( setCVarInteger );
- SWF_NATIVE_FUNCTION_SWF_DECLARE( strReplace );
-
- SWF_NATIVE_FUNCTION_SWF_DECLARE( acos );
- SWF_NATIVE_FUNCTION_SWF_DECLARE( cos );
- SWF_NATIVE_FUNCTION_SWF_DECLARE( sin );
- SWF_NATIVE_FUNCTION_SWF_DECLARE( round );
- SWF_NATIVE_FUNCTION_SWF_DECLARE( pow );
- SWF_NATIVE_FUNCTION_SWF_DECLARE( sqrt );
- SWF_NATIVE_FUNCTION_SWF_DECLARE( abs );
- SWF_NATIVE_FUNCTION_SWF_DECLARE( rand );
- SWF_NATIVE_FUNCTION_SWF_DECLARE( floor );
- SWF_NATIVE_FUNCTION_SWF_DECLARE( ceil );
-
- SWF_NATIVE_FUNCTION_SWF_DECLARE( toUpper );
+ SWF_NATIVE_FUNCTION_SWF_ASAPI_RETURNVAL_DECLARE( getPlatform, Number, 2 );
+ SWF_NATIVE_FUNCTION_SWF_ASAPI_RETURNVAL_DECLARE( getTruePlatform, Number, 2 );
+ SWF_NATIVE_FUNCTION_SWF_ASAPI_RETURNVAL_DECLARE( getLocalString, String, parms[0] );
+ SWF_NATIVE_FUNCTION_SWF_ASAPI_RETURNVAL_DECLARE( swapPS3Buttons, Boolean, false );
+ SWF_NATIVE_FUNCTION_SWF_ASAPI_RETURNVAL_DECLARE( getCVarInteger, Number , 1 );
+ SWF_NATIVE_FUNCTION_SWF_NOASAPI_DECLARE( setCVarInteger );
+ SWF_NATIVE_FUNCTION_SWF_ASAPI_RETURNVAL_DECLARE( strReplace, String, parms[0].replace( parms[1], parms[2] ) );
+ SWF_NATIVE_FUNCTION_SWF_NOASAPI_DECLARE( trace );
+ SWF_NATIVE_FUNCTION_SWF_NOASAPI_DECLARE( ArrayToString );
+ SWF_NATIVE_FUNCTION_SWF_NOASAPI_DECLARE( registerUserMouse );
+ SWF_NATIVE_FUNCTION_SWF_NOASAPI_DECLARE( String );
+
+ SWF_NATIVE_FUNCTION_SWF_ASAPI_RETURNVAL_DECLARE( acos, Number, Math.acos( parms[0] ) );
+ SWF_NATIVE_FUNCTION_SWF_ASAPI_RETURNVAL_DECLARE( cos, Number, Math.cos( parms[0] ) );
+ SWF_NATIVE_FUNCTION_SWF_NOASAPI_DECLARE( sin );
+ SWF_NATIVE_FUNCTION_SWF_NOASAPI_DECLARE( round );
+ SWF_NATIVE_FUNCTION_SWF_NOASAPI_DECLARE( pow );
+ SWF_NATIVE_FUNCTION_SWF_NOASAPI_DECLARE( sqrt );
+ SWF_NATIVE_FUNCTION_SWF_NOASAPI_DECLARE( abs );
+ SWF_NATIVE_FUNCTION_SWF_NOASAPI_DECLARE( rand );
+ SWF_NATIVE_FUNCTION_SWF_NOASAPI_DECLARE( floor );
+ SWF_NATIVE_FUNCTION_SWF_NOASAPI_DECLARE( ceil );
+ SWF_NATIVE_FUNCTION_SWF_ASAPI_RETURNVAL_DECLARE( random, Number, Math.random( parms ) );
+
+ SWF_NATIVE_FUNCTION_SWF_NOASAPI_DECLARE( toUpper );
SWF_NATIVE_VAR_DECLARE_NESTED_READONLY( platform, idSWFScriptFunction_getPlatform, Call( object, idSWFParmList() ) );
SWF_NATIVE_VAR_DECLARE_NESTED( blackbars, idSWF );
SWF_NATIVE_VAR_DECLARE_NESTED( crop, idSWF );
+ class idSWFScriptFunction_Object;
+ SWF_NATIVE_VAR_DECLARE_NESTED_READONLY( Object, idSWFScriptFunction_Object, Call( object, idSWFParmList() ) );
class idSWFScriptFunction_Object : public idSWFScriptFunction
{
public:
@@ -516,6 +560,12 @@ class idSWF
// SWF_Zlib.cpp
//----------------------------------
bool Inflate( const byte* input, int inputSize, byte* output, int outputSize );
+ //----------------------------------
+ // SWF_Abc.cpp
+ //----------------------------------
+ void DoABC( idSWFBitStream& bitstream ) ;
+ void SymbolClass( idSWFBitStream& bitstream ) ;
+
// RB begin
bool Deflate( const byte* input, int inputSize, byte* output, int& outputSize );
// RB end
@@ -531,6 +581,8 @@ class idSWF
static const char* GetTagName( swfTag_t tag );
static const char* GetActionName( swfAction_t action );
+ void CreateAbcObjects( idSWFScriptObject* globals );
+ SWF_SymbolClass symbolClasses;
};
#endif // !__SWF_H__
diff --git a/neo/swf/SWF_Abc.cpp b/neo/swf/SWF_Abc.cpp
new file mode 100644
index 0000000000..bbeccf0089
--- /dev/null
+++ b/neo/swf/SWF_Abc.cpp
@@ -0,0 +1,879 @@
+/*
+===========================================================================
+
+Doom 3 BFG Edition GPL Source Code
+Copyright (C) 2023 Harrie van Ginneken
+
+This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
+
+Doom 3 BFG Edition Source Code 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.
+
+Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code. If not, see .
+
+In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
+
+If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
+
+===========================================================================
+*/
+
+//.AS test
+//trace( "hello" )
+//trace( "world" )
+//var clickCount = 0;
+//function playAnimation( event:MouseEvent ) :void {
+// clickCount++;
+// trace( text1.text )
+// text1.text = "clicked me " + clickCount;
+//}
+//// Register the function as a listener with the button.
+//addEventListener( MouseEvent.CLICK, playAnimation );
+
+#include "precompiled.h"
+#pragma hdrstop
+
+#include "SWF_Abc.h"
+
+idCVar swf_abc_verbose( "swf_abc_verbose", "0", CVAR_INTEGER, "1 : writes out all abc data read \n 2 : print bytecode " );
+
+#pragma warning( disable: 4189 ) // local variable is initialized but not referenced
+
+void trace( const char* fmt, ... )
+{
+ if( swf_abc_verbose.GetInteger() == 1 )
+ {
+ //common->PrintPrefix("[SWF]");
+ va_list argptr;
+ va_start( argptr, fmt );
+ common->VPrintf( fmt, argptr );
+ va_end( argptr );
+ //common->PrintPrefix("");
+ }
+}
+
+#define toString(x) asString(x,constant_pool)
+
+idStr SWF_AbcFile::asString( swfConstantKind_t kind, swfConstant_pool_info& constant_pool )
+{
+ idStr type;
+#define switchTrace( n ) case n: type = #n;break;
+ switch( kind )
+ {
+ switchTrace( unused_0x00 );
+ switchTrace( Utf8 );
+ switchTrace( Int );
+ switchTrace( UInt );
+ switchTrace( PrivateNs );
+ switchTrace( Double );
+ switchTrace( Qname );
+ switchTrace( Namespace );
+ switchTrace( False );
+ switchTrace( True );
+ switchTrace( Null );
+ switchTrace( QnameA );
+ switchTrace( RTQname );
+ switchTrace( RTQnameA );
+ switchTrace( RTQnameL );
+ switchTrace( RTQnameLA );
+ switchTrace( Multiname );
+ switchTrace( MultinameA );
+ switchTrace( MultinameL );
+ switchTrace( MultinameLA );
+ switchTrace( PackageNamespace );
+ switchTrace( PackageInternalNs );
+ switchTrace( ProtectedNamespace );
+ switchTrace( ExplicitNamespace );
+ switchTrace( StaticProtectedNs );
+ }
+ return type;
+#undef switchTrace
+}
+
+idStr SWF_AbcFile::asString( swfMultiname* mn, swfConstant_pool_info& constant_pool, bool prefix /*= true*/ )
+{
+ idStr ret;
+ if( prefix )
+ {
+ ret += toString( mn->type );
+ }
+ switch( mn->type )
+ {
+ case RTQnameL:
+ case RTQnameLA:
+ ret += "null::null";
+ break;
+ case Qname:
+ case QnameA:
+ ret += " ";
+ ret += *constant_pool.namespaceNames[mn->index];
+ if( mn->index != 1 )
+ {
+ ret += ".";
+ }
+ ret += constant_pool.utf8Strings[mn->nameIndex];
+ break;
+
+ case RTQname:
+ case RTQnameA:
+ ret += " ";
+ ret += constant_pool.utf8Strings[mn->nameIndex];
+ break;
+
+ case TypeName:
+ case Multiname:
+ case MultinameA:
+ ret += " ";
+ ret += asString( &constant_pool.multinameInfos[mn->index], constant_pool );
+ ret += ".";
+ ret += constant_pool.utf8Strings[mn->nameIndex];
+ break;
+
+ case MultinameL:
+ case MultinameLA:
+ ret += " ";
+ for( auto* str : constant_pool.namespaceSets[mn->index] )
+ {
+ ret += *str;
+ ret += ".";
+ };
+ break;
+ case unused_0x00:
+ ret += " unused_0x00";
+ break;
+ default:
+ common->FatalError( "Invalid Multiname type" );
+ break;
+ }
+
+ return ret;
+}
+
+void SWF_AbcFile::traceMN( const char* name, swfMultiname* mn, swfConstant_pool_info& constant_pool )
+{
+ idStr type = asString( mn, constant_pool );
+ trace( "%s %s \n", name, type.c_str() );
+}
+
+void SWF_AbcFile::traceConstantPool( swfConstant_pool_info& constant_pool )
+{
+ int cnt = 0;
+
+ trace( "^8========================================================\n" );
+ trace( " constant pool \n" );
+ trace( "^8========================================================\n" );
+
+ trace( "^8integers : ^7%i\n", constant_pool.integers.Num() );
+ for( auto& t : constant_pool.integers )
+ {
+ trace( "^8[^7%i^8]\t ^7%i \n", cnt++, t );
+ }
+ trace( "^8uIntegers ^7: %i\n", constant_pool.uIntegers.Num() );
+ cnt = 0;
+ for( auto& t : constant_pool.uIntegers )
+ {
+ trace( "^8[^7%i^8]\t ^7%i \n", cnt++, ( int )t );
+ }
+ trace( "^8doubles ^7: %i\n", constant_pool.doubles.Num() );
+ cnt = 0;
+ for( auto& t : constant_pool.doubles )
+ {
+ trace( "^8[^7%i^8]\t ^7%f \n", cnt++, ( float ) t );
+ }
+ trace( "^8utf8Strings ^7: %i\n", constant_pool.utf8Strings.Num() );
+ cnt = 0;
+ for( auto& t : constant_pool.utf8Strings )
+ {
+ trace( "^8[^7%i^8]\t ^7%s \n", cnt++, t.c_str() );
+ }
+ trace( "^8namespaceNames ^7: %i\n", constant_pool.namespaceNames.Num() );
+ cnt = 0;
+ for( auto& t : constant_pool.namespaceNames )
+ {
+ trace( "^8[^7%i^8]\t ^7%s \n", cnt++, t->c_str() );
+ }
+
+ trace( "^8namespaceSets ^7: %i\n", constant_pool.namespaceSets.Num() );
+ cnt = 0;
+ for( auto& t : constant_pool.namespaceSets )
+ {
+ for( auto& ts : t )
+ {
+ trace( "^8[^7%i^8]\t ^7%s \n", cnt++, ts->c_str() );
+ }
+ }
+
+ trace( "^8multinameInfos ^7: %i\n", constant_pool.multinameInfos.Num() );
+ cnt = 0;
+ for( auto& t : constant_pool.multinameInfos )
+ {
+ idStr pre = "^8[^7";
+ pre += idStr( cnt++ );
+ pre += "^8]^7\t";
+ traceMN( pre.c_str(), &t, constant_pool );
+ }
+
+ trace( "^8========================================================\n" );
+}
+
+
+void ReadMultiName( idSWFBitStream& bitstream , swfMultiname& target )
+{
+ target.type = ( swfConstantKind_t )bitstream.ReadU8();
+ target.index = 0;
+ target.nameIndex = 0;
+ switch( target.type )
+ {
+ case RTQnameL:
+ case RTQnameLA:
+ //0,0
+ break;
+ case Qname:
+ case QnameA:
+ target.index = bitstream.ReadEncodedU32();
+ target.nameIndex = bitstream.ReadEncodedU32();
+ break;
+
+ case RTQname:
+ case RTQnameA:
+ target.nameIndex = bitstream.ReadEncodedU32();
+ break;
+
+ case TypeName:
+ target.nameIndex = bitstream.ReadEncodedU32();
+ target.nameIndexT = bitstream.ReadEncodedU32();
+ target.indexT = bitstream.ReadEncoded();
+ break;
+ case Multiname:
+ case MultinameA:
+ target.nameIndex = bitstream.ReadEncodedU32();
+ target.index = bitstream.ReadEncodedU32();
+ break;
+
+ case MultinameL:
+ case MultinameLA:
+ target.index = bitstream.ReadEncodedU32();
+ break;
+ default:
+ common->FatalError( "Invalid Multiname type" );
+ break;
+ }
+}
+
+void ReadConstantPoolInfo( idSWFBitStream& bitstream , swfConstant_pool_info& target )
+{
+ /*cpool_info{}*/
+ uint32 int_count = bitstream.ReadEncodedU32() ;
+ target.integers.Alloc() = 0;
+ for( uint i = 1; i < int_count; i++ )
+ {
+ target.integers.Alloc() = bitstream.ReadEncoded();
+ }
+
+ uint32 uint_count = bitstream.ReadEncodedU32();
+ target.uIntegers.Alloc() = 0;
+ for( uint i = 1; i < uint_count; i++ )
+ {
+ target.uIntegers.Alloc() = bitstream.ReadEncodedU32();
+ }
+
+ uint32 double_count = bitstream.ReadEncodedU32();
+ target.doubles.Alloc() = 0.0;
+ for( uint i = 1; i < double_count; i++ )
+ {
+ //WARNING IEEE-754
+ target.doubles.Alloc() = *( double* )bitstream.ReadData( 8 );
+ }
+
+ uint32 string_count = bitstream.ReadEncodedU32();
+ target.utf8Strings.Alloc().Append( "*" );
+ for( uint i = 1; i < string_count; i++ )
+ {
+ uint32 str_len = bitstream.ReadEncodedU32();
+ target.utf8Strings.Alloc().Append( ( char* ) bitstream.ReadData( str_len ), str_len );
+ }
+
+ uint32 namespace_count = bitstream.ReadEncodedU32();
+ target.namespaceNames.Alloc() = &target.utf8Strings[0];
+ for( uint i = 1; i < namespace_count; i++ )
+ {
+ target.namespaceKinds.Alloc() = ( swfConstantKind_t )bitstream.ReadU8();
+ uint32 str_idx = bitstream.ReadEncodedU32();
+ target.namespaceNames.Alloc() = &target.utf8Strings[( int )str_idx];
+ }
+
+ uint32 namespace_set_count = bitstream.ReadEncodedU32();
+ target.namespaceSets.Alloc().Alloc() = target.namespaceNames[0];
+ for( uint i = 1; i < namespace_set_count; i++ )
+ {
+ uint32 count = bitstream.ReadEncodedU32();
+ auto& newSet = target.namespaceSets.Alloc();
+ for( uint j = 0; j < count; j++ )
+ {
+ uint32 idx = bitstream.ReadEncodedU32();
+ newSet.Alloc() = target.namespaceNames[( int )idx];
+ }
+ }
+
+ uint32 multiname_count = bitstream.ReadEncodedU32();
+ auto& empty = target.multinameInfos.Alloc();
+ empty.index = 0;
+ empty.nameIndex = 0;
+ empty.type = unused_0x00;
+ for( uint i = 1; i < multiname_count; i++ )
+ {
+ auto& newMn = target.multinameInfos.Alloc();
+ ReadMultiName( bitstream, newMn );
+ }
+}
+
+void SWF_AbcFile::ReadOptionInfo( idSWFBitStream& bitstream, swfOption_info& newOption )
+{
+ newOption.option_count = bitstream.ReadEncodedU32();
+ for( uint i = 0; i < newOption.option_count; i++ )
+ {
+ auto& newItem = newOption.options.Alloc();
+ newItem.val = bitstream.ReadEncodedU32();
+ newItem.kind = constant_pool.namespaceKinds[bitstream.ReadEncodedU32()];
+ }
+}
+
+void SWF_AbcFile::ReadMetaDataInfo( idSWFBitStream& bitstream , swfMetadata_info& newMetadata )
+{
+ newMetadata.name = &constant_pool.utf8Strings[bitstream.ReadEncodedU32()];
+ uint32 item_count = bitstream.ReadEncodedU32();
+ for( uint i = 0; i < item_count; i++ )
+ {
+ auto& newItem = newMetadata.items.Alloc();
+ newItem.key = &constant_pool.utf8Strings[bitstream.ReadEncodedU32()];
+ newItem.value = &constant_pool.utf8Strings[bitstream.ReadEncodedU32()];
+ }
+}
+
+void SWF_AbcFile::ReadTraitData( idSWFBitStream& bitstream, swfTraits_info& newTraitsData )
+{
+ swfTraits_info::Type kind = ( swfTraits_info::Type )( ( newTraitsData.kind << 4 ) >> 4 ); // snip upper half, lower 4 bits should remain.
+ uint8 attrib = ( newTraitsData.kind >> 4 ); // snip lower half, upper 4 bits should remain.
+
+ switch( kind )
+ {
+ case swfTraits_info::Trait_Slot:
+ case swfTraits_info::Trait_Const:
+ {
+ newTraitsData.data = Mem_ClearedAlloc( sizeof( swfTrait_slot ) , TAG_SWF );
+ swfTrait_slot& slot = *( ( swfTrait_slot* )( newTraitsData.data ) );
+ slot.slot_id = bitstream.ReadEncodedU32();
+ slot.type_name = &constant_pool.multinameInfos[bitstream.ReadEncodedU32()];
+ slot.vindex = bitstream.ReadEncodedU32();
+ if( slot.vindex != 0 )
+ {
+ slot.vkind = bitstream.ReadU8();
+ }
+ }
+ break;
+ case swfTraits_info::Trait_Method:
+ case swfTraits_info::Trait_Getter:
+ case swfTraits_info::Trait_Setter:
+ {
+ newTraitsData.data = Mem_ClearedAlloc( sizeof( swfTrait_method ), TAG_SWF );
+ swfTrait_method& method = *( swfTrait_method* )( newTraitsData.data );
+ method.disp_id = bitstream.ReadEncodedU32();
+ method.method = &methods[bitstream.ReadEncodedU32()];
+ }
+ break;
+ case swfTraits_info::Trait_Class:
+ {
+ newTraitsData.data = Mem_ClearedAlloc( sizeof( swfTrait_class ), TAG_SWF );
+ swfTrait_class& tclass = *( swfTrait_class* )( newTraitsData.data );
+ tclass.slot_id = bitstream.ReadEncodedU32();
+ tclass.classi = &classes[bitstream.ReadEncodedU32()];
+ }
+ break;
+ case swfTraits_info::Trait_Function:
+ {
+ newTraitsData.data = Mem_ClearedAlloc( sizeof( swfTrait_function ), TAG_SWF );
+ swfTrait_function& func = *( swfTrait_function* )( newTraitsData.data );
+ func.slot_id = bitstream.ReadEncodedU32();
+ func.func = &methods[bitstream.ReadEncodedU32()];
+ }
+ break;
+
+ default:
+ common->FatalError( "Unknown trait data" );
+ break;
+ }
+}
+
+//struct idSWFScriptObject::swfNamedVar_t ;
+
+template<>
+idSWFScriptObject::swfNamedVar_t* SWF_AbcFile::GetTrait( const swfTraits_info& trait, idSWFScriptObject* globals )
+{
+ swfTraits_info::Type kind = ( swfTraits_info::Type )( ( trait.kind << 4 ) >> 4 ); // snip upper half, lower 4 bits should remain.
+ uint8 attrib = ( trait.kind >> 4 ); // snip lower half, upper 4 bits should remain.
+
+ //idSWFScriptObject* newObj = new idSWFScriptObject();
+ idSWFScriptObject::swfNamedVar_t* newVar = new idSWFScriptObject::swfNamedVar_t();
+ newVar->value.traitsInfo = &trait;
+ switch( kind )
+ {
+ case swfTraits_info::Trait_Slot:
+ case swfTraits_info::Trait_Const:
+ {
+ //member variable.
+ swfTrait_slot& slot = *( ( swfTrait_slot* )( trait.data ) );
+ newVar->name = constant_pool.utf8Strings[trait.name->nameIndex];
+ //if ( slot.slot_id )
+ //{
+ // newVar = newObj->GetVariable(slot.slot_id,true);
+ // newVar->name = constant_pool.utf8Strings[trait.name->nameIndex];
+ //}else
+ // newVar = newObj->GetVariable(constant_pool.utf8Strings[trait.name->nameIndex].c_str(),true);
+
+ if( slot.vindex != 0 )
+ switch( slot.vkind )
+ {
+ case Utf8:
+ newVar->value.SetString( constant_pool.utf8Strings[slot.vindex] );
+ break;
+ case Int:
+ newVar->value.SetInteger( constant_pool.integers[slot.vindex] );
+ break;
+ case UInt:
+ newVar->value.SetInteger( ( int32 )( constant_pool.uIntegers[slot.vindex] ) );
+ break;
+ case Double: // crap.
+ newVar->value.SetFloat( ( float )( constant_pool.doubles[slot.vindex] ) );
+ break;
+ case Qname:
+ {
+
+ }
+ case Namespace:
+ newVar->value.SetString( *constant_pool.namespaceNames[slot.vindex] );
+ break;
+ case Multiname:
+ break;
+ case False:
+ newVar->value.SetBool( false );
+ break;
+ case True:
+ newVar->value.SetBool( true );
+ break;
+ case Null:
+ newVar->value.SetUndefined();
+ break;
+ case QnameA:
+ {
+ idStr& typeName = constant_pool.utf8Strings[slot.vindex];
+ if( globals->HasProperty( typeName.c_str() ) )
+ {
+ newVar->value.SetObject( globals->GetObject( typeName ) );
+ }
+ else
+ {
+ newVar->value.SetUndefined();
+ }
+ break;
+ }
+ break;
+ case MultinameA:
+ break;
+ case RTQname:
+ break;
+ case RTQnameA:
+ break;
+ case RTQnameL:
+ break;
+ case RTQnameLA:
+ break;
+ case NamespaceSet:
+ break;
+ case PackageNamespace:
+ break;
+ case PackageInternalNs:
+ break;
+ case ProtectedNamespace:
+ break;
+ case ExplicitNamespace:
+ break;
+ case StaticProtectedNs:
+ break;
+ case MultinameL:
+ break;
+ case MultinameLA:
+ break;
+ case TypeName:
+ break;
+ default:
+ break;
+ }
+ else
+ {
+ idStr& typeName = constant_pool.utf8Strings[slot.type_name->nameIndex];
+ if( globals->HasProperty( typeName.c_str() ) )
+ {
+ auto* newobj = idSWFScriptObject::Alloc();
+ newobj->SetPrototype( globals->GetObject( typeName.c_str() ) );
+ newVar->value.SetObject( newobj );
+ }
+ else
+ {
+ newVar->value.SetUndefined();
+ }
+ break;
+ }
+
+ return newVar;
+ }
+ break;
+ case swfTraits_info::Trait_Method:
+ case swfTraits_info::Trait_Getter:
+ case swfTraits_info::Trait_Setter:
+ {
+ newVar->name = constant_pool.utf8Strings[trait.name->nameIndex];
+ swfTrait_method& method = *( ( swfTrait_method* )( trait.data ) );
+
+ idStrPtr name = method.method->name;
+ idStr owner;
+ //string method owner
+ //common->FatalError("This is wrong. now dont keep using the debug info but start resolving it properly!!!!");
+ //check frame scripts!
+ int slashPos = name->Find( "/" );
+ if( slashPos != -1 )
+ {
+ owner = idStr( name->c_str(), 0, slashPos );
+ }
+
+ slashPos = owner.Find( ":" );
+ if( slashPos != -1 )
+ {
+ owner = idStr( owner.c_str(), slashPos + 1, owner.Length() );
+ }
+
+ if( globals->HasProperty( owner.c_str() ) )
+ {
+ idSWFScriptFunction_Script* func = idSWFScriptFunction_Script::Alloc();
+ func->SetAbcFile( this );
+ func->SetData( method.method );
+ newVar->value = idSWFScriptVar( func ) ;
+ }
+ else
+ {
+ newVar->value.SetUndefined();
+ }
+ break;
+
+ }
+ break;
+ case swfTraits_info::Trait_Class:
+ {
+ int a = 0;
+ //newTraitsData.data = Mem_ClearedAlloc( sizeof( swfTrait_class ) );
+ //swfTrait_class &tclass = *( swfTrait_class * ) ( newTraitsData.data );
+ //tclass.slot_id = bitstream.ReadEncodedU32();
+ //tclass.classi = &classes[bitstream.ReadEncodedU32()];
+ }
+ break;
+ case swfTraits_info::Trait_Function:
+ {
+ int a = 0;
+ //newTraitsData.data = Mem_ClearedAlloc( sizeof( swfTrait_function ) );
+ //swfTrait_function &func = *( swfTrait_function * ) ( newTraitsData.data );
+ //func.slot_id = bitstream.ReadEncodedU32();
+ //func.func = &methods[bitstream.ReadEncodedU32()];
+ }
+ break;
+
+ default:
+ common->FatalError( "Unknown trait data" );
+ break;
+ }
+
+ return newVar;
+}
+
+void SWF_AbcFile::ReadTraitsInfo( idSWFBitStream& bitstream, swfTraits_info& newTraitsData )
+{
+ newTraitsData.name = &constant_pool.multinameInfos[bitstream.ReadEncodedU32()];
+ //The kind field contains two four-bit fields. The lower four bits determine the kind of this trait. The
+ // upper four bits comprise a bit vector providing attributes of the trait. See the following tables and
+ // sections for full descriptions.
+
+ newTraitsData.kind = bitstream.ReadU8();
+ ReadTraitData( bitstream, newTraitsData );
+ uint8 attrib = ( newTraitsData.kind >> 4 ); // snip lower half, upper 4 bits should remain.
+ if( ( attrib & swfTraits_info::Attrib::Metadata ) != 0 )
+ {
+ uint32 meta_count = bitstream.ReadEncodedU32();
+ for( uint i = 0 ; i < meta_count; i++ )
+ {
+ newTraitsData.metadatas.Alloc() = &metadatas[bitstream.ReadEncodedU32()];
+ //fix this.
+ }
+ }
+}
+
+void SWF_AbcFile::ReadClassInfo( idSWFBitStream& bitstream, swfClass_info& newClassData )
+{
+ newClassData.cinit = &methods[bitstream.ReadEncodedU32()];
+ uint32 trait_count = bitstream.ReadEncodedU32();
+ newClassData.traits.AssureSize( trait_count );
+ for( uint i = 0; i < trait_count; i++ )
+ {
+ ReadTraitsInfo( bitstream, newClassData.traits[i] );
+ }
+
+}
+
+//The last entry in that array is the entry point for the ABC file; that is, the last entry�s
+//initialization method contains the first bytecode that�s run when the ABC file is executed.
+void SWF_AbcFile::ReadScriptInfo( idSWFBitStream& bitstream, swfScript_info& newScriptData )
+{
+ uint32 init = bitstream.ReadEncodedU32();
+ uint32 trait_count = bitstream.ReadEncodedU32();
+ newScriptData.init = &methods[init];
+ trace( "%s \n", newScriptData.init->name->c_str() );
+ newScriptData.traits.AssureSize( trait_count );
+ for( uint i = 0; i < trait_count; i++ )
+ {
+ ReadTraitsInfo( bitstream, newScriptData.traits[i] );
+ }
+}
+
+void SWF_AbcFile::ReadMethodBodyInfo( idSWFBitStream& bitstream, swfMethod_body_info& newMethodBody )
+{
+ newMethodBody.method = &methods[bitstream.ReadEncodedU32()];
+ assert( newMethodBody.method->body == nullptr );
+ newMethodBody.method->body = &newMethodBody;
+
+ newMethodBody.max_stack = bitstream.ReadEncodedU32();
+ newMethodBody.localCount = bitstream.ReadEncodedU32();
+ newMethodBody.initScopeDepth = bitstream.ReadEncodedU32();
+ newMethodBody.maxScopeDepth = bitstream.ReadEncodedU32();
+ newMethodBody.codeLength = bitstream.ReadEncodedU32();
+ newMethodBody.code.Load( bitstream.ReadData( newMethodBody.codeLength ), newMethodBody.codeLength, true ); // ( byte * ) Mem_ClearedAlloc( sizeof( byte ) * newMethodBody.codeLength );
+ extern void swf_PrintStream( SWF_AbcFile * file , idSWFBitStream & bitstream );
+ if( swf_abc_verbose.GetInteger() == 2 )
+ {
+ common->Printf( "============================\n" );
+ common->Printf( "Method %s 's bytecode \n", newMethodBody.method->name->c_str() );
+ common->Printf( "============================\n" );
+ swf_PrintStream( this, newMethodBody.code );
+ }
+ //memcpy(newMethodBody.code,bitstream.ReadData(newMethodBody.codeLength),newMethodBody.codeLength);
+ uint32 exception_count = bitstream.ReadEncodedU32();
+ for( uint i = 0; i < exception_count; i++ )
+ {
+ auto& newExceptionInfo = newMethodBody.exceptions.Alloc();
+ ReadExceptionInfo( bitstream, newExceptionInfo );
+ }
+ uint32 trait_count = bitstream.ReadEncodedU32();
+ for( uint i = 0; i < trait_count; i++ )
+ {
+ auto& newTrait = newMethodBody.traits.Alloc();
+ ReadTraitsInfo( bitstream, newTrait );
+ }
+}
+
+void SWF_AbcFile::ReadExceptionInfo( idSWFBitStream& bitstream, swfException_info& newException )
+{
+ newException.from = bitstream.ReadEncodedU32();
+ newException.to = bitstream.ReadEncodedU32();
+ newException.target = bitstream.ReadEncodedU32();
+ newException.exc_type = &constant_pool.utf8Strings[bitstream.ReadEncodedU32()];
+ newException.var_name = &constant_pool.utf8Strings[bitstream.ReadEncodedU32()];
+}
+
+void SWF_AbcFile::ReadInstanceInfo( idSWFBitStream& bitstream, swfInstance_info& newInstancedata )
+{
+ newInstancedata.name = &constant_pool.multinameInfos[bitstream.ReadEncodedU32()];
+ newInstancedata.super_name = &constant_pool.multinameInfos[bitstream.ReadEncodedU32()];
+
+ if( swf_abc_verbose.GetBool() )
+ {
+ traceMN( "newInstancedata.name", newInstancedata.name, constant_pool );
+ traceMN( "newInstancedata.super_name", newInstancedata.super_name, constant_pool );
+ }
+
+ newInstancedata.flags = ( swfInstanceFlags_t )bitstream.ReadU8();
+ if( ( newInstancedata.flags & swfInstanceFlags_t::ClassProtectedNs ) != 0 )
+ {
+ newInstancedata.protectedNs = bitstream.ReadEncodedU32();
+ }
+ uint32 interface_count = bitstream.ReadEncodedU32();
+
+ for( uint i = 0; i < interface_count; i++ )
+ {
+ newInstancedata.interfaces.Alloc() = &constant_pool.multinameInfos[bitstream.ReadEncodedU32()];
+ }
+
+ newInstancedata.iinit = &methods[bitstream.ReadEncodedU32()];
+
+ uint32 trait_count = bitstream.ReadEncodedU32();
+
+ for( uint i = 0; i < trait_count; i++ )
+ {
+ auto& newTrait = newInstancedata.traits.Alloc();
+ ReadTraitsInfo( bitstream, newTrait );
+ }
+
+}
+
+void SWF_AbcFile::ReadMethodInfo( idSWFBitStream& bitstream , swfMethod_info& newMethod )
+{
+ uint32 idx = 0;
+ newMethod.paramCount = bitstream.ReadEncodedU32();
+ idx = bitstream.ReadEncodedU32();
+ newMethod.returnType = &constant_pool.multinameInfos[idx];
+
+ for( uint i = 0; i < newMethod.paramCount; i++ )
+ {
+ idx = bitstream.ReadEncodedU32();
+ newMethod.paramTypes.Alloc() = &constant_pool.multinameInfos[idx];
+ }
+ idx = bitstream.ReadEncodedU32();
+ newMethod.name = &constant_pool.utf8Strings[idx];
+ newMethod.flags = bitstream.ReadU8();
+ newMethod.options.option_count = 0;
+ if( ( newMethod.flags & swfMethod_info::HAS_OPTIONAL ) != 0 )
+ {
+ ReadOptionInfo( bitstream, newMethod.options );
+ }
+
+ trace( "newMethod.name %s \n", newMethod.name->c_str() );
+
+ if( ( newMethod.flags & swfMethod_info::HAS_PARAM_NAMES ) != 0 )
+ {
+ trace( "newMethod.params %i \n", ( int )newMethod.paramCount );
+
+ for( uint i = 0; i < newMethod.paramCount; i++ )
+ {
+ idx = bitstream.ReadEncodedU32();
+ newMethod.paramNames.Alloc() = &constant_pool.utf8Strings[idx];
+
+ trace( "newMethod.param %s \n", constant_pool.utf8Strings[idx].c_str() );
+ }
+ }
+
+}
+
+
+void SWF_AbcFile::WriteBinary( idFileLocal& file )
+{
+ file->WriteBig( ( int )AbcTagData.Length() );
+ file->Write( AbcTagData.Ptr(), AbcTagData.Length() );
+}
+
+void SWF_AbcFile::LoadBinary( idFile* file )
+{
+ uint32 len;
+ file->ReadBig( len );
+ AbcTagData.LoadFromFile( file, len );
+}
+
+//Remove Accessibility
+void idSWF::DoABC( idSWFBitStream& bitstream )
+{
+ SWF_AbcFile& newAbcFile = abcFile;
+ int strmSize = bitstream.Length() + 6; // codeLength(uin16) + recordLength(uin32)
+
+ if( !newAbcFile.AbcTagData.Length() )
+ {
+ newAbcFile.AbcTagData.Load( bitstream.Ptr(), bitstream.Length(), true );
+ }
+
+ uint32 flags = bitstream.ReadU32();
+ idStr name = bitstream.ReadString();
+ int dataSize = bitstream.Length() - name.Length();
+ common->Printf( "DoABC %s flags %i tagsize %i bytecode size %i \n", name.c_str(), flags, strmSize, dataSize );
+
+ bitstream.ReadLittle( newAbcFile.minor_version );
+ bitstream.ReadLittle( newAbcFile.major_version );
+
+ ReadConstantPoolInfo( bitstream, newAbcFile.constant_pool );
+ SWF_AbcFile::traceConstantPool( newAbcFile.constant_pool );
+
+ uint32 method_count = bitstream.ReadEncodedU32() ;
+ newAbcFile.methods.AssureSize( method_count );
+ trace( "method_count %i \n", method_count );
+ for( uint i = 0; i < method_count; i++ )
+ {
+ auto& newMethod = newAbcFile.methods[i];
+ newAbcFile.ReadMethodInfo( bitstream, newMethod );
+ }
+
+ uint32 meta_count = bitstream.ReadEncodedU32();
+ newAbcFile.metadatas.AssureSize( meta_count );
+ trace( "meta_count %i \n", meta_count );
+ for( uint i = 0; i < meta_count; i++ )
+ {
+ auto& newMeta = newAbcFile.metadatas[i];
+ newAbcFile.ReadMetaDataInfo( bitstream, newMeta );
+ }
+
+ newAbcFile.class_count = bitstream.ReadEncodedU32();
+ newAbcFile.instances.AssureSize( newAbcFile.class_count );
+ trace( "class_count %i (Instance) \n", newAbcFile.class_count );
+ for( uint i = 0; i < newAbcFile.class_count ; i++ )
+ {
+ auto& newInstance = newAbcFile.instances[i];
+ newAbcFile.ReadInstanceInfo( bitstream, newInstance );
+ }
+
+ trace( "class_count %i (Class) \n", newAbcFile.class_count );
+ newAbcFile.classes.AssureSize( newAbcFile.class_count );
+ for( uint i = 0; i < newAbcFile.class_count ; i++ )
+ {
+ auto& newClass = newAbcFile.classes[i];
+ newAbcFile.ReadClassInfo( bitstream, newClass );
+ }
+
+ uint32 script_count = bitstream.ReadEncodedU32();
+ newAbcFile.scripts.AssureSize( script_count );
+ trace( "script_count %i \n", script_count );
+ for( uint i = 0; i < script_count; i++ )
+ {
+ auto& newScript = newAbcFile.scripts[i];
+ newAbcFile.ReadScriptInfo( bitstream, newScript );
+ }
+
+ uint32 methBody_count = bitstream.ReadEncodedU32();
+ newAbcFile.method_bodies.AssureSize( methBody_count );
+ trace( "methBody_count %i \n", methBody_count );
+ for( uint i = 0; i < methBody_count; i++ )
+ {
+ auto& newMethBody = newAbcFile.method_bodies[i];
+ newAbcFile.ReadMethodBodyInfo( bitstream, newMethBody );
+ }
+}
+
+void idSWF::SymbolClass( idSWFBitStream& bitstream )
+{
+
+ //Header RECORDHEADER Tag type = 76
+ //NumSymbols UI16 Number of symbols that will be associated by this tag.
+ //Tag1 U16 The 16 - bit character tag ID for the symbol to associate
+ //Name1 STRING The fully - qualified name of the ActionScript 3.0 class with which to associate this symbol.The class must have already been declared by a DoABC tag.
+ //... ... ...
+ //TagN U16 Tag ID for symbol N
+ //NameN STRING Fully - qualified class name for symbol N
+ uint16 numSymbols = bitstream.ReadU16();
+ for( uint i = 0 ; i < numSymbols; i++ )
+ {
+ auto& newSymbol = symbolClasses.symbols.Alloc();
+ newSymbol.tag = bitstream.ReadU16();
+ newSymbol.name = bitstream.ReadString();
+ trace( "SymbolClass ^5%i ^7tag ^5%i ^2%s \n", i, newSymbol.tag, newSymbol.name.c_str() );
+ }
+}
+
+
diff --git a/neo/swf/SWF_Abc.h b/neo/swf/SWF_Abc.h
new file mode 100644
index 0000000000..e12e2a8cd6
--- /dev/null
+++ b/neo/swf/SWF_Abc.h
@@ -0,0 +1,272 @@
+/*
+===========================================================================
+
+Doom 3 BFG Edition GPL Source Code
+Copyright (C) 2023 Harrie van Ginneken
+
+This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
+
+Doom 3 BFG Edition Source Code 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.
+
+Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code. If not, see .
+
+In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
+
+If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
+
+===========================================================================
+*/
+#pragma once
+
+#include "SWF_Enums.h"
+
+struct swfMultiname
+{
+ swfConstantKind_t type;
+ uint32 nameIndex;
+ uint32 index;
+ uint32 nameIndexT; //second Multiname for types
+ uint32 indexT; //
+};
+
+struct swfConstant_pool_info
+{
+ idList integers; //u30 int_count s32 integer[int_count]
+ idList uIntegers; //u30 uint_count u32 uinteger[uint_count]
+ idList doubles; //u30 double_count d64 double[double_count]
+ idStrList utf8Strings; //u30 string_count string_info string[string_count] (char is 16bit code point)
+ idList namespaceKinds; //u30 namespace_count namespace_info namespace[namespace_count] (namespaceinfo_t.kind)
+ idStrPtrList namespaceNames; //u30 namespace_count namespace_info namespace[namespace_count] (namespaceinfo_t.name)
+ idList namespaceSets; //u30 ns_set_count ns_set_info ns_set[ns_set_count]
+ idList multinameInfos; //u30 multiname_count multiname_info multiname[multiname_count]
+};
+
+struct swfMetadata_info
+{
+ struct item //item_info
+ {
+ idStrPtr key; //u30 key
+ idStrPtr value; //u30 value
+ };
+ idStrPtr name; //u30 name
+ idList- items; //u30 item_count item_info items[item_count]
+};
+
+struct swfOption_info
+{
+ struct item //option_detail
+ {
+ uint32 val; //u30 val
+ swfConstantKind_t kind; //u8 kind
+ };
+ uint32 option_count; //u30 option_count
+ idList
- options; //option_detail option[option_count]
+};
+
+struct swfMethod_body_info;
+struct swfMethod_info
+{
+ //zero before use.
+ enum Flags
+ {
+ NEED_ARGUMENTS = 0x01, // Suggests to the run - time that an �arguments� object( as specified by the ActionScript 3.0 Language Reference ) be created.Must not be used together with NEED_REST.See Chapter 3.
+ NEED_ACTIVATION = 0x02, // Must be set if this method uses the newactivation opcode.
+ NEED_REST = 0x04, // This flag creates an ActionScript 3.0 rest arguments array.Must not be used with NEED_ARGUMENTS.See Chapter 3.
+ HAS_OPTIONAL = 0x08, // Must be set if this method has optional parameters andthe options field is present in this method_info structure.
+ IGNORE_REST = 0x10,
+ NATIVE = 0x20,
+ SET_DXNS = 0x40, // Must be set if this method uses the dxns or dxnslate opcodes.
+ HAS_PARAM_NAMES = 0x80, // Must be set when the param_names field is present in this method_info structure.
+ };
+
+ uint32 paramCount; //u30 param_count
+ swfMultiname* returnType; //u30 return_type
+ idList paramTypes; //u30 param_count //u30 param_type[param_count]
+ idStrPtr name; //u30 name
+ uint8 flags; //u8 flags
+ swfOption_info options; //option_info options
+ idStrPtrList paramNames; // ( param_info ) param_names u30 param_name[param_count]
+
+ swfMethod_body_info* body = nullptr;
+};
+
+struct swfTraits_info
+{
+ enum Attrib // upper 4 bits of kind
+ {
+ Final = 0x1, // Is used with Trait_Method, Trait_Getter andTrait_Setter.It marks a method that cannot be overridden by a sub - class
+ Override = 0x2, // Is used with Trait_Method, Trait_Getter andTrait_Setter.It marks a method that has been overridden in this class
+ Metadata = 0x4, // Is used to signal that the fields metadata_count and metadata follow the data field in the traits_info entry
+ };
+ enum Type
+ {
+ Trait_Slot = 0,
+ Trait_Method = 1,
+ Trait_Getter = 2,
+ Trait_Setter = 3,
+ Trait_Class = 4,
+ Trait_Function = 5,
+ Trait_Const = 6,
+ Trait_Count = Trait_Const + 1,
+ Trait_Mask = 15
+ };
+ swfMultiname* name; //u30 name
+ uint8 kind; //u8 kind
+ void* data; //u8 data[]
+ idList metadatas; //u30 metadata_count u30 metadata[metadata_count]
+};
+
+struct swfInstance_info
+{
+ swfMultiname* name; //u30 name
+ swfMultiname* super_name; //u30 super_name
+ swfInstanceFlags_t flags; //u8 flags
+ uint32 protectedNs; //u30 protectedNs
+ idList interfaces; //u30 intrf_count u30 interface[intrf_count]
+ swfMethod_info* iinit; //u30 iinit
+ idList traits; //u30 trait_count traits_info trait[trait_count]
+};
+
+struct swfTrait_slot
+{
+ uint32 slot_id; //u30 slot_id
+ swfMultiname* type_name; //u30 type_name
+ uint32 vindex; //u30 vindex
+ uint8 vkind; //u8 vkind
+};
+
+struct swfClass_info
+{
+ swfMethod_info* cinit; //u30 cinit
+ idList traits; //u30 trait_count traits_info traits[trait_count]
+};
+
+struct swfTrait_class
+{
+ uint32 slot_id; //u30 slot_id
+ swfClass_info* classi; //u30 classi
+};
+
+struct swfTrait_function
+{
+ uint32 slot_id; //u30 slot_id
+ swfMethod_info* func; //u30 function
+};
+
+struct swfTrait_method
+{
+ uint32 disp_id; //u30 disp_id
+ swfMethod_info* method; //u30 method
+};
+
+struct swfScript_info
+{
+ swfMethod_info* init; //u30 init
+ idList traits; //u30 trait_count traits_info traits[trait_count]
+};
+
+struct swfException_info
+{
+ uint32 from; //u30 from
+ uint32 to; //u30 to
+ uint32 target; //u30 target
+ idStrPtr exc_type; //u30 exc_type
+ idStrPtr var_name; //u30 var_name
+};
+
+struct swfMethod_body_info
+{
+ swfMethod_info* method; //u30 method
+ uint32 max_stack; //u30 max_stack
+ uint32 localCount; //u30 local_count
+ uint32 initScopeDepth; //u30 init_scope_depth
+ uint32 maxScopeDepth; //u30 max_scope_depth
+ uint32 codeLength; //u30 code_length
+ idSWFBitStream code; //u8 code[code_length]
+ idList exceptions; //u30 exception_count exception_info exception[exception_count]
+ idList traits; //u30 trait_count traits_info traits[trait_count]
+};
+
+class idSWFScriptObject;
+struct SWF_AbcFile
+{
+ template
+ T* GetTrait( const swfTraits_info& trait, idSWFScriptObject* globals = nullptr );
+
+ void ReadMethodInfo( idSWFBitStream& bitstream, swfMethod_info& newMethod );
+ void ReadOptionInfo( idSWFBitStream& bitstream, swfOption_info& newOption );
+ void ReadMetaDataInfo( idSWFBitStream& bitstream, swfMetadata_info& newMetadata );
+ void ReadInstanceInfo( idSWFBitStream& bitstream, swfInstance_info& newInstancedata );
+ void ReadTraitData( idSWFBitStream& bitstream, swfTraits_info& newTraitsData );
+ void ReadTraitsInfo( idSWFBitStream& bitstream, swfTraits_info& newTraitsData );
+ void ReadClassInfo( idSWFBitStream& bitstream, swfClass_info& newClassData );
+ void ReadScriptInfo( idSWFBitStream& bitstream, swfScript_info& newScriptData );
+ void ReadMethodBodyInfo( idSWFBitStream& bitstream, swfMethod_body_info& newMethodBody );
+ void ReadExceptionInfo( idSWFBitStream& bitstream, swfException_info& newException );
+
+ static idStr asString( swfConstantKind_t kind, swfConstant_pool_info& constant_pool );
+ static idStr asString( swfMultiname* mn, swfConstant_pool_info& constant_pool, bool prefix = true );
+ static void traceMN( const char* name, swfMultiname* mn, swfConstant_pool_info& constant_pool );
+ static void traceConstantPool( swfConstant_pool_info& constant_pool );
+
+ uint16 minor_version;
+ uint16 major_version;
+ swfConstant_pool_info constant_pool;
+ idList methods; //u30 method_count method_info method[method_count]
+ idList metadatas; //u30 metadata_count metadata_info metadata[metadata_count]
+ uint32 class_count; //u30 class_count
+ idList instances; //instance_info instance[class_count]
+ idList classes; //class_info class[class_count]
+ idList scripts; //u30 script_count script_info script[script_count]
+ idList method_bodies; //u30 method_body_count method_body_info method_body[method_body_count]
+
+ //Writing the whole bytestream as whole for now, but :
+ // debug info plus unused tags and bytecode should be removed, constant pools need to stay the same
+ // accessibility can also be removed.
+ idSWFBitStream AbcTagData;
+ void WriteBinary( idFileLocal& file );
+ void LoadBinary( idFile* file );
+};
+
+struct SWF_SymbolClass
+{
+ struct Item
+ {
+ uint16 tag;
+ idStr name;
+ };
+ idList
- symbols;
+};
+
+enum SWFAbcOpcode
+{
+#define ABC_OP(operandCount, canThrow, stack, internalOnly, nameToken) OP_##nameToken,
+#define ABC_UNUSED_OP(operandCount, canThrow, stack, internalOnly, nameToken) ABC_OP(operandCount, canThrow, stack, internalOnly, nameToken)
+#include "opcodes.tbl"
+#undef ABC_OP
+#undef ABC_UNUSED_OP
+
+ //-----
+ OP_end_of_op_codes
+};
+
+struct AbcOpcodeInfo
+{
+ int8_t operandCount; // uses -1 for "invalid", we can avoid that if necessary
+ int8_t canThrow; // always 0 or 1
+ int8_t stack; // stack movement not taking into account run-time names or function arguments
+ uint16_t wordCode; // a map used during translation
+ const char* name; // instruction name or OP_0xNN for undefined instructions #IFDEF DEBUGGER
+};
+
+extern const AbcOpcodeInfo opcodeInfo[];
+extern const unsigned char kindToPushOp[];
diff --git a/neo/swf/SWF_Bitstream.cpp b/neo/swf/SWF_Bitstream.cpp
index 68d169850f..73efb0f0ab 100644
--- a/neo/swf/SWF_Bitstream.cpp
+++ b/neo/swf/SWF_Bitstream.cpp
@@ -3,6 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
+Copyright (C) 2023 Harrie van Ginneken
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@@ -61,6 +62,19 @@ idSWFBitStream::idSWFBitStream()
Free();
}
+void idSWFBitStream::LoadFromFile( idFile* file, uint32 len )
+{
+ Free();
+ free = true;
+ startp = ( const byte* )Mem_Alloc( len, TAG_SWF );
+ file->Read( ( byte* )startp, len );
+
+ endp = startp + len;
+ readp = startp;
+
+ ResetBits();
+}
+
/*
========================
idSWFBitStream::operator=
diff --git a/neo/swf/SWF_Bitstream.h b/neo/swf/SWF_Bitstream.h
index 6951682b48..e4a3333c0f 100644
--- a/neo/swf/SWF_Bitstream.h
+++ b/neo/swf/SWF_Bitstream.h
@@ -3,6 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
+Copyright (C) 2023 Harrie van Ginneken
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@@ -45,6 +46,7 @@ class idSWFBitStream
idSWFBitStream& operator=( idSWFBitStream& other );
idSWFBitStream& operator=( idSWFBitStream&& other );
+ void LoadFromFile( idFile* file, uint32 len );
void Load( const byte* data, uint32 len, bool copy );
void Free();
const byte* Ptr()
@@ -85,6 +87,23 @@ class idSWFBitStream
uint32 ReadU32();
int16 ReadS16();
int32 ReadS32();
+ int32 ReadS24();
+ template< typename T >
+ T ReadEncoded()
+ {
+ T result = 0;
+ for( int i = 0; i < 5; i++ )
+ {
+ byte b = ReadU8();
+ result |= ( b & 0x7F ) << ( 7 * i );
+ if( ( b & 0x80 ) == 0 )
+ {
+ return result;
+ }
+ }
+ return result;
+ }
+
uint32 ReadEncodedU32();
float ReadFixed8();
float ReadFixed16();
@@ -169,6 +188,19 @@ ID_INLINE int16 idSWFBitStream::ReadS16()
readp += 2;
return ( readp[-2] | ( readp[-1] << 8 ) );
}
+
+ID_INLINE int idSWFBitStream::ReadS24()
+{
+ ResetBits();
+ readp += 3;
+ int32 i = ( readp[-3] | ( readp[-2] << 8 ) | ( readp[-1] << 16 ) );
+ if( i & ( 0x80 << 16 ) )
+ {
+ i |= 0xff << ( 24 );
+ }
+ return ( int& )i;
+}
+
ID_INLINE int32 idSWFBitStream::ReadS32()
{
ResetBits();
@@ -212,4 +244,7 @@ ID_INLINE double idSWFBitStream::ReadDouble()
return d;
}
+
+
+
#endif // !__SWF_BITSTREAM_H__
diff --git a/neo/swf/SWF_Dictionary.cpp b/neo/swf/SWF_Dictionary.cpp
index 215219727f..d99394ba78 100644
--- a/neo/swf/SWF_Dictionary.cpp
+++ b/neo/swf/SWF_Dictionary.cpp
@@ -3,6 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
+Copyright (C) 2023 Harrie van Ginneken
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@@ -43,7 +44,10 @@ idSWFDictionaryEntry::idSWFDictionaryEntry() :
edittext( NULL ),
imageSize( 0, 0 ),
imageAtlasOffset( 0, 0 ),
- channelScale( 1.0f, 1.0f, 1.0f, 1.0f )
+ channelScale( 1.0f, 1.0f, 1.0f, 1.0f ),
+ scriptClass(),
+ resolved( false ),
+ name( NULL )
{
}
@@ -78,6 +82,9 @@ idSWFDictionaryEntry& idSWFDictionaryEntry::operator=( idSWFDictionaryEntry& oth
edittext = other.edittext;
imageSize = other.imageSize;
imageAtlasOffset = other.imageAtlasOffset;
+ scriptClass = other.scriptClass;
+ resolved = other.resolved;
+ name = other.name;
other.type = SWF_DICT_NULL;
other.material = NULL;
other.shape = NULL;
@@ -85,6 +92,9 @@ idSWFDictionaryEntry& idSWFDictionaryEntry::operator=( idSWFDictionaryEntry& oth
other.font = NULL;
other.text = NULL;
other.edittext = NULL;
+ other.resolved = false;
+ other.name = NULL;
+ other.scriptClass = idSWFScriptVar();
return *this;
}
diff --git a/neo/swf/SWF_Enums.h b/neo/swf/SWF_Enums.h
index 3247bcfe35..3b964da5b0 100644
--- a/neo/swf/SWF_Enums.h
+++ b/neo/swf/SWF_Enums.h
@@ -3,6 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
+Copyright (C) 2023 Harrie van Ginneken
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@@ -28,6 +29,52 @@ If you have questions concerning this license or the applicable additional terms
#ifndef __SWF_ENUMS_H__
#define __SWF_ENUMS_H__
+
+enum swfInstanceFlags_t
+{
+ ClassSealed = 0x01, //The class is sealed: properties can not be dynamically added to instances of the class.
+ ClassFinal = 0x02, //The class is final : it cannot be a base class for any other class.
+ ClassInterface = 0x04, //The class is an interface.
+ ClassProtectedNs = 0x08, //The class uses its protected namespace andthe protectedNs
+};
+
+enum swfConstantKind_t
+{
+ unused_0x00 = 0x00,
+ Utf8 = 0x01,
+#ifdef SWF_FLOAT
+ Float = 0x02,
+#endif
+ Int = 0x03,
+ UInt = 0x04,
+ PrivateNs = 0x05, // non-shared namespace
+ Double = 0x06,
+ Qname = 0x07, // o.ns::name, ct ns, ct name
+ Namespace = 0x08,
+ Multiname = 0x09, // o.name, ct nsset, ct name
+ False = 0x0A,
+ True = 0x0B,
+ Null = 0x0C,
+ QnameA = 0x0D, // o.@ns::name, ct ns, ct attr-name
+ MultinameA = 0x0E, // o.@name, ct attr-name
+ RTQname = 0x0F, // o.ns::name, rt ns, ct name
+ RTQnameA = 0x10, // o.@ns::name, rt ns, ct attr-name
+ RTQnameL = 0x11, // o.ns::[name], rt ns, rt name
+ RTQnameLA = 0x12, // o.@ns::[name], rt ns, rt attr-name
+ NamespaceSet = 0x15,
+ PackageNamespace = 0x16,
+ PackageInternalNs = 0x17,
+ ProtectedNamespace = 0x18,
+ ExplicitNamespace = 0x19,
+ StaticProtectedNs = 0x1A,
+ MultinameL = 0x1B,
+ MultinameLA = 0x1C,
+ TypeName = 0x1D,
+#ifdef SWF_FLOAT
+ Float4 = 0x1E,
+#endif
+};
+
enum swfDictType_t
{
SWF_DICT_NULL,
diff --git a/neo/swf/SWF_EventDispatcher.cpp b/neo/swf/SWF_EventDispatcher.cpp
new file mode 100644
index 0000000000..e90cd95b89
--- /dev/null
+++ b/neo/swf/SWF_EventDispatcher.cpp
@@ -0,0 +1,182 @@
+/*
+===========================================================================
+
+Doom 3 BFG Edition GPL Source Code
+Copyright (C) 2023 Harrie van Ginneken
+
+This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
+
+Doom 3 BFG Edition Source Code 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.
+
+Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code. If not, see .
+
+In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
+
+If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
+
+===========================================================================
+*/
+#include "precompiled.h"
+#pragma hdrstop
+
+#include "SWF_EventDispatcher.h"
+
+/*
+========================
+idSWFScriptObject_EventDispatcherPrototype
+========================
+*/
+#define SWF_EVENTDISPATCHER_FUNCTION_DEFINE( x ) idSWFScriptVar idSWFScriptObject_EventDispatcherPrototype::idSWFScriptFunction_##x::Call( idSWFScriptObject * thisObject, const idSWFParmList & parms )
+#define SWF_EVENTDISPATCHER_NATIVE_VAR_DEFINE_GET( x ) idSWFScriptVar idSWFScriptObject_EventDispatcherPrototype::idSWFScriptNativeVar_##x::Get( class idSWFScriptObject * object )
+#define SWF_EVENTDISPATCHER_NATIVE_VAR_DEFINE_SET( x ) void idSWFScriptObject_EventDispatcherPrototype::idSWFScriptNativeVar_##x::Set( class idSWFScriptObject * object, const idSWFScriptVar & value )
+
+#define SWF_EVENTDISPATCHER_PTHIS_FUNC( x ) idSWFScriptObject * pThis = thisObject ? thisObject : NULL; if ( !verify( pThis != NULL ) ) { idLib::Warning( "SWF: tried to call " x " on NULL object" ); return idSWFScriptVar(); }
+#define SWF_EVENTDISPATCHER_PTHIS_GET( x ) idSWFScriptObject * pThis = object ? object : NULL; if ( pThis == NULL ) { return idSWFScriptVar(); }
+#define SWF_EVENTDISPATCHER_PTHIS_SET( x ) idSWFScriptObject * pThis = object ? object : NULL; if ( pThis == NULL ) { return; }
+
+#define SWF_EVENTDISPATCHER_FUNCTION_SET( x ) scriptFunction_##x.AddRef(); Set( #x, &scriptFunction_##x );
+#define SWF_EVENTDISPATCHER_NATIVE_VAR_SET( x ) SetNative( #x, &swfScriptVar_##x );
+
+
+idSWFScriptObject_EventDispatcherPrototype::idSWFScriptObject_EventDispatcherPrototype()
+{
+ SWF_EVENTDISPATCHER_NATIVE_VAR_SET( MouseEvent );
+ SWF_EVENTDISPATCHER_NATIVE_VAR_SET( Event );
+ SWF_EVENTDISPATCHER_FUNCTION_SET( addEventListener );
+}
+
+SWF_EVENTDISPATCHER_NATIVE_VAR_DEFINE_SET( MouseEvent ) {}
+SWF_EVENTDISPATCHER_NATIVE_VAR_DEFINE_SET( Event ) {}
+
+SWF_EVENTDISPATCHER_NATIVE_VAR_DEFINE_GET( MouseEvent )
+{
+ static idSWFScriptObject* mouseEventObj = nullptr;
+ if( mouseEventObj == nullptr )
+ {
+ mouseEventObj = idSWFScriptObject::Alloc();
+ idSWFScriptObject* eventParms = idSWFScriptObject::Alloc();
+
+ eventParms->Set( "type", "MouseEvent" );
+ mouseEventObj->Set( "[MouseEvent]", eventParms );
+ //constants
+ mouseEventObj->Set( "CLICK", "click" );
+ mouseEventObj->Set( "CONTEXT_MENU", "contextMenu" );
+ mouseEventObj->Set( "DOUBLE_CLICK", "doubleClick" );
+ mouseEventObj->Set( "MIDDLE_CLICK", "middleClick" );
+ mouseEventObj->Set( "MIDDLE_MOUSE_DOWN", "middleMouseDown" );
+ mouseEventObj->Set( "MIDDLE_MOUSE_UP", "middleMouseUp" );
+ mouseEventObj->Set( "MOUSE_DOWN", "mouseDown" );
+ mouseEventObj->Set( "MOUSE_MOVE", "mouseMove" );
+ mouseEventObj->Set( "MOUSE_OUT", "mouseOut" );
+ mouseEventObj->Set( "MOUSE_OVER", "mouseOver" );
+ mouseEventObj->Set( "MOUSE_UP", "mouseUp" );
+ mouseEventObj->Set( "MOUSE_WHEEL ", "mouseWheel" );
+ mouseEventObj->Set( "RELEASE_OUTSIDE", "releaseOutside" );
+ mouseEventObj->Set( "RIGHT_CLICK", "rightClick" );
+ mouseEventObj->Set( "RIGHT_MOUSE_DOWN", "rightMouseDown" );
+ mouseEventObj->Set( "RIGHT_MOUSE_UP", "rightMouseUp" );
+ mouseEventObj->Set( "ROLL_OUT", "rollOut" );
+ mouseEventObj->Set( "ROLL_OVER", "rollOver" );
+ }
+ return mouseEventObj;
+}
+
+SWF_EVENTDISPATCHER_NATIVE_VAR_DEFINE_GET( Event )
+{
+ static idSWFScriptObject* eventObj = nullptr;
+ if( eventObj == nullptr )
+ {
+ eventObj = idSWFScriptObject::Alloc();
+ idSWFScriptObject* eventParms = idSWFScriptObject::Alloc();
+
+ eventParms->Set( "type", "Event" );
+ eventObj->Set( "[Event]", eventParms );
+
+ //constants
+ eventObj->Set( "ACTIVATE", "activate" );
+ eventObj->Set( "ADDED", "added" );
+ eventObj->Set( "ADDED_TO_STAGE", "addedToStage" );
+ eventObj->Set( "BROWSER_ZOOM_CHANGE", "browserZoomChange" );
+ eventObj->Set( "CANCEL", "cancel" );
+ eventObj->Set( "CHANGE", "change" );
+ eventObj->Set( "CHANNEL_MESSAGE", "channelMessage" );
+ eventObj->Set( "CHANNEL_STATE", "channelState" );
+ eventObj->Set( "CLEAR", "clear" );
+ eventObj->Set( "CLOSE", "close" );
+ eventObj->Set( "CLOSING", "closing" );
+ eventObj->Set( "COMPLETE", "complete" );
+ eventObj->Set( "CONNECT", "connect" );
+ eventObj->Set( "CONTEXT3D_CREATE", "context3DCreate" );
+ eventObj->Set( "COPY", "copy" );
+ eventObj->Set( "CUT", "cut" );
+ eventObj->Set( "DEACTIVATE", "deactivate" );
+ eventObj->Set( "DISPLAYING", "displaying" );
+ eventObj->Set( "ENTER_FRAME", "enterFrame" );
+ eventObj->Set( "EXIT_FRAME", "exitFrame" );
+ eventObj->Set( "EXITING", "exiting" );
+ eventObj->Set( "FRAME_CONSTRUCTED", "frameConstructed" );
+ eventObj->Set( "FRAME_LABEL", "frameLabel" );
+ eventObj->Set( "FULLSCREEN", "fullScreen" );
+ eventObj->Set( "HTML_BOUNDS_CHANGE", "htmlBoundsChange" );
+ eventObj->Set( "HTML_DOM_INITIALIZE", "htmlDOMInitialize" );
+ eventObj->Set( "HTML_RENDER", "htmlRender" );
+ eventObj->Set( "ID3", "id3" );
+ eventObj->Set( "INIT", "init" );
+ eventObj->Set( "LOCATION_CHANGE", "locationChange" );
+ eventObj->Set( "MOUSE_LEAVE", "mouseLeave" );
+ eventObj->Set( "NETWORK_CHANGE", "networkChange" );
+ eventObj->Set( "OPEN", "open" );
+ eventObj->Set( "PASTE", "paste" );
+ eventObj->Set( "PREPARING", "preparing" );
+ eventObj->Set( "REMOVED", "removed" );
+ eventObj->Set( "REMOVED_FROM_STAGE", "removedFromStage" );
+ eventObj->Set( "RENDER", "render" );
+ eventObj->Set( "RESIZE", "resize" );
+ eventObj->Set( "SCROLL", "scroll" );
+ eventObj->Set( "SELECT", "select" );
+ eventObj->Set( "SELECT_ALL", "selectAll" );
+ eventObj->Set( "SOUND_COMPLETE", "soundComplete" );
+ eventObj->Set( "STANDARD_ERROR_CLOSE", "standardErrorClose" );
+ eventObj->Set( "STANDARD_INPUT_CLOSE", "standardInputClose" );
+ eventObj->Set( "STANDARD_OUTPUT_CLOSE", "standardOutputClose" );
+ eventObj->Set( "SUSPEND", "suspend" );
+ eventObj->Set( "TAB_CHILDREN_CHANGE", "tabChildrenChange" );
+ eventObj->Set( "TAB_ENABLED_CHANGE", "tabEnabledChange" );
+ eventObj->Set( "TAB_INDEX_CHANGE", "tabIndexChange" );
+ eventObj->Set( "TEXT_INTERACTION_MODE_CHANGE", "textInteractionModeChange" );
+ eventObj->Set( "TEXTURE_READY", "textureReady" );
+ eventObj->Set( "UNLOAD", "unload" );
+ eventObj->Set( "USER_IDLE", "userIdle" );
+ eventObj->Set( "USER_PRESENT", "userPresent" );
+ eventObj->Set( "VIDEO_FRAME", "videoFrame" );
+ eventObj->Set( "WORKER_STATE", "workerState" );
+ }
+ return eventObj;
+}
+
+SWF_EVENTDISPATCHER_FUNCTION_DEFINE( addEventListener )
+{
+ SWF_EVENTDISPATCHER_PTHIS_FUNC( "addEventListener" );
+ swfNamedVar_t* dispatcher = thisObject->GetVariable( "__eventDispatcher__", true );
+
+ if( dispatcher->value.IsUndefined() )
+ {
+ dispatcher->value.SetObject( idSWFScriptObject::Alloc() );
+ }
+
+ dispatcher->value.GetObject()->Set( parms[0].ToString(), parms[1] );
+ common->DPrintf( "{%s} AddEventListener(%s,%s)\n", thisObject->GetSprite()->name.c_str(), parms[0].ToString().c_str(), parms[1].ToString().c_str() );
+ //add listener
+ return idSWFScriptVar();
+}
+
+
diff --git a/neo/swf/SWF_EventDispatcher.h b/neo/swf/SWF_EventDispatcher.h
new file mode 100644
index 0000000000..38204416d9
--- /dev/null
+++ b/neo/swf/SWF_EventDispatcher.h
@@ -0,0 +1,64 @@
+/*
+===========================================================================
+
+Doom 3 BFG Edition GPL Source Code
+Copyright (C) 2023 Harrie van Ginneken
+
+This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
+
+Doom 3 BFG Edition Source Code 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.
+
+Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code. If not, see .
+
+In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
+
+If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
+
+===========================================================================
+*/
+#ifndef __SWF_EVENTDISPATCHER_H__
+#define __SWF_EVENTDISPATCHER_H__
+
+#include "SWF_ScriptObject.h"
+#include "SWF_ParmList.h"
+#include "SWF_Types.h"
+#include "SWF_Sprites.h"
+#include "SWF.h"
+#include "SWF_Abc.h"
+
+class idSWFScriptObject_EventDispatcherPrototype : public idSWFScriptObject
+{
+public:
+ idSWFScriptObject_EventDispatcherPrototype();
+#define SWF_EVENTDISPATCHER_FUNCTION_DECLARE( x ) \
+ class idSWFScriptFunction_##x : public idSWFScriptFunction { \
+ public: \
+ void AddRef() {} \
+ void Release() {} \
+ idSWFScriptVar Call( idSWFScriptObject * thisObject, const idSWFParmList & parms ); \
+ } scriptFunction_##x
+
+ SWF_NATIVE_VAR_DECLARE( MouseEvent );
+ SWF_NATIVE_VAR_DECLARE( Event );
+
+ SWF_EVENTDISPATCHER_FUNCTION_DECLARE( addEventListener );
+ //SWF_EVENTDISPATHCER_FUNCTION_DECLARE( removeEventListener );
+ //SWF_EVENTDISPATHCER_FUNCTION_DECLARE( dispatchEvent );
+ //SWF_EVENTDISPATHCER_FUNCTION_DECLARE( dispatchQueue );
+
+ //object.addEventListener = _fEventDispatcher.addEventListener;
+ //object.removeEventListener = _fEventDispatcher.removeEventListener;
+ //object.dispatchEvent = _fEventDispatcher.dispatchEvent;
+ //object.dispatchQueue = _fEventDispatcher.dispatchQueue;
+};
+
+#endif //__SWF_EVENTDISPATCHER_H__
diff --git a/neo/swf/SWF_Events.cpp b/neo/swf/SWF_Events.cpp
index 57ddfdb1f3..3bd05f54ba 100644
--- a/neo/swf/SWF_Events.cpp
+++ b/neo/swf/SWF_Events.cpp
@@ -4,6 +4,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2016-2017 Dustin Land
+Copyright (C) 2023 Harrie van Ginneken
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@@ -28,6 +29,36 @@ If you have questions concerning this license or the applicable additional terms
*/
#include "precompiled.h"
#pragma hdrstop
+idSWFScriptObject* GetMouseEventDispatcher( idSWFScriptObject* object )
+{
+ idSWFScriptObject* dispatcher = nullptr;
+ if( object->HasValidProperty( "__eventDispatcher__" ) )
+ {
+ dispatcher = object->Get( "__eventDispatcher__" ).GetObject();
+ if( dispatcher->HasValidProperty( "click" )
+ || dispatcher->HasValidProperty( "contextMenu" )
+ || dispatcher->HasValidProperty( "doubleClick" )
+ || dispatcher->HasValidProperty( "middleClick" )
+ || dispatcher->HasValidProperty( "middleMouseDown" )
+ || dispatcher->HasValidProperty( "middleMouseUp" )
+ || dispatcher->HasValidProperty( "mouseDown" )
+ || dispatcher->HasValidProperty( "mouseMove" )
+ || dispatcher->HasValidProperty( "mouseOut" )
+ || dispatcher->HasValidProperty( "mouseOver" )
+ || dispatcher->HasValidProperty( "mouseUp" )
+ || dispatcher->HasValidProperty( "mouseWheel" )
+ || dispatcher->HasValidProperty( "releaseOutside" )
+ || dispatcher->HasValidProperty( "rightClick" )
+ || dispatcher->HasValidProperty( "rightMouseDown" )
+ || dispatcher->HasValidProperty( "rightMouseUp" )
+ || dispatcher->HasValidProperty( "rollOut" )
+ || dispatcher->HasValidProperty( "rollOver" ) )
+ {
+ return dispatcher;
+ }
+ }
+ return nullptr;
+}
/*
===================
@@ -51,15 +82,24 @@ idSWFScriptObject* idSWF::HitTest( idSWFSpriteInstance* spriteInstance, const sw
return NULL;
}
- if( spriteInstance->scriptObject->HasValidProperty( "onRelease" )
- || spriteInstance->scriptObject->HasValidProperty( "onPress" )
- || spriteInstance->scriptObject->HasValidProperty( "onRollOver" )
- || spriteInstance->scriptObject->HasValidProperty( "onRollOut" )
- || spriteInstance->scriptObject->HasValidProperty( "onDrag" )
- )
+ idSWFScriptObject* dispatcher = GetMouseEventDispatcher( spriteInstance->scriptObject );
+
+ if( dispatcher != nullptr )
{
parentObject = spriteInstance->scriptObject;
}
+ else
+ {
+ if( spriteInstance->scriptObject->HasValidProperty( "onRelease" )
+ || spriteInstance->scriptObject->HasValidProperty( "onPress" )
+ || spriteInstance->scriptObject->HasValidProperty( "onRollOver" )
+ || spriteInstance->scriptObject->HasValidProperty( "onRollOut" )
+ || spriteInstance->scriptObject->HasValidProperty( "onDrag" )
+ )
+ {
+ parentObject = spriteInstance->scriptObject;
+ }
+ }
// rather than returning the first object we find, we actually want to return the last object we find
idSWFScriptObject* returnObject = NULL;
@@ -123,20 +163,25 @@ idSWFScriptObject* idSWF::HitTest( idSWFSpriteInstance* spriteInstance, const sw
{
// FIXME: this should be roughly the same as SWF_DICT_SHAPE
}
- else if( entry->type == SWF_DICT_TEXT )
- {
- // FIXME: this should be roughly the same as SWF_DICT_SHAPE
- }
- else if( entry->type == SWF_DICT_EDITTEXT )
+ else if( entry->type == SWF_DICT_EDITTEXT || entry->type == SWF_DICT_TEXT )
{
idSWFScriptObject* editObject = NULL;
- if( display.textInstance->scriptObject.HasProperty( "onRelease" ) || display.textInstance->scriptObject.HasProperty( "onPress" ) )
+ idSWFScriptObject* textdispatcher = nullptr;
+ if( display.textInstance )
+ {
+ dispatcher = GetMouseEventDispatcher( &display.textInstance->scriptObject );
+ }
+ if( dispatcher != nullptr )
+ {
+ editObject = &display.textInstance->scriptObject;
+ }
+ else if( display.textInstance && ( display.textInstance->scriptObject.HasProperty( "onRelease" ) || display.textInstance->scriptObject.HasProperty( "onPress" ) ) )
{
// if the edit box itself can be clicked, then we want to return it when it's clicked on
editObject = &display.textInstance->scriptObject;
}
- else if( parentObject != NULL )
+ else if( !dispatcher && parentObject != NULL )
{
// otherwise, we want to return the parent object
editObject = parentObject;
@@ -147,7 +192,7 @@ idSWFScriptObject* idSWF::HitTest( idSWFSpriteInstance* spriteInstance, const sw
continue;
}
- if( display.textInstance->text.IsEmpty() )
+ if( !display.textInstance || display.textInstance->text.IsEmpty() )
{
continue;
}
@@ -254,6 +299,7 @@ bool idSWF::HandleEvent( const sysEvent_t* event )
{
mouseEnabled = true;
idSWFScriptVar var;
+ idSWFScriptVar eventDispatcher = mainspriteInstance->GetScriptObject()->Get( "__eventDispatcher__" );
if( event->evValue2 )
{
@@ -277,6 +323,36 @@ bool idSWF::HandleEvent( const sysEvent_t* event )
mouseObject = hitObject;
mouseObject->AddRef();
+ eventDispatcher = hitObject->Get( "__eventDispatcher__" );
+
+ if( !eventDispatcher.IsUndefined() && !var.IsFunction() )
+ {
+ var = eventDispatcher.GetObject()->Get( "click" );
+ if( !var.IsFunction() )
+ {
+ var = eventDispatcher.GetObject()->Get( "mouseDown" );
+ }
+ }
+ if( var.IsFunction() )
+ {
+ idSWFScriptVar eventArg;
+ auto* eventObj = globals->Get( "EventDispatcher" ).GetObject()
+ ->Get( "MouseEvent" ).GetObject()
+ ->Get( "[MouseEvent]" ).GetObject();
+ eventArg.SetObject( idSWFScriptObject::Alloc() );
+ eventArg.GetObject()->DeepCopy( eventObj );
+ idSWFParmList parms;
+ parms.Append( eventArg );
+ parms.Append( event->inputDevice );
+ if( !( ( idSWFScriptFunction_Script* ) var.GetFunction() )->GetScope()->Num() )
+ {
+ ( ( idSWFScriptFunction_Script* ) var.GetFunction() )->GetScope()->Append( globals );
+ }
+ var.GetFunction()->Call( hitObject, parms );
+ parms.Clear();
+ return true;
+ }
+
var = hitObject->Get( "onPress" );
if( var.IsFunction() )
{
@@ -309,12 +385,40 @@ bool idSWF::HandleEvent( const sysEvent_t* event )
{
if( mouseObject )
{
+ eventDispatcher = mouseObject->Get( "__eventDispatcher__" );
+
+ if( !eventDispatcher.IsUndefined() && !var.IsFunction() )
+ {
+ var = eventDispatcher.GetObject()->Get( "mouseUp" );
+ }
+ if( var.IsFunction() )
+ {
+ idSWFScriptVar eventArg;
+ auto* eventObj = globals->Get( "EventDispatcher" ).GetObject()
+ ->Get( "MouseEvent" ).GetObject()
+ ->Get( "[MouseEvent]" ).GetObject();
+ eventArg.SetObject( idSWFScriptObject::Alloc() );
+ eventArg.GetObject()->DeepCopy( eventObj );
+ idSWFParmList parms;
+ parms.Append( eventArg );
+ if( !( ( idSWFScriptFunction_Script* ) var.GetFunction() )->GetScope()->Num() )
+ {
+ ( ( idSWFScriptFunction_Script* ) var.GetFunction() )->GetScope()->Append( globals );
+ }
+ var.GetFunction()->Call( mouseObject, parms );
+ parms.Clear();
+ mouseObject->Release();
+ mouseObject = NULL;
+ return true;
+ }
+
var = mouseObject->Get( "onRelease" );
if( var.IsFunction() )
{
idSWFParmList parms;
parms.Append( mouseObject ); // FIXME: Remove this
var.GetFunction()->Call( mouseObject, parms );
+ parms.Clear();
}
mouseObject->Release();
mouseObject = NULL;
@@ -494,13 +598,39 @@ bool idSWF::HandleEvent( const sysEvent_t* event )
hasHitObject = false;
}
+ idSWFScriptVar eventDispatcher;
if( hitObject != hoverObject )
{
+
// First check to see if we should call onRollOut on our previous hoverObject
if( hoverObject != NULL )
{
idSWFScriptVar var = hoverObject->Get( "onRollOut" );
- if( var.IsFunction() )
+
+ eventDispatcher = hoverObject->Get( "__eventDispatcher__" );
+ if( !eventDispatcher.IsUndefined() && !var.IsFunction() )
+ {
+ var = eventDispatcher.GetObject()->Get( "mouseOut" );
+ if( var.IsFunction() )
+ {
+ idSWFScriptVar eventArg;
+ auto* eventObj = globals->Get( "EventDispatcher" ).GetObject()
+ ->Get( "MouseEvent" ).GetObject()
+ ->Get( "[MouseEvent]" ).GetObject();
+ eventArg.SetObject( idSWFScriptObject::Alloc() );
+ eventArg.GetObject()->DeepCopy( eventObj );
+ idSWFParmList parms;
+ parms.Append( eventArg );
+ if( !( ( idSWFScriptFunction_Script* ) var.GetFunction() )->GetScope()->Num() )
+ {
+ ( ( idSWFScriptFunction_Script* ) var.GetFunction() )->GetScope()->Append( globals );
+ }
+ var.GetFunction()->Call( hoverObject, parms );
+ parms.Clear();
+ retVal = true;
+ }
+ }
+ else if( var.IsFunction() )
{
var.GetFunction()->Call( hoverObject, idSWFParmList() );
retVal = true;
@@ -514,7 +644,31 @@ bool idSWF::HandleEvent( const sysEvent_t* event )
hoverObject = hitObject;
hoverObject->AddRef();
idSWFScriptVar var = hitObject->Get( "onRollOver" );
- if( var.IsFunction() )
+
+ eventDispatcher = hoverObject->Get( "__eventDispatcher__" );
+ if( !eventDispatcher.IsUndefined() && !var.IsFunction() )
+ {
+ var = eventDispatcher.GetObject()->Get( "mouseOver" );
+ if( var.IsFunction() )
+ {
+ idSWFScriptVar eventArg;
+ auto* eventObj = globals->Get( "EventDispatcher" ).GetObject()
+ ->Get( "MouseEvent" ).GetObject()
+ ->Get( "[MouseEvent]" ).GetObject();
+ eventArg.SetObject( idSWFScriptObject::Alloc() );
+ eventArg.GetObject()->DeepCopy( eventObj );
+ idSWFParmList parms;
+ parms.Append( eventArg );
+ if( !( ( idSWFScriptFunction_Script* ) var.GetFunction() )->GetScope()->Num() )
+ {
+ ( ( idSWFScriptFunction_Script* ) var.GetFunction() )->GetScope()->Append( globals );
+ }
+ var.GetFunction()->Call( hoverObject, parms );
+ parms.Clear();
+ retVal = true;
+ }
+ }
+ else if( var.IsFunction() )
{
var.GetFunction()->Call( hitObject, idSWFParmList() );
retVal = true;
diff --git a/neo/swf/SWF_Interpreter.cpp b/neo/swf/SWF_Interpreter.cpp
new file mode 100644
index 0000000000..8f945ed41e
--- /dev/null
+++ b/neo/swf/SWF_Interpreter.cpp
@@ -0,0 +1,1611 @@
+/*
+===========================================================================
+
+Doom 3 BFG Edition GPL Source Code
+Copyright (C) 2023 Harrie van Ginneken
+
+This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
+
+Doom 3 BFG Edition Source Code 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.
+
+Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code. If not, see .
+
+In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
+
+If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
+
+===========================================================================
+*/
+#include "precompiled.h"
+#pragma hdrstop
+
+//#include "SWF_Bitstream.h"
+//#include "SWF_Enums.h"
+//#include "SWF_Abc.h"
+//#include "SWF_ScriptObject.h"
+//#include "SWF_ScriptFunction.h"
+//#include "framework/Common.h"
+
+inline int32 readS24( const byte* pc )
+{
+ return ( ( uint16_t* )pc )[0] | ( ( int8_t* )pc )[2] << 16;
+}
+
+inline uint32 readU30( const uint8_t*& pc )
+{
+ uint32 result = 0;
+ for( int i = 0; i < 5; i++ )
+ {
+ byte b = *pc++;
+ result |= ( b & 0x7F ) << ( 7 * i );
+ if( ( b & 0x80 ) == 0 )
+ {
+ return result;
+ }
+ }
+ return result;
+}
+
+const AbcOpcodeInfo opcodeInfo[] =
+{
+ // For stack movement ("stk") only constant movement is accounted for; variable movement,
+ // as for arguments to CALL, CONSTRUCT, APPLYTYPE, et al, and for run-time parts of
+ // names, must be handled separately.
+
+#define ABC_OP(operandCount, canThrow, stack, internalOnly, nameToken) { operandCount, canThrow, stack , OP_##nameToken , #nameToken },
+#define ABC_UNUSED_OP(operandCount, canThrow, stack, internalOnly, nameToken) { operandCount, canThrow, stack , 0 , #nameToken },
+
+#include "opcodes.tbl"
+
+#undef ABC_OP
+#undef ABC_UNUSED_OP
+#undef ABC_OP_F
+};
+
+void debugfile( SWF_AbcFile* file, idSWFBitStream& bitstream )
+{
+ common->Printf( " debugfile %s\n", file->constant_pool.utf8Strings[bitstream.ReadEncodedU32()].c_str() );
+}
+
+void debugline( SWF_AbcFile* file, idSWFBitStream& bitstream )
+{
+ common->Printf( " debugline %i\n", ( int )bitstream.ReadEncodedU32() );
+}
+
+void swf_PrintStream( SWF_AbcFile* file, idSWFBitStream& bitstream )
+{
+ //(case.*OP_)([A-Za-z0-9]*_?[A-Za-z0-9]*)(.*\n)(.*)
+ idSWFStack stack;
+ static idList codeMap;
+ idStr type;
+ const AbcOpcodeInfo* info = nullptr;
+ while( bitstream.Tell() < bitstream.Length() )
+ {
+#define DoWordCode( n ) case OP_##n: type = #n; info = &opcodeInfo[opCode]; break;
+#define ExecWordCode( n ) case OP_##n: type = #n; info = &opcodeInfo[opCode]; n(file,bitstream); continue;
+ SWFAbcOpcode opCode = ( SWFAbcOpcode ) bitstream.ReadU8();
+ switch( opCode )
+ {
+ DoWordCode( bkpt );
+ DoWordCode( nop );
+ DoWordCode( throw );
+ DoWordCode( getsuper );
+ DoWordCode( setsuper );
+ DoWordCode( dxns );
+ DoWordCode( dxnslate );
+ DoWordCode( kill );
+ DoWordCode( label );
+ DoWordCode( ifnlt );
+ DoWordCode( ifnle );
+ DoWordCode( ifngt );
+ DoWordCode( ifnge );
+ DoWordCode( jump );
+ DoWordCode( iftrue );
+ DoWordCode( iffalse );
+ DoWordCode( ifeq );
+ DoWordCode( ifne );
+ DoWordCode( iflt );
+ DoWordCode( ifle );
+ DoWordCode( ifgt );
+ DoWordCode( ifge );
+ DoWordCode( ifstricteq );
+ DoWordCode( ifstrictne );
+ DoWordCode( lookupswitch );
+ DoWordCode( pushwith );
+ DoWordCode( popscope );
+ DoWordCode( nextname );
+ DoWordCode( hasnext );
+ DoWordCode( pushnull );
+ DoWordCode( pushundefined );
+ DoWordCode( DISABLED_pushfloat );
+ DoWordCode( nextvalue );
+ DoWordCode( pushbyte );
+ DoWordCode( pushshort );
+ DoWordCode( pushtrue );
+ DoWordCode( pushfalse );
+ DoWordCode( pushnan );
+ DoWordCode( pop );
+ DoWordCode( dup );
+ DoWordCode( swap );
+ DoWordCode( pushstring );
+ DoWordCode( pushint );
+ DoWordCode( pushuint );
+ DoWordCode( pushdouble );
+ DoWordCode( pushscope );
+ DoWordCode( pushnamespace );
+ DoWordCode( hasnext2 );
+ DoWordCode( lix8 );
+ DoWordCode( lix16 );
+ DoWordCode( li8 );
+ DoWordCode( li16 );
+ DoWordCode( li32 );
+ DoWordCode( lf32 );
+ DoWordCode( lf64 );
+ DoWordCode( si8 );
+ DoWordCode( si16 );
+ DoWordCode( si32 );
+ DoWordCode( sf32 );
+ DoWordCode( sf64 );
+ DoWordCode( newfunction );
+ DoWordCode( call );
+ DoWordCode( construct );
+ DoWordCode( callmethod );
+ DoWordCode( callstatic );
+ DoWordCode( callsuper );
+ DoWordCode( callproperty );
+ DoWordCode( returnvoid );
+ DoWordCode( returnvalue );
+ DoWordCode( constructsuper );
+ DoWordCode( constructprop );
+ DoWordCode( callsuperid );
+ DoWordCode( callproplex );
+ DoWordCode( callinterface );
+ DoWordCode( callsupervoid );
+ DoWordCode( callpropvoid );
+ DoWordCode( sxi1 );
+ DoWordCode( sxi8 );
+ DoWordCode( sxi16 );
+ DoWordCode( applytype );
+ DoWordCode( DISABLED_pushfloat4 );
+ DoWordCode( newobject );
+ DoWordCode( newarray );
+ DoWordCode( newactivation );
+ DoWordCode( newclass );
+ DoWordCode( getdescendants );
+ DoWordCode( newcatch );
+ DoWordCode( findpropglobalstrict );
+ DoWordCode( findpropglobal );
+ DoWordCode( findpropstrict );
+ DoWordCode( findproperty );
+ DoWordCode( finddef );
+ DoWordCode( getlex );
+ DoWordCode( setproperty );
+ DoWordCode( getlocal );
+ DoWordCode( setlocal );
+ DoWordCode( getglobalscope );
+ DoWordCode( getscopeobject );
+ DoWordCode( getproperty );
+ DoWordCode( getouterscope );
+ DoWordCode( initproperty );
+ DoWordCode( deleteproperty );
+ DoWordCode( getslot );
+ DoWordCode( setslot );
+ DoWordCode( getglobalslot );
+ DoWordCode( setglobalslot );
+ DoWordCode( convert_s );
+ DoWordCode( esc_xelem );
+ DoWordCode( esc_xattr );
+ DoWordCode( convert_i );
+ DoWordCode( convert_u );
+ DoWordCode( convert_d );
+ DoWordCode( convert_b );
+ DoWordCode( convert_o );
+ DoWordCode( checkfilter );
+ //DoWordCode ( DISABLED_convert );
+ //DoWordCode ( DISABLED_unplus );
+ //DoWordCode ( DISABLED_convert );
+ DoWordCode( coerce );
+ DoWordCode( coerce_b );
+ DoWordCode( coerce_a );
+ DoWordCode( coerce_i );
+ DoWordCode( coerce_d );
+ DoWordCode( coerce_s );
+ DoWordCode( astype );
+ DoWordCode( astypelate );
+ DoWordCode( coerce_u );
+ DoWordCode( coerce_o );
+ DoWordCode( negate );
+ DoWordCode( increment );
+ DoWordCode( inclocal );
+ DoWordCode( decrement );
+ DoWordCode( declocal );
+ DoWordCode( typeof );
+ DoWordCode( not );
+ DoWordCode( bitnot );
+ DoWordCode( add );
+ DoWordCode( subtract );
+ DoWordCode( multiply );
+ DoWordCode( divide );
+ DoWordCode( modulo );
+ DoWordCode( lshift );
+ DoWordCode( rshift );
+ DoWordCode( urshift );
+ DoWordCode( bitand );
+ DoWordCode( bitor );
+ DoWordCode( bitxor );
+ DoWordCode( equals );
+ DoWordCode( strictequals );
+ DoWordCode( lessthan );
+ DoWordCode( lessequals );
+ DoWordCode( greaterthan );
+ DoWordCode( greaterequals );
+ DoWordCode( instanceof );
+ DoWordCode( istype );
+ DoWordCode( istypelate );
+ DoWordCode( in );
+ DoWordCode( increment_i );
+ DoWordCode( decrement_i );
+ DoWordCode( inclocal_i );
+ DoWordCode( declocal_i );
+ DoWordCode( negate_i );
+ DoWordCode( add_i );
+ DoWordCode( subtract_i );
+ DoWordCode( multiply_i );
+ DoWordCode( getlocal0 );
+ DoWordCode( getlocal1 );
+ DoWordCode( getlocal2 );
+ DoWordCode( getlocal3 );
+ DoWordCode( setlocal0 );
+ DoWordCode( setlocal1 );
+ DoWordCode( setlocal2 );
+ DoWordCode( setlocal3 );
+ DoWordCode( debug );
+ ExecWordCode( debugline );
+ ExecWordCode( debugfile );
+ DoWordCode( bkptline );
+ DoWordCode( timestamp );
+ DoWordCode( restargc );
+ DoWordCode( restarg );
+ default:
+ common->Printf( "default %s %s\n", type.c_str() , info ? info->name : "Empty" );
+ }
+ static const char* tabs[] = { " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "};
+ if( info && info->operandCount > 0 )
+ {
+ bitstream.ReadData( info->operandCount );
+ }
+ common->Printf( " %s %s o %s%i \t s %s%i \n" ,
+ info ? info->name : type.c_str(),
+ tabs[int( 18 - ( int( idStr::Length( info->name ) ) ) )],
+ info->operandCount > 0 ? "^2" : "^1" ,
+ info->operandCount,
+ info->stack < 0 ? "^2" : "^1",
+ info->stack
+ );
+ }
+ bitstream.Rewind();
+#undef DoWordCode
+#undef ExecWordCode
+}
+
+void idSWFScriptFunction_Script::findproperty( SWF_AbcFile* file, idSWFStack& stack, idSWFBitStream& bitstream )
+{
+ const auto& cp = file->constant_pool;
+ const auto& mn = file->constant_pool.multinameInfos[bitstream.ReadEncodedU32()];
+ const idStrPtr propName = ( idStrPtr )&cp.utf8Strings[mn.nameIndex];
+ //search up scope stack.
+ for( int i = scope.Num() - 1; i >= 0; i-- )
+ {
+ auto* s = scope[i];
+ while( s )
+ if( s->HasProperty( propName->c_str() ) )
+ {
+ stack.Alloc() = s->Get( propName->c_str() );
+ return;
+ }
+ else if( s->GetPrototype() && s->GetPrototype()->GetPrototype() )
+ {
+ s = s->GetPrototype()->GetPrototype();
+ }
+ else
+ {
+ s = NULL;
+ }
+ }
+ auto prop = scope[0]->GetVariable( *propName, true );
+ stack.Alloc() = prop->value;
+}
+
+void idSWFScriptFunction_Script::findpropstrict( SWF_AbcFile* file, idSWFStack& stack, idSWFBitStream& bitstream )
+{
+ const auto& cp = file->constant_pool;
+ const auto& mn = file->constant_pool.multinameInfos[bitstream.ReadEncodedU32()];
+ const idStrPtr propName = ( idStrPtr ) &cp.utf8Strings[mn.nameIndex];
+ //search up scope stack.
+ for( int i = scope.Num() - 1; i >= 0; i-- )
+ {
+ auto* s = scope[i];
+ while( s )
+ if( s->HasProperty( propName->c_str() ) )
+ {
+ stack.Alloc() = s->Get( propName->c_str() );
+ return;
+ }
+ else if( s->GetPrototype() && s->GetPrototype()->GetPrototype() )
+ {
+ s = s->GetPrototype()->GetPrototype();
+ }
+ else
+ {
+ s = NULL;
+ }
+ }
+ common->Warning( "idSWFScriptFunction_Script::findpropstrict cant find %s", propName->c_str() );
+ stack.Alloc().SetObject( idSWFScriptObject::Alloc() );
+ stack.A().GetObject()->Release();
+}
+
+void idSWFScriptFunction_Script::getlex( SWF_AbcFile* file, idSWFStack& stack, idSWFBitStream& bitstream )
+{
+ const auto& cp = file->constant_pool;
+ const auto& mn = file->constant_pool.multinameInfos[bitstream.ReadEncodedU32()];
+ const idStrPtr propName = ( idStrPtr ) &cp.utf8Strings[mn.nameIndex];
+ //search up scope stack.
+ for( int i = scope.Num() - 1; i >= 0; i-- )
+ {
+ auto* s = scope[i];
+ while( s )
+ if( s->HasProperty( propName->c_str() ) )
+ {
+ stack.Alloc() = s->Get( propName->c_str() );
+ return;
+ }
+ else if( s->GetPrototype() && s->GetPrototype()->GetPrototype() )
+ {
+ s = s->GetPrototype()->GetPrototype();
+ }
+ else
+ {
+ s = NULL;
+ }
+ }
+}
+
+void idSWFScriptFunction_Script::getscopeobject( SWF_AbcFile* file, idSWFStack& stack, idSWFBitStream& bitstream )
+{
+ uint8 index = bitstream.ReadEncodedU32();
+ stack.Alloc() = scope[( scope.Num() - 1 ) - index];
+}
+
+void idSWFScriptFunction_Script::pushscope( SWF_AbcFile* file, idSWFStack& stack, idSWFBitStream& bitstream )
+{
+ if( stack.Num() > 0 )
+ {
+ if( stack.A().IsObject() )
+ {
+ auto stackOBj = stack.A().GetObject();
+ stackOBj->AddRef();
+ scope.Alloc() = stackOBj;
+
+ }
+ else
+ {
+ common->DWarning( "tried to push a non object onto scope" );
+ }
+ stack.Pop( 1 );
+ }
+}
+
+void idSWFScriptFunction_Script::getlocal0( SWF_AbcFile* file, idSWFStack& stack, idSWFBitStream& bitstream )
+{
+ stack.Alloc() = registers[0];
+}
+
+//Classes are constructed implicitly
+void idSWFScriptFunction_Script::newclass( SWF_AbcFile* file, idSWFStack& stack, idSWFBitStream& bitstream )
+{
+ const auto& ci = file->classes[bitstream.ReadEncodedU32()];
+ idSWFScriptVar base = stack.A();
+ stack.Pop( 1 );
+ idSWFScriptVar* thisObj = ®isters[0];
+ common->FatalError( "Bytestream corrupted? Classes should already be created in CreateAbcObjects()!" );
+}
+
+void idSWFScriptFunction_Script::callpropvoid( SWF_AbcFile* file, idSWFStack& stack, idSWFBitStream& bitstream )
+{
+ const auto& cp = file->constant_pool;
+ const auto& mn = file->constant_pool.multinameInfos[bitstream.ReadEncodedU32()];
+ const idStrPtr funcName = ( idStrPtr ) &cp.utf8Strings[mn.nameIndex];
+
+ uint32 arg_count = bitstream.ReadEncodedU32();
+
+ //Todo Optimize: search for addFrameScript string index in constantpool!
+ if( *funcName == "addFrameScript" )
+ {
+ stack.Pop( arg_count );
+ arg_count = 0;
+ }
+ idSWFParmList parms( arg_count );
+
+ for( int i = 0; i < parms.Num(); i++ )
+ {
+ parms[parms.Num() - 1 - i] = stack.A();
+ stack.Pop( 1 );
+ }
+ if( stack.Num() )
+ {
+ idSWFScriptVar& item = stack.A();
+ if( item.IsFunction() )
+ {
+ auto func = ( ( idSWFScriptFunction_Script* )item.GetFunction() );
+ if( !func->GetScope()->Num() )
+ {
+ func->SetScope( *GetScope() );
+ }
+ item.GetFunction()->Call( registers[0].GetObject(), parms );
+ }
+ else if( item.IsObject() )
+ {
+ auto func = item.GetObject()->Get( funcName->c_str() );
+ if( func.IsFunction() )
+ {
+ if( !( ( idSWFScriptFunction_Script* )func.GetFunction() )->GetScope()->Num() )
+ {
+ ( ( idSWFScriptFunction_Script* )func.GetFunction() )->SetScope( *GetScope() );
+ }
+ func.GetFunction()->Call( item.GetObject(), parms );
+ }
+ }
+ stack.Pop( 1 );
+ }
+}
+
+/*
+========================
+idSWFScriptFunction_Script::RunAbc bytecode
+========================
+*/
+idSWFScriptVar idSWFScriptFunction_Script::RunAbc( idSWFScriptObject* thisObject, idSWFStack& stack, idSWFBitStream& bitstream )
+{
+ static int abcCallstackLevel = -1;
+ assert( abcFile );
+ idSWFScriptVar returnValue;
+
+ idSWFSpriteInstance* thisSprite = thisObject->GetSprite();
+ idSWFSpriteInstance* currentTarget = thisSprite;
+
+ if( currentTarget == NULL )
+ {
+ thisSprite = currentTarget = defaultSprite;
+ }
+
+ abcCallstackLevel++;
+ while( bitstream.Tell() < bitstream.Length() )
+ {
+#define ExecWordCode( n ) case OP_##n: n(abcFile,stack,bitstream); continue;
+#define InlineWordCode( n ) case OP_##n:
+ SWFAbcOpcode opCode = ( SWFAbcOpcode ) bitstream.ReadU8();
+ switch( opCode )
+ {
+ //ExecWordCode( bkpt );
+ //ExecWordCode( throw );
+ //ExecWordCode( getsuper );
+ //ExecWordCode( setsuper );
+ //ExecWordCode( dxns );
+ //ExecWordCode( dxnslate );
+ InlineWordCode( kill )
+ {
+ registers[bitstream.ReadEncodedU32()].SetUndefined();
+ continue;
+ }
+ InlineWordCode( nop );
+ InlineWordCode( label )
+ {
+ continue;
+ }
+ InlineWordCode( ifnlt )
+ {
+ int offset = bitstream.ReadS24();
+ auto& lH = stack.B();
+ auto& rH = stack.A();
+ stack.Pop( 2 );
+ bool condition = false;
+ switch( lH.GetType() )
+ {
+ case idSWFScriptVar::SWF_VAR_STRING:
+ condition = !( lH.ToString() < rH.ToString() );
+ break;
+ case idSWFScriptVar::SWF_VAR_FLOAT:
+ condition = !( lH.ToFloat() < rH.ToFloat() );
+ break;
+ case idSWFScriptVar::SWF_VAR_INTEGER:
+ condition = !( lH.ToInteger() < rH.ToInteger() );
+ break;
+ default:
+ common->Warning( " Tried to compare incompatible types %s + %s", lH.TypeOf(), rH.TypeOf() );
+ }
+ if( condition )
+ {
+ bitstream.Seek( offset );
+ }
+ continue;
+ }
+ InlineWordCode( ifnle )
+ {
+ int offset = bitstream.ReadS24();
+ const auto& lH = stack.B();
+ const auto& rH = stack.A();
+ stack.Pop( 2 );
+ bool condition = false;
+ switch( lH.GetType() )
+ {
+ case idSWFScriptVar::SWF_VAR_STRING:
+ condition = !( lH.ToString() <= rH.ToString() );
+ break;
+ case idSWFScriptVar::SWF_VAR_FLOAT:
+ condition = !( lH.ToFloat() <= rH.ToFloat() );
+ break;
+ case idSWFScriptVar::SWF_VAR_INTEGER:
+ condition = !( lH.ToInteger() <= rH.ToInteger() );
+ break;
+ default:
+ common->Warning( " Tried to compare incompatible types %s + %s", lH.TypeOf(), rH.TypeOf() );
+ }
+ if( condition )
+ {
+ bitstream.Seek( offset );
+ }
+ continue;
+ }
+ InlineWordCode( ifngt )
+ {
+ int offset = bitstream.ReadS24();
+ auto& lH = stack.B();
+ auto& rH = stack.A();
+ stack.Pop( 2 );
+ bool condition = false;
+ switch( lH.GetType() )
+ {
+ case idSWFScriptVar::SWF_VAR_STRING:
+ condition = !( lH.ToString() > rH.ToString() );
+ break;
+ case idSWFScriptVar::SWF_VAR_FLOAT:
+ condition = !( lH.ToFloat() > rH.ToFloat() );
+ break;
+ case idSWFScriptVar::SWF_VAR_INTEGER:
+ condition = !( lH.ToInteger() > rH.ToInteger() );
+ break;
+ default:
+ common->Warning( " Tried to compare incompatible types %s + %s", lH.TypeOf(), rH.TypeOf() );
+ }
+ if( condition )
+ {
+ bitstream.Seek( offset );
+ }
+ continue;
+ }
+ InlineWordCode( ifnge )
+ {
+ int offset = bitstream.ReadS24();
+ auto& lH = stack.B();
+ auto& rH = stack.A();
+ stack.Pop( 2 );
+ bool condition = false;
+ switch( lH.GetType() )
+ {
+ case idSWFScriptVar::SWF_VAR_STRING:
+ condition = !( lH.ToString() >= rH.ToString() );
+ break;
+ case idSWFScriptVar::SWF_VAR_FLOAT:
+ condition = !( lH.ToFloat() >= rH.ToFloat() );
+ break;
+ case idSWFScriptVar::SWF_VAR_INTEGER:
+ condition = !( lH.ToInteger() >= rH.ToInteger() );
+ break;
+ default:
+ common->Warning( " Tried to compare incompatible types %s + %s", lH.TypeOf(), rH.TypeOf() );
+ }
+ if( condition )
+ {
+ bitstream.Seek( offset );
+ }
+ continue;
+ }
+ InlineWordCode( jump )
+ {
+ int offset = bitstream.ReadS24();
+ bitstream.Seek( offset );
+ continue;
+ }
+ InlineWordCode( iftrue )
+ {
+ int offset = bitstream.ReadS24();
+ idSWFScriptVar value = stack.A();
+ stack.Pop( 1 );
+ bool condition = value.ToBool();
+ if( condition )
+ {
+ bitstream.Seek( offset );
+ }
+ continue;
+ }
+ InlineWordCode( iffalse )
+ {
+ int offset = bitstream.ReadS24();
+ if( !stack.A().ToBool() )
+ {
+ bitstream.Seek( offset );
+ }
+ stack.Pop( 1 );
+ continue;
+ }
+ InlineWordCode( ifeq )
+ {
+ int offset = bitstream.ReadS24();
+ auto& lH = stack.B();
+ auto& rH = stack.A();
+ stack.Pop( 2 );
+ bool condition = false;
+ switch( lH.GetType() )
+ {
+ case idSWFScriptVar::SWF_VAR_STRING:
+ condition = lH.ToString() == rH.ToString();
+ break;
+ case idSWFScriptVar::SWF_VAR_FLOAT:
+ condition = lH.ToFloat() == rH.ToFloat();
+ break;
+ case idSWFScriptVar::SWF_VAR_INTEGER:
+ condition = lH.ToInteger() == rH.ToInteger();
+ break;
+ default:
+ common->Warning( " Tried to compare incompatible types %s + %s", lH.TypeOf(), rH.TypeOf() );
+ }
+ if( condition )
+ {
+ bitstream.Seek( offset );
+ }
+ continue;
+ }
+ InlineWordCode( ifne )
+ {
+ int offset = bitstream.ReadS24();
+ auto& lH = stack.B();
+ auto& rH = stack.A();
+ stack.Pop( 2 );
+ bool condition = false;
+ switch( lH.GetType() )
+ {
+ case idSWFScriptVar::SWF_VAR_STRING:
+ condition = lH.ToString() != rH.ToString();
+ break;
+ case idSWFScriptVar::SWF_VAR_FLOAT:
+ condition = lH.ToFloat() != rH.ToFloat();
+ break;
+ case idSWFScriptVar::SWF_VAR_INTEGER:
+ condition = lH.ToInteger() != rH.ToInteger();
+ break;
+ default:
+ common->Warning( " Tried to compare incompatible types %s + %s", lH.TypeOf(), rH.TypeOf() );
+ }
+ if( condition )
+ {
+ bitstream.Seek( offset );
+ }
+ continue;
+ }
+ InlineWordCode( iflt )
+ {
+ int offset = bitstream.ReadS24();
+ auto& lH = stack.B();
+ auto& rH = stack.A();
+ stack.Pop( 2 );
+ bool condition = false;
+ switch( lH.GetType() )
+ {
+ case idSWFScriptVar::SWF_VAR_STRING:
+ condition = lH.ToString() < rH.ToString();
+ break;
+ case idSWFScriptVar::SWF_VAR_FLOAT:
+ condition = lH.ToFloat() < rH.ToFloat();
+ break;
+ case idSWFScriptVar::SWF_VAR_INTEGER:
+ condition = lH.ToInteger() < rH.ToInteger();
+ break;
+ default:
+ common->Warning( " Tried to compare incompatible types %s + %s", lH.TypeOf(), rH.TypeOf() );
+ }
+ if( condition )
+ {
+ bitstream.Seek( offset );
+ }
+ continue;
+ }
+ InlineWordCode( ifle )
+ {
+ int offset = bitstream.ReadS24();
+ auto& lH = stack.B();
+ auto& rH = stack.A();
+ stack.Pop( 2 );
+ bool condition = false;
+ switch( lH.GetType() )
+ {
+ case idSWFScriptVar::SWF_VAR_STRING:
+ condition = lH.ToString() <= rH.ToString();
+ break;
+ case idSWFScriptVar::SWF_VAR_FLOAT:
+ condition = lH.ToFloat() <= rH.ToFloat();
+ break;
+ case idSWFScriptVar::SWF_VAR_INTEGER:
+ condition = lH.ToInteger() <= rH.ToInteger();
+ break;
+ default:
+ common->Warning( " Tried to compare incompatible types %s + %s", lH.TypeOf(), rH.TypeOf() );
+ }
+ if( condition )
+ {
+ bitstream.Seek( offset );
+ }
+ continue;
+ }
+ InlineWordCode( ifgt )
+ {
+ int offset = bitstream.ReadS24();
+ auto& lH = stack.B();
+ auto& rH = stack.A();
+ stack.Pop( 2 );
+ bool condition = false;
+ switch( lH.GetType() )
+ {
+ case idSWFScriptVar::SWF_VAR_STRING:
+ condition = lH.ToString() > rH.ToString();
+ break;
+ case idSWFScriptVar::SWF_VAR_FLOAT:
+ condition = lH.ToFloat() > rH.ToFloat();
+ break;
+ case idSWFScriptVar::SWF_VAR_INTEGER:
+ condition = lH.ToInteger() > rH.ToInteger();
+ break;
+ default:
+ common->Warning( " Tried to compare incompatible types %s + %s", lH.TypeOf(), rH.TypeOf() );
+ }
+ if( condition )
+ {
+ bitstream.Seek( offset );
+ }
+ continue;
+ }
+ InlineWordCode( ifge )
+ {
+ int offset = bitstream.ReadS24();
+ auto& lH = stack.B();
+ auto& rH = stack.A();
+ stack.Pop( 2 );
+ bool condition = false;
+ switch( lH.GetType() )
+ {
+ case idSWFScriptVar::SWF_VAR_STRING:
+ condition = lH.ToString() >= rH.ToString();
+ break;
+ case idSWFScriptVar::SWF_VAR_FLOAT:
+ condition = lH.ToFloat() >= rH.ToFloat();
+ break;
+ case idSWFScriptVar::SWF_VAR_INTEGER:
+ condition = lH.ToInteger() >= rH.ToInteger();
+ break;
+ default:
+ common->Warning( " Tried to compare incompatible types %s + %s", lH.TypeOf(), rH.TypeOf() );
+ }
+ if( condition )
+ {
+ bitstream.Seek( offset );
+ }
+ continue;
+ }
+ InlineWordCode( ifstricteq )
+ {
+ int offset = bitstream.ReadS24();
+ auto& lH = stack.B();
+ auto& rH = stack.A();
+ stack.Pop( 2 );
+ bool condition = false;
+ if( lH.GetType() != rH.GetType() )
+ {
+ condition = false;
+ }
+ else
+ {
+ switch( lH.GetType() )
+ {
+ case idSWFScriptVar::SWF_VAR_STRING:
+ condition = lH.ToString() == rH.ToString();
+ break;
+ case idSWFScriptVar::SWF_VAR_FLOAT:
+ condition = lH.ToFloat() == rH.ToFloat();
+ break;
+ case idSWFScriptVar::SWF_VAR_INTEGER:
+ condition = lH.ToInteger() == rH.ToInteger();
+ break;
+ default:
+ common->Warning( " Tried to compare incompatible types %s + %s", lH.TypeOf(), rH.TypeOf() );
+ }
+ }
+ if( condition )
+ {
+ bitstream.Seek( offset );
+ }
+ continue;
+ }
+ InlineWordCode( ifstrictne )
+ {
+ int offset = bitstream.ReadS24();
+ auto& lH = stack.B();
+ auto& rH = stack.A();
+ stack.Pop( 2 );
+ bool condition = false;
+ if( lH.GetType() != rH.GetType() )
+ {
+ condition = true;
+ }
+ else
+ {
+ switch( lH.GetType() )
+ {
+ case idSWFScriptVar::SWF_VAR_STRING:
+ condition = ( lH.ToString() != rH.ToString() );
+ break;
+ case idSWFScriptVar::SWF_VAR_FLOAT:
+ condition = lH.ToFloat() != rH.ToFloat();
+ break;
+ case idSWFScriptVar::SWF_VAR_INTEGER:
+ condition = lH.ToInteger() != rH.ToInteger();
+ break;
+ default:
+ common->Warning( " Tried to compare incompatible types %s + %s", lH.TypeOf(), rH.TypeOf() );
+ }
+ }
+ if( condition )
+ {
+ bitstream.Seek( offset );
+ }
+ continue;
+ }
+ //ExecWordCode( lookupswitch );
+ //ExecWordCode( pushwith );
+ InlineWordCode( popscope )
+ {
+ scope[scope.Num() - 1]->Release();
+ scope.SetNum( scope.Num() - 1 );
+ continue;
+ }
+ //ExecWordCode( nextname );
+ //ExecWordCode( hasnext );
+ InlineWordCode( pushnull )
+ {
+ stack.Append( idSWFScriptVar( ( idSWFScriptObject* )( NULL ) ) );
+ continue;
+ }
+ InlineWordCode( pushundefined )
+ {
+ stack.Append( idSWFScriptVar() );
+ continue;
+ }
+ //ExecWordCode( nextvalue );
+ InlineWordCode( pushbyte )
+ {
+ stack.Append( idSWFScriptVar( ( int )bitstream.ReadU8() ) );
+ continue;
+ }
+ InlineWordCode( pushshort )
+ {
+ stack.Append( idSWFScriptVar( ( int )bitstream.ReadEncodedU32() ) );
+ continue;
+ }
+ InlineWordCode( pushtrue )
+ {
+ stack.Append( idSWFScriptVar( true ) );
+ continue;
+ }
+ InlineWordCode( pushfalse )
+ {
+ stack.Append( idSWFScriptVar( false ) );
+ continue;
+ }
+ //ExecWordCode ( pushnan );
+ InlineWordCode( pop )
+ {
+ stack.Pop( 1 );
+ continue;
+ }
+ InlineWordCode( dup )
+ {
+ stack.Alloc() = idSWFScriptVar( stack.A() );
+ continue;
+ }
+ InlineWordCode( swap )
+ {
+ common->FatalError( "swap not implemented" );
+ continue;
+ }
+ InlineWordCode( pushstring )
+ {
+ const auto& cp = abcFile->constant_pool.utf8Strings;
+ const auto& mn = cp[bitstream.ReadEncodedU32()];
+ stack.Append( idSWFScriptString( mn ) );
+ continue;
+ }
+ InlineWordCode( pushint )
+ {
+ const auto& cp = abcFile->constant_pool.integers;
+ const auto& val = cp[bitstream.ReadEncodedU32()];
+ stack.Append( idSWFScriptVar( val ) );
+ continue;
+ }
+ InlineWordCode( pushuint )
+ {
+ const auto& cp = abcFile->constant_pool.uIntegers;
+ const auto& val = cp[bitstream.ReadEncodedU32()];
+ stack.Append( idSWFScriptVar( ( int )val ) );
+ continue;
+ }
+ InlineWordCode( pushdouble )
+ {
+ const auto& cp = abcFile->constant_pool.doubles;
+ const auto& val = cp[bitstream.ReadEncodedU32()];
+ stack.Append( idSWFScriptVar( ( float )val ) );
+ continue;
+ }
+ ExecWordCode( pushscope )
+ //ExecWordCode( pushnamespace );
+ //ExecWordCode( hasnext2 );
+ //ExecWordCode( lix8 );
+ //ExecWordCode( lix16 );
+ //ExecWordCode( li8 );
+ //ExecWordCode( li16 );
+ //ExecWordCode( li32 );
+ //ExecWordCode( lf32 );
+ //ExecWordCode( lf64 );
+ //ExecWordCode( si8 );
+ //ExecWordCode( si8 );
+ //ExecWordCode( si16 );
+ //ExecWordCode( si32 );
+ //ExecWordCode( sf32 );
+ //ExecWordCode( sf64 );
+ InlineWordCode( newfunction )
+ {
+ const auto& cp = abcFile->constant_pool;
+ auto& method = abcFile->methods[bitstream.ReadEncodedU32()];
+ idSWFScriptFunction_Script* func = idSWFScriptFunction_Script::Alloc();
+ func->SetAbcFile( abcFile );
+ func->methodInfo = &method;
+ func->SetScope( scope );
+ func->SetConstants( constants );
+ func->SetDefaultSprite( defaultSprite );
+ stack.Alloc() = idSWFScriptVar( func );
+ stack.A().GetFunction()->Release();
+ continue;
+ }
+ InlineWordCode( call )
+ InlineWordCode( construct )
+ InlineWordCode( callmethod )
+ InlineWordCode( callstatic )
+ InlineWordCode( callsuper )
+ {
+ common->FatalError( "Not implemented" );
+ continue;
+ }
+ InlineWordCode( callproperty )
+ {
+ //fold this with callpropvoid.
+ const auto& cp = abcFile->constant_pool;
+ const auto& mn = abcFile->constant_pool.multinameInfos[bitstream.ReadEncodedU32()];
+ const idStrPtr funcName = ( idStrPtr ) &cp.utf8Strings[mn.nameIndex];
+ uint32 arg_count = bitstream.ReadEncodedU32();
+
+ idSWFParmList parms( arg_count );
+
+ for( int i = 0; i < parms.Num(); i++ )
+ {
+ parms[parms.Num() - 1 - i] = stack.A();
+ stack.Pop( 1 );
+ }
+ idSWFScriptVar& item = stack.A();
+
+ if( item.IsFunction() )
+ {
+ stack.Pop( 1 );
+ stack.Alloc() = item.GetFunction()->Call( registers[0].GetObject(), parms );
+ }
+ else if( item.IsObject() )
+ {
+ auto func = item.GetObject()->Get( funcName->c_str() );
+ if( !func.IsFunction() ) // search up scope
+ {
+ for( int i = scope.Num() - 1; i >= 0; i-- )
+ {
+ auto* s = scope[i];
+ while( s )
+ {
+ if( s->HasProperty( funcName->c_str() ) )
+ {
+ func = s->Get( funcName->c_str() );
+ s = NULL;
+ i = -1;
+ break;
+ }
+ else if( s->GetPrototype() && s->GetPrototype()->GetPrototype() )
+ {
+ s = s->GetPrototype()->GetPrototype();
+ }
+ else
+ {
+ s = NULL;
+ }
+ }
+ }
+ }
+ if( func.IsFunction() )
+ {
+ stack.Alloc() = func.GetFunction()->Call( item.GetObject(), parms );
+ }
+ }
+ continue;
+ }
+ InlineWordCode( returnvalue )
+ {
+ returnValue = stack.A();
+ [[fallthrough]];
+ }
+ InlineWordCode( returnvoid )
+ {
+ if( scope.Num() )
+ {
+ scope[scope.Num() - 1]->Release();
+ scope.SetNum( scope.Num() - 1 );
+ }
+ continue;
+ }
+ InlineWordCode( constructsuper )
+ {
+ uint32 args = bitstream.ReadEncodedU32();
+ stack.Pop( args );
+ continue;
+ }
+ InlineWordCode( constructprop )
+ {
+ //no need to call constructors for props that
+ const auto& cp = abcFile->constant_pool;
+ const auto& mn = abcFile->constant_pool.multinameInfos[bitstream.ReadEncodedU32()];
+ const idStrPtr propName = ( idStrPtr ) &cp.utf8Strings[mn.nameIndex];
+ uint32 arg_count = bitstream.ReadEncodedU32();
+ if( *propName == "Array" )
+ {
+ for( int i = 0; i < arg_count; i++ )
+ {
+ stack[stack.Num() - ( arg_count + 1 )].GetObject()->Set( i, stack[stack.Num() - arg_count + i] );
+ }
+ }
+ stack.Pop( arg_count );
+ continue;
+ }
+ //ExecWordCode( callsuperid );
+ //ExecWordCode( callproplex );
+ //ExecWordCode( callinterface );
+ //ExecWordCode( callsupervoid );
+ ExecWordCode( callpropvoid );
+ //ExecWordCode( sxi1 );
+ //ExecWordCode( sxi8 );
+ //ExecWordCode( sxi16 );
+ //ExecWordCode( applytype );
+ //ExecWordCode( DISABLED_pushfloat4 );
+ InlineWordCode( newarray )
+ {
+ auto* newArray = idSWFScriptObject::Alloc();
+
+ newArray->MakeArray();
+
+ uint32 args = bitstream.ReadEncodedU32();
+ for( int i = 0; i < args; i++ )
+ {
+ newArray->Set( i, stack.A() );
+ stack.Pop( 1 );
+ }
+
+ idSWFScriptVar baseObjConstructor = scope[0]->Get( "Object" );
+ idSWFScriptFunction* baseObj = baseObjConstructor.GetFunction();
+ newArray->SetPrototype( baseObj->GetPrototype() );
+ stack.Alloc().SetObject( newArray );
+
+ newArray->Release();
+ continue;
+ }
+ InlineWordCode( newobject );
+ InlineWordCode( newactivation )
+ {
+ idSWFScriptObject* object = idSWFScriptObject::Alloc();
+ idSWFScriptVar baseObjConstructor = scope[0]->Get( "Object" );
+ idSWFScriptFunction* baseObj = baseObjConstructor.GetFunction();
+ object->SetPrototype( baseObj->GetPrototype() );
+ stack.Alloc().SetObject( object );
+ object->Release();
+ continue;
+ }
+ ExecWordCode( newclass );
+ //ExecWordCode ( getdescendants );
+ //ExecWordCode ( newcatch );
+ //ExecWordCode ( findpropglobalstrict );
+ //ExecWordCode ( findpropglobal );
+ ExecWordCode( findproperty );
+ ExecWordCode( findpropstrict );
+
+ //ExecWordCode ( finddef );
+ ExecWordCode( getlex );
+ InlineWordCode( setproperty )
+ {
+ const auto& cp = abcFile->constant_pool;
+ const auto& mn = cp.multinameInfos[bitstream.ReadEncodedU32()];
+ const auto& n = cp.utf8Strings[mn.nameIndex];
+ idStr index = n;
+ idSWFScriptObject* target = nullptr;
+
+ if( mn.nameIndex && !stack.B().IsObject() )
+ {
+ target = scope[0];
+ }
+ else if( !mn.nameIndex )
+ {
+ index = stack.B().ToString();
+ idSWFScriptVar val = stack.A();
+ stack.Pop( 2 );
+ target = stack.A().GetObject();
+ stack.Alloc() = val;
+ }
+ else if( stack.B().IsObject() )
+ {
+ target = stack.B().GetObject();
+ }
+ target->Set( index, stack.A() );
+ stack.Pop( 2 );
+ continue;
+ }
+ InlineWordCode( getlocal )
+ {
+ stack.Alloc() = registers[bitstream.ReadEncodedU32()];
+ continue;
+ }
+ InlineWordCode( setlocal );
+ {
+ registers[bitstream.ReadEncodedU32()] = stack.A();
+ stack.Pop( 1 );
+ continue;
+ }
+ //ExecWordCode ( getglobalscope );
+ ExecWordCode( getscopeobject );
+ InlineWordCode( getproperty )
+ {
+ const auto& cp = abcFile->constant_pool;
+ const auto& mn = cp.multinameInfos[bitstream.ReadEncodedU32()];
+ const auto& n = cp.utf8Strings[mn.nameIndex];
+
+ idStr index = n;
+ idSWFScriptObject* target = nullptr;
+
+ if( mn.nameIndex && !stack.A().IsObject() )
+ {
+ target = scope[0];
+ }
+ else if( !mn.nameIndex )
+ {
+ target = stack.B().GetObject();
+ index = stack.A().ToString();
+ stack.Pop( 1 );
+ }
+ else
+ {
+ target = stack.A().GetObject();
+ }
+
+ stack.Pop( 1 );
+
+ if( target->HasProperty( index.c_str() ) )
+ {
+ stack.Append( target->Get( index.c_str() ) );
+ }
+ else
+ {
+ stack.Alloc().SetObject( idSWFScriptObject::Alloc() );
+ stack.A().GetObject()->Release();
+ }
+
+ continue;
+ }
+ //ExecWordCode ( getouterscope );
+ InlineWordCode( initproperty )
+ {
+ const auto& cp = abcFile->constant_pool;
+ const auto& mn = cp.multinameInfos[bitstream.ReadEncodedU32()];
+ const auto& n = cp.utf8Strings[mn.nameIndex];
+
+ idSWFScriptVar value = stack.A();
+ stack.Pop( 1 );
+ stack.A().GetObject()->Set( n, value );
+ continue;
+ }
+ //ExecWordCode ( 0x69 );
+ //ExecWordCode ( deleteproperty );
+ //ExecWordCode ( 0x6B );
+ InlineWordCode( getslot )
+ {
+ if( stack.A().IsObject() )
+ {
+ stack.Append( stack.A().GetObject()->Get( bitstream.ReadEncodedU32() ) );
+ }
+ continue;
+ }
+
+ InlineWordCode( setslot )
+ {
+ auto var = stack.A();
+
+ if( stack.B().IsUndefined() || stack.B().IsNULL() )
+ {
+ stack.B().SetObject( idSWFScriptObject::Alloc() );
+ stack.B().GetObject()->MakeArray();
+ }
+
+ stack.B().GetObject()->Set( bitstream.ReadEncodedU32(), var );
+ continue;
+ }
+ //ExecWordCode ( getglobalslot );
+ //ExecWordCode ( setglobalslot );
+ //ExecWordCode ( convert_s );
+ //ExecWordCode ( esc_xelem );
+ //ExecWordCode ( esc_xattr );
+ //ExecWordCode ( convert_i );
+ //ExecWordCode ( convert_u );
+ //ExecWordCode ( convert_d );
+ //ExecWordCode ( convert_b );
+ //ExecWordCode ( convert_o );
+ //ExecWordCode ( checkfilter );
+ //ExecWordCode ( DISABLED_convert );
+ //ExecWordCode ( DISABLED_unplus );
+ //ExecWordCode ( DISABLED_convert );
+ //ExecWordCode ( coerce );
+ //ExecWordCode ( coerce_b );
+ InlineWordCode( coerce_a )
+ {
+ auto var = stack.A();
+ stack.Pop( 1 );
+ if( !stack.A().IsValid() )
+ {
+ stack.A().SetNULL();
+ stack.Append( var );
+ }
+ else
+ {
+ if( !var.IsUndefined() )
+ {
+ stack.Append( var.ToString() );
+ }
+ else
+ {
+ stack.Append( var );
+ }
+
+ }
+
+ continue;
+ }
+ //ExecWordCode ( coerce_i );
+ //ExecWordCode ( coerce_d );
+ //ExecWordCode ( coerce_s );
+ //ExecWordCode ( astype );
+ //ExecWordCode ( astypelate );
+ //ExecWordCode ( coerce_u );
+ //ExecWordCode ( coerce_o );
+ InlineWordCode( negate_i )
+ InlineWordCode( negate )
+ {
+ auto& val = stack.A();
+ idSWFScriptVar result;
+ switch( val.GetType() )
+ {
+ case idSWFScriptVar::SWF_VAR_FLOAT:
+ val.SetFloat( -val.ToFloat() );
+ continue;
+ case idSWFScriptVar::SWF_VAR_INTEGER:
+ val.SetInteger( -val.ToInteger() );
+ continue;
+ default:
+ common->Warning( " Tried to increment incompatible type %s", val.TypeOf() );
+ }
+ continue;
+ }
+ InlineWordCode( increment_i )
+ InlineWordCode( increment )
+ {
+ auto& val = stack.A();
+ idSWFScriptVar result;
+ switch( val.GetType() )
+ {
+ case idSWFScriptVar::SWF_VAR_FLOAT:
+ val.SetFloat( val.ToFloat() + 1.0f );
+ continue;
+ case idSWFScriptVar::SWF_VAR_INTEGER:
+ val.SetInteger( val.ToInteger() + 1 );
+ continue;
+ default:
+ common->Warning( " Tried to increment incompatible type %s", val.TypeOf() );
+ }
+ continue;
+ }
+ InlineWordCode( inclocal_i )
+ InlineWordCode( inclocal )
+ {
+ auto& val = registers[bitstream.ReadEncodedU32()];
+ idSWFScriptVar result;
+ switch( val.GetType() )
+ {
+ case idSWFScriptVar::SWF_VAR_FLOAT:
+ val.SetFloat( val.ToFloat() + 1.0f );
+ continue;
+ case idSWFScriptVar::SWF_VAR_INTEGER:
+ val.SetInteger( val.ToInteger() + 1 );
+ continue;
+ default:
+ common->Warning( " Tried to increment incompatible type %s", val.TypeOf() );
+ }
+ continue;
+ }
+ InlineWordCode( decrement_i )
+ InlineWordCode( decrement )
+ {
+ auto& val = stack.A();
+ idSWFScriptVar result;
+ switch( val.GetType() )
+ {
+ case idSWFScriptVar::SWF_VAR_FLOAT:
+ val.SetFloat( val.ToFloat() - 1.0f );
+ continue;
+ case idSWFScriptVar::SWF_VAR_INTEGER:
+ val.SetInteger( val.ToInteger() + 1 );
+ continue;
+ default:
+ common->Warning( " Tried to decrement incompatible type %s", val.TypeOf() );
+ }
+ continue;
+ }
+ InlineWordCode( declocal_i );
+ InlineWordCode( declocal );
+ {
+ auto& val = registers[bitstream.ReadEncodedU32()];
+ idSWFScriptVar result;
+ switch( val.GetType() )
+ {
+ case idSWFScriptVar::SWF_VAR_FLOAT:
+ val.SetFloat( val.ToFloat() - 1.0f );
+ continue;
+ case idSWFScriptVar::SWF_VAR_INTEGER:
+ val.SetInteger( val.ToInteger() - 1 );
+ continue;
+ default:
+ common->Warning( " Tried to decrement incompatible type %s", val.TypeOf() );
+ }
+ continue;
+ }
+ //ExecWordCode ( typeof );
+ InlineWordCode( not )
+ {
+ stack.A().SetBool( !stack.A().ToBool() );
+ continue;
+ }
+ //ExecWordCode ( bitnot );
+ InlineWordCode( add_i )
+ InlineWordCode( add )
+ {
+ auto& lH = stack.B();
+ auto& rH = stack.A();
+ idSWFScriptVar result;
+ switch( lH.GetType() )
+ {
+ case idSWFScriptVar::SWF_VAR_STRING:
+ result.SetString( lH.ToString() + rH.ToString() );
+ break;
+ case idSWFScriptVar::SWF_VAR_FLOAT:
+ result.SetFloat( lH.ToFloat() + rH.ToFloat() );
+ break;
+ case idSWFScriptVar::SWF_VAR_INTEGER:
+ result.SetInteger( lH.ToInteger() + rH.ToInteger() );
+ break;
+ case idSWFScriptVar::SWF_VAR_FUNCTION:
+ result.SetString( lH.ToString() + rH.ToString() );
+ break;
+ default:
+ common->Warning( " Tried to add incompatible types %s + %s", lH.TypeOf(), rH.TypeOf() );
+ }
+
+ stack.Pop( 2 );
+ stack.Alloc() = result;
+ continue;
+ }
+ InlineWordCode( subtract_i )
+ InlineWordCode( subtract )
+ {
+ auto& lH = stack.A();
+ auto& rH = stack.B();
+ idSWFScriptVar result;
+ switch( lH.GetType() )
+ {
+ case idSWFScriptVar::SWF_VAR_FLOAT:
+ result.SetFloat( lH.ToFloat() - rH.ToFloat() );
+ break;
+ case idSWFScriptVar::SWF_VAR_INTEGER:
+ result.SetInteger( lH.ToInteger() - rH.ToInteger() );
+ break;
+ default:
+ common->Warning( " Tried to subtract incompatible types %s + %s", lH.TypeOf(), rH.TypeOf() );
+ }
+
+ stack.Pop( 2 );
+ stack.Alloc() = result;
+ continue;
+ }
+ InlineWordCode( multiply_i )
+ InlineWordCode( multiply )
+ {
+ auto& lH = stack.A();
+ auto& rH = stack.B();
+ idSWFScriptVar result;
+ switch( lH.GetType() )
+ {
+ case idSWFScriptVar::SWF_VAR_FLOAT:
+ result.SetFloat( lH.ToFloat() * rH.ToFloat() );
+ break;
+ case idSWFScriptVar::SWF_VAR_INTEGER:
+ result.SetInteger( lH.ToInteger() * rH.ToInteger() );
+ break;
+ default:
+ common->Warning( " Tried to multiply incompatible types %s + %s", lH.TypeOf(), rH.TypeOf() );
+ }
+
+ stack.Pop( 2 );
+ stack.Alloc() = result;
+ continue;
+ }
+ InlineWordCode( divide )
+ {
+ auto& lH = stack.A();
+ auto& rH = stack.B();
+ idSWFScriptVar result;
+ switch( lH.GetType() )
+ {
+ case idSWFScriptVar::SWF_VAR_FLOAT:
+ result.SetFloat( lH.ToFloat() / rH.ToFloat() );
+ break;
+ case idSWFScriptVar::SWF_VAR_INTEGER:
+ result.SetInteger( lH.ToInteger() / rH.ToInteger() );
+ break;
+ default:
+ common->Warning( " Tried to divide incompatible types %s + %s", lH.TypeOf(), rH.TypeOf() );
+ }
+
+ stack.Pop( 2 );
+ stack.Alloc() = result;
+ continue;
+ }
+ //ExecWordCode ( modulo );
+ //ExecWordCode ( lshift );
+ //ExecWordCode ( rshift );
+ //ExecWordCode ( urshift );
+ //ExecWordCode ( bitand );
+ //ExecWordCode ( bitor );
+ //ExecWordCode ( bitxor );
+ InlineWordCode( equals )
+ {
+ auto& lH = stack.A();
+ auto& rH = stack.B();
+ stack.Pop( 2 );
+ stack.Alloc() = lH.AbstractEquals( rH );
+ continue;
+ }
+ InlineWordCode( strictequals )
+ {
+ auto& lH = stack.A();
+ auto& rH = stack.B();
+ stack.Pop( 2 );
+ stack.Alloc() = lH.StrictEquals( rH );
+ continue;
+ }
+ //ExecWordCode ( lessthan );
+ //ExecWordCode ( lessequals );
+ //ExecWordCode ( greaterthan );
+ //ExecWordCode ( greaterequals );
+ //ExecWordCode ( instanceof );
+ //ExecWordCode ( istype );
+ //ExecWordCode ( istypelate );
+ //ExecWordCode ( in );
+ InlineWordCode( getlocal0 )
+ {
+ stack.Alloc() = registers[0];
+ continue;
+ }
+ InlineWordCode( getlocal1 )
+ {
+ stack.Alloc() = registers[1];
+ continue;
+ }
+ InlineWordCode( getlocal2 )
+ {
+ stack.Alloc() = registers[2];
+ continue;
+ }
+ InlineWordCode( getlocal3 )
+ {
+ stack.Alloc() = registers[3];
+ continue;
+ }
+ InlineWordCode( setlocal0 )
+ {
+ registers[0] = stack.A();
+ stack.Pop( 1 );
+ continue;
+ }
+ InlineWordCode( setlocal1 )
+ {
+ registers[1] = stack.A();
+ stack.Pop( 1 );
+ continue;
+ }
+ InlineWordCode( setlocal2 )
+ {
+ registers[2] = stack.A();
+ stack.Pop( 1 );
+ continue;
+ }
+ InlineWordCode( setlocal3 )
+ {
+ registers[3] = stack.A();
+ stack.Pop( 1 );
+ continue;
+ }
+ InlineWordCode( debug )
+ {
+ uint8 type = bitstream.ReadU8();
+ uint32 index = bitstream.ReadEncodedU32();
+ uint8 reg = bitstream.ReadU8();
+ uint32 extra = bitstream.ReadEncodedU32();
+ continue;
+ }
+ InlineWordCode( debugline )
+ InlineWordCode( debugfile )
+ {
+ uint32 nr = bitstream.ReadEncodedU32();
+ continue;
+ }
+ //ExecWordCode ( bkptline );
+ //ExecWordCode ( timestamp );
+ //ExecWordCode ( restargc );
+ //ExecWordCode ( restarg );
+ //ExecWordCode ( codes );
+ default:
+ {
+ const AbcOpcodeInfo* info = &opcodeInfo[opCode];
+ common->DWarning( "^5Unhandled Opcode %s\n", info ? info->name : "Empty" );
+#ifdef _WIN32
+ DebugBreak();
+#endif
+ }
+
+ }
+ }
+ abcCallstackLevel--;
+ return returnValue;
+}
diff --git a/neo/swf/SWF_Load.cpp b/neo/swf/SWF_Load.cpp
index a01945059f..2be81abd46 100644
--- a/neo/swf/SWF_Load.cpp
+++ b/neo/swf/SWF_Load.cpp
@@ -4,6 +4,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2013-2015 Robert Beckebans
+Copyright (C) 2023 Harrie van Ginneken
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@@ -32,11 +33,15 @@ If you have questions concerning this license or the applicable additional terms
#include "../renderer/Image.h"
//#include "../../libs/rapidjson/include/rapidjson/document.h"
-using namespace rapidjson;
+using namespace rapidjson;//bleh
#pragma warning(disable: 4355) // 'this' : used in base member initializer list
-#define BSWF_VERSION 16 // bumped to 16 for storing atlas image dimensions for unbuffered loads
+
+idCVar swf_fatalVersionMismatch( "swf_fatalVersionMismatch", "0", CVAR_BOOL, "Version number mismatch results in fatal error" );
+// bumped to 16 for storing atlas image dimensions for unbuffered loads
+// should be bumped to 17 for storing ABC Tag
+#define BSWF_VERSION 16
#define BSWF_MAGIC ( ( 'B' << 24 ) | ( 'S' << 16 ) | ( 'W' << 8 ) | BSWF_VERSION )
// RB begin
@@ -68,11 +73,14 @@ bool idSWF::LoadSWF( const char* fullpath )
return false;
}
- if( header.version > 9 )
+ if( header.version >= 9 )
{
idLib::Warning( "Unsupported version %d", header.version );
- delete rawfile;
- return false;
+ if( swf_fatalVersionMismatch.GetBool() )
+ {
+ delete rawfile;
+ return false;
+ }
}
bool compressed;
@@ -614,6 +622,25 @@ bool idSWF::LoadBinary( const char* bfilename, ID_TIME_T sourceTimeStamp )
}
}
}
+
+ if( f->Tell() < f->Length() )
+ {
+ abcFile.LoadBinary( f );
+
+ f->ReadBig( num );
+ symbolClasses.symbols.SetNum( num );
+ for( int i = 0; i < symbolClasses.symbols.Num(); i++ )
+ {
+ f->ReadBig( symbolClasses.symbols[i].tag );
+ f->ReadString( symbolClasses.symbols[i].name );
+ }
+
+ if( abcFile.AbcTagData.Length() )
+ {
+ DoABC( abcFile.AbcTagData );
+ }
+ }
+
delete f;
return true;
@@ -790,6 +817,14 @@ void idSWF::WriteBinary( const char* bfilename )
}
}
}
+
+ abcFile.WriteBinary( file );
+ file->WriteBig( symbolClasses.symbols.Num() );
+ for( int i = 0; i < symbolClasses.symbols.Num(); i++ )
+ {
+ file->WriteBig( symbolClasses.symbols[i].tag );
+ file->WriteString( symbolClasses.symbols[i].name );
+ }
}
diff --git a/neo/swf/SWF_Main.cpp b/neo/swf/SWF_Main.cpp
index 3d98b573a1..154da31462 100644
--- a/neo/swf/SWF_Main.cpp
+++ b/neo/swf/SWF_Main.cpp
@@ -4,6 +4,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2013-2015 Robert Beckebans
+Copyright (C) 2022-2023 Harrie van Ginneken
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@@ -35,13 +36,115 @@ If you have questions concerning this license or the applicable additional terms
idCVar swf_loadBinary( "swf_loadBinary", "1", CVAR_INTEGER, "used to set whether to load binary swf from generated" );
+idCVar swf_printAbcObjects( "swf_printAbcObjects", "0", CVAR_INTEGER, "used to set whether to print all classes constructed from the DoAbc tag" );
+idCVar swf_enableAbcTrace( "swf_enableAbcTrace", "1", CVAR_INTEGER, "used to set whether to print all actionscript traces to the console " );
+
int idSWF::mouseX = -1;
int idSWF::mouseY = -1;
bool idSWF::isMouseInClientArea = false;
extern idCVar in_useJoystick;
+idSWFScriptObject_EventDispatcherPrototype eventDispatcherScriptObjectPrototype;
+
+void idSWF::CreateAbcObjects( idSWFScriptObject* globals )
+{
+ //2 passes.
+ //1. Create all classes
+ int idx = 0;
+ for( auto& classInfo : abcFile.classes )
+ {
+ swfInstance_info& instanceInfo = abcFile.instances[idx];
+
+ idSWFScriptObject* tmp = idSWFScriptObject::Alloc();
+ idStr& className = abcFile.constant_pool.utf8Strings[instanceInfo.name->nameIndex];
+ //if these are namespace sets, concat all?
+ idStr fullClassName = *abcFile.constant_pool.namespaceNames[instanceInfo.name->index];
+ if( !fullClassName.IsEmpty() )
+ {
+ fullClassName += ".";
+ }
+ fullClassName += abcFile.constant_pool.utf8Strings[instanceInfo.name->nameIndex];
+ idStr& superName = abcFile.constant_pool.utf8Strings[instanceInfo.super_name->nameIndex];
+ //lookup prototype
+ if( globals->HasValidProperty( superName ) )
+ {
+ if( superName == "Object" )
+ {
+ idSWFScriptVar baseObjConstructor = globals->Get( "Object" );
+ idSWFScriptFunction* baseObj = baseObjConstructor.GetFunction();
+ tmp->SetPrototype( baseObj->GetPrototype() );
+ }
+ else
+ {
+ tmp->SetPrototype( globals->GetObject( superName )->GetPrototype() );
+ }
+
+ }
+ else
+ {
+ common->Warning( " prototype %s not found for %s ", superName.c_str(), className.c_str() );
+ }
+
+ idSWFScriptFunction_Script* init = idSWFScriptFunction_Script::Alloc();
+ init->SetData( classInfo.cinit );
+ tmp->Set( "__initializer__", idSWFScriptVar( init ) );
+ init->SetAbcFile( &abcFile );
+ idSWFScriptFunction_Script* constr = idSWFScriptFunction_Script::Alloc();
+ constr->SetData( instanceInfo.iinit );
+ tmp->Set( "__constructor__", idSWFScriptVar( constr ) );
+ constr->SetAbcFile( &abcFile );
+ globals->Set( className, tmp );
+ globals->Set( fullClassName, tmp );
+ idx++;
+ //check release
+ init->Release();
+ constr->Release();
+ }
+ idx = 0;
+
+ //2, create all traits
+ for( auto& classInfo : abcFile.classes )
+ {
+ swfInstance_info& instanceInfo = abcFile.instances[idx];
+ idStr fullClassName = *abcFile.constant_pool.namespaceNames[instanceInfo.name->index];
+ if( !fullClassName.IsEmpty() )
+ {
+ fullClassName += ".";
+ }
+ fullClassName += abcFile.constant_pool.utf8Strings[instanceInfo.name->nameIndex];
+ idStr& className = abcFile.constant_pool.utf8Strings[instanceInfo.name->nameIndex];
+ idSWFScriptObject* tmp = globals->GetObject( fullClassName );
+ auto* target = idSWFScriptObject::Alloc();
+ auto* var = tmp->GetVariable( "[" + fullClassName + "]", true );
+
+ for( swfTraits_info& trait : instanceInfo.traits )
+ {
+ target->Set( abcFile.constant_pool.utf8Strings[trait.name->nameIndex],
+ abcFile.GetTrait( trait, globals )->value );
+ }
+ var->value.SetObject( target );
+ target->Release();
+
+ for( swfTraits_info& trait : classInfo.traits )
+ {
+ tmp->Set( abcFile.constant_pool.utf8Strings[trait.name->nameIndex],
+ abcFile.GetTrait( trait, globals )->value
+ );
+ }
+
+ tmp->Set( fullClassName, target );
+
+ if( swf_printAbcObjects.GetBool() )
+ {
+ tmp->PrintToConsole( className.c_str() );
+ target->PrintToConsole( "[" + fullClassName + "]" );
+ }
+ idx++;
+ }
+ //should remove all API scriptinfo's here.
+}
/*
===================
@@ -348,16 +451,74 @@ idSWF::idSWF( const char* filename_, idSoundWorld* soundWorld_, bool exportJSON,
globals = idSWFScriptObject::Alloc();
globals->Set( "_global", globals );
+ SWF_NATIVE_API_OBJECT_DECLARE( _global );
+
+ auto* accessibilityPropertiesObj = idSWFScriptObject::Alloc();
+ //accessibilityPropertiesObj->Set( "", idSWFScriptObject::Alloc() );
+ auto* dispatcherObj = idSWFScriptObject::Alloc();
+ dispatcherObj->SetPrototype( &eventDispatcherScriptObjectPrototype );
+
+ extern idSWFScriptObject_SpriteInstancePrototype spriteInstanceScriptObjectPrototype;
+ auto* movieclipObj = idSWFScriptObject::Alloc();
+ movieclipObj->SetPrototype( &spriteInstanceScriptObjectPrototype );
+
+ if( spriteInstanceScriptObjectPrototype.GetPrototype() == NULL )
+ {
+ spriteInstanceScriptObjectPrototype.SetPrototype( &eventDispatcherScriptObjectPrototype );
+ }
+
+ auto* arrayObj = idSWFScriptObject::Alloc();
+ arrayObj->SetPrototype( scriptFunction_Object.GetPrototype() );
+ arrayObj->MakeArray();
+ arrayObj->Set( "toString", scriptFunction_ArrayToString.Bind( this ) );
+
+ globals->Set( "Array", arrayObj );
globals->Set( "Object", &scriptFunction_Object );
+ globals->Set( "EventDispatcher", dispatcherObj );
+ globals->Set( "DisplayObject", idSWFScriptObject::Alloc() );
+ globals->Set( "InteractiveObject", idSWFScriptObject::Alloc() );
+ globals->Set( "AccessibilityProperties", accessibilityPropertiesObj );
+ globals->Set( "Dictionary", idSWFScriptObject::Alloc() );
+ globals->Set( "DisplayObjectContainer", idSWFScriptObject::Alloc() );
+ globals->Set( "Sprite", idSWFScriptObject::Alloc() );
+ globals->Set( "DisplayObjectContainer", idSWFScriptObject::Alloc() );
+ globals->Set( "MovieClip", movieclipObj );
+
+ CreateAbcObjects( globals );
+ bool skipInitOnContruct = symbolClasses.symbols.Num() > 0;
mainspriteInstance = spriteInstanceAllocator.Alloc();
+ mainspriteInstance->abcFile = &abcFile;
+ mainspriteInstance->scriptObject = idSWFScriptObject::Alloc();
+
+ //stage class.
+ for( auto& symbol : symbolClasses.symbols )
+ {
+ if( !symbol.tag )
+ {
+ mainspriteInstance->name = symbol.name;
+ idStr objName;
+ mainspriteInstance->name.ExtractFileExtension( objName );
+
+ auto* super = globals->Get( symbol.name ).GetObject();
+ auto dcopy = super->Get( "[" + symbol.name + "]" );
+ if( dcopy.IsObject() )
+ {
+ mainspriteInstance->scriptObject->DeepCopy( dcopy.GetObject() );
+ }
+
+ mainspriteInstance->scriptObject->SetPrototype( super );
+ mainspriteInstance->scriptObject->Set( "root", mainspriteInstance->scriptObject );
+ }
+ }
mainspriteInstance->Init( mainsprite, NULL, 0 );
shortcutKeys = idSWFScriptObject::Alloc();
scriptFunction_shortcutKeys_clear.Bind( this );
scriptFunction_shortcutKeys_clear.Call( shortcutKeys, idSWFParmList() );
- globals->Set( "shortcutKeys", shortcutKeys );
+ globals->Set( "shortcutKeys", idSWFScriptVar( shortcutKeys ) );
+ SWF_NATIVE_API_OBJECT_DECLARE( shortcutKeys );
globals->Set( "deactivate", scriptFunction_deactivate.Bind( this ) );
globals->Set( "inhibitControl", scriptFunction_inhibitControl.Bind( this ) );
@@ -370,10 +531,14 @@ idSWF::idSWF( const char* filename_, idSoundWorld* soundWorld_, bool exportJSON,
globals->Set( "getLocalString", scriptFunction_getLocalString.Bind( this ) );
globals->Set( "swapPS3Buttons", scriptFunction_swapPS3Buttons.Bind( this ) );
globals->Set( "_root", mainspriteInstance->scriptObject );
+ globals->Set( "root", mainspriteInstance->scriptObject );
globals->Set( "strReplace", scriptFunction_strReplace.Bind( this ) );
globals->Set( "getCVarInteger", scriptFunction_getCVarInteger.Bind( this ) );
globals->Set( "setCVarInteger", scriptFunction_setCVarInteger.Bind( this ) );
+ globals->Set( "registerUserMouse", scriptFunction_registerUserMouse.Bind( this ) );
+ globals->Set( "Random", scriptFunction_random.Bind( this ) );
+ globals->Set( "random", scriptFunction_random.Bind( this ) );
globals->Set( "acos", scriptFunction_acos.Bind( this ) );
globals->Set( "cos", scriptFunction_cos.Bind( this ) );
globals->Set( "sin", scriptFunction_sin.Bind( this ) );
@@ -385,6 +550,8 @@ idSWF::idSWF( const char* filename_, idSoundWorld* soundWorld_, bool exportJSON,
globals->Set( "floor", scriptFunction_floor.Bind( this ) );
globals->Set( "ceil", scriptFunction_ceil.Bind( this ) );
globals->Set( "toUpper", scriptFunction_toUpper.Bind( this ) );
+ globals->Set( "trace", scriptFunction_trace.Bind( this ) );
+ globals->Set( "String", scriptFunction_String.Bind( this ) );
globals->SetNative( "platform", swfScriptVar_platform.Bind( &scriptFunction_getPlatform ) );
globals->SetNative( "blackbars", swfScriptVar_blackbars.Bind( this ) );
@@ -394,13 +561,21 @@ idSWF::idSWF( const char* filename_, idSoundWorld* soundWorld_, bool exportJSON,
// Do this to touch any external references (like sounds)
// But disable script warnings because many globals won't have been created yet
+ // THIS DOES NOT APPLY TO AS3.
extern idCVar swf_debug;
int debug = swf_debug.GetInteger();
swf_debug.SetInteger( 0 );
- mainspriteInstance->Run();
- mainspriteInstance->RunActions();
- mainspriteInstance->RunTo( 0 );
+
+ //The original impl does an initial run when contructing the stage.
+ //This is not possible with swf's that have the tag DoABC / run abc-bytecode
+ if( !skipInitOnContruct )
+ {
+ mainspriteInstance->Run();
+ mainspriteInstance->RunActions();
+ mainspriteInstance->RunTo( 0 );
+ mainspriteInstance->constructed = true;
+ }
swf_debug.SetInteger( debug );
@@ -578,6 +753,11 @@ idSWF::idSWFScriptFunction_precacheSound::Call
*/
idSWFScriptVar idSWF::idSWFScriptFunction_precacheSound::Call( idSWFScriptObject* thisObject, const idSWFParmList& parms )
{
+ if( !parms.Num() )
+ {
+ return "[Undefined]";
+ }
+
const idSoundShader* soundShader = declManager->FindSound( parms[0].ToString(), true );
return soundShader->GetName();
}
@@ -739,6 +919,7 @@ idSWFScriptVar idSWF::idSWFScriptFunction_setCVarInteger::Call( idSWFScriptObjec
return idSWFScriptVar();
}
+
/*
===================
idSWF::idSWFScriptFunction_acos::Call
@@ -905,6 +1086,48 @@ idSWFScriptVar idSWF::idSWFScriptFunction_ceil::Call( idSWFScriptObject* thisObj
return idSWFScriptVar( idMath::Ceil( num ) );
}
+/*
+===================
+idSWF::idSWFScriptFunction_random::Call
+===================
+*/
+idSWFScriptVar idSWF::idSWFScriptFunction_random::Call( idSWFScriptObject* thisObject, const idSWFParmList& parms )
+{
+ float min = 0.0f;
+ float max = 1.0f;
+ switch( parms.Num() )
+ {
+ case 0:
+ return 0;
+ break;
+ case 1:
+ switch( parms[0].GetType() )
+ {
+ case idSWFScriptVar::SWF_VAR_FLOAT:
+ return pThis->GetRandom().RandomFloat() * parms[0].ToFloat();
+ case idSWFScriptVar::SWF_VAR_INTEGER:
+ return pThis->GetRandom().RandomInt( parms[0].ToInteger() );
+ default:
+ return 0;
+ }
+ break;
+ default:
+ min = parms[0].ToFloat();
+ max = parms[1].ToFloat();
+ break;
+ }
+
+ switch( parms[0].GetType() )
+ {
+ case idSWFScriptVar::SWF_VAR_FLOAT:
+ return min + pThis->GetRandom().RandomFloat() * ( max - min );
+ case idSWFScriptVar::SWF_VAR_INTEGER:
+ return ( int )min + pThis->GetRandom().RandomInt() * ( int )( max - min );
+ default:
+ return 0;
+ }
+}
+
/*
========================
idSWFScriptFunction_toUpper::Call
@@ -956,7 +1179,7 @@ idSWFScriptVar idSWF::idSWFScriptFunction_shortcutKeys_clear::Call( idSWFScriptO
object->Set( "MWHEELDOWN", "MWHEEL_DOWN" );
object->Set( "MWHEELUP", "MWHEEL_UP" );
object->Set( "K_TAB", "TAB" );
-
+ object->Set( "K_BACKSPACE", "BACKSPACE" );
// FIXME: I'm an RTARD and didn't realize the keys all have "ARROW" after them
object->Set( "LEFTARROW", "LEFT" );
@@ -964,7 +1187,6 @@ idSWFScriptVar idSWF::idSWFScriptFunction_shortcutKeys_clear::Call( idSWFScriptO
object->Set( "UPARROW", "UP" );
object->Set( "DOWNARROW", "DOWN" );
-
return idSWFScriptVar();
}
@@ -988,6 +1210,50 @@ void idSWF::idSWFScriptNativeVar_crop::Set( idSWFScriptObject* object, const idS
pThis->crop = value.ToBool();
}
+idSWFScriptVar idSWF::idSWFScriptFunction_trace::Call( idSWFScriptObject* thisObject, const idSWFParmList& parms )
+{
+ if( swf_enableAbcTrace.GetBool() )
+ {
+ common->Printf( "^1 [%s] ^8 % s\n", thisObject->GetSprite() ? thisObject->GetSprite()->name.c_str() : "NONAME",
+ parms[0].ToString().c_str() );
+ }
+ return idSWFScriptVar();
+}
+
+idSWFScriptVar idSWF::idSWFScriptFunction_ArrayToString::Call( idSWFScriptObject* thisObject, const idSWFParmList& parms )
+{
+ idStr val;
+ int length = thisObject->Get( "length" ).ToInteger();
+ for( int i = 0; i < length; i++ )
+ {
+ if( i )
+ {
+ val += ",";
+ }
+ val += thisObject->Get( i ).ToString();
+ }
+ return val;
+}
+
+idSWFScriptVar idSWF::idSWFScriptFunction_registerUserMouse::Call( idSWFScriptObject* thisObject, const idSWFParmList& parms )
+{
+ common->Printf( "^1 registerUserMouse \n" );
+
+ return idSWFScriptVar();
+}
+
+
+idSWFScriptVar idSWF::idSWFScriptFunction_String::Call( idSWFScriptObject* thisObject, const idSWFParmList& parms )
+{
+ idStr val;
+ int length = parms.Num();
+ for( int i = 0; i < length; i++ )
+ {
+ val += parms[i].ToString();
+ }
+ return val;
+}
+
// RB begin
CONSOLE_COMMAND_SHIP( exportFlash, "Export all .bswf files to the exported/swf/ folder", NULL )
{
diff --git a/neo/swf/SWF_PlaceObject.cpp b/neo/swf/SWF_PlaceObject.cpp
index 47d81b513b..ede8ce5f96 100644
--- a/neo/swf/SWF_PlaceObject.cpp
+++ b/neo/swf/SWF_PlaceObject.cpp
@@ -45,6 +45,7 @@ void idSWFSpriteInstance::PlaceObject2( idSWFBitStream& bitstream )
uint64 flags = bitstream.ReadU8();
int depth = bitstream.ReadU16();
+
int characterID = -1;
if( ( flags & PlaceFlagHasCharacter ) != 0 )
{
@@ -146,10 +147,12 @@ void idSWFSpriteInstance::PlaceObject3( idSWFBitStream& bitstream )
uint64 flags2 = bitstream.ReadU8();
uint16 depth = bitstream.ReadU16();
+ /* RB: TODO REVIEW - it has been removed compared to BFG edition
if( ( flags2 & PlaceFlagHasClassName ) != 0 || ( ( ( flags2 & PlaceFlagHasImage ) != 0 ) && ( ( flags1 & PlaceFlagHasCharacter ) != 0 ) ) )
{
bitstream.ReadString(); // ignored
}
+ */
int characterID = -1;
if( ( flags1 & PlaceFlagHasCharacter ) != 0 )
diff --git a/neo/swf/SWF_Render.cpp b/neo/swf/SWF_Render.cpp
index a7865ee842..5bc8debf95 100644
--- a/neo/swf/SWF_Render.cpp
+++ b/neo/swf/SWF_Render.cpp
@@ -834,7 +834,7 @@ void idSWF::RenderShape( idRenderSystem* gui, const idSWFShape* shape, const swf
uint32 packedColorM = LittleLong( PackColor( color.mul ) );
uint32 packedColorA = LittleLong( PackColor( ( color.add * 0.5f ) + idVec4( 0.5f ) ) ); // Compress from -1..1 to 0..1
- gui->SetGLState( GLStateForRenderState( renderState ) | GLS_POLYMODE_LINE );
+ gui->SetGLState( GLStateForRenderState( renderState ) );
idDrawVert* verts = gui->AllocTris( line.startVerts.Num(), line.indices.Ptr(), line.indices.Num(), white, renderState.stereoDepth );
if( verts == NULL )
diff --git a/neo/swf/SWF_ScriptFunction.cpp b/neo/swf/SWF_ScriptFunction.cpp
index a8c6becb01..6cc6e6eaad 100644
--- a/neo/swf/SWF_ScriptFunction.cpp
+++ b/neo/swf/SWF_ScriptFunction.cpp
@@ -4,6 +4,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2015 Robert Beckebans
+Copyright (C) 2022-2023 Harrie van Ginneken
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@@ -32,6 +33,57 @@ If you have questions concerning this license or the applicable additional terms
idCVar swf_debug( "swf_debug", "0", CVAR_INTEGER | CVAR_ARCHIVE, "debug swf scripts. 1 shows traces/errors. 2 also shows warnings. 3 also shows disassembly. 4 shows parameters in the disassembly." );
idCVar swf_debugInvoke( "swf_debugInvoke", "0", CVAR_INTEGER, "debug swf functions being called from game." );
+idList idSwfActionScriptAPI::actionScriptAPIs;
+idList idSwfActionScriptAPI::actionScriptVariableAPIs;
+idList idSwfActionScriptAPI::actionScriptVariableNames;
+
+void idSwfActionScriptAPI::AddObjectAPI( idStr var )
+{
+ if( !actionScriptVariableNames.Find( var ) )
+ {
+ actionScriptVariableNames.Alloc() = var;
+ idStr& tmpStr = idSwfActionScriptAPI::actionScriptVariableAPIs.Alloc();
+ tmpStr = "/** \n * Generated by RBDoom3BFG \n*/\npackage{\n\tpublic class ";
+ tmpStr += var;
+ tmpStr += +" extends Object{};}";
+ }
+}
+
+CONSOLE_COMMAND_SHIP( swf_ExportActionScriptAPI, "writes all .as files", NULL )
+{
+ for( auto func : idSwfActionScriptAPI::actionScriptAPIs )
+ {
+ idStr result;
+ idStr name = func->GetActionScriptAPI( result );
+ if( !name.IsEmpty() )
+ {
+ idStrStatic< MAX_OSPATH > generatedFileName = name;
+ generatedFileName.Insert( "ActionscriptAPI/", 0 );
+ generatedFileName.SetFileExtension( "as" );
+ idFileLocal file( fileSystem->OpenFileWrite( generatedFileName, "fs_basepath" ) );
+ file->Printf( result );
+
+ common->Printf( "Written %s:\n ^4%s^7\n", generatedFileName.c_str(), result.c_str() );
+ }
+ }
+
+ for( int i = 0; i < idSwfActionScriptAPI::actionScriptVariableNames.Num(); i++ )
+ {
+ const idStr& name = idSwfActionScriptAPI::actionScriptVariableNames[i];
+ const idStr& apiStr = idSwfActionScriptAPI::actionScriptVariableAPIs[i];
+ if( !name.IsEmpty() && !apiStr.IsEmpty() )
+ {
+ idStrStatic< MAX_OSPATH > generatedFileName = name;
+ generatedFileName.Insert( "ActionscriptAPI/", 0 );
+ generatedFileName.SetFileExtension( "as" );
+ idFileLocal file( fileSystem->OpenFileWrite( generatedFileName, "fs_basepath" ) );
+ file->Printf( apiStr );
+
+ common->Printf( "Written %s:\n ^4%s^7\n", generatedFileName.c_str(), apiStr.c_str() );
+ }
+ }
+}
+
idSWFConstantPool::idSWFConstantPool()
{
}
@@ -137,26 +189,27 @@ idSWFScriptVar idSWFScriptFunction_Script::Call( idSWFScriptObject* thisObject,
for( int i = 0; i < parms.Num(); i++ )
{
stack[ parms.Num() - i - 1 ] = parms[i];
-
// Unfortunately at this point we don't have the function name anymore, so our warning messages aren't very detailed
if( i < parameters.Num() )
{
if( parameters[i].reg > 0 && parameters[i].reg < registers.Num() )
{
- registers[ parameters[i].reg ] = parms[i];
+ registers[parameters[i].reg] = parms[i];
}
locals->Set( parameters[i].name, parms[i] );
}
}
+
// Set any additional parameters to undefined
for( int i = parms.Num(); i < parameters.Num(); i++ )
{
if( parameters[i].reg > 0 && parameters[i].reg < registers.Num() )
{
- registers[ parameters[i].reg ].SetUndefined();
+ registers[parameters[i].reg].SetUndefined();
}
locals->Set( parameters[i].name, idSWFScriptVar() );
}
+
stack.A().SetInteger( parms.Num() );
int preloadReg = 1;
@@ -247,10 +300,25 @@ idSWFScriptVar idSWFScriptFunction_Script::Call( idSWFScriptObject* thisObject,
int scopeSize = scope.Num();
scope.Append( locals );
locals->AddRef();
+ idSWFScriptVar retVal;
+ if( methodInfo != nullptr )
+ {
+ assert( methodInfo->body );
+ auto* body = methodInfo->body;
+ registers[0].SetObject( thisObject );
+ idSWFBitStream abcStream( body->code.Ptr(), body->codeLength, false );
+ retVal = RunAbc( thisObject, stack, abcStream );
+
+ //-- FIXME
+ //-- Although some of the abc bytecode is skipped, scopes should match!
+ //assert(scope.Num() == scopeSize + 1);
+ }
+ else
+ {
+ retVal = Run( thisObject, stack, bitstream );
+ assert( scope.Num() == scopeSize + 1 );
+ }
- idSWFScriptVar retVal = Run( thisObject, stack, bitstream );
-
- assert( scope.Num() == scopeSize + 1 );
for( int i = scopeSize; i < scope.Num(); i++ )
{
if( verify( scope[i] ) )
diff --git a/neo/swf/SWF_ScriptFunction.h b/neo/swf/SWF_ScriptFunction.h
index d310f8f215..eaef35cdd1 100644
--- a/neo/swf/SWF_ScriptFunction.h
+++ b/neo/swf/SWF_ScriptFunction.h
@@ -4,6 +4,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2015 Robert Beckebans
+Copyright (C) 2023 Harrie van Ginneken
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@@ -28,6 +29,18 @@ If you have questions concerning this license or the applicable additional terms
*/
#ifndef __SWF_SCRIPTFUNCTION_H__
#define __SWF_SCRIPTFUNCTION_H__
+#include "SWF_Abc.h"
+
+#define SWF_NATIVE_API_OBJECT_DECLARE( x ) idSwfActionScriptAPI::AddObjectAPI(#x);
+
+class idSwfActionScriptAPI
+{
+public:
+ static idList actionScriptAPIs;
+ static idList actionScriptVariableAPIs;
+ static idList actionScriptVariableNames;
+ static void AddObjectAPI( idStr var );
+};
/*
========================
@@ -43,6 +56,13 @@ class idSWFScriptFunction
{
return idSWFScriptVar();
}; // this should never be hit
+
+ //Used to generate [returnVal].as file with public stub function to be used while compiling actionscript 3.0
+ virtual const char* GetActionScriptAPI( idStr& out )
+ {
+ return "";
+ };
+
virtual void AddRef() {};
virtual void Release() {};
virtual idSWFScriptObject* GetPrototype()
@@ -50,6 +70,8 @@ class idSWFScriptFunction
return NULL;
}
virtual void SetPrototype( idSWFScriptObject* _object ) { }
+
+
};
/*
@@ -185,7 +207,7 @@ idSWFScriptFunction_Script is a script function that's implemented in action scr
class idSWFScriptFunction_Script : public idSWFScriptFunction
{
public:
- idSWFScriptFunction_Script() : refCount( 1 ), flags( 0 ), data( NULL ), length( 0 ), prototype( NULL ), defaultSprite( NULL )
+ idSWFScriptFunction_Script() : refCount( 1 ), flags( 0 ), data( NULL ), length( 0 ), prototype( NULL ), defaultSprite( NULL ), methodInfo( NULL ), abcFile( NULL )
{
registers.SetNum( 4 );
}
@@ -217,7 +239,23 @@ class idSWFScriptFunction_Script : public idSWFScriptFunction
data = _data;
length = _length;
}
+ void SetData( swfMethod_info* _method )
+ {
+ methodInfo = _method;
+ }
+ void SetAbcFile( SWF_AbcFile* _file )
+ {
+ abcFile = _file;
+ }
+ swfMethod_info* GetMethodInfo()
+ {
+ return methodInfo;
+ }
void SetScope( idList& scope );
+ idList* GetScope()
+ {
+ return &scope;
+ }
void SetConstants( const idSWFConstantPool& _constants )
{
constants.Copy( _constants );
@@ -257,9 +295,20 @@ class idSWFScriptFunction_Script : public idSWFScriptFunction
idStr CallToScript( idSWFScriptObject* thisObject, const idSWFParmList& parms, const char* filename, int characterID, int actionID );
private:
- idSWFScriptVar Run( idSWFScriptObject* thisObject, idSWFStack& stack, idSWFBitStream& bitstream );
-
+ //////////////////////////////////////////////////////////////////////////
+ //////////////////////ABC Wordcode Interpretation/////////////////////////
+ //////////////////////////////////////////////////////////////////////////
+ void findproperty( SWF_AbcFile* file, idSWFStack& stack, idSWFBitStream& bitstream );
+ void findpropstrict( SWF_AbcFile* file, idSWFStack& stack, idSWFBitStream& bitstream );
+ void getlex( SWF_AbcFile* file, idSWFStack& stack, idSWFBitStream& bitstream );
+ void getscopeobject( SWF_AbcFile* file, idSWFStack& stack, idSWFBitStream& bitstream );
+ void pushscope( SWF_AbcFile* file, idSWFStack& stack, idSWFBitStream& bitstream );
+ void getlocal0( SWF_AbcFile* file, idSWFStack& stack, idSWFBitStream& bitstream );
+ void newclass( SWF_AbcFile* file, idSWFStack& stack, idSWFBitStream& bitstream );
+ void callpropvoid( SWF_AbcFile* file, idSWFStack& stack, idSWFBitStream& bitstream );
+ //////////////////////////////////////////////////////////////////////////
+ idSWFScriptVar Run( idSWFScriptObject* thisObject, idSWFStack& stack, idSWFBitStream& bitstream );
struct ActionBlock
{
@@ -280,6 +329,9 @@ class idSWFScriptFunction_Script : public idSWFScriptFunction
idStr ExportToScript( idSWFScriptObject* thisObject, idSWFStack& stack, idSWFBitStream& bitstream, const char* filename, int characterID, int actionID );
// RB end
+
+ idSWFScriptVar RunAbc( idSWFScriptObject* thisObject, idSWFStack& stack, idSWFBitStream& bitstream );
+ SWF_AbcFile* abcFile;
private:
std::atomic refCount;
@@ -300,7 +352,9 @@ class idSWFScriptFunction_Script : public idSWFScriptFunction
const char* name;
uint8 reg;
};
- idList< parmInfo_t, TAG_SWF > parameters;
+ idList< parmInfo_t > parameters;
+
+ swfMethod_info* methodInfo;
};
#endif // !__SWF_SCRIPTFUNCTION_H__
diff --git a/neo/swf/SWF_ScriptObject.cpp b/neo/swf/SWF_ScriptObject.cpp
index 908dd60a18..02731ec125 100644
--- a/neo/swf/SWF_ScriptObject.cpp
+++ b/neo/swf/SWF_ScriptObject.cpp
@@ -59,6 +59,17 @@ idSWFScriptObject::swfNamedVar_t& idSWFScriptObject::swfNamedVar_t::operator=( c
return *this;
}
+void idSWFScriptObject::DeepCopy( idSWFScriptObject* _object )
+{
+ if( _object != NULL )
+ {
+ for( int i = 0; i < _object->NumVariables(); i++ )
+ {
+ Set( _object->EnumVariable( i ), _object->Get( _object->EnumVariable( i ) ) );
+ }
+ }
+}
+
/*
========================
idSWFScriptObject::idSWFScriptObject
@@ -668,11 +679,21 @@ idSWFTextInstance* idSWFScriptObject::GetNestedText( const char* arg1, const cha
idSWFScriptObject::PrintToConsole
========================
*/
-void idSWFScriptObject::PrintToConsole() const
+void idSWFScriptObject::PrintToConsole( const char* name ) const
{
+ static int recursionCount = 0;
+ common->Printf( "------------------------------------------------------------\n" );
+
if( variables.Num() > 0 )
{
- idLib::Printf( "%d subelements:\n", variables.Num() );
+ if( name )
+ {
+ idLib::Printf( "[%s] %d subelements:\n", name, variables.Num() );
+ }
+ else
+ {
+ idLib::Printf( "%d subelements:\n", variables.Num() );
+ }
int maxVarLength = 0;
for( int i = 0; i < variables.Num(); ++i )
@@ -699,6 +720,14 @@ void idSWFScriptObject::PrintToConsole() const
}
else
{
- idLib::Printf( "No subelements\n" );
+ if( name )
+ {
+ idLib::Printf( "[%s] No subelements:\n", name );
+ }
+ else
+ {
+ idLib::Printf( "No subelements\n" );
+ }
+
}
}
diff --git a/neo/swf/SWF_ScriptObject.h b/neo/swf/SWF_ScriptObject.h
index d9a12d2cd9..e18b7c571e 100644
--- a/neo/swf/SWF_ScriptObject.h
+++ b/neo/swf/SWF_ScriptObject.h
@@ -140,6 +140,7 @@ class idSWFScriptObject
return ( objectType == SWF_OBJECT_TEXT ) ? data.text : NULL;
}
+ void DeepCopy( idSWFScriptObject* _object );
// Also accessible via __proto__ property
idSWFScriptObject* GetPrototype()
{
@@ -181,18 +182,8 @@ class idSWFScriptObject
idSWFSpriteInstance* GetNestedSprite( const char* arg1, const char* arg2 = NULL, const char* arg3 = NULL, const char* arg4 = NULL, const char* arg5 = NULL, const char* arg6 = NULL );
idSWFTextInstance* GetNestedText( const char* arg1, const char* arg2 = NULL, const char* arg3 = NULL, const char* arg4 = NULL, const char* arg5 = NULL, const char* arg6 = NULL );
- void PrintToConsole() const;
+ void PrintToConsole( const char* name = nullptr ) const;
-private:
- std::atomic refCount;
- bool noAutoDelete;
-
- enum swfNamedVarFlags_t
- {
- SWF_VAR_FLAG_NONE = 0,
- SWF_VAR_FLAG_READONLY = BIT( 1 ),
- SWF_VAR_FLAG_DONTENUM = BIT( 2 )
- };
struct swfNamedVar_t
{
swfNamedVar_t() : native( NULL ) { }
@@ -206,6 +197,20 @@ class idSWFScriptObject
idSWFScriptNativeVariable* native;
int flags;
};
+
+ swfNamedVar_t* GetVariable( int index, bool create );
+ swfNamedVar_t* GetVariable( const char* name, bool create );
+private:
+ std::atomic refCount;
+ bool noAutoDelete;
+
+ enum swfNamedVarFlags_t
+ {
+ SWF_VAR_FLAG_NONE = 0,
+ SWF_VAR_FLAG_READONLY = BIT( 1 ),
+ SWF_VAR_FLAG_DONTENUM = BIT( 2 )
+ };
+
idList< swfNamedVar_t, TAG_SWF > variables;
static const int VARIABLE_HASH_BUCKETS = 16;
@@ -226,9 +231,6 @@ class idSWFScriptObject
idSWFSpriteInstance* sprite; // only valid if objectType == SWF_OBJECT_SPRITE
idSWFTextInstance* text; // only valid if objectType == SWF_OBJECT_TEXT
} data;
-
- swfNamedVar_t* GetVariable( int index, bool create );
- swfNamedVar_t* GetVariable( const char* name, bool create );
};
#endif // !__SWF_SCRIPTOBJECT_H__
diff --git a/neo/swf/SWF_ScriptVar.cpp b/neo/swf/SWF_ScriptVar.cpp
index 3456d4f878..652e7e54c2 100644
--- a/neo/swf/SWF_ScriptVar.cpp
+++ b/neo/swf/SWF_ScriptVar.cpp
@@ -3,6 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
+Copyright (C) 2023 Harrie van Ginneken
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@@ -51,6 +52,7 @@ idSWFScriptVar::idSWFScriptVar( const idSWFScriptVar& other )
{
other.value.function->AddRef();
}
+ traitsInfo = other.traitsInfo;
}
/*
diff --git a/neo/swf/SWF_ScriptVar.h b/neo/swf/SWF_ScriptVar.h
index 41044dc1c3..0fe1f9b654 100644
--- a/neo/swf/SWF_ScriptVar.h
+++ b/neo/swf/SWF_ScriptVar.h
@@ -3,6 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
+Copyright (C) 2023 Harrie van Ginneken
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@@ -68,40 +69,41 @@ these can be on the stack, in a script object, passed around as parameters, etc
they can contain raw data (int, float), strings, functions, or objects
========================
*/
+struct swfTraits_info;
class idSWFScriptVar
{
public:
- idSWFScriptVar() : type( SWF_VAR_UNDEF ) { }
+ idSWFScriptVar() : traitsInfo( NULL ), type( SWF_VAR_UNDEF ) { }
idSWFScriptVar( const idSWFScriptVar& other );
- idSWFScriptVar( idSWFScriptObject* o ) : type( SWF_VAR_UNDEF )
+ idSWFScriptVar( idSWFScriptObject* o ) : traitsInfo( NULL ), type( SWF_VAR_UNDEF )
{
SetObject( o );
}
- idSWFScriptVar( idStrId s ) : type( SWF_VAR_UNDEF )
+ idSWFScriptVar( idStrId s ) : traitsInfo( NULL ), type( SWF_VAR_UNDEF )
{
SetString( s );
}
- idSWFScriptVar( const idStr& s ) : type( SWF_VAR_UNDEF )
+ idSWFScriptVar( const idStr& s ) : traitsInfo( NULL ), type( SWF_VAR_UNDEF )
{
SetString( s );
}
- idSWFScriptVar( const char* s ) : type( SWF_VAR_UNDEF )
+ idSWFScriptVar( const char* s ) : traitsInfo( NULL ), type( SWF_VAR_UNDEF )
{
SetString( idStr( s ) );
}
- idSWFScriptVar( float f ) : type( SWF_VAR_UNDEF )
+ idSWFScriptVar( float f ) : traitsInfo( NULL ), type( SWF_VAR_UNDEF )
{
SetFloat( f );
}
- idSWFScriptVar( bool b ) : type( SWF_VAR_UNDEF )
+ idSWFScriptVar( bool b ) : traitsInfo( NULL ), type( SWF_VAR_UNDEF )
{
SetBool( b );
}
- idSWFScriptVar( int32 i ) : type( SWF_VAR_UNDEF )
+ idSWFScriptVar( int32 i ) : traitsInfo( NULL ), type( SWF_VAR_UNDEF )
{
SetInteger( i );
}
- idSWFScriptVar( idSWFScriptFunction* nf ) : type( SWF_VAR_UNDEF )
+ idSWFScriptVar( idSWFScriptFunction* nf ) : traitsInfo( NULL ), type( SWF_VAR_UNDEF )
{
SetFunction( nf );
}
@@ -272,6 +274,7 @@ class idSWFScriptVar
return type;
}
+ const swfTraits_info* traitsInfo;
private:
void Free();
swfScriptVarType type;
diff --git a/neo/swf/SWF_ShapeParser.cpp b/neo/swf/SWF_ShapeParser.cpp
index a6266236d0..a0d718396a 100644
--- a/neo/swf/SWF_ShapeParser.cpp
+++ b/neo/swf/SWF_ShapeParser.cpp
@@ -3,6 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
+Copyright (C) 2023 Harrie van Ginneken
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@@ -31,6 +32,81 @@ If you have questions concerning this license or the applicable additional terms
#pragma warning( disable: 4189 ) // local variable is initialized but not referenced
+// HarrievG begin
+void idSWFShapeParser::MakeCap( idSWFShapeParser::swfSPDrawLine_t& spld, idSWFShapeDrawLine& ld, swfSPMorphEdge_t& edge, bool start )
+{
+ //figure out what the orientation of the cap is.
+ uint16 v0StartIndex = edge.start.v0;
+ uint16 v1StartIndex = ( edge.start.cp == 0xFFFF ) ? edge.start.v1 : edge.start.cp;
+
+ uint16 v0EndIndex = ( edge.end.cp == 0xFFFF ) ? edge.end.v0 : edge.end.cp;
+ uint16 v1EndIndex = edge.end.v1;
+
+ uint16 v0 = v0StartIndex;
+ uint16 v1 = v1StartIndex;
+
+ if( !start )
+ {
+ v0 = v0EndIndex;
+ v1 = v1EndIndex;
+ }
+
+ idVec2 up = ( verts[v0] - verts[v1] );
+ idVec2 down = ( verts[v1] - verts[v0] );
+ idVec2 cross = idVec2( down.y, -down.x );
+ idVec2 crossUp = idVec2( up.y, -up.x );
+
+ uint8 vertIndex;
+ if( !start )
+ {
+ vertIndex = v1;
+ }
+ else
+ {
+ vertIndex = v0;
+ cross = crossUp;
+ }
+
+ float scale = ( float )( 1.0f / 20 ) * ( ld.style.startWidth * 0.5 ) ;
+
+ //vert
+ int capCenterIdx = ld.startVerts.AddUnique( verts[vertIndex] );
+ int pointCnt;
+ float x, z;
+ swfMatrix_t matrix;
+ float s, c;
+ idVec2 xup( 1.0f, 0.0f );
+ float angle = idMath::ATan( xup.y - cross.y, xup.x - cross.x ) + idMath::PI;
+
+ idMath::SinCos( angle, s, c );
+
+ matrix.xx = c * scale;
+ matrix.yx = s * scale;
+ matrix.xy = -s * scale;
+ matrix.yy = c * scale;
+ int A, B;
+ for( float w = -10; w <= 180 + 10; w += 10 )
+ {
+ idMath::SinCos( DEG2RAD( w ), z, x );
+
+ ld.indices.Append( capCenterIdx );
+ A = ld.startVerts.AddUnique( matrix.Transform( idVec2( x, z ) ) + ld.startVerts[capCenterIdx] );
+
+ if( w >= 0.0f )
+ {
+ ld.indices.Append( B );
+ ld.indices.Append( A );
+ ld.indices.Append( capCenterIdx );
+ }
+
+ ld.indices.Append( A );
+
+ idMath::SinCos( DEG2RAD( w ), z, x );
+ B = ld.startVerts.AddUnique( matrix.Transform( idVec2( x , z ) ) + ld.startVerts[capCenterIdx] );
+ ld.indices.Append( B );
+ }
+}
+
/*
========================
idSWFShapeParser::ParseShape
@@ -57,28 +133,73 @@ void idSWFShapeParser::Parse( idSWFBitStream& bitstream, idSWFShape& shape, int
ParseShapes( bitstream, NULL, false );
TriangulateSoup( shape );
+ //generate triangle mesh
shape.lineDraws.SetNum( lineDraws.Num() );
+ int last = 0;
for( int i = 0; i < lineDraws.Num(); i++ )
{
+
idSWFShapeDrawLine& ld = shape.lineDraws[i];
swfSPDrawLine_t& spld = lineDraws[i];
ld.style = spld.style;
+ float startWidth = ld.style.startWidth;
+ float endWidth = ld.style.endWidth;
ld.indices.SetNum( spld.edges.Num() * 3 );
ld.indices.SetNum( 0 );
+
+ //edge list
for( int e = 0; e < spld.edges.Num(); e++ )
{
- int v0 = ld.startVerts.AddUnique( verts[ spld.edges[e].start.v0 ] );
- ld.indices.Append( v0 );
- ld.indices.Append( v0 );
+ //startcap
+ //only supporting round
+ if( ld.style.startCapStyle == 0 )
+ {
+ MakeCap( spld, ld, spld.edges[e], true );
+ }
+
+ uint16 v0StartIndex = spld.edges[e].start.v0;
+ uint16 v1StartIndex = ( spld.edges[e].start.cp == 0xFFFF ) ? spld.edges[e].start.v1 : spld.edges[e].start.cp;
+
+ uint16 v0EndIndex = ( spld.edges[e].end.cp == 0xFFFF ) ? spld.edges[e].end.v0 : spld.edges[e].end.cp;
+ uint16 v1EndIndex = spld.edges[e].end.v1;
+
+ uint16 v0 = v0StartIndex;
+ uint16 v1 = v1StartIndex;
+
+ idVec2 up = ( verts[v0] - verts[v1] );
+ idVec2 down = ( verts[v1] - verts[v0] );
+ idVec2 cross = idVec2( down.y, -down.x );
+ idVec2 crossUp = idVec2( up.y, -up.x );
+
+ float scale = ( float )( 1.0f / 20 ) * ( ld.style.startWidth * 0.5 );
+
+ idVec2 offSetA = crossUp * ( ( ( 1.0f / 20 ) / down.Length() ) * ld.style.startWidth ) * 0.5f ;
+ idVec2 offSetB = cross * ( ( ( 1.0f / 20 ) / down.Length() ) * ld.style.startWidth ) * 0.5f;
+
+ v0 = ld.startVerts.AddUnique( verts[ spld.edges[e].start.v0 ] - offSetB );
+ int v0x = ld.startVerts.AddUnique( verts[ spld.edges[e].start.v0 ] - offSetA );
+
+ //straight line
+ if( spld.edges[e].start.cp == 0xFFFF )
+ {
+ ld.indices.Append( v0 );
+ ld.indices.Append( v0x );
+ }
// Rather then tesselating curves at run time, we do them once here by inserting a vert every 10 units
// It may not wind up being 10 actual pixels when rendered because the shape may have scaling applied to it
if( spld.edges[e].start.cp != 0xFFFF )
{
assert( spld.edges[e].end.cp != 0xFFFF );
- float length1 = ( verts[ spld.edges[e].start.v0 ] - verts[ spld.edges[e].start.v1 ] ).Length();
- float length2 = ( verts[ spld.edges[e].end.v0 ] - verts[ spld.edges[e].end.v1 ] ).Length();
+ float length1 = ( verts[ spld.edges[e].start.v0 ] - verts[ spld.edges[e].start.v1 ] ).Length() * scale;
+ float length2 = ( verts[ spld.edges[e].end.v0 ] - verts[ spld.edges[e].end.v1 ] ).Length() * scale;
int numPoints = 1 + idMath::Ftoi( Max( length1, length2 ) / 10.0f );
+ int lastV1;
+ int last;
+ v0 = ld.startVerts.AddUnique( verts[spld.edges[e].end.v0] + offSetB );
+ v0x = ld.startVerts.AddUnique( verts[spld.edges[e].end.v0] + offSetA );
+ ld.indices.Append( v0 );
+
for( int ti = 0; ti < numPoints; ti++ )
{
float t0 = ( ti + 1 ) / ( ( float ) numPoints + 1.0f );
@@ -91,16 +212,103 @@ void idSWFShapeParser::Parse( idSWFBitStream& bitstream, idSWFShape& shape, int
p1 += c2 * verts[ spld.edges[e].start.cp ];
p1 += c3 * verts[ spld.edges[e].start.v1 ];
- int v1 = ld.startVerts.AddUnique( p1 );
- ld.indices.Append( v1 );
- ld.indices.Append( v1 );
+ t0 = ( ti + 1 + 1 ) / ( ( float ) numPoints + 1.0f );
+ t1 = ( 1.0f - t0 );
+ c1 = t1 * t1;
+ c2 = t0 * t1 * 2.0f;
+ c3 = t0 * t0;
+
+ idVec2 p2 = c1 * verts[spld.edges[e].start.v0];
+ p2 += c2 * verts[spld.edges[e].start.cp];
+ p2 += c3 * verts[spld.edges[e].start.v1];
+
+ idVec2 iup = p1 - p2;
+ idVec2 idown = p2 - p1;
+ idVec2 icross = idVec2( idown.y, -idown.x );
+ idVec2 icrossUp = idVec2( iup.y, -iup.x );
+ idVec2 ioffSetA = icrossUp * ( ( ( 1.0f / 20 ) / idown.Length() ) * ld.style.startWidth ) * 0.5f;
+ idVec2 ioffSetB = icross * ( ( ( 1.0f / 20 ) / idown.Length() ) * ld.style.startWidth ) * 0.5f;
+
+ v1 = ld.startVerts.AddUnique( p1 + ioffSetB );
+ int v2 = ld.startVerts.AddUnique( p1 + ioffSetA );
+
+ if( ti > 0 )
+ {
+ ld.indices.Append( v2 );
+ ld.indices.Append( lastV1 );
+ }
+
ld.indices.Append( v1 );
+ ld.indices.Append( v2 );
+ if( ti > 0 )
+ {
+ ld.indices.Append( v2 );
+ ld.indices.Append( v1 );
+ }
+ else
+ {
+ ld.indices.Append( v2 );
+ }
+
+ if( ti == numPoints - 1 )
+ {
+ ld.indices.Append( v2 );
+ }
+
+ if( ti == 0 )
+ {
+
+ ld.indices.Append( v0 );
+ ld.indices.Append( v0x );
+ ld.indices.Append( v1 );
+ ld.indices.Append( v2 );
+ }
+
+ lastV1 = v1;
+ last = v2;
}
+
+ v0 = v0EndIndex;
+ v1 = v1EndIndex;
+
+ up = ( verts[v0] - verts[v1] );
+ down = ( verts[v1] - verts[v0] );
+ cross = idVec2( down.y, -down.x );
+ crossUp = idVec2( up.y, -up.x );
+
+ offSetA = crossUp * ( ( ( 1.0f / 20 ) / down.Length() ) * ld.style.startWidth ) * 0.5f;
+ offSetB = cross * ( ( ( 1.0f / 20 ) / down.Length() ) * ld.style.startWidth ) * 0.5f;
+
+
+ ld.indices.Append( lastV1 );
+ ld.indices.Append( ld.startVerts.AddUnique( verts[spld.edges[e].end.v1] + offSetA ) );
+ ld.indices.Append( ld.startVerts.AddUnique( verts[spld.edges[e].end.v1] + offSetB ) );
+
+ ld.indices.Append( last );
+ ld.indices.Append( lastV1 );
+ ld.indices.Append( ld.startVerts.AddUnique( verts[spld.edges[e].end.v1] + offSetA ) );
+ }
+ else
+ {
+ //straight line
+ ld.indices.Append( ld.startVerts.AddUnique( verts[spld.edges[e].end.v1] - offSetB ) );
+
+ ld.indices.Append( ld.startVerts.AddUnique( verts[spld.edges[e].end.v1] - offSetA ) );
+ ld.indices.Append( v0x );
+ ld.indices.Append( ld.startVerts.AddUnique( verts[spld.edges[e].end.v1] - offSetB ) );
+ }
+
+ last = ld.indices.Num() - 1;
+
+ //endcap
+ if( ld.style.endCapStyle == 0 )
+ {
+ MakeCap( spld, ld, spld.edges[e], false );
}
- ld.indices.Append( ld.startVerts.AddUnique( verts[ spld.edges[e].start.v1 ] ) );
}
}
}
+// HarrievG end
/*
========================
@@ -600,7 +808,7 @@ void idSWFShapeParser::MakeLoops()
}
if( shape == -1 )
{
- idLib::Warning( "idSWFShapeParser: Hole not in a shape" );
+ idLib::Warning( "idSWFShapeParser: Hole not in a shape, try to smoothen or straighten the erroneous shape" );
fill.loops.RemoveIndexFast( hole );
continue;
}
@@ -1003,12 +1211,11 @@ void idSWFShapeParser::ReadFillStyle( idSWFBitStream& bitstream )
{
lineStyleCount = bitstream.ReadU16();
}
-
+ int idx = lineDraws.Num();
lineDraws.SetNum( lineDraws.Num() + lineStyleCount );
- lineDraws.SetNum( 0 );
for( int i = 0; i < lineStyleCount; i++ )
{
- swfLineStyle_t& lineStyle = lineDraws.Alloc().style;
+ swfLineStyle_t& lineStyle = lineDraws[idx + i].style;
lineStyle.startWidth = bitstream.ReadU16();
if( lineStyle2 )
{
@@ -1023,6 +1230,13 @@ void idSWFShapeParser::ReadFillStyle( idSWFBitStream& bitstream )
uint8 reserved = bitstream.ReadU( 5 );
bool noClose = bitstream.ReadBool();
uint8 endCapStyle = bitstream.ReadU( 2 );
+ lineStyle.endCapStyle = swfLineStyle_t::capStyle( endCapStyle );
+ lineStyle.startCapStyle = swfLineStyle_t::capStyle( startCapStyle );
+
+ if( noClose )
+ {
+ idLib::Warning( "noClose was set but Ignored." );
+ }
if( joinStyle == 2 )
{
uint16 miterLimitFactor = bitstream.ReadU16();
diff --git a/neo/swf/SWF_ShapeParser.h b/neo/swf/SWF_ShapeParser.h
index 3ce5a00358..6a11d5090a 100644
--- a/neo/swf/SWF_ShapeParser.h
+++ b/neo/swf/SWF_ShapeParser.h
@@ -3,6 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
+Copyright (C) 2023 Harrie van Ginneken
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@@ -89,7 +90,7 @@ class idSWFShapeParser
void TriangulateSoup( idSWFFontGlyph& shape );
int FindEarVert( const swfSPLineLoop_t& loop );
void AddUniqueVert( idSWFShapeDrawFill& drawFill, const idVec2& start, const idVec2& end );
-
+ void MakeCap( swfSPDrawLine_t& spld, idSWFShapeDrawLine& ld , swfSPMorphEdge_t& edge, bool start );
};
#endif // !__SWF_SHAPEPARSER_H__
diff --git a/neo/swf/SWF_SpriteInstance.cpp b/neo/swf/SWF_SpriteInstance.cpp
index 5caaf0fd67..cc2f11e8dc 100644
--- a/neo/swf/SWF_SpriteInstance.cpp
+++ b/neo/swf/SWF_SpriteInstance.cpp
@@ -3,6 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
+Copyright (C) 2023 Harrie van Ginneken
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@@ -45,6 +46,7 @@ idSWFSpriteInstance::idSWFSpriteInstance() :
sprite( NULL ),
parent( NULL ),
depth( 0 ),
+ lastFrame( 0 ),
itemIndex( 0 ),
materialOverride( NULL ),
materialWidth( 0 ),
@@ -54,7 +56,10 @@ idSWFSpriteInstance::idSWFSpriteInstance() :
moveToXScale( 1.0f ),
moveToYScale( 1.0f ),
moveToSpeed( 1.0f ),
- stereoDepth( 0 )
+ stereoDepth( 0 ),
+ actionScript( NULL ),
+ scriptObject( NULL ),
+ constructed( false )
{
}
@@ -71,18 +76,25 @@ void idSWFSpriteInstance::Init( idSWFSprite* _sprite, idSWFSpriteInstance* _pare
frameCount = sprite->frameCount;
- scriptObject = idSWFScriptObject::Alloc();
- scriptObject->SetPrototype( &spriteInstanceScriptObjectPrototype );
+ if( !scriptObject )
+ {
+ scriptObject = idSWFScriptObject::Alloc();
+ scriptObject->SetPrototype( &spriteInstanceScriptObjectPrototype );
+
+ }
scriptObject->SetSprite( this );
firstRun = true;
- actionScript = idSWFScriptFunction_Script::Alloc();
-
- idList scope;
- scope.Append( sprite->swf->globals );
- scope.Append( scriptObject );
- actionScript->SetScope( scope );
+ //this is already set if this is the main timeline
+ if( !actionScript )
+ {
+ actionScript = idSWFScriptFunction_Script::Alloc();
+ idList scope;
+ scope.Append( sprite->swf->globals );
+ scope.Append( scriptObject );
+ actionScript->SetScope( scope );
+ }
actionScript->SetDefaultSprite( this );
for( int i = 0; i < sprite->doInitActions.Num(); i++ )
@@ -122,8 +134,15 @@ void idSWFSpriteInstance::FreeDisplayList()
{
for( int i = 0; i < displayList.Num(); i++ )
{
- sprite->swf->spriteInstanceAllocator.Free( displayList[i].spriteInstance );
- sprite->swf->textInstanceAllocator.Free( displayList[i].textInstance );
+ if( displayList[i].spriteInstance )
+ {
+ sprite->swf->spriteInstanceAllocator.Free( displayList[i].spriteInstance );
+ }
+
+ if( displayList[i].textInstance )
+ {
+ sprite->swf->textInstanceAllocator.Free( displayList[i].textInstance );
+ }
}
displayList.SetNum( 0 ); // not calling Clear() so we don't continuously re-allocate memory
currentFrame = 0;
@@ -182,17 +201,64 @@ swfDisplayEntry_t* idSWFSpriteInstance::AddDisplayEntry( int depth, int characte
idSWFDictionaryEntry* dictEntry = sprite->swf->FindDictionaryEntry( characterID );
if( dictEntry != NULL )
{
+ if( !dictEntry->resolved )
+ {
+ for( auto& symbol : sprite->swf->symbolClasses.symbols )
+ {
+ if( symbol.tag == characterID )
+ {
+ dictEntry->scriptClass = sprite->swf->globals->Get( symbol.name );
+ dictEntry->name = &symbol.name;
+ break;
+ }
+ }
+ dictEntry->resolved = true;//dictEntry->scriptClass != nullptr;
+ }
+
if( dictEntry->type == SWF_DICT_SPRITE )
{
display.spriteInstance = sprite->swf->spriteInstanceAllocator.Alloc();
+ display.spriteInstance->abcFile = this->abcFile;
+ if( dictEntry->scriptClass.IsValid() )
+ {
+ display.spriteInstance->scriptObject = idSWFScriptObject::Alloc();
+ auto* super = dictEntry->scriptClass.GetObject();
+
+ auto dcopy = super->Get( *dictEntry->name );
+ if( dcopy.IsObject() )
+ {
+ display.spriteInstance->scriptObject->DeepCopy( dcopy.GetObject() );
+ }
+
+ display.spriteInstance->scriptObject->SetPrototype( super );
+ }
+
display.spriteInstance->Init( dictEntry->sprite, this, depth );
display.spriteInstance->RunTo( 1 );
}
else if( dictEntry->type == SWF_DICT_EDITTEXT )
{
display.textInstance = sprite->swf->textInstanceAllocator.Alloc();
+
+ if( dictEntry->scriptClass.IsValid() )
+ {
+ auto* super = dictEntry->scriptClass.GetObject();
+ auto dcopy = super->Get( *dictEntry->name );
+ if( dcopy.IsObject() )
+ {
+ display.textInstance->scriptObject.DeepCopy( dcopy.GetObject() );
+ }
+
+ display.textInstance->scriptObject.SetPrototype( super );
+ }
+
display.textInstance->Init( dictEntry->edittext, sprite->GetSWF() );
}
+ else if( dictEntry->type == SWF_DICT_TEXT )
+ {
+ //display.textInstance = sprite->swf->textInstanceAllocator.Alloc();
+ //display.textInstance->Init( dictEntry->text, sprite->GetSWF() );
+ }
}
return &display;
}
@@ -207,8 +273,14 @@ void idSWFSpriteInstance::RemoveDisplayEntry( int depth )
swfDisplayEntry_t* entry = FindDisplayEntry( depth );
if( entry != NULL )
{
- sprite->swf->spriteInstanceAllocator.Free( entry->spriteInstance );
- sprite->swf->textInstanceAllocator.Free( entry->textInstance );
+ if( entry->spriteInstance )
+ {
+ sprite->swf->spriteInstanceAllocator.Free( entry->spriteInstance );
+ }
+ if( entry->textInstance )
+ {
+ sprite->swf->textInstanceAllocator.Free( entry->textInstance );
+ }
displayList.RemoveIndex( displayList.IndexOf( entry ) );
}
}
@@ -312,14 +384,73 @@ bool idSWFSpriteInstance::RunActions()
if( !isVisible )
{
actions.SetNum( 0 );
+ functionActions.SetNum( 0 );
return false;
}
- if( firstRun && scriptObject->HasProperty( "onLoad" ) )
+ if( !constructed )
+ {
+ if( scriptObject->HasProperty( "__constructor__" ) )
+ {
+ //common->DPrintf( "Calling constructor for %s%\n", name.c_str() );
+ idSWFScriptVar instanceInit = scriptObject->Get( "__constructor__" );
+ idSWFScriptFunction_Script* constructor = ( idSWFScriptFunction_Script* )instanceInit.GetFunction();
+ if( !actionScript->GetScope()->Num() )
+ {
+ actionScript->GetScope()->Alloc() = sprite->swf->globals;
+ }
+ actionScript->SetData( constructor->GetMethodInfo() );
+ actionScript->SetAbcFile( abcFile );
+ actionScript->Call( scriptObject, idSWFParmList() );
+ constructed = true;
+ }
+ }
+
+ if( firstRun && ( scriptObject->HasProperty( "__eventDispatcher__" ) || scriptObject->HasProperty( "onLoad" ) ) )
{
firstRun = false;
idSWFScriptVar onLoad = scriptObject->Get( "onLoad" );
- onLoad.GetFunction()->Call( scriptObject, idSWFParmList() );
+ if( onLoad.IsValid() )
+ {
+ if( !( ( idSWFScriptFunction_Script* )onLoad.GetFunction() )->GetScope()->Num() )
+ {
+ ( ( idSWFScriptFunction_Script* )onLoad.GetFunction() )->GetScope()->Append( sprite->swf->globals );
+ }
+
+ onLoad.GetFunction()->Call( scriptObject, idSWFParmList() );
+ }
+
+ if( scriptObject->HasProperty( "__eventDispatcher__" ) )
+ {
+ idSWFScriptObject* eventDispatcher = scriptObject->Get( "__eventDispatcher__" ).GetObject();
+ idSWFScriptVar var = eventDispatcher->Get( "addedToStage" );
+ if( var.IsFunction() )
+ {
+
+ idSWFScriptObject* eventObj = sprite->swf->globals
+ ->Get( "EventDispatcher" ).GetObject()
+ ->Get( "Event" ).GetObject()
+ ->Get( "[Event]" ).GetObject();
+
+ idSWFScriptVar eventParm;
+ eventParm.SetObject( idSWFScriptObject::Alloc() );
+ eventParm.GetObject()->DeepCopy( eventObj );
+
+ idSWFScriptVar eventArg;
+ eventArg.SetObject( idSWFScriptObject::Alloc() );
+ eventArg.GetObject()->Set( "Event", eventParm );
+
+ idSWFParmList parms;
+ parms.Append( eventArg );
+
+ idSWFScriptFunction_Script* eventFunc = ( idSWFScriptFunction_Script* )var.GetFunction();
+
+ actionScript->SetData( eventFunc->GetMethodInfo() );
+ actionScript->SetAbcFile( abcFile );
+ actionScript->Call( scriptObject, parms );
+ parms.Clear();
+ }
+ }
}
if( onEnterFrame.IsFunction() )
@@ -334,6 +465,13 @@ bool idSWFSpriteInstance::RunActions()
}
actions.SetNum( 0 );
+ for( int i = 0; i < functionActions.Num(); i++ )
+ {
+ actionScript->SetData( ( ( idSWFScriptFunction_Script* )functionActions[i] )->GetMethodInfo() );
+ actionScript->Call( scriptObject, idSWFParmList() );
+ }
+ functionActions.SetNum( 0 );
+
for( int i = 0; i < displayList.Num(); i++ )
{
if( displayList[i].spriteInstance != NULL )
@@ -341,6 +479,7 @@ bool idSWFSpriteInstance::RunActions()
Prefetch( displayList[i].spriteInstance, 0 );
}
}
+
for( int i = 0; i < displayList.Num(); i++ )
{
if( displayList[i].spriteInstance != NULL )
@@ -434,7 +573,8 @@ void idSWFSpriteInstance::RunTo( int targetFrame )
for( uint32 c = sprite->frameOffsets[ currentFrame ]; c < sprite->frameOffsets[ targetFrame ]; c++ )
{
idSWFSprite::swfSpriteCommand_t& command = sprite->commands[ c ];
- if( command.tag == Tag_DoAction && c < firstActionCommand )
+
+ if( command.tag == Tag_DoAction && c < firstActionCommand )
{
// Skip DoAction up to the firstActionCommand
// This is to properly support skipping to a specific frame
@@ -458,6 +598,22 @@ void idSWFSpriteInstance::RunTo( int targetFrame )
}
}
+ idStr frameId = idStr( "frame" ) + targetFrame ;
+ idSWFScriptObject* obj = scriptObject;
+ if( obj && obj->HasValidProperty( frameId.c_str() ) )
+ {
+ idSWFScriptVar frameFunc = obj->Get( frameId.c_str() );
+ if( frameFunc.IsFunction() )
+ {
+ idSWFScriptFunction* funcPtr = frameFunc.GetFunction();
+ if( !( ( idSWFScriptFunction_Script* )funcPtr )->GetScope()->Num() )
+ {
+ ( ( idSWFScriptFunction_Script* )funcPtr )->SetScope( *actionScript->GetScope() );
+ }
+ DoAction( funcPtr );
+ }
+ }
+
currentFrame = targetFrame;
}
@@ -475,6 +631,11 @@ void idSWFSpriteInstance::DoAction( idSWFBitStream& bitstream )
#endif
}
+void idSWFSpriteInstance::DoAction( idSWFScriptFunction* function )
+{
+ functionActions.Alloc() = function;
+}
+
/*
========================
idSWFSpriteInstance::FindChildSprite
@@ -1026,6 +1187,7 @@ idSWFScriptObject_SpriteInstancePrototype
idSWFScriptObject_SpriteInstancePrototype::idSWFScriptObject_SpriteInstancePrototype()
{
+ SWF_SPRITE_FUNCTION_SET( addFrameScript );
SWF_SPRITE_FUNCTION_SET( duplicateMovieClip );
SWF_SPRITE_FUNCTION_SET( gotoAndPlay );
SWF_SPRITE_FUNCTION_SET( gotoAndStop );
@@ -1046,6 +1208,7 @@ idSWFScriptObject_SpriteInstancePrototype::idSWFScriptObject_SpriteInstanceProto
SWF_SPRITE_NATIVE_VAR_SET( _height );
SWF_SPRITE_NATIVE_VAR_SET( _rotation );
SWF_SPRITE_NATIVE_VAR_SET( _name );
+ SWF_SPRITE_NATIVE_VAR_SET( name );
SWF_SPRITE_NATIVE_VAR_SET( _currentframe );
SWF_SPRITE_NATIVE_VAR_SET( _totalframes );
SWF_SPRITE_NATIVE_VAR_SET( _target );
@@ -1111,6 +1274,15 @@ SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _height )
}
SWF_SPRITE_NATIVE_VAR_DEFINE_SET( _height ) { }
+
+SWF_SPRITE_FUNCTION_DEFINE( addFrameScript )
+{
+ SWF_SPRITE_PTHIS_FUNC( "addFrameScript" );
+ // Frame/timeline actionScript code is added implicitly
+ return idSWFScriptVar();
+}
+
+
SWF_SPRITE_FUNCTION_DEFINE( duplicateMovieClip )
{
SWF_SPRITE_PTHIS_FUNC( "duplicateMovieClip" );
@@ -1157,8 +1329,9 @@ SWF_SPRITE_FUNCTION_DEFINE( gotoAndPlay )
if( parms.Num() > 0 )
{
+ uint32 targetFrame = pThis->FindFrame( parms[0].ToString() );
pThis->actions.Clear();
- pThis->RunTo( pThis->FindFrame( parms[0].ToString() ) );
+ pThis->RunTo( targetFrame );
pThis->Play();
}
else
@@ -1499,6 +1672,14 @@ SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _name )
return pThis->name.c_str();
}
+// HarrievG: I'm not sure how much of the 'legacy' underscore prefixed functions need to be changed for as3.0.
+//if more is needed, we should change the macro to work for both legacy AS and 3.0
+SWF_SPRITE_NATIVE_VAR_DEFINE_GET( name )
+{
+ SWF_SPRITE_PTHIS_GET( "name" );
+ return pThis->name.c_str();
+}
+
SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _currentframe )
{
SWF_SPRITE_PTHIS_GET( "_currentframe" );
diff --git a/neo/swf/SWF_SpriteInstance.h b/neo/swf/SWF_SpriteInstance.h
index 1fbb3098f9..123c04d614 100644
--- a/neo/swf/SWF_SpriteInstance.h
+++ b/neo/swf/SWF_SpriteInstance.h
@@ -3,6 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
+Copyright (C) 2023 Harrie van Ginneken
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@@ -147,9 +148,11 @@ class idSWFSpriteInstance
bool childrenRunning;
bool firstRun;
+ bool constructed;
// currentFrame is the frame number currently in the displayList
// we use 1 based frame numbers because currentFrame = 0 means nothing is in the display list
// it's also convenient because Flash also uses 1 based frame numbers
+ uint16 lastFrame;
uint16 currentFrame;
uint16 frameCount;
@@ -184,6 +187,7 @@ class idSWFSpriteInstance
idList< swfDisplayEntry_t, TAG_SWF > displayList;
swfDisplayEntry_t* FindDisplayEntry( int depth );
+ SWF_AbcFile* abcFile;
// name of this sprite instance
idStr name;
@@ -193,6 +197,7 @@ class idSWFSpriteInstance
uint32 dataLength;
};
idList< swfAction_t, TAG_SWF > actions;
+ idList< idSWFScriptFunction*, TAG_SWF > functionActions;
idSWFScriptFunction_Script* actionScript;
@@ -232,6 +237,7 @@ class idSWFSpriteInstance
void SwapDepths( int depth1, int depth2 );
void DoAction( idSWFBitStream& bitstream );
+ void DoAction( idSWFScriptFunction* function );
idSWFSpriteInstance* FindChildSprite( const char* childName );
idSWFSpriteInstance* ResolveTarget( const char* targetName );
@@ -258,6 +264,7 @@ class idSWFScriptObject_SpriteInstancePrototype : public idSWFScriptObject
idSWFScriptVar Call( idSWFScriptObject * thisObject, const idSWFParmList & parms ); \
} scriptFunction_##x
+ SWF_SPRITE_FUNCTION_DECLARE( addFrameScript );
SWF_SPRITE_FUNCTION_DECLARE( duplicateMovieClip );
SWF_SPRITE_FUNCTION_DECLARE( gotoAndPlay );
SWF_SPRITE_FUNCTION_DECLARE( gotoAndStop );
@@ -279,6 +286,7 @@ class idSWFScriptObject_SpriteInstancePrototype : public idSWFScriptObject
SWF_NATIVE_VAR_DECLARE( _rotation );
SWF_NATIVE_VAR_DECLARE_READONLY( _name );
+ SWF_NATIVE_VAR_DECLARE_READONLY( name );
SWF_NATIVE_VAR_DECLARE_READONLY( _currentframe );
SWF_NATIVE_VAR_DECLARE_READONLY( _totalframes );
SWF_NATIVE_VAR_DECLARE_READONLY( _target );
diff --git a/neo/swf/SWF_Sprites.cpp b/neo/swf/SWF_Sprites.cpp
index 563ad8913a..fca27a3411 100644
--- a/neo/swf/SWF_Sprites.cpp
+++ b/neo/swf/SWF_Sprites.cpp
@@ -129,6 +129,8 @@ void idSWFSprite::Load( idSWFBitStream& bitstream, bool parseDictionary )
HANDLE_SWF_TAG( DefineText );
HANDLE_SWF_TAG( DefineText2 );
HANDLE_SWF_TAG( DefineEditText );
+ HANDLE_SWF_TAG( DoABC );
+ HANDLE_SWF_TAG( SymbolClass );
#undef HANDLE_SWF_TAG
default:
handled = false;
diff --git a/neo/swf/SWF_TextInstance.cpp b/neo/swf/SWF_TextInstance.cpp
index 92fc00dc05..a15794c0ac 100644
--- a/neo/swf/SWF_TextInstance.cpp
+++ b/neo/swf/SWF_TextInstance.cpp
@@ -3,6 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
+Copyright (C) 2023 Harrie van Ginneken
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@@ -68,6 +69,81 @@ idSWFTextInstance::~idSWFTextInstance()
subtitleTimingInfo.Clear();
}
+// HarrievG begin
+void idSWFTextInstance::Init( idSWFText* _text, idSWF* _swf )
+{
+ editText = nullptr;
+ staticText = _text;
+ swf = _swf;
+
+ text = "staticText";//idLocalization::GetString( staticText->textRecords[0]. );
+
+ lengthCalculated = false;
+ //if ( editText )
+ //{
+ // variable = editText->variable;
+ // color = editText->color;
+ //}
+ visible = true;
+
+ selectionStart = -1;
+ selectionEnd = -1;
+
+ scroll = 0;
+ scrollTime = 0;
+ maxscroll = 0;
+ maxLines = 0;
+ linespacing = 0;
+ glyphScale = 1.0f;
+
+ shiftHeld = false;
+ tooltip = false;
+ renderMode = SWF_TEXT_RENDER_NORMAL;
+ generatingText = false;
+ triggerGenerate = false;
+ rndSpotsVisible = 0;
+ textSpotsVisible = 0;
+ startRndTime = 0;
+ charMultiplier = 0;
+ prevReplaceIndex = 0;
+ scrollUpdate = false;
+ ignoreColor = false;
+
+ isSubtitle = false;
+ subLength = 0;
+ subAlign = 0;
+ subUpdating = false;
+ subCharStartIndex = 0;
+ subNextStartIndex = 0;
+ subCharEndIndex = 0;
+ subDisplayTime = 0;
+ subStartTime = -1;
+ subSourceID = -1;
+ subNeedsSwitch = false;
+ subForceKill = false;
+ subKillTimeDelay = 0;
+ subSwitchTime = 0;
+ subLastWordIndex = 0;
+ subPrevLastWordIndex = 0;
+ subInitialLine = true;
+
+ textLength = 0;
+
+ inputTextStartChar = 0;
+
+ renderDelay = swf_textRndLetterDelay.GetInteger();
+ needsSoundUpdate = false;
+ useDropShadow = false;
+ useStroke = false;
+ strokeStrength = 1.0f;
+ strokeWeight = swf_textStrokeSize.GetFloat();
+
+ scriptObject.SetPrototype( &textInstanceScriptObjectPrototype );
+ scriptObject.SetText( this );
+ scriptObject.SetNoAutoDelete( true );
+}
+// HarrievG end
+
/*
========================
idSWFTextInstance::Init
@@ -1028,6 +1104,7 @@ idSWFScriptObject_TextInstancePrototype::idSWFScriptObject_TextInstancePrototype
SWF_TEXT_NATIVE_VAR_SET( text );
SWF_TEXT_NATIVE_VAR_SET( _textLength ); // only works on single lines of text not multiline
+ SWF_TEXT_NATIVE_VAR_SET( length ); // only works on single lines of text not multiline
SWF_TEXT_NATIVE_VAR_SET( autoSize );
SWF_TEXT_NATIVE_VAR_SET( dropShadow );
SWF_TEXT_NATIVE_VAR_SET( _stroke );
@@ -1252,6 +1329,11 @@ SWF_TEXT_NATIVE_VAR_DEFINE_GET( _textLength )
SWF_TEXT_PTHIS_GET( "_textLength" );
return pThis->GetTextLength();
}
+SWF_TEXT_NATIVE_VAR_DEFINE_GET( length )
+{
+ SWF_TEXT_PTHIS_GET( "length" );
+ return pThis->GetTextLength();
+}
SWF_TEXT_NATIVE_VAR_DEFINE_SET( mode )
{
diff --git a/neo/swf/SWF_TextInstance.h b/neo/swf/SWF_TextInstance.h
index 8e61fc32e7..5257431fe9 100644
--- a/neo/swf/SWF_TextInstance.h
+++ b/neo/swf/SWF_TextInstance.h
@@ -3,6 +3,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
+Copyright (C) 2023 Harrie van Ginneken
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@@ -47,7 +48,8 @@ class idSWFTextInstance
idSWFTextInstance();
~idSWFTextInstance();
- void Init( idSWFEditText* editText, idSWF* _swf );
+ void Init( idSWFEditText* _editText, idSWF* _swf );
+ void Init( idSWFText* _text, idSWF* _swf );
idSWFScriptObject* GetScriptObject()
{
@@ -175,12 +177,18 @@ class idSWFTextInstance
lengthCalculated = false;
}
+ const idSWFText* GetText() const
+ {
+ return staticText;
+ }
+
// Removing the private access control statement due to cl 214702
// Apparently MS's C++ compiler supports the newer C++ standard, and GCC supports C++03
// In the new C++ standard, nested members of a friend class have access to private/protected members of the class granting friendship
// In C++03, nested members defined in a friend class do NOT have access to private/protected members of the class granting friendship
idSWFEditText* editText;
+ idSWFText* staticText;
idSWF* swf;
// this text instance's script object
@@ -316,6 +324,7 @@ class idSWFScriptObject_TextInstancePrototype : public idSWFScriptObject
SWF_NATIVE_VAR_DECLARE( subtitleSpeaker );
SWF_NATIVE_VAR_DECLARE_READONLY( _textLength );
+ SWF_NATIVE_VAR_DECLARE_READONLY( length );
SWF_TEXT_FUNCTION_DECLARE( subtitleSourceCheck );
SWF_TEXT_FUNCTION_DECLARE( subtitleStart );
diff --git a/neo/swf/SWF_Types.h b/neo/swf/SWF_Types.h
index 65b8051a12..0485f165e1 100644
--- a/neo/swf/SWF_Types.h
+++ b/neo/swf/SWF_Types.h
@@ -4,6 +4,7 @@
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
Copyright (C) 2013-2015 Robert Beckebans
+Copyright (C) 2023 Harrie van Ginneken
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
@@ -162,6 +163,12 @@ struct swfLineStyle_t
uint16 endWidth;
swfColorRGBA_t startColor;
swfColorRGBA_t endColor;
+
+ // HarrievG begin
+ uint8 startCapStyle;
+ uint8 endCapStyle;
+ enum capStyle { round = 0, none, square };
+ // HarrievG end
};
struct swfGradientRecord_t
{
diff --git a/neo/swf/opcodes.tbl b/neo/swf/opcodes.tbl
new file mode 100644
index 0000000000..ab58bc8402
--- /dev/null
+++ b/neo/swf/opcodes.tbl
@@ -0,0 +1,297 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/*
+ * Includers must define an ABC_OP and ABC_UNUSED_OP macros of the following form:
+ *
+ * #define ABC_OP(opCount, throw, stack, internal, name) ... // defines regular op code
+ * #define ABC_UNUSED_OP(opCount, throw, stack, internal, name) ... // defines unused op code
+ *
+ * Selected arguments can then be used within the macro expansions.
+ * - opCount Number of operands encoded in the instruction. Uses -1 for "invalid", we can avoid that if necessary
+ * - throw 1 if the operation can throw, 0 otherwise
+ * - stack Stack movement not taking into account run-time names or function arguments
+ * - internal 1 if the operation is internal to the VM, 0 otherwise
+ * - name Unquoted name of operation.
+ *
+ * There MUST be exactly 256 entries in this table.
+ * The location of an opcode definition in this table determines its hex value, which is
+ * what must correspond to what is read out of the ABC file.
+ * Entries should never be added or removed from this table. New abc instructions may be added
+ * by updating entries for unused op codes. Unused op codes have a "name" that is a hex value.
+ *
+ */
+//--------------------------------------------------------------------------------------------------------
+#ifndef ABC_OP_F
+# ifdef VMCFG_FLOAT
+# define ABC_OP_F ABC_OP
+# else
+# define ABC_OP_F(o,t,s,i,n) ABC_UNUSED_OP(-1, 0, 0, 0, DISABLED_##n)
+# endif
+# define ABC_OP_F_DEFINED
+#endif
+
+// opCount throw stack internal name hex
+ABC_UNUSED_OP( -1, 0, 0, 0, 0x00) // 0x00
+ABC_OP( 0, 0, 0, 0, bkpt) // 0x01
+ABC_OP( 0, 0, 0, 0, nop) // 0x02
+ABC_OP( 0, 1, -1, 0, throw) // 0x03
+ABC_OP( 1, 1, 0, 0, getsuper) // 0x04
+ABC_OP( 1, 1, -2, 0, setsuper) // 0x05
+ABC_OP( 1, 1, 0, 0, dxns) // 0x06
+ABC_OP( 0, 1, -1, 0, dxnslate) // 0x07
+ABC_OP( 1, 0, 0, 0, kill) // 0x08
+ABC_OP( 0, 0, 0, 0, label) // 0x09
+ABC_OP_F( 0, 1, 0, 0, lf32x4) // 0x0A
+ABC_OP_F( 0, 1, -2, 0, sf32x4) // 0x0B
+ABC_OP( 1, 1, -2, 0, ifnlt) // 0x0C
+ABC_OP( 1, 1, -2, 0, ifnle) // 0x0D
+ABC_OP( 1, 1, -2, 0, ifngt) // 0x0E
+ABC_OP( 1, 1, -2, 0, ifnge) // 0x0F
+ABC_OP( 1, 0, 0, 0, jump) // 0x10
+ABC_OP( 1, 0, -1, 0, iftrue) // 0x11
+ABC_OP( 1, 0, -1, 0, iffalse) // 0x12
+ABC_OP( 1, 1, -2, 0, ifeq) // 0x13
+ABC_OP( 1, 1, -2, 0, ifne) // 0x14
+ABC_OP( 1, 1, -2, 0, iflt) // 0x15
+ABC_OP( 1, 1, -2, 0, ifle) // 0x16
+ABC_OP( 1, 1, -2, 0, ifgt) // 0x17
+ABC_OP( 1, 1, -2, 0, ifge) // 0x18
+ABC_OP( 1, 0, -2, 0, ifstricteq) // 0x19
+ABC_OP( 1, 0, -2, 0, ifstrictne) // 0x1A
+ABC_OP( 2, 0, -1, 0, lookupswitch) // 0x1B
+ABC_OP( 0, 1, -1, 0, pushwith) // 0x1C
+ABC_OP( 0, 0, 0, 0, popscope) // 0x1D
+ABC_OP( 0, 1, -1, 0, nextname) // 0x1E
+ABC_OP( 0, 1, -1, 0, hasnext) // 0x1F
+ABC_OP( 0, 0, 1, 0, pushnull) // 0x20
+ABC_OP( 0, 0, 1, 0, pushundefined) // 0x21
+ABC_OP_F( 1, 0, 1, 0, pushfloat) // 0x22
+ABC_OP( 0, 1, -1, 0, nextvalue) // 0x23
+ABC_OP( 1, 0, 1, 0, pushbyte) // 0x24
+ABC_OP( 1, 0, 1, 0, pushshort) // 0x25
+ABC_OP( 0, 0, 1, 0, pushtrue) // 0x26
+ABC_OP( 0, 0, 1, 0, pushfalse) // 0x27
+ABC_OP( 0, 0, 1, 0, pushnan) // 0x28
+ABC_OP( 0, 0, -1, 0, pop) // 0x29
+ABC_OP( 0, 0, 1, 0, dup) // 0x2A
+ABC_OP( 0, 0, 0, 0, swap) // 0x2B
+ABC_OP( 1, 0, 1, 0, pushstring) // 0x2C
+ABC_OP( 1, 0, 1, 0, pushint) // 0x2D
+ABC_OP( 1, 0, 1, 0, pushuint) // 0x2E
+ABC_OP( 1, 0, 1, 0, pushdouble) // 0x2F
+ABC_OP( 0, 1, -1, 0, pushscope) // 0x30
+ABC_OP( 1, 0, 1, 0, pushnamespace) // 0x31
+ABC_OP( 2, 1, 1, 0, hasnext2) // 0x32
+ABC_OP( -1, 1, 0, 1, lix8) // 0x33
+ABC_OP( -1, 1, 0, 1, lix16) // 0x34
+ABC_OP( 0, 1, 0, 0, li8) // 0x35
+ABC_OP( 0, 1, 0, 0, li16) // 0x36
+ABC_OP( 0, 1, 0, 0, li32) // 0x37
+ABC_OP( 0, 1, 0, 0, lf32) // 0x38
+ABC_OP( 0, 1, 0, 0, lf64) // 0x39
+ABC_OP( 0, 1, -2, 0, si8) // 0x3A
+ABC_OP( 0, 1, -2, 0, si16) // 0x3B
+ABC_OP( 0, 1, -2, 0, si32) // 0x3C
+ABC_OP( 0, 1, -2, 0, sf32) // 0x3D
+ABC_OP( 0, 1, -2, 0, sf64) // 0x3E
+ABC_UNUSED_OP( -1, 0, 0, 0, 0x3F) // 0x3F
+ABC_OP( 1, 1, 1, 0, newfunction) // 0x40
+ABC_OP( 1, 1, -1, 0, call) // 0x41
+ABC_OP( 1, 1, 0, 0, construct) // 0x42
+ABC_OP( 2, 1, 0, 0, callmethod) // 0x43
+ABC_OP( 2, 1, 0, 0, callstatic) // 0x44
+ABC_OP( 2, 1, 0, 0, callsuper) // 0x45
+ABC_OP( 2, 1, 0, 0, callproperty) // 0x46
+ABC_OP( 0, 0, 0, 0, returnvoid) // 0x47
+ABC_OP( 0, 1, -1, 0, returnvalue) // 0x48
+ABC_OP( 1, 1, -1, 0, constructsuper) // 0x49
+ABC_OP( 2, 1, 0, 0, constructprop) // 0x4A
+ABC_OP( -1, 1, 0, 1, callsuperid) // 0x4B
+ABC_OP( 2, 1, 0, 0, callproplex) // 0x4C
+ABC_OP( -1, 1, 0, 1, callinterface) // 0x4D
+ABC_OP( 2, 1, -1, 0, callsupervoid) // 0x4E
+ABC_OP( 2, 1, -1, 0, callpropvoid) // 0x4F
+ABC_OP( 0, 1, 0, 0, sxi1) // 0x50
+ABC_OP( 0, 1, 0, 0, sxi8) // 0x51
+ABC_OP( 0, 1, 0, 0, sxi16) // 0x52
+ABC_OP( 1, 1, 0, 0, applytype) // 0x53
+ABC_OP_F( 1, 0, 1, 0, pushfloat4) // 0x54
+ABC_OP( 1, 1, 1, 0, newobject) // 0x55
+ABC_OP( 1, 1, 1, 0, newarray) // 0x56
+ABC_OP( 0, 1, 1, 0, newactivation) // 0x57
+ABC_OP( 1, 1, 0, 0, newclass) // 0x58
+ABC_OP( 1, 1, 0, 0, getdescendants) // 0x59
+ABC_OP( 1, 1, 1, 0, newcatch) // 0x5A
+ABC_OP( -1, 1, 0, 1, findpropglobalstrict) // 0x5B
+ABC_OP( -1, 1, 0, 1, findpropglobal) // 0x5C
+ABC_OP( 1, 1, 1, 0, findpropstrict) // 0x5D
+ABC_OP( 1, 1, 1, 0, findproperty) // 0x5E
+ABC_OP( 1, 1, 1, 0, finddef) // 0x5F
+ABC_OP( 1, 1, 1, 0, getlex) // 0x60
+ABC_OP( 1, 1, -2, 0, setproperty) // 0x61
+ABC_OP( 1, 0, 1, 0, getlocal) // 0x62
+ABC_OP( 1, 0, -1, 0, setlocal) // 0x63
+ABC_OP( 0, 0, 1, 0, getglobalscope) // 0x64
+ABC_OP( 1, 0, 1, 0, getscopeobject) // 0x65
+ABC_OP( 1, 1, 0, 0, getproperty) // 0x66
+ABC_OP( 1, 0, 1, 0, getouterscope) // 0x67
+ABC_OP( 1, 1, -2, 0, initproperty) // 0x68
+ABC_UNUSED_OP( -1, 0, 0, 0, 0x69) // 0x69
+ABC_OP( 1, 1, 0, 0, deleteproperty) // 0x6A
+ABC_UNUSED_OP( -1, 0, 0, 0, 0x6B) // 0x6B
+ABC_OP( 1, 1, 0, 0, getslot) // 0x6C
+ABC_OP( 1, 1, -2, 0, setslot) // 0x6D
+ABC_OP( 1, 0, 1, 0, getglobalslot) // 0x6E
+ABC_OP( 1, 1, -1, 0, setglobalslot) // 0x6F
+ABC_OP( 0, 1, 0, 0, convert_s) // 0x70
+ABC_OP( 0, 1, 0, 0, esc_xelem) // 0x71
+ABC_OP( 0, 1, 0, 0, esc_xattr) // 0x72
+ABC_OP( 0, 1, 0, 0, convert_i) // 0x73
+ABC_OP( 0, 1, 0, 0, convert_u) // 0x74
+ABC_OP( 0, 1, 0, 0, convert_d) // 0x75
+ABC_OP( 0, 1, 0, 0, convert_b) // 0x76
+ABC_OP( 0, 1, 0, 0, convert_o) // 0x77
+ABC_OP( 0, 1, 0, 0, checkfilter) // 0x78
+ABC_OP_F( 0, 1, 0, 0, convert_f) // 0x79
+ABC_OP_F( 0, 1, 0, 0, unplus) // 0x7A
+ABC_OP_F( 0, 1, 0, 0, convert_f4) // 0x7B
+ABC_UNUSED_OP( -1, 0, 0, 0, 0x7C) // 0x7C
+ABC_UNUSED_OP( -1, 0, 0, 0, 0x7D) // 0x7D
+ABC_UNUSED_OP( -1, 0, 0, 0, 0x7E) // 0x7E
+ABC_UNUSED_OP( -1, 0, 0, 0, 0x7F) // 0x7F
+ABC_OP( 1, 1, 0, 0, coerce) // 0x80
+ABC_OP( 0, 1, 0, 0, coerce_b) // 0x81
+ABC_OP( 0, 1, 0, 0, coerce_a) // 0x82
+ABC_OP( 0, 1, 0, 0, coerce_i) // 0x83
+ABC_OP( 0, 1, 0, 0, coerce_d) // 0x84
+ABC_OP( 0, 1, 0, 0, coerce_s) // 0x85
+ABC_OP( 1, 1, 0, 0, astype) // 0x86
+ABC_OP( 0, 1, -1, 0, astypelate) // 0x87
+ABC_OP( 0, 1, 0, 0, coerce_u) // 0x88
+ABC_OP( 0, 1, 0, 0, coerce_o) // 0x89
+ABC_UNUSED_OP( -1, 0, 0, 0, 0x8A) // 0x8A
+ABC_UNUSED_OP( -1, 0, 0, 0, 0x8B) // 0x8B
+ABC_UNUSED_OP( -1, 0, 0, 0, 0x8C) // 0x8C
+ABC_UNUSED_OP( -1, 0, 0, 0, 0x8D) // 0x8D
+ABC_UNUSED_OP( -1, 0, 0, 0, 0x8E) // 0x8E
+ABC_UNUSED_OP( -1, 0, 0, 0, 0x8F) // 0x8F
+ABC_OP( 0, 1, 0, 0, negate) // 0x90
+ABC_OP( 0, 1, 0, 0, increment) // 0x91
+ABC_OP( 1, 1, 0, 0, inclocal) // 0x92
+ABC_OP( 0, 1, 0, 0, decrement) // 0x93
+ABC_OP( 1, 1, 0, 0, declocal) // 0x94
+ABC_OP( 0, 0, 0, 0, typeof) // 0x95
+ABC_OP( 0, 0, 0, 0, not) // 0x96
+ABC_OP( 0, 1, 0, 0, bitnot) // 0x97
+ABC_UNUSED_OP( -1, 0, 0, 0, 0x98) // 0x98
+ABC_UNUSED_OP( -1, 0, 0, 0, 0x99) // 0x99
+ABC_UNUSED_OP( -1, 0, 0, 0, 0x9A) // 0x9A
+ABC_UNUSED_OP( -1, 0, 0, 0, 0x9B) // 0x9B
+ABC_UNUSED_OP( -1, 0, 0, 0, 0x9C) // 0x9C
+ABC_UNUSED_OP( -1, 0, 0, 0, 0x9D) // 0x9D
+ABC_UNUSED_OP( -1, 0, 0, 0, 0x9E) // 0x9E
+ABC_UNUSED_OP( -1, 0, 0, 0, 0x9F) // 0x9F
+ABC_OP( 0, 1, -1, 0, add) // 0xA0
+ABC_OP( 0, 1, -1, 0, subtract) // 0xA1
+ABC_OP( 0, 1, -1, 0, multiply) // 0xA2
+ABC_OP( 0, 1, -1, 0, divide) // 0xA3
+ABC_OP( 0, 1, -1, 0, modulo) // 0xA4
+ABC_OP( 0, 1, -1, 0, lshift) // 0xA5
+ABC_OP( 0, 1, -1, 0, rshift) // 0xA6
+ABC_OP( 0, 1, -1, 0, urshift) // 0xA7
+ABC_OP( 0, 1, -1, 0, bitand) // 0xA8
+ABC_OP( 0, 1, -1, 0, bitor) // 0xA9
+ABC_OP( 0, 1, -1, 0, bitxor) // 0xAA
+ABC_OP( 0, 1, -1, 0, equals) // 0xAB
+ABC_OP( 0, 1, -1, 0, strictequals) // 0xAC
+ABC_OP( 0, 1, -1, 0, lessthan) // 0xAD
+ABC_OP( 0, 1, -1, 0, lessequals) // 0xAE
+ABC_OP( 0, 1, -1, 0, greaterthan) // 0xAF
+ABC_OP( 0, 1, -1, 0, greaterequals) // 0xB0
+ABC_OP( 0, 1, -1, 0, instanceof) // 0xB1
+ABC_OP( 1, 1, 0, 0, istype) // 0xB2
+ABC_OP( 0, 1, -1, 0, istypelate) // 0xB3
+ABC_OP( 0, 1, -1, 0, in) // 0xB4
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xB5) // 0xB5
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xB6) // 0xB6
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xB7) // 0xB7
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xB8) // 0xB8
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xB9) // 0xB9
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xBA) // 0xBA
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xBB) // 0xBB
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xBC) // 0xBC
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xBD) // 0xBD
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xBE) // 0xBE
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xBF) // 0xBF
+ABC_OP( 0, 1, 0, 0, increment_i) // 0xC0
+ABC_OP( 0, 1, 0, 0, decrement_i) // 0xC1
+ABC_OP( 1, 1, 0, 0, inclocal_i) // 0xC2
+ABC_OP( 1, 1, 0, 0, declocal_i) // 0xC3
+ABC_OP( 0, 1, 0, 0, negate_i) // 0xC4
+ABC_OP( 0, 1, -1, 0, add_i) // 0xC5
+ABC_OP( 0, 1, -1, 0, subtract_i) // 0xC6
+ABC_OP( 0, 1, -1, 0, multiply_i) // 0xC7
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xC8) // 0xC8
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xC9) // 0xC9
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xCA) // 0xCA
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xCB) // 0xCB
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xCC) // 0xCC
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xCD) // 0xCD
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xCE) // 0xCE
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xCF) // 0xCF
+ABC_OP( 0, 0, 1, 0, getlocal0) // 0xD0
+ABC_OP( 0, 0, 1, 0, getlocal1) // 0xD1
+ABC_OP( 0, 0, 1, 0, getlocal2) // 0xD2
+ABC_OP( 0, 0, 1, 0, getlocal3) // 0xD3
+ABC_OP( 0, 0, -1, 0, setlocal0) // 0xD4
+ABC_OP( 0, 0, -1, 0, setlocal1) // 0xD5
+ABC_OP( 0, 0, -1, 0, setlocal2) // 0xD6
+ABC_OP( 0, 0, -1, 0, setlocal3) // 0xD7
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xD8) // 0xD8
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xD9) // 0xD9
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xDA) // 0xDA
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xDB) // 0xDB
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xDC) // 0xDC
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xDD) // 0xDD
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xDE) // 0xDE
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xDF) // 0xDF
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xE0) // 0xE0
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xE1) // 0xE1
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xE2) // 0xE2
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xE3) // 0xE3
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xE4) // 0xE4
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xE5) // 0xE5
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xE6) // 0xE6
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xE7) // 0xE7
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xE8) // 0xE8
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xE9) // 0xE9
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xEA) // 0xEA
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xEB) // 0xEB
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xEC) // 0xEC
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xED) // 0xED
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xEE) // 0xEE - was OP_abs_jump
+ABC_OP( 4, 1, 0, 0, debug) // 0xEF
+ABC_OP( 1, 1, 0, 0, debugline) // 0xF0
+ABC_OP( 1, 1, 0, 0, debugfile) // 0xF1
+ABC_OP( 1, 0, 0, 0, bkptline) // 0xF2
+ABC_OP( 0, 0, 0, 0, timestamp) // 0xF3
+ABC_OP( -1, 1, 0, 1, restargc) // 0xF4
+ABC_OP( -1, 1, 0, 1, restarg) // 0xF5
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xF6) // 0xF6
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xF7) // 0xF7
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xF8) // 0xF8
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xF9) // 0xF9
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xFA) // 0xFA
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xFB) // 0xFB
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xFC) // 0xFC
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xFD) // 0xFD
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xFE) // 0xFE
+ABC_UNUSED_OP( -1, 0, 0, 0, 0xFF) // 0xFF
+#ifdef ABC_OP_F_DEFINED
+# undef ABC_OP_F
+# undef ABC_OP_F_DEFINED
+#endif
diff --git a/neo/ui/UserInterface.cpp b/neo/ui/UserInterface.cpp
index 8c940fc3ef..9af3846ebe 100644
--- a/neo/ui/UserInterface.cpp
+++ b/neo/ui/UserInterface.cpp
@@ -455,14 +455,26 @@ bool idUserInterfaceLocal::InitFromFile( const char* qpath, bool rebuild, bool c
else
{
desktop->SetFlag( WIN_DESKTOP );
- desktop->name = "Desktop";
- desktop->text = va( "Invalid GUI: %s", qpath );
- desktop->rect = idRectangle( 0.0f, 0.0f, 640.0f, 480.0f );
- desktop->drawRect = desktop->rect;
- desktop->foreColor = idVec4( 1.0f, 1.0f, 1.0f, 1.0f );
- desktop->backColor = idVec4( 0.0f, 0.0f, 0.0f, 1.0f );
+ desktop->swf = new( TAG_OLD_UI )idSWF( qpath, NULL );
+
+ if( !desktop->swf->IsLoaded() )
+ {
+ desktop->name = "Desktop";
+ desktop->text = va( "Invalid GUI: %s", qpath );
+ desktop->rect = idRectangle( 0.0f, 0.0f, 640.0f, 480.0f );
+ desktop->foreColor = idVec4( 1.0f, 1.0f, 1.0f, 1.0f );
+ desktop->backColor = idVec4( 0.0f, 0.0f, 0.0f, 1.0f );
+ common->Warning( "Couldn't load gui: '%s'", source.c_str() );
+ }
+ else
+ {
+ desktop->rect = idRectangle( 0.0f, 0.0f, desktop->swf->GetFrameWidth(), desktop->swf->GetFrameHeight() );
+ desktop->name = desktop->swf->GetName();
+ common->Warning( "loaded SWF gui: '%s'", source.c_str() );
+ }
+
desktop->SetupFromState();
- common->Warning( "Couldn't load gui: '%s'", source.c_str() );
+
}
interactive = desktop->Interactive();
@@ -537,8 +549,9 @@ void idUserInterfaceLocal::DrawCursor()
{
dc->DrawCursor( &cursorX, &cursorY, 32.0f );
}
- else
+ else if( !desktop->swf )
{
+
dc->DrawCursor( &cursorX, &cursorY, 56.0f );
}
}
diff --git a/neo/ui/Window.cpp b/neo/ui/Window.cpp
index 50cf8d49aa..390a7a9cee 100644
--- a/neo/ui/Window.cpp
+++ b/neo/ui/Window.cpp
@@ -149,7 +149,7 @@ void idWindow::CommonInit()
timeLine = -1;
textShadow = 0;
hover = false;
-
+ swf = NULL;
for( int i = 0; i < SCRIPT_COUNT; i++ )
{
scripts[i] = NULL;
@@ -262,6 +262,12 @@ void idWindow::CleanUp()
{
delete scripts[i];
}
+
+ if( swf != NULL )
+ {
+ delete swf;
+ }
+
CommonInit();
}
@@ -799,6 +805,12 @@ const char* idWindow::HandleEvent( const sysEvent_t* event, bool* updateVisuals
{
dc->SetCursor( idDeviceContext::CURSOR_ARROW );
}
+
+ if( swf && swf->IsLoaded() )
+ {
+ swf->HandleEvent( event );
+ }
+
}
if( visible && !noEvents )
@@ -1513,6 +1525,16 @@ void idWindow::Redraw( float x, float y, bool hud )
}
}
+ if( swf != NULL )
+ {
+ if( !swf->IsActive() )
+ {
+ swf->Activate( true );
+ }
+
+ swf->Render( renderSystem, Sys_Milliseconds() );
+ }
+
// Put transforms back to what they were before the children were processed
dc->SetTransformInfo( oldOrg, oldTrans );
@@ -4276,6 +4298,10 @@ idWindow::Interactive
*/
bool idWindow::Interactive()
{
+ if( swf != NULL )
+ {
+ return true;// return swf->isMouseInClientArea;
+ }
if( scripts[ ON_ACTION ] )
{
return true;
diff --git a/neo/ui/Window.h b/neo/ui/Window.h
index 67b830d172..3d6231a8e0 100644
--- a/neo/ui/Window.h
+++ b/neo/ui/Window.h
@@ -482,6 +482,8 @@ class idWindow
idRegisterList regList;
idWinBool hideCursor;
+
+ idSWF* swf;
};
ID_INLINE void idWindow::AddDefinedVar( idWinVar* var )