123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458 |
- /*
- ===========================================================================
- Doom 3 BFG Edition GPL Source Code
- Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
- 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 <http://www.gnu.org/licenses/>.
- 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 hdrstop
- #include "../idlib/precompiled.h"
- /*
- ===================
- idSWF::HitTest
- ===================
- */
- idSWFScriptObject * idSWF::HitTest( idSWFSpriteInstance * spriteInstance, const swfRenderState_t & renderState, int x, int y, idSWFScriptObject * parentObject ) {
- if ( spriteInstance->parent != NULL ) {
- swfDisplayEntry_t * thisDisplayEntry = spriteInstance->parent->FindDisplayEntry( spriteInstance->depth );
- if ( thisDisplayEntry->cxf.mul.w + thisDisplayEntry->cxf.add.w < 0.001f ) {
- return NULL;
- }
- }
- if ( !spriteInstance->isVisible ) {
- return NULL;
- }
- 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;
-
- float xOffset = spriteInstance->xOffset;
- float yOffset = spriteInstance->yOffset;
-
- for ( int i = 0; i < spriteInstance->displayList.Num(); i++ ) {
- const swfDisplayEntry_t & display = spriteInstance->displayList[i];
- idSWFDictionaryEntry * entry = FindDictionaryEntry( display.characterID );
- if ( entry == NULL ) {
- continue;
- }
- swfRenderState_t renderState2;
- renderState2.matrix = display.matrix.Multiply( renderState.matrix );
- renderState2.ratio = display.ratio;
- if ( entry->type == SWF_DICT_SPRITE ) {
- idSWFScriptObject * object = HitTest( display.spriteInstance, renderState2, x, y, parentObject );
- if ( object != NULL && object->Get( "_visible" ).ToBool() ) {
- returnObject = object;
- }
- } else if ( entry->type == SWF_DICT_SHAPE && ( parentObject != NULL ) ) {
- idSWFShape * shape = entry->shape;
- for ( int i = 0; i < shape->fillDraws.Num(); i++ ) {
- const idSWFShapeDrawFill & fill = shape->fillDraws[i];
- for ( int j = 0; j < fill.indices.Num(); j+=3 ) {
- idVec2 xy1 = renderState2.matrix.Transform( fill.startVerts[fill.indices[j+0]] );
- idVec2 xy2 = renderState2.matrix.Transform( fill.startVerts[fill.indices[j+1]] );
- idVec2 xy3 = renderState2.matrix.Transform( fill.startVerts[fill.indices[j+2]] );
- idMat3 edgeEquations;
- edgeEquations[0].Set( xy1.x + xOffset, xy1.y + yOffset, 1.0f );
- edgeEquations[1].Set( xy2.x + xOffset, xy2.y + yOffset, 1.0f );
- edgeEquations[2].Set( xy3.x + xOffset, xy3.y + yOffset, 1.0f );
- edgeEquations.InverseSelf();
- idVec3 p( x, y, 1.0f );
- idVec3 signs = p * edgeEquations;
- bool bx = signs.x > 0;
- bool by = signs.y > 0;
- bool bz = signs.z > 0;
- if ( bx == by && bx == bz ) {
- // point inside
- returnObject = parentObject;
- }
- }
- }
- } else if ( entry->type == SWF_DICT_MORPH ) {
- // 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 ) {
- idSWFScriptObject * editObject = NULL;
- if ( 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 ) {
- // otherwise, we want to return the parent object
- editObject = parentObject;
- }
- if ( editObject == NULL ) {
- continue;
- }
- if ( display.textInstance->text.IsEmpty() ) {
- continue;
- }
- const idSWFEditText * shape = entry->edittext;
- const idSWFEditText * text = display.textInstance->GetEditText();
- float textLength = display.textInstance->GetTextLength();
- float lengthDiff = fabs( shape->bounds.br.x - shape->bounds.tl.x ) - textLength;
-
- idVec3 tl;
- idVec3 tr;
- idVec3 br;
- idVec3 bl;
- float xOffset = spriteInstance->xOffset;
- float yOffset = spriteInstance->yOffset;
- float topOffset = 0.0f;
- if ( text->align == SWF_ET_ALIGN_LEFT ) {
- tl.ToVec2() = renderState2.matrix.Transform( idVec2( shape->bounds.tl.x + xOffset, shape->bounds.tl.y + topOffset + yOffset ) );
- tr.ToVec2() = renderState2.matrix.Transform( idVec2( shape->bounds.br.x - lengthDiff + xOffset, shape->bounds.tl.y + topOffset + yOffset ) );
- br.ToVec2() = renderState2.matrix.Transform( idVec2( shape->bounds.br.x - lengthDiff + xOffset, shape->bounds.br.y + topOffset + yOffset ) );
- bl.ToVec2() = renderState2.matrix.Transform( idVec2( shape->bounds.tl.x + xOffset, shape->bounds.br.y + topOffset + yOffset ) );
- } else if ( text->align == SWF_ET_ALIGN_RIGHT ) {
- tl.ToVec2() = renderState2.matrix.Transform( idVec2( shape->bounds.tl.x + lengthDiff + xOffset, shape->bounds.tl.y + topOffset + yOffset ) );
- tr.ToVec2() = renderState2.matrix.Transform( idVec2( shape->bounds.br.x + xOffset, shape->bounds.tl.y + topOffset + yOffset ) );
- br.ToVec2() = renderState2.matrix.Transform( idVec2( shape->bounds.br.x + xOffset, shape->bounds.br.y + topOffset + yOffset ) );
- bl.ToVec2() = renderState2.matrix.Transform( idVec2( shape->bounds.tl.x + lengthDiff + xOffset, shape->bounds.br.y + topOffset + yOffset ) );
- } else if ( text->align == SWF_ET_ALIGN_CENTER ) {
- float middle = ( ( shape->bounds.br.x + xOffset ) + ( shape->bounds.tl.x + xOffset ) ) / 2.0f;
- tl.ToVec2() = renderState2.matrix.Transform( idVec2( middle - ( textLength / 2.0f ), shape->bounds.tl.y + topOffset + yOffset ) );
- tr.ToVec2() = renderState2.matrix.Transform( idVec2( middle + ( textLength / 2.0f ), shape->bounds.tl.y + topOffset + yOffset ) );
- br.ToVec2() = renderState2.matrix.Transform( idVec2( middle + ( textLength / 2.0f ), shape->bounds.br.y + topOffset + yOffset ) );
- bl.ToVec2() = renderState2.matrix.Transform( idVec2( middle - ( textLength / 2.0f ), shape->bounds.br.y + topOffset + yOffset ) );
- } else {
- tl.ToVec2() = renderState2.matrix.Transform( idVec2( shape->bounds.tl.x + xOffset, shape->bounds.tl.y + topOffset + yOffset ) );
- tr.ToVec2() = renderState2.matrix.Transform( idVec2( shape->bounds.br.x + xOffset, shape->bounds.tl.y + topOffset + yOffset ) );
- br.ToVec2() = renderState2.matrix.Transform( idVec2( shape->bounds.br.x + xOffset, shape->bounds.br.y + topOffset + yOffset ) );
- bl.ToVec2() = renderState2.matrix.Transform( idVec2( shape->bounds.tl.x + xOffset, shape->bounds.br.y + topOffset + yOffset ) );
- }
- tl.z = 1.0f;
- tr.z = 1.0f;
- br.z = 1.0f;
- bl.z = 1.0f;
- idMat3 edgeEquations;
- edgeEquations[0] = tl;
- edgeEquations[1] = tr;
- edgeEquations[2] = br;
- edgeEquations.InverseSelf();
- idVec3 p( x, y, 1.0f );
- idVec3 signs = p * edgeEquations;
- bool bx = signs.x > 0;
- bool by = signs.y > 0;
- bool bz = signs.z > 0;
- if ( bx == by && bx == bz ) {
- // point inside top right triangle
- returnObject = editObject;
- }
- edgeEquations[0] = tl;
- edgeEquations[1] = br;
- edgeEquations[2] = bl;
- edgeEquations.InverseSelf();
- signs = p * edgeEquations;
- bx = signs.x > 0;
- by = signs.y > 0;
- bz = signs.z > 0;
- if ( bx == by && bx == bz ) {
- // point inside bottom left triangle
- returnObject = editObject;
- }
- }
- }
- return returnObject;
- }
- /*
- ===================
- idSWF::HandleEvent
- ===================
- */
- bool idSWF::HandleEvent( const sysEvent_t * event ) {
- if ( !IsLoaded() || !IsActive() || ( !inhibitControl && useInhibtControl ) ) {
- return false;
- }
- if ( event->evType == SE_KEY ) {
- if ( event->evValue == K_MOUSE1 ) {
- mouseEnabled = true;
- idSWFScriptVar var;
- if ( event->evValue2 ) {
- idSWFScriptVar waitInput = globals->Get( "waitInput" );
- if ( waitInput.IsFunction() ) {
- useMouse = false;
- idSWFParmList waitParms;
- waitParms.Append( event->evValue );
- waitInput.GetFunction()->Call( NULL, waitParms );
- waitParms.Clear();
- } else {
- useMouse = true;
- }
- idSWFScriptObject * hitObject = HitTest( mainspriteInstance, swfRenderState_t(), mouseX, mouseY, NULL );
- if ( hitObject != NULL ) {
- mouseObject = hitObject;
- mouseObject->AddRef();
-
- var = hitObject->Get( "onPress" );
- if ( var.IsFunction() ) {
- idSWFParmList parms;
- parms.Append( event->inputDevice );
- var.GetFunction()->Call( hitObject, parms );
- parms.Clear();
- return true;
- }
- idSWFScriptVar var = hitObject->Get( "onDrag" );
- if ( var.IsFunction() ) {
- idSWFParmList parms;
- parms.Append( mouseX );
- parms.Append( mouseY );
- parms.Append( true );
- var.GetFunction()->Call( hitObject, parms );
- parms.Clear();
- return true;
- }
- }
- idSWFParmList parms;
- parms.Append( hitObject );
- Invoke( "setHitObject", parms );
- } else {
- if ( mouseObject ) {
- var = mouseObject->Get( "onRelease" );
- if ( var.IsFunction() ) {
- idSWFParmList parms;
- parms.Append( mouseObject ); // FIXME: Remove this
- var.GetFunction()->Call( mouseObject, parms );
- }
- mouseObject->Release();
- mouseObject = NULL;
- }
- if ( hoverObject ) {
- hoverObject->Release();
- hoverObject = NULL;
- }
- if ( var.IsFunction() ) {
- return true;
- }
- }
-
- return false;
- }
- const char * keyName = idKeyInput::KeyNumToString( (keyNum_t)event->evValue );
- idSWFScriptVar var = shortcutKeys->Get( keyName );
- // anything more than 32 levels of indirection we can be pretty sure is an infinite loop
- for ( int runaway = 0; runaway < 32; runaway++ ) {
- idSWFParmList eventParms;
- eventParms.Clear();
- eventParms.Append( event->inputDevice );
- if ( var.IsString() ) {
- // alias to another key
- var = shortcutKeys->Get( var.ToString() );
- continue;
- } else if ( var.IsObject() ) {
- // if this object is a sprite, send fake mouse events to it
- idSWFScriptObject * object = var.GetObject();
- // make sure we don't send an onRelease event unless we have already sent that object an onPress
- bool wasPressed = object->Get( "_pressed" ).ToBool();
- object->Set( "_pressed", event->evValue2 );
- if ( event->evValue2 ) {
- var = object->Get( "onPress" );
- } else if ( wasPressed ) {
- var = object->Get( "onRelease" );
- }
- if ( var.IsFunction() ) {
- var.GetFunction()->Call( object, eventParms );
- return true;
- }
- } else if ( var.IsFunction() ) {
- if ( event->evValue2 ) {
- // anonymous functions only respond to key down events
- var.GetFunction()->Call( NULL, eventParms );
- return true;
- }
- return false;
- }
- idSWFScriptVar useFunction = globals->Get( "useFunction" );
- if ( useFunction.IsFunction() && event->evValue2 ) {
- const char * action = idKeyInput::GetBinding( event->evValue );
- if ( idStr::Cmp( "_use", action ) == 0 ) {
- useFunction.GetFunction()->Call( NULL, idSWFParmList() );
- }
- }
- idSWFScriptVar waitInput = globals->Get( "waitInput" );
- if ( waitInput.IsFunction() ) {
- useMouse = false;
- if ( event->evValue2 ) {
- idSWFParmList waitParms;
- waitParms.Append( event->evValue );
- waitInput.GetFunction()->Call( NULL, waitParms );
- }
- } else {
- useMouse = true;
- }
- idSWFScriptVar focusWindow = globals->Get( "focusWindow" );
- if ( focusWindow.IsObject() ) {
- idSWFScriptVar onKey = focusWindow.GetObject()->Get( "onKey" );
- if ( onKey.IsFunction() ) {
- // make sure we don't send an onRelease event unless we have already sent that object an onPress
- idSWFScriptObject * object = focusWindow.GetObject();
- bool wasPressed = object->Get( "_kpressed" ).ToBool();
- object->Set( "_kpressed", event->evValue2 );
- if ( event->evValue2 || wasPressed ) {
- idSWFParmList parms;
- parms.Append( event->evValue );
- parms.Append( event->evValue2 );
- onKey.GetFunction()->Call( focusWindow.GetObject(), parms ).ToBool();
- return true;
- } else if ( event->evValue == K_LSHIFT || event->evValue == K_RSHIFT ) {
- idSWFParmList parms;
- parms.Append( event->evValue );
- parms.Append( event->evValue2 );
- onKey.GetFunction()->Call( focusWindow.GetObject(), parms ).ToBool();
- }
- }
- }
- return false;
- }
- idLib::Warning( "Circular reference in %s shortcutKeys.%s", filename.c_str(), keyName );
- } else if ( event->evType == SE_CHAR ) {
- idSWFScriptVar focusWindow = globals->Get( "focusWindow" );
- if ( focusWindow.IsObject() ) {
- idSWFScriptVar onChar = focusWindow.GetObject()->Get( "onChar" );
- if ( onChar.IsFunction() ) {
- idSWFParmList parms;
- parms.Append( event->evValue );
- parms.Append( idKeyInput::KeyNumToString( (keyNum_t)event->evValue ) );
- onChar.GetFunction()->Call( focusWindow.GetObject(), parms ).ToBool();
- return true;
- }
- }
- } else if ( event->evType == SE_MOUSE_ABSOLUTE || event->evType == SE_MOUSE ) {
- mouseEnabled = true;
- isMouseInClientArea = true;
- // Mouse position in screen space needs to be converted to SWF space
- if ( event->evType == SE_MOUSE_ABSOLUTE ) {
- const float pixelAspect = renderSystem->GetPixelAspect();
- const float sysWidth = renderSystem->GetWidth() * ( pixelAspect > 1.0f ? pixelAspect : 1.0f );
- const float sysHeight = renderSystem->GetHeight() / ( pixelAspect < 1.0f ? pixelAspect : 1.0f );
- float scale = swfScale * sysHeight / (float)frameHeight;
- float invScale = 1.0f / scale;
- float tx = 0.5f * ( sysWidth - ( frameWidth * scale ) );
- float ty = 0.5f * ( sysHeight - ( frameHeight * scale ) );
- mouseX = idMath::Ftoi( ( static_cast<float>( event->evValue ) - tx ) * invScale );
- mouseY = idMath::Ftoi( ( static_cast<float>( event->evValue2 ) - ty ) * invScale );
- } else {
- mouseX += event->evValue;
- mouseY += event->evValue2;
- mouseX = Max( Min( mouseX, idMath::Ftoi( frameWidth + renderBorder ) ), idMath::Ftoi( 0.0f - renderBorder ) );
- mouseY = Max( Min( mouseY, idMath::Ftoi(frameHeight) ), 0 );
- }
- bool retVal = false;
- idSWFScriptObject * hitObject = HitTest( mainspriteInstance, swfRenderState_t(), mouseX, mouseY, NULL );
- if ( hitObject != NULL ) {
- hasHitObject = true;
- } else {
- hasHitObject = false;
- }
- 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() ) {
- var.GetFunction()->Call( hoverObject, idSWFParmList() );
- retVal = true;
- }
- hoverObject->Release();
- hoverObject = NULL;
- }
- // Then call onRollOver on our hitObject
- if ( hitObject != NULL ) {
- hoverObject = hitObject;
- hoverObject->AddRef();
- idSWFScriptVar var = hitObject->Get( "onRollOver" );
- if ( var.IsFunction() ) {
- var.GetFunction()->Call( hitObject, idSWFParmList() );
- retVal = true;
- }
- }
- }
- if ( mouseObject != NULL ) {
- idSWFScriptVar var = mouseObject->Get( "onDrag" );
- if ( var.IsFunction() ) {
- idSWFParmList parms;
- parms.Append( mouseX );
- parms.Append( mouseY );
- parms.Append( false );
- var.GetFunction()->Call( mouseObject, parms );
- return true;
- }
- }
- return retVal;
- } else if ( event->evType == SE_MOUSE_LEAVE ) {
- isMouseInClientArea = false;
- } else if ( event->evType == SE_JOYSTICK ) {
- idSWFParmList parms;
- parms.Append( event->evValue );
- parms.Append( event->evValue2 / 32.0f );
- Invoke( "onJoystick", parms );
- }
- return false;
- }
|