DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

SWF_SpriteInstance.cpp (40392B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 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.
     23 
     24 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.
     25 
     26 ===========================================================================
     27 */
     28 #pragma hdrstop
     29 #include "../idlib/precompiled.h"
     30 
     31 idSWFScriptObject_SpriteInstancePrototype spriteInstanceScriptObjectPrototype;
     32 
     33 /*
     34 ========================
     35 idSWFSpriteInstance::idSWFSpriteInstance
     36 ========================
     37 */
     38 idSWFSpriteInstance::idSWFSpriteInstance() :
     39 sprite( NULL ),
     40 parent( NULL ),
     41 depth( 0 ),
     42 isPlaying( true ),
     43 isVisible( true ),
     44 childrenRunning( true ),
     45 currentFrame( 0 ),
     46 itemIndex( 0 ),
     47 materialOverride( NULL ),
     48 materialWidth( 0 ),
     49 materialHeight( 0 ),
     50 xOffset( 0.0f ),
     51 yOffset( 0.0f ),
     52 moveToXScale( 1.0f ),
     53 moveToYScale( 1.0f ), 
     54 moveToSpeed( 1.0f ),
     55 firstRun( false ),
     56 stereoDepth( 0 )
     57 {
     58 }
     59 
     60 /*
     61 ========================
     62 idSWFSpriteInstance::Init
     63 ========================
     64 */
     65 void idSWFSpriteInstance::Init( idSWFSprite * _sprite, idSWFSpriteInstance * _parent, int _depth )  {
     66 	sprite = _sprite;
     67 	parent = _parent;
     68 	depth = _depth;
     69 
     70 	frameCount = sprite->frameCount;
     71 
     72 	scriptObject = idSWFScriptObject::Alloc();
     73 	scriptObject->SetPrototype( &spriteInstanceScriptObjectPrototype );
     74 	scriptObject->SetSprite( this );
     75 
     76 	firstRun = true;
     77 
     78 	actionScript = idSWFScriptFunction_Script::Alloc();
     79 
     80 	idList<idSWFScriptObject *, TAG_SWF> scope;
     81 	scope.Append( sprite->swf->globals );
     82 	scope.Append( scriptObject );
     83 	actionScript->SetScope( scope );
     84 	actionScript->SetDefaultSprite( this );
     85 
     86 	for	(int i = 0; i < sprite->doInitActions.Num(); i++) {
     87 		actionScript->SetData( sprite->doInitActions[i].Ptr(), sprite->doInitActions[i].Length() );
     88 		actionScript->Call( scriptObject, idSWFParmList() );
     89 	}
     90 
     91 	Play();
     92 }
     93 
     94 /*
     95 ========================
     96 idSWFSpriteInstance::~idSWFSpriteInstance
     97 ========================
     98 */
     99 idSWFSpriteInstance::~idSWFSpriteInstance() {
    100 	if ( parent != NULL ) {
    101 		parent->scriptObject->Set( name, idSWFScriptVar() );
    102 	}
    103 	FreeDisplayList();
    104 	displayList.Clear();
    105 	scriptObject->SetSprite( NULL );
    106 	scriptObject->Clear();
    107 	scriptObject->Release();
    108 	actionScript->Release();
    109 }
    110 
    111 /*
    112 ========================
    113 idSWFSpriteInstance::FreeDisplayList
    114 ========================
    115 */
    116 void idSWFSpriteInstance::FreeDisplayList() {
    117 	for ( int i = 0; i < displayList.Num(); i++ ) {
    118 		sprite->swf->spriteInstanceAllocator.Free( displayList[i].spriteInstance );
    119 		sprite->swf->textInstanceAllocator.Free( displayList[i].textInstance );
    120 	}
    121 	displayList.SetNum( 0 );	// not calling Clear() so we don't continuously re-allocate memory
    122 	currentFrame = 0;
    123 }
    124 
    125 /*
    126 ========================
    127 idSWFSpriteInstance::FindDisplayEntry
    128 ========================
    129 */
    130 swfDisplayEntry_t * idSWFSpriteInstance::FindDisplayEntry( int depth ) {
    131 	int len = displayList.Num();
    132 	int mid = len;
    133 	int offset = 0;
    134 	while ( mid > 0 ) {
    135 		mid = len >> 1;
    136 		if ( displayList[offset+mid].depth <= depth ) {
    137 			offset += mid;
    138 		}
    139 		len -= mid;
    140 	}
    141 	if ( displayList[offset].depth == depth ) {
    142 		return &displayList[offset];
    143 	}
    144 	return NULL;
    145 }
    146 
    147 /*
    148 ========================
    149 idSWFSpriteInstance::AddDisplayEntry
    150 ========================
    151 */
    152 swfDisplayEntry_t * idSWFSpriteInstance::AddDisplayEntry( int depth, int characterID ) {
    153 	int i = 0;
    154 	for ( ; i < displayList.Num(); i++ ) {
    155 		if ( displayList[i].depth == depth ) {
    156 			return NULL;
    157 		}
    158 		if ( displayList[i].depth > depth ) {
    159 			break;
    160 		}
    161 	}
    162 
    163 	swfDisplayEntry_t & display = displayList[ displayList.Insert( swfDisplayEntry_t(), i ) ];
    164 	display.depth = depth;
    165 	display.characterID = characterID;
    166 
    167 	idSWFDictionaryEntry * dictEntry = sprite->swf->FindDictionaryEntry( characterID );
    168 	if ( dictEntry != NULL ) {
    169 		if ( dictEntry->type == SWF_DICT_SPRITE ) {
    170 			display.spriteInstance = sprite->swf->spriteInstanceAllocator.Alloc();
    171 			display.spriteInstance->Init( dictEntry->sprite, this, depth );
    172 			display.spriteInstance->RunTo( 1 );
    173 		} else if ( dictEntry->type == SWF_DICT_EDITTEXT ) {
    174 			display.textInstance = sprite->swf->textInstanceAllocator.Alloc();
    175 			display.textInstance->Init( dictEntry->edittext, sprite->GetSWF() );
    176 		}
    177 	}
    178 	return &display;
    179 }
    180 
    181 /*
    182 ========================
    183 idSWFSpriteInstance::RemoveDisplayEntry
    184 ========================
    185 */
    186 void idSWFSpriteInstance::RemoveDisplayEntry( int depth ) {
    187 	swfDisplayEntry_t * entry = FindDisplayEntry( depth );
    188 	if ( entry != NULL ) {
    189 		sprite->swf->spriteInstanceAllocator.Free( entry->spriteInstance );
    190 		sprite->swf->textInstanceAllocator.Free( entry->textInstance );
    191 		displayList.RemoveIndex( displayList.IndexOf( entry ) );
    192 	}
    193 }
    194 
    195 /*
    196 ================================================
    197 idSort_SpriteDepth 
    198 ================================================
    199 */
    200 class idSort_SpriteDepth : public idSort_Quick< swfDisplayEntry_t, idSort_SpriteDepth > {
    201 public:
    202 	int Compare( const swfDisplayEntry_t & a, const swfDisplayEntry_t & b ) const { return a.depth - b.depth; }
    203 };
    204 
    205 /*
    206 ========================
    207 idSWFSpriteInstance::SwapDepths
    208 ========================
    209 */
    210 void idSWFSpriteInstance::SwapDepths( int depth1, int depth2 ) {
    211 	for ( int i = 0; i < displayList.Num(); i++ ) {
    212 		if ( displayList[i].depth == depth1 ) {
    213 			displayList[i].depth = depth2;
    214 
    215 		} else if ( displayList[i].depth == depth2 ) {
    216 			displayList[i].depth = depth1;
    217 		}
    218 		if ( displayList[i].spriteInstance != NULL ) {
    219 			displayList[i].spriteInstance->depth = displayList[i].depth;
    220 		}
    221 	}
    222 
    223 	displayList.SortWithTemplate( idSort_SpriteDepth() );
    224 }
    225 
    226 /*
    227 ===================
    228 idSWFSpriteInstance::Run
    229 ===================
    230 */
    231 bool idSWFSpriteInstance::Run() {
    232 	if ( !isVisible ) {
    233 		return false;
    234 	}
    235 
    236 	if ( childrenRunning ) {
    237 		childrenRunning = false;
    238 		for ( int i = 0; i < displayList.Num(); i++ ) {
    239 			if ( displayList[i].spriteInstance != NULL ) {
    240 				Prefetch( displayList[i].spriteInstance, 0 );
    241 			}
    242 		}
    243 		for ( int i = 0; i < displayList.Num(); i++ ) {
    244 			if ( displayList[i].spriteInstance != NULL ) {
    245 				childrenRunning |= displayList[i].spriteInstance->Run();
    246 			}
    247 		}
    248 	}
    249 	if ( isPlaying ) {
    250 		if ( currentFrame == frameCount ) {
    251 			if ( frameCount > 1 ) {
    252 				FreeDisplayList();
    253 				RunTo( 1 );
    254 			}
    255 		} else {
    256 			RunTo( currentFrame + 1 );
    257 		}
    258 	}
    259 	return childrenRunning || isPlaying;
    260 }
    261 
    262 /*
    263 ===================
    264 idSWFSpriteInstance::RunActions
    265 ===================
    266 */
    267 bool idSWFSpriteInstance::RunActions() {
    268 	if ( !isVisible ) {
    269 		actions.SetNum( 0 );
    270 		return false;
    271 	}
    272 
    273 	if ( firstRun && scriptObject->HasProperty( "onLoad" ) ) {
    274 		firstRun = false;
    275 		idSWFScriptVar onLoad = scriptObject->Get( "onLoad" );
    276 		onLoad.GetFunction()->Call( scriptObject, idSWFParmList() );
    277 	}
    278 
    279 	if ( onEnterFrame.IsFunction() ) {
    280 		onEnterFrame.GetFunction()->Call( scriptObject, idSWFParmList() );
    281 	}
    282 
    283 	for ( int i = 0; i < actions.Num(); i++ ) {
    284 		actionScript->SetData( actions[i].data, actions[i].dataLength );
    285 		actionScript->Call( scriptObject, idSWFParmList() );
    286 	}
    287 	actions.SetNum( 0 );
    288 
    289 	for ( int i = 0; i < displayList.Num(); i++ ) {
    290 		if ( displayList[i].spriteInstance != NULL ) {
    291 			Prefetch( displayList[i].spriteInstance, 0 );
    292 		}
    293 	}
    294 	for ( int i = 0; i < displayList.Num(); i++ ) {
    295 		if ( displayList[i].spriteInstance != NULL ) {
    296 			displayList[i].spriteInstance->RunActions();
    297 		}
    298 	}
    299 
    300 	return true;
    301 }
    302 
    303 /*
    304 ===================
    305 idSWFSpriteInstance::NextFrame
    306 ===================
    307 */
    308 void idSWFSpriteInstance::NextFrame() {
    309 	if ( currentFrame < frameCount ) {
    310 		RunTo( currentFrame + 1 );
    311 	}
    312 }
    313 
    314 /*
    315 ===================
    316 idSWFSpriteInstance::PrevFrame
    317 ===================
    318 */
    319 void idSWFSpriteInstance::PrevFrame() {
    320 	if ( currentFrame > 1 ) {
    321 		RunTo( currentFrame - 1 );
    322 	}
    323 }
    324 
    325 /*
    326 ===================
    327 idSWFSpriteInstance::Play
    328 ===================
    329 */
    330 void idSWFSpriteInstance::Play() {
    331 	for ( idSWFSpriteInstance * p = parent; p != NULL; p = p->parent ) {
    332 		p->childrenRunning = true;
    333 	}
    334 	isPlaying = true;
    335 }
    336 
    337 /*
    338 ===================
    339 idSWFSpriteInstance::Stop
    340 ===================
    341 */
    342 void idSWFSpriteInstance::Stop() {
    343 	isPlaying = false;
    344 }
    345 
    346 /*
    347 ===================
    348 idSWFSpriteInstance::RunTo
    349 ===================
    350 */
    351 void idSWFSpriteInstance::RunTo( int targetFrame ) {
    352 	if ( targetFrame == currentFrame ) {
    353 		return; // otherwise we'll re-run the current frame
    354 	}
    355 	if ( targetFrame < currentFrame ) {
    356 		FreeDisplayList();
    357 	}
    358 	if ( targetFrame < 1 ) {
    359 		return;
    360 	}
    361 
    362 	if ( targetFrame > sprite->frameOffsets.Num() - 1 ) {
    363 		targetFrame = sprite->frameOffsets.Num() - 1;
    364 	}
    365 
    366 	//actions.Clear();
    367 
    368 	uint32 firstActionCommand = sprite->frameOffsets[ targetFrame - 1 ];
    369 
    370 	for ( uint32 c = sprite->frameOffsets[ currentFrame ]; c < sprite->frameOffsets[ targetFrame ]; c++ ) {
    371 		idSWFSprite::swfSpriteCommand_t & command = sprite->commands[ c ];
    372 		if ( command.tag == Tag_DoAction && c < firstActionCommand ) {
    373 			// Skip DoAction up to the firstActionCommand
    374 			// This is to properly support skipping to a specific frame
    375 			// for example if we're on frame 3 and skipping to frame 10, we want
    376 			// to run all the commands PlaceObject commands for frames 4-10 but
    377 			// only the DoAction commands for frame 10
    378 			continue;
    379 		}
    380 		command.stream.Rewind();
    381 		switch ( command.tag ) {
    382 #define HANDLE_SWF_TAG( x ) case Tag_##x: x( command.stream ); break;
    383 		HANDLE_SWF_TAG( PlaceObject2 );
    384 		HANDLE_SWF_TAG( PlaceObject3 );
    385 		HANDLE_SWF_TAG( RemoveObject2 );
    386 		HANDLE_SWF_TAG( StartSound );
    387 		HANDLE_SWF_TAG( DoAction );
    388 #undef HANDLE_SWF_TAG
    389 		default:
    390 			idLib::Printf( "Run Sprite: Unhandled tag %s\n", idSWF::GetTagName( command.tag ) );
    391 		}
    392 	}
    393 
    394 	currentFrame = targetFrame;
    395 }
    396 
    397 /*
    398 ========================
    399 idSWFSpriteInstance::DoAction
    400 ========================
    401 */
    402 void idSWFSpriteInstance::DoAction( idSWFBitStream & bitstream ) {
    403 	swfAction_t & action = actions.Alloc();
    404 	action.data = bitstream.ReadData( bitstream.Length() );
    405 	action.dataLength = bitstream.Length();
    406 }
    407 
    408 /*
    409 ========================
    410 idSWFSpriteInstance::FindChildSprite
    411 ========================
    412 */
    413 idSWFSpriteInstance * idSWFSpriteInstance::FindChildSprite( const char * targetName ) {
    414 	for ( int i = 0; i < displayList.Num(); i++ ) {
    415 		if ( displayList[i].spriteInstance != NULL ) {
    416 			if ( displayList[i].spriteInstance->name.Icmp( targetName ) == 0 ) {
    417 				return displayList[i].spriteInstance;
    418 			}
    419 		}
    420 	}
    421 	return NULL;
    422 }
    423 
    424 /*
    425 ========================
    426 idSWFSpriteInstance::ResolveTarget
    427 Gets the sprite instance for names like:
    428 ../foo/bar
    429 /foo/bar
    430 foo/bar
    431 ========================
    432 */
    433 idSWFSpriteInstance * idSWFSpriteInstance::ResolveTarget( const char * targetName ) {
    434 	if ( targetName[0] == 0 ) {
    435 		return this;
    436 	}
    437 	idSWFSpriteInstance * target = this;
    438 	const char * c = targetName;
    439 	if ( c[0] == '/' ) {
    440 		while ( target->parent != NULL ) {
    441 			target = target->parent;
    442 		}
    443 		c++;
    444 	}
    445 	idStrList spriteNames;
    446 	spriteNames.Append( c );
    447 	for ( int index = 0, ofs = spriteNames[index].Find( '/' ); ofs != -1; index++, ofs = spriteNames[index].Find( '/' ) ) {
    448 		spriteNames.Append( spriteNames[index].c_str() + ofs + 1 );
    449 		spriteNames[index].CapLength( ofs );
    450 	}
    451 	for ( int i = 0; i < spriteNames.Num(); i++ ) {
    452 		if ( spriteNames[i] == ".." ) {
    453 			target = target->parent;
    454 		} else {
    455 			target = target->FindChildSprite( spriteNames[i] );
    456 		}
    457 		if ( target == NULL ) {
    458 			// Everything is likely to fail after this point
    459 			idLib::Warning( "SWF: Could not resolve %s, %s not found", targetName, spriteNames[i].c_str() );
    460 			return this;
    461 		}
    462 	}
    463 	return target;
    464 }
    465 
    466 /*
    467 ========================
    468 idSWFSpriteInstance::FindFrame
    469 ========================
    470 */
    471 uint32 idSWFSpriteInstance::FindFrame( const char * labelName ) const {
    472 	int frameNum = atoi( labelName );
    473 	if ( frameNum > 0 ) {
    474 		return frameNum;
    475 	}
    476 	for ( int i = 0; i < sprite->frameLabels.Num(); i++ ) {
    477 		if ( sprite->frameLabels[i].frameLabel.Icmp( labelName ) == 0 ) {
    478 			return sprite->frameLabels[i].frameNum;
    479 		}
    480 	}
    481 	idLib::Warning( "Could not find frame '%s' in sprite '%s'", labelName, GetName() );
    482 	return currentFrame;
    483 }
    484 
    485 /*
    486 ========================
    487 idSWFSpriteInstance::FrameExists
    488 ========================
    489 */
    490 bool idSWFSpriteInstance::FrameExists( const char * labelName ) const {
    491 	int frameNum = atoi( labelName );
    492 	if ( frameNum > 0 ) {
    493 		return frameNum <= sprite->frameCount;
    494 	}
    495 
    496 	for ( int i = 0; i < sprite->frameLabels.Num(); i++ ) {
    497 		if ( sprite->frameLabels[i].frameLabel.Icmp( labelName ) == 0 ) {
    498 			return true;
    499 		}
    500 	}
    501 
    502 	return false;
    503 }
    504 
    505 /*
    506 ========================
    507 idSWFSpriteInstance::IsBetweenFrames
    508 Checks if the current frame is between the given inclusive range.
    509 ========================
    510 */
    511 bool idSWFSpriteInstance::IsBetweenFrames( const char * frameLabel1, const char * frameLabel2 ) const {
    512 	return currentFrame >= FindFrame( frameLabel1 ) && currentFrame <= FindFrame( frameLabel2 );
    513 }
    514 
    515 /*
    516 ========================
    517 idSWFSpriteInstance::SetMaterial
    518 ========================
    519 */
    520 void idSWFSpriteInstance::SetMaterial( const idMaterial * material, int width, int height ) {
    521 	materialOverride = material;
    522 
    523 	if ( materialOverride != NULL ) {
    524 		// Converting this to a short should be safe since we don't support images larger than 8k anyway
    525 		if ( materialOverride->GetStage(0) != NULL && materialOverride->GetStage(0)->texture.cinematic != NULL ) {
    526 			materialWidth = 256;
    527 			materialHeight = 256;
    528 		} else {
    529 			assert( materialOverride->GetImageWidth() > 0 && materialOverride->GetImageHeight() > 0 );
    530 			assert( materialOverride->GetImageWidth() <= 8192 && materialOverride->GetImageHeight() <= 8192 );
    531 			materialWidth = (uint16)materialOverride->GetImageWidth();
    532 			materialHeight = (uint16)materialOverride->GetImageHeight();
    533 		}
    534 	} else {
    535 		materialWidth = 0;
    536 		materialHeight = 0;
    537 	}
    538 
    539 	if ( width >= 0 ) {
    540 		materialWidth = (uint16)width;
    541 	}
    542 
    543 	if ( height >= 0 ) {
    544 		materialHeight = (uint16)height;
    545 	}
    546 }
    547 
    548 /*
    549 ========================
    550 idSWFSpriteInstance::SetVisible
    551 ========================
    552 */
    553 void idSWFSpriteInstance::SetVisible( bool visible ) {
    554 	isVisible = visible;
    555 	if ( isVisible ) {
    556 		for ( idSWFSpriteInstance * p = parent; p != NULL; p = p->parent ) {
    557 			p->childrenRunning = true;
    558 		}
    559 	}
    560 }
    561 
    562 /*
    563 ========================
    564 idSWFSpriteInstance::PlayFrame
    565 ========================
    566 */
    567 void idSWFSpriteInstance::PlayFrame( const idSWFParmList & parms ) {
    568 	if ( parms.Num() > 0 ) {
    569 		actions.Clear();
    570 		RunTo( FindFrame( parms[0].ToString() ) );
    571 		Play();
    572 	} else {
    573 		idLib::Warning( "gotoAndPlay: expected 1 paramater" );
    574 	}
    575 }
    576 
    577 /*
    578 ========================
    579 idSWFSpriteInstance::StopFrame
    580 ========================
    581 */
    582 void idSWFSpriteInstance::StopFrame( const idSWFParmList & parms ) {
    583 	if ( parms.Num() > 0 ) {
    584 		if ( parms[0].IsNumeric() && parms[0].ToInteger() < 1 ) {
    585 			RunTo( FindFrame( "1" ) );
    586 		} else {
    587 			RunTo( FindFrame( parms[0].ToString() ) );
    588 		}
    589 		Stop();
    590 	} else {
    591 		idLib::Warning( "gotoAndStop: expected 1 paramater" );
    592 	}
    593 }
    594 
    595 /*
    596 ========================
    597 idSWFSpriteInstance::GetXPos
    598 ========================
    599 */
    600 float idSWFSpriteInstance::GetXPos() const {
    601 	if ( parent == NULL ) {
    602 		return 0.0f;
    603 	}
    604 
    605 	swfDisplayEntry_t * thisDisplayEntry = parent->FindDisplayEntry( depth );
    606 	if ( thisDisplayEntry == NULL || thisDisplayEntry->spriteInstance != this ) {
    607 		idLib::Warning( "GetXPos: Couldn't find our display entry in our parent's display list for depth %d", depth );
    608 		return 0.0f;
    609 	}
    610 
    611 	return thisDisplayEntry->matrix.tx;
    612 }
    613 
    614 /*
    615 ========================
    616 idSWFSpriteInstance::GetYPos
    617 ========================
    618 */
    619 float idSWFSpriteInstance::GetYPos( bool overallPos ) const {
    620 	if ( parent == NULL ) {
    621 		return 0.0f;
    622 	}
    623 
    624 	swfDisplayEntry_t * thisDisplayEntry = parent->FindDisplayEntry( depth );
    625 	if ( thisDisplayEntry == NULL || thisDisplayEntry->spriteInstance != this ) {
    626 		idLib::Warning( "GetYPos: Couldn't find our display entry in our parents display list for depth %d", depth );
    627 		return 0.0f;
    628 	}
    629 
    630 	return thisDisplayEntry->matrix.ty;
    631 }
    632 
    633 /*
    634 ========================
    635 idSWFSpriteInstance::SetXPos
    636 ========================
    637 */
    638 void idSWFSpriteInstance::SetXPos( float xPos ) {
    639 	if ( parent == NULL ) {
    640 		return;
    641 	}
    642 
    643 	swfDisplayEntry_t * thisDisplayEntry = parent->FindDisplayEntry( depth );
    644 	if ( thisDisplayEntry == NULL || thisDisplayEntry->spriteInstance != this ) {
    645 		idLib::Warning( "_y: Couldn't find our display entry in our parents display list" );
    646 		return;
    647 	}
    648 
    649 	thisDisplayEntry->matrix.tx = xPos;
    650 }
    651 
    652 /*
    653 ========================
    654 idSWFSpriteInstance::SetYPos
    655 ========================
    656 */
    657 void idSWFSpriteInstance::SetYPos( float yPos ) {
    658 	if ( parent == NULL ) {
    659 		return;
    660 	}
    661 
    662 	swfDisplayEntry_t * thisDisplayEntry = parent->FindDisplayEntry( depth );
    663 	if ( thisDisplayEntry == NULL || thisDisplayEntry->spriteInstance != this ) {
    664 		idLib::Warning( "_y: Couldn't find our display entry in our parents display list" );
    665 		return;
    666 	}
    667 
    668 	thisDisplayEntry->matrix.ty = yPos;
    669 }
    670 
    671 /*
    672 ========================
    673 idSWFSpriteInstance::SetPos
    674 ========================
    675 */
    676 void idSWFSpriteInstance::SetPos( float xPos, float yPos ) {
    677 	if ( parent == NULL ) {
    678 		return;
    679 	}
    680 
    681 	swfDisplayEntry_t * thisDisplayEntry = parent->FindDisplayEntry( depth );
    682 	if ( thisDisplayEntry == NULL || thisDisplayEntry->spriteInstance != this ) {
    683 		idLib::Warning( "_y: Couldn't find our display entry in our parents display list" );
    684 		return;
    685 	}
    686 
    687 	thisDisplayEntry->matrix.tx = xPos;
    688 	thisDisplayEntry->matrix.ty = yPos;
    689 }
    690 
    691 /*
    692 ========================
    693 idSWFSpriteInstance::SetRotation
    694 ========================
    695 */
    696 void idSWFSpriteInstance::SetRotation( float rot ) {
    697 	if ( parent == NULL ) {
    698 		return;
    699 	}
    700 	swfDisplayEntry_t * thisDisplayEntry = parent->FindDisplayEntry( depth );
    701 	if ( thisDisplayEntry == NULL || thisDisplayEntry->spriteInstance != this ) {
    702 		idLib::Warning( "_rotation: Couldn't find our display entry in our parents display list" );
    703 		return;
    704 	}
    705 
    706 	swfMatrix_t & matrix = thisDisplayEntry->matrix;
    707 	float xscale = matrix.Scale( idVec2( 1.0f, 0.0f ) ).Length(); 
    708 	float yscale = matrix.Scale( idVec2( 0.0f, 1.0f ) ).Length(); 
    709 
    710 	float s, c;
    711 	idMath::SinCos( DEG2RAD( rot ), s, c ); 
    712 	matrix.xx = c * xscale;
    713 	matrix.yx = s * xscale;
    714 	matrix.xy = -s * yscale;
    715 	matrix.yy = c * yscale;
    716 }
    717 
    718 /*
    719 ========================
    720 idSWFSpriteInstance::SetScale
    721 ========================
    722 */
    723 void idSWFSpriteInstance::SetScale( float x, float y ) {
    724 	if ( parent == NULL ) {
    725 		return;
    726 	}
    727 	swfDisplayEntry_t * thisDisplayEntry = parent->FindDisplayEntry( depth );
    728 	if ( thisDisplayEntry == NULL || thisDisplayEntry->spriteInstance != this ) {
    729 		idLib::Warning( "scale: Couldn't find our display entry in our parents display list" );
    730 		return;
    731 	}
    732 
    733 	float newScale = x / 100.0f;
    734 	// this is done funky to maintain the current rotation
    735 	idVec2 currentScale = thisDisplayEntry->matrix.Scale( idVec2( 1.0f, 0.0f ) );
    736 	if ( currentScale.Normalize() == 0.0f ) {
    737 		thisDisplayEntry->matrix.xx = newScale;
    738 		thisDisplayEntry->matrix.yx = 0.0f;
    739 	} else {
    740 		thisDisplayEntry->matrix.xx = currentScale.x * newScale;
    741 		thisDisplayEntry->matrix.yx = currentScale.y * newScale;
    742 	}
    743 	
    744 	newScale = y / 100.0f;
    745 	// this is done funky to maintain the current rotation
    746 	currentScale = thisDisplayEntry->matrix.Scale( idVec2( 0.0f, 1.0f ) );
    747 	if ( currentScale.Normalize() == 0.0f ) {
    748 		thisDisplayEntry->matrix.yy = newScale;
    749 		thisDisplayEntry->matrix.xy = 0.0f;
    750 	} else {
    751 		thisDisplayEntry->matrix.yy = currentScale.y * newScale;
    752 		thisDisplayEntry->matrix.xy = currentScale.x * newScale;
    753 	}
    754 }
    755 
    756 /*
    757 ========================
    758 idSWFSpriteInstance::SetMoveToScale
    759 ========================
    760 */
    761 void idSWFSpriteInstance::SetMoveToScale( float x, float y ) {
    762 	moveToXScale = x;
    763 	moveToYScale = y;
    764 }
    765 
    766 /*
    767 ========================
    768 idSWFSpriteInstance::SetMoveToScale
    769 ========================
    770 */
    771 bool idSWFSpriteInstance::UpdateMoveToScale( float speed ) {
    772 
    773 	if ( parent == NULL ) {
    774 		return false;
    775 	}
    776 	swfDisplayEntry_t * thisDisplayEntry = parent->FindDisplayEntry( depth );
    777 	if ( thisDisplayEntry == NULL || thisDisplayEntry->spriteInstance != this ) {
    778 		idLib::Warning( "SetMoveToScale: Couldn't find our display entry in our parents display list" );
    779 		return false;
    780 	}
    781 
    782 	swfMatrix_t & matrix = thisDisplayEntry->matrix;
    783 	float xscale = matrix.Scale( idVec2( 1.0f, 0.0f ) ).Length() * 100.0f; 
    784 	float yscale = matrix.Scale( idVec2( 0.0f, 1.0f ) ).Length() * 100.0f;
    785 	
    786 	float toX = xscale;
    787 	if ( moveToXScale >= 0.0f ) {
    788 		toX = moveToXScale * 100.0f;
    789 	}
    790 
    791 	float toY = yscale;
    792 	if ( moveToYScale >= 0.0f ) {
    793 		toY = moveToYScale * 100.0f;
    794 	}
    795 
    796 	int rXTo = idMath::Ftoi( toX + 0.5f );
    797 	int rYTo = idMath::Ftoi( toY + 0.5f );
    798 	int rXScale = idMath::Ftoi( xscale + 0.5f );
    799 	int rYScale = idMath::Ftoi( yscale + 0.5f );
    800 
    801 	if ( rXTo == rXScale && rYTo == rYScale ) {
    802 		return false;
    803 	}
    804 
    805 	float newXScale = xscale;
    806 	float newYScale = yscale;
    807 
    808 	if ( rXTo != rXScale && toX >= 0.0f ) {
    809 		if ( toX < xscale ) {
    810 			newXScale -= speed;
    811 			newXScale = idMath::ClampFloat( toX, 100.0f, newXScale );
    812 		} else if ( toX > xscale ) {
    813 			newXScale += speed;
    814 			newXScale = idMath::ClampFloat( 0.0f, toX, newXScale );
    815 		}
    816 	}
    817 
    818 	if ( rYTo != rYScale && toY >= 0.0f ) {
    819 		if ( toY < yscale ) {
    820 			newYScale -= speed;
    821 			newYScale = idMath::ClampFloat( toY, 100.0f, newYScale );
    822 		} else if ( toY > yscale ) {
    823 			newYScale += speed;
    824 			newYScale = idMath::ClampFloat( 0.0f, toY, newYScale );
    825 		}
    826 	}
    827 
    828 	SetScale( newXScale, newYScale );
    829 	return true;
    830 }
    831 
    832 /*
    833 ========================
    834 idSWFSpriteInstance::SetAlpha
    835 ========================
    836 */
    837 void idSWFSpriteInstance::SetAlpha( float val ) {
    838 	if ( parent == NULL ) {
    839 		return;
    840 	}
    841 
    842 	swfDisplayEntry_t * thisDisplayEntry = parent->FindDisplayEntry( depth );
    843 	if ( thisDisplayEntry == NULL || thisDisplayEntry->spriteInstance != this ) {
    844 		idLib::Warning( "_alpha: Couldn't find our display entry in our parents display list" );
    845 		return;
    846 	}
    847 	thisDisplayEntry->cxf.mul.w = val;
    848 }
    849 
    850 /*
    851 ========================
    852 idSWFScriptObject_SpriteInstancePrototype
    853 ========================
    854 */
    855 #define SWF_SPRITE_FUNCTION_DEFINE( x ) idSWFScriptVar idSWFScriptObject_SpriteInstancePrototype::idSWFScriptFunction_##x::Call( idSWFScriptObject * thisObject, const idSWFParmList & parms )
    856 #define SWF_SPRITE_NATIVE_VAR_DEFINE_GET( x ) idSWFScriptVar idSWFScriptObject_SpriteInstancePrototype::idSWFScriptNativeVar_##x::Get( class idSWFScriptObject * object )
    857 #define SWF_SPRITE_NATIVE_VAR_DEFINE_SET( x ) void  idSWFScriptObject_SpriteInstancePrototype::idSWFScriptNativeVar_##x::Set( class idSWFScriptObject * object, const idSWFScriptVar & value )
    858 
    859 #define SWF_SPRITE_PTHIS_FUNC( x ) idSWFSpriteInstance * pThis = thisObject ? thisObject->GetSprite() : NULL; if ( !verify( pThis != NULL ) ) { idLib::Warning( "SWF: tried to call " x " on NULL sprite" ); return idSWFScriptVar(); }
    860 #define SWF_SPRITE_PTHIS_GET( x ) idSWFSpriteInstance * pThis = object ? object->GetSprite() : NULL; if ( pThis == NULL ) { return idSWFScriptVar(); }
    861 #define SWF_SPRITE_PTHIS_SET( x ) idSWFSpriteInstance * pThis = object ? object->GetSprite() : NULL; if ( pThis == NULL ) { return; }
    862 
    863 #define SWF_SPRITE_FUNCTION_SET( x ) scriptFunction_##x.AddRef(); Set( #x, &scriptFunction_##x );
    864 #define SWF_SPRITE_NATIVE_VAR_SET( x ) SetNative( #x, &swfScriptVar_##x );
    865 
    866 idSWFScriptObject_SpriteInstancePrototype::idSWFScriptObject_SpriteInstancePrototype() {
    867 	SWF_SPRITE_FUNCTION_SET( duplicateMovieClip );
    868 	SWF_SPRITE_FUNCTION_SET( gotoAndPlay );
    869 	SWF_SPRITE_FUNCTION_SET( gotoAndStop );
    870 	SWF_SPRITE_FUNCTION_SET( swapDepths );
    871 	SWF_SPRITE_FUNCTION_SET( nextFrame );
    872 	SWF_SPRITE_FUNCTION_SET( prevFrame );
    873 	SWF_SPRITE_FUNCTION_SET( play );
    874 	SWF_SPRITE_FUNCTION_SET( stop );
    875 
    876 	SWF_SPRITE_NATIVE_VAR_SET( _x );
    877 	SWF_SPRITE_NATIVE_VAR_SET( _y );
    878 	SWF_SPRITE_NATIVE_VAR_SET( _xscale );
    879 	SWF_SPRITE_NATIVE_VAR_SET( _yscale );
    880 	SWF_SPRITE_NATIVE_VAR_SET( _alpha );
    881 	SWF_SPRITE_NATIVE_VAR_SET( _brightness );
    882 	SWF_SPRITE_NATIVE_VAR_SET( _visible );
    883 	SWF_SPRITE_NATIVE_VAR_SET( _width );
    884 	SWF_SPRITE_NATIVE_VAR_SET( _height );
    885 	SWF_SPRITE_NATIVE_VAR_SET( _rotation );
    886 	SWF_SPRITE_NATIVE_VAR_SET( _name );
    887 	SWF_SPRITE_NATIVE_VAR_SET( _currentframe );
    888 	SWF_SPRITE_NATIVE_VAR_SET( _totalframes );
    889 	SWF_SPRITE_NATIVE_VAR_SET( _target );
    890 	SWF_SPRITE_NATIVE_VAR_SET( _framesloaded );
    891 	SWF_SPRITE_NATIVE_VAR_SET( _droptarget );
    892 	SWF_SPRITE_NATIVE_VAR_SET( _url );
    893 	SWF_SPRITE_NATIVE_VAR_SET( _highquality );
    894 	SWF_SPRITE_NATIVE_VAR_SET( _focusrect );
    895 	SWF_SPRITE_NATIVE_VAR_SET( _soundbuftime );
    896 	SWF_SPRITE_NATIVE_VAR_SET( _quality );
    897 	SWF_SPRITE_NATIVE_VAR_SET( _mousex );
    898 	SWF_SPRITE_NATIVE_VAR_SET( _mousey );
    899 
    900 	SWF_SPRITE_NATIVE_VAR_SET( _stereoDepth );
    901 	SWF_SPRITE_NATIVE_VAR_SET( _itemindex );
    902 	SWF_SPRITE_NATIVE_VAR_SET( material );
    903 	SWF_SPRITE_NATIVE_VAR_SET( materialWidth );
    904 	SWF_SPRITE_NATIVE_VAR_SET( materialHeight );
    905 	SWF_SPRITE_NATIVE_VAR_SET( xOffset );
    906 
    907 	SWF_SPRITE_NATIVE_VAR_SET( onEnterFrame );
    908 	//SWF_SPRITE_NATIVE_VAR_SET( onLoad );
    909 }
    910 
    911 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _target ) { return ""; }
    912 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _droptarget ) { return ""; }
    913 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _url ) { return ""; }
    914 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _highquality ) { return 2; }
    915 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _focusrect ) { return true; }
    916 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _soundbuftime ) { return 0; }
    917 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _quality ) { return "BEST"; }
    918 
    919 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _width ) { return 0.0f; }
    920 SWF_SPRITE_NATIVE_VAR_DEFINE_SET( _width ) { }
    921 
    922 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _height ) { return 0.0f; }
    923 SWF_SPRITE_NATIVE_VAR_DEFINE_SET( _height ) { }
    924 
    925 SWF_SPRITE_FUNCTION_DEFINE( duplicateMovieClip ) {
    926 	SWF_SPRITE_PTHIS_FUNC( "duplicateMovieClip" );
    927 
    928 	if ( pThis->parent == NULL ) {
    929 		idLib::Warning( "Tried to duplicate root movie clip" );
    930 		return idSWFScriptVar();
    931 	}
    932 	if ( parms.Num() < 2 ) {
    933 		idLib::Warning( "duplicateMovieClip: expected 2 parameters" );
    934 		return idSWFScriptVar();
    935 	}	
    936 	swfDisplayEntry_t * thisDisplayEntry = pThis->parent->FindDisplayEntry( pThis->depth );
    937 	if ( thisDisplayEntry == NULL || thisDisplayEntry->spriteInstance != pThis ) {
    938 		idLib::Warning( "duplicateMovieClip: Couldn't find our display entry in our parents display list" );
    939 		return idSWFScriptVar();
    940 	}
    941 
    942 	swfMatrix_t matrix = thisDisplayEntry->matrix;
    943 	swfColorXform_t cxf = thisDisplayEntry->cxf;
    944 
    945 	swfDisplayEntry_t * display = pThis->parent->AddDisplayEntry( 16384 + parms[1].ToInteger(), thisDisplayEntry->characterID );
    946 	if ( display == NULL ) {
    947 		return idSWFScriptVar();
    948 	}
    949 	display->matrix = matrix;
    950 	display->cxf = cxf;
    951 
    952 	idStr name = parms[0].ToString();
    953 	pThis->parent->scriptObject->Set( name, display->spriteInstance->scriptObject );
    954 	display->spriteInstance->name = name;
    955 	display->spriteInstance->RunTo( 1 );
    956 
    957 	return display->spriteInstance->scriptObject;
    958 }
    959 
    960 SWF_SPRITE_FUNCTION_DEFINE( gotoAndPlay ) {
    961 	SWF_SPRITE_PTHIS_FUNC( "gotoAndPlay" );
    962 
    963 	if ( parms.Num() > 0 ) {
    964 		pThis->actions.Clear();
    965 		pThis->RunTo( pThis->FindFrame( parms[0].ToString() ) );
    966 		pThis->Play();
    967 	} else {
    968 		idLib::Warning( "gotoAndPlay: expected 1 paramater" );
    969 	}
    970 	return idSWFScriptVar();
    971 }
    972 
    973 SWF_SPRITE_FUNCTION_DEFINE( gotoAndStop ) {
    974 	SWF_SPRITE_PTHIS_FUNC( "gotoAndStop" );
    975 
    976 	if ( parms.Num() > 0 ) {
    977 		// Flash forces frames values less than 1 to 1.
    978 		if ( parms[0].IsNumeric() && parms[0].ToInteger() < 1 ) {
    979 			pThis->RunTo( pThis->FindFrame( "1" ) );
    980 		} else {
    981 			pThis->RunTo( pThis->FindFrame( parms[0].ToString() ) );
    982 		}
    983 		pThis->Stop();
    984 	} else {
    985 		idLib::Warning( "gotoAndStop: expected 1 paramater" );
    986 	}
    987 	return idSWFScriptVar();
    988 }
    989 
    990 SWF_SPRITE_FUNCTION_DEFINE( swapDepths ) {
    991 	SWF_SPRITE_PTHIS_FUNC( "swapDepths" );
    992 
    993 	if ( pThis->parent == NULL ) {
    994 		idLib::Warning( "Tried to swap depths on root movie clip" );
    995 		return idSWFScriptVar();
    996 	}
    997 	if ( parms.Num() < 1 ) {
    998 		idLib::Warning( "swapDepths: expected 1 parameters" );
    999 		return idSWFScriptVar();
   1000 	}
   1001 	pThis->parent->SwapDepths( pThis->depth, parms[0].ToInteger() );
   1002 	return idSWFScriptVar();
   1003 }
   1004 
   1005 SWF_SPRITE_FUNCTION_DEFINE( nextFrame ) {
   1006 	SWF_SPRITE_PTHIS_FUNC( "nextFrame" );
   1007 	pThis->NextFrame();
   1008 	return idSWFScriptVar();
   1009 }
   1010 
   1011 SWF_SPRITE_FUNCTION_DEFINE( prevFrame ) {
   1012 	SWF_SPRITE_PTHIS_FUNC( "prevFrame" );
   1013 	pThis->PrevFrame();
   1014 	return idSWFScriptVar();
   1015 }
   1016 SWF_SPRITE_FUNCTION_DEFINE( play ) {
   1017 	SWF_SPRITE_PTHIS_FUNC( "play" );
   1018 	pThis->Play();
   1019 	return idSWFScriptVar();
   1020 }
   1021 SWF_SPRITE_FUNCTION_DEFINE( stop ) {
   1022 	SWF_SPRITE_PTHIS_FUNC( "stop" );
   1023 	pThis->Stop();
   1024 	return idSWFScriptVar();
   1025 }
   1026 
   1027 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _x ) {
   1028 	SWF_SPRITE_PTHIS_GET( "_x" );
   1029 	return pThis->GetXPos();
   1030 }
   1031 
   1032 SWF_SPRITE_NATIVE_VAR_DEFINE_SET( _x ) {
   1033 	SWF_SPRITE_PTHIS_SET( "_x" );
   1034 	pThis->SetXPos( value.ToFloat() );
   1035 }
   1036 
   1037 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _y ) {
   1038 	SWF_SPRITE_PTHIS_GET( "_y" );
   1039 	return pThis->GetYPos();
   1040 }
   1041 
   1042 SWF_SPRITE_NATIVE_VAR_DEFINE_SET( _y ) {
   1043 	SWF_SPRITE_PTHIS_SET( "_y" );
   1044 	pThis->SetYPos( value.ToFloat() );
   1045 }
   1046 
   1047 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _xscale ) {
   1048 	SWF_SPRITE_PTHIS_GET( "_xscale" );
   1049 	if ( pThis->parent == NULL ) {
   1050 		return 1.0f;
   1051 	}
   1052 	swfDisplayEntry_t * thisDisplayEntry = pThis->parent->FindDisplayEntry( pThis->depth );
   1053 	if ( thisDisplayEntry == NULL || thisDisplayEntry->spriteInstance != pThis ) {
   1054 		idLib::Warning( "_xscale: Couldn't find our display entry in our parents display list" );
   1055 		return 1.0f;
   1056 	}
   1057 	return thisDisplayEntry->matrix.Scale( idVec2( 1.0f, 0.0f ) ).Length() * 100.0f;
   1058 }
   1059 
   1060 SWF_SPRITE_NATIVE_VAR_DEFINE_SET( _xscale ) {
   1061 	SWF_SPRITE_PTHIS_SET( "_xscale" );
   1062 	if ( pThis->parent == NULL ) {
   1063 		return;
   1064 	}
   1065 	swfDisplayEntry_t * thisDisplayEntry = pThis->parent->FindDisplayEntry( pThis->depth );
   1066 	if ( thisDisplayEntry == NULL || thisDisplayEntry->spriteInstance != pThis ) {
   1067 		idLib::Warning( "_xscale: Couldn't find our display entry in our parents display list" );
   1068 		return;
   1069 	}
   1070 	float newScale = value.ToFloat() / 100.0f;
   1071 	// this is done funky to maintain the current rotation
   1072 	idVec2 currentScale = thisDisplayEntry->matrix.Scale( idVec2( 1.0f, 0.0f ) );
   1073 	if ( currentScale.Normalize() == 0.0f ) {
   1074 		thisDisplayEntry->matrix.xx = newScale;
   1075 		thisDisplayEntry->matrix.yx = 0.0f;
   1076 	} else {
   1077 		thisDisplayEntry->matrix.xx = currentScale.x * newScale;
   1078 		thisDisplayEntry->matrix.yx = currentScale.y * newScale;
   1079 	}
   1080 }
   1081 
   1082 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _yscale ) {
   1083 	SWF_SPRITE_PTHIS_GET( "_yscale" );
   1084 	if ( pThis->parent == NULL ) {
   1085 		return 1.0f;
   1086 	}
   1087 	swfDisplayEntry_t * thisDisplayEntry = pThis->parent->FindDisplayEntry( pThis->depth );
   1088 	if ( thisDisplayEntry == NULL || thisDisplayEntry->spriteInstance != pThis ) {
   1089 		idLib::Warning( "_yscale: Couldn't find our display entry in our parents display list" );
   1090 		return 1.0f;
   1091 	}
   1092 	return thisDisplayEntry->matrix.Scale( idVec2( 0.0f, 1.0f ) ).Length() * 100.0f;
   1093 }
   1094 
   1095 SWF_SPRITE_NATIVE_VAR_DEFINE_SET( _yscale ) {
   1096 	SWF_SPRITE_PTHIS_SET( "_yscale" );
   1097 	if ( pThis->parent == NULL ) {
   1098 		return;
   1099 	}
   1100 	swfDisplayEntry_t * thisDisplayEntry = pThis->parent->FindDisplayEntry( pThis->depth );
   1101 	if ( thisDisplayEntry == NULL || thisDisplayEntry->spriteInstance != pThis ) {
   1102 		idLib::Warning( "_yscale: Couldn't find our display entry in our parents display list" );
   1103 		return;
   1104 	}
   1105 	float newScale = value.ToFloat() / 100.0f;
   1106 	// this is done funky to maintain the current rotation
   1107 	idVec2 currentScale = thisDisplayEntry->matrix.Scale( idVec2( 0.0f, 1.0f ) );
   1108 	if ( currentScale.Normalize() == 0.0f ) {
   1109 		thisDisplayEntry->matrix.yy = newScale;
   1110 		thisDisplayEntry->matrix.xy = 0.0f;
   1111 	} else {
   1112 		thisDisplayEntry->matrix.yy = currentScale.y * newScale;
   1113 		thisDisplayEntry->matrix.xy = currentScale.x * newScale;
   1114 	}
   1115 }
   1116 
   1117 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _alpha ) {
   1118 	SWF_SPRITE_PTHIS_GET( "_alpha" );
   1119 	if ( pThis->parent == NULL ) {
   1120 		return 1.0f;
   1121 	}
   1122 	swfDisplayEntry_t * thisDisplayEntry = pThis->parent->FindDisplayEntry( pThis->depth );
   1123 	if ( thisDisplayEntry == NULL || thisDisplayEntry->spriteInstance != pThis ) {
   1124 		idLib::Warning( "_alpha: Couldn't find our display entry in our parents display list" );
   1125 		return 1.0f;
   1126 	}
   1127 	return thisDisplayEntry->cxf.mul.w;
   1128 }
   1129 
   1130 SWF_SPRITE_NATIVE_VAR_DEFINE_SET( _alpha ) {
   1131 	SWF_SPRITE_PTHIS_SET( "_alpha" );
   1132 
   1133 	pThis->SetAlpha( value.ToFloat() );
   1134 }
   1135 
   1136 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _brightness ) {
   1137 	SWF_SPRITE_PTHIS_GET( "_brightness" );
   1138 	if ( pThis->parent == NULL ) {
   1139 		return 1.0f;
   1140 	}
   1141 	swfDisplayEntry_t * thisDisplayEntry = pThis->parent->FindDisplayEntry( pThis->depth );
   1142 	if ( thisDisplayEntry == NULL || thisDisplayEntry->spriteInstance != pThis ) {
   1143 		idLib::Warning( "_brightness: Couldn't find our display entry in our parents display list" );
   1144 		return 1.0f;
   1145 	}
   1146 	// This works as long as the user only used the "brightess" control in the editor
   1147 	// If they used anything else (tint/advanced) then this will return fairly random values
   1148 	const idVec4 & mul = thisDisplayEntry->cxf.mul;
   1149 	const idVec4 & add = thisDisplayEntry->cxf.add;
   1150 	float avgMul = ( mul.x + mul.y + mul.z ) / 3.0f;
   1151 	float avgAdd = ( add.x + add.y + add.z ) / 3.0f;
   1152 	if ( avgAdd > 1.0f ) {
   1153 		return avgAdd;
   1154 	} else {
   1155 		return avgMul - 1.0f;
   1156 	}
   1157 }
   1158 
   1159 SWF_SPRITE_NATIVE_VAR_DEFINE_SET( _brightness ) {
   1160 	SWF_SPRITE_PTHIS_SET( "_brightness" );
   1161 	if ( pThis->parent == NULL ) {
   1162 		return;
   1163 	}
   1164 	swfDisplayEntry_t * thisDisplayEntry = pThis->parent->FindDisplayEntry( pThis->depth );
   1165 	if ( thisDisplayEntry == NULL || thisDisplayEntry->spriteInstance != pThis ) {
   1166 		idLib::Warning( "_brightness: Couldn't find our display entry in our parents display list" );
   1167 		return;
   1168 	}
   1169 	// This emulates adjusting the "brightness" slider in the editor
   1170 	// Although the editor forces alpha to 100%
   1171 	float b = value.ToFloat();
   1172 	float c = 1.0f - b;
   1173 	if ( b < 0.0f ) {
   1174 		c = 1.0f + b;
   1175 		b = 0.0f;
   1176 	}
   1177 	thisDisplayEntry->cxf.add.Set( b, b, b, thisDisplayEntry->cxf.add.w );
   1178 	thisDisplayEntry->cxf.mul.Set( c, c, c, thisDisplayEntry->cxf.mul.w );
   1179 }
   1180 
   1181 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _visible ) {
   1182 	SWF_SPRITE_PTHIS_GET( "_visible" );
   1183 	return pThis->isVisible;
   1184 }
   1185 
   1186 SWF_SPRITE_NATIVE_VAR_DEFINE_SET( _visible ) {
   1187 	SWF_SPRITE_PTHIS_SET( "_visible" );
   1188 	pThis->isVisible = value.ToBool();
   1189 	if ( pThis->isVisible ) {
   1190 		for ( idSWFSpriteInstance * p = pThis->parent; p != NULL; p = p->parent ) {
   1191 			p->childrenRunning = true;
   1192 		}
   1193 	}
   1194 }
   1195 
   1196 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _rotation ) {
   1197 	SWF_SPRITE_PTHIS_GET( "_rotation" );
   1198 	if ( pThis->parent == NULL ) {
   1199 		return 0.0f;
   1200 	}
   1201 	swfDisplayEntry_t * thisDisplayEntry = pThis->parent->FindDisplayEntry( pThis->depth );
   1202 	if ( thisDisplayEntry == NULL || thisDisplayEntry->spriteInstance != pThis ) {
   1203 		idLib::Warning( "_rotation: Couldn't find our display entry in our parents display list" );
   1204 		return 0.0f;
   1205 	}
   1206 	idVec2 scale = thisDisplayEntry->matrix.Scale( idVec2( 0.0f, 1.0f ) );
   1207 	scale.Normalize();
   1208 	float rotation = RAD2DEG( idMath::ACos( scale.y ) );
   1209 	if ( scale.x < 0.0f ) {
   1210 		rotation = -rotation;
   1211 	}
   1212 	return rotation;
   1213 }
   1214 
   1215 SWF_SPRITE_NATIVE_VAR_DEFINE_SET( _rotation ) {
   1216 	SWF_SPRITE_PTHIS_SET( "_rotation" );
   1217 	if ( pThis->parent == NULL ) {
   1218 		return;
   1219 	}
   1220 	swfDisplayEntry_t * thisDisplayEntry = pThis->parent->FindDisplayEntry( pThis->depth );
   1221 	if ( thisDisplayEntry == NULL || thisDisplayEntry->spriteInstance != pThis ) {
   1222 		idLib::Warning( "_rotation: Couldn't find our display entry in our parents display list" );
   1223 		return;
   1224 	}
   1225 	swfMatrix_t & matrix = thisDisplayEntry->matrix;
   1226 	float xscale = matrix.Scale( idVec2( 1.0f, 0.0f ) ).Length(); 
   1227 	float yscale = matrix.Scale( idVec2( 0.0f, 1.0f ) ).Length(); 
   1228 
   1229 	float s, c;
   1230 	idMath::SinCos( DEG2RAD( value.ToFloat() ), s, c ); 
   1231 	matrix.xx = c * xscale;
   1232 	matrix.yx = s * xscale;
   1233 	matrix.xy = -s * yscale;
   1234 	matrix.yy = c * yscale;
   1235 }
   1236 
   1237 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _name ) {
   1238 	SWF_SPRITE_PTHIS_GET( "_name" );
   1239 	return pThis->name.c_str();
   1240 }
   1241 
   1242 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _currentframe ) {
   1243 	SWF_SPRITE_PTHIS_GET( "_currentframe" );
   1244 	return pThis->currentFrame;
   1245 }
   1246 
   1247 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _totalframes ) {
   1248 	SWF_SPRITE_PTHIS_GET( "_totalframes" );
   1249 	return pThis->frameCount;
   1250 }
   1251 
   1252 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _framesloaded ) {
   1253 	SWF_SPRITE_PTHIS_GET( "_framesloaded" );
   1254 	return pThis->frameCount;
   1255 }
   1256 
   1257 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _mousex ) {
   1258 	SWF_SPRITE_PTHIS_GET( "_mousex" );
   1259 	if ( pThis->parent == NULL ) {
   1260 		return pThis->sprite->GetSWF()->GetMouseX();
   1261 	}
   1262 	swfDisplayEntry_t * thisDisplayEntry = pThis->parent->FindDisplayEntry( pThis->depth );
   1263 	if ( thisDisplayEntry == NULL || thisDisplayEntry->spriteInstance != pThis ) {
   1264 		idLib::Warning( "_mousex: Couldn't find our display entry in our parents display list" );
   1265 		return pThis->sprite->GetSWF()->GetMouseX();
   1266 	}
   1267 	return pThis->sprite->GetSWF()->GetMouseX() - thisDisplayEntry->matrix.ty;
   1268 }
   1269 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _mousey ) {
   1270 	SWF_SPRITE_PTHIS_GET( "_mousey" );
   1271 	if ( pThis->parent == NULL ) {
   1272 		return pThis->sprite->GetSWF()->GetMouseY();
   1273 	}
   1274 	swfDisplayEntry_t * thisDisplayEntry = pThis->parent->FindDisplayEntry( pThis->depth );
   1275 	if ( thisDisplayEntry == NULL || thisDisplayEntry->spriteInstance != pThis ) {
   1276 		idLib::Warning( "_mousey: Couldn't find our display entry in our parents display list" );
   1277 		return pThis->sprite->GetSWF()->GetMouseY();
   1278 	}
   1279 	return pThis->sprite->GetSWF()->GetMouseY() - thisDisplayEntry->matrix.ty;
   1280 }
   1281 
   1282 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _itemindex ) {
   1283 	SWF_SPRITE_PTHIS_GET( "_itemindex" );
   1284 	return pThis->itemIndex;
   1285 }
   1286 
   1287 SWF_SPRITE_NATIVE_VAR_DEFINE_SET( _itemindex ) {
   1288 	SWF_SPRITE_PTHIS_SET( "_itemindex" );
   1289 	pThis->itemIndex = value.ToInteger();
   1290 }
   1291 
   1292 SWF_SPRITE_NATIVE_VAR_DEFINE_SET( _stereoDepth ) {
   1293 	SWF_SPRITE_PTHIS_SET( "_stereoDepth" );
   1294 	pThis->stereoDepth = value.ToInteger();
   1295 }
   1296 
   1297 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( _stereoDepth ) {
   1298 	SWF_SPRITE_PTHIS_GET( "_stereoDepth" );
   1299 	return pThis->stereoDepth;
   1300 }
   1301 
   1302 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( material ) {
   1303 	SWF_SPRITE_PTHIS_GET( "material" );
   1304 	if ( pThis->materialOverride == NULL ) {
   1305 		return idSWFScriptVar();
   1306 	} else {
   1307 		return pThis->materialOverride->GetName();
   1308 	}
   1309 }
   1310 
   1311 SWF_SPRITE_NATIVE_VAR_DEFINE_SET( material ) {
   1312 	SWF_SPRITE_PTHIS_SET( "material" );
   1313 	if ( !value.IsString() ) {
   1314 		pThis->materialOverride = NULL;
   1315 	} else {
   1316 		// God I hope this material was referenced during map load
   1317 		pThis->SetMaterial( declManager->FindMaterial( value.ToString(), false ) );
   1318 	}
   1319 }
   1320 
   1321 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( materialWidth ) {
   1322 	SWF_SPRITE_PTHIS_GET( "materialWidth" );
   1323 	return pThis->materialWidth;
   1324 }
   1325 
   1326 SWF_SPRITE_NATIVE_VAR_DEFINE_SET( materialWidth ) {
   1327 	SWF_SPRITE_PTHIS_SET( "materialWidth" );
   1328 	assert( value.ToInteger() > 0 );
   1329 	assert( value.ToInteger() <= 8192 );
   1330 	pThis->materialWidth = (uint16)value.ToInteger();
   1331 }
   1332 
   1333 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( materialHeight ) {
   1334 	SWF_SPRITE_PTHIS_GET( "materialHeight" );
   1335 	return pThis->materialHeight;
   1336 }
   1337 
   1338 SWF_SPRITE_NATIVE_VAR_DEFINE_SET( materialHeight ) {
   1339 	SWF_SPRITE_PTHIS_SET( "materialHeight" );
   1340 	assert( value.ToInteger() > 0 );
   1341 	assert( value.ToInteger() <= 8192 );
   1342 	pThis->materialHeight = (uint16)value.ToInteger();
   1343 }
   1344 
   1345 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( xOffset ) {
   1346 	SWF_SPRITE_PTHIS_GET( "xOffset" );
   1347 	return pThis->xOffset;
   1348 }
   1349 
   1350 SWF_SPRITE_NATIVE_VAR_DEFINE_SET( xOffset ) {
   1351 	SWF_SPRITE_PTHIS_SET( "xOffset" );
   1352 	pThis->xOffset = value.ToFloat();
   1353 }
   1354 
   1355 SWF_SPRITE_NATIVE_VAR_DEFINE_GET( onEnterFrame ) {
   1356 	SWF_SPRITE_PTHIS_GET( "onEnterFrame" );
   1357 	return pThis->onEnterFrame;
   1358 }
   1359 
   1360 SWF_SPRITE_NATIVE_VAR_DEFINE_SET( onEnterFrame ) {
   1361 	SWF_SPRITE_PTHIS_SET( "onEnterFrame" );
   1362 	pThis->onEnterFrame = value;
   1363 }