///////////////////////////////////////////////////////////////////////////////// // // FILE : ScaleformComplexObjectMgr.cpp // PURPOSE : manages the processing of use of Complex Object in Scaleform // and linking directly to movies // keeps complex object code to simple, one line calls // since we are going to be moving over to more complex object use then // we should maintain this in one place, link up each stored value and // track and log output to find movies that have been deleted but still // have movieclip references attached. // this allows ui systems to use complex object without using gfxvalue // directly. This may be handy with expansion for future script support // of complex objects // complex objects can be access and used on both UT and RT // invokes to the complex objects can be sent through the ScaleformMgr // on UT and RT // AUTHOR : Derek Payne // STARTED : 28/02/2014 // ///////////////////////////////////////////////////////////////////////////////// // Rage headers #include "atl/hashstring.h" #include "Scaleform/scaleform.h" #include "scr_scaleform/scaleform.h" #include "frontend/ui_channel.h" #include "string/stringutil.h" #include "system/param.h" #include "vector/color32.h" // Game headers #include "Frontend/Scaleform/ScaleFormComplexObjectMgr.h" #include "Frontend/Scaleform/ScaleFormMgr.h" SCALEFORM_OPTIMISATIONS(); //OPTIMISATIONS_OFF() #define __FULL_SANITY_CHECKS (!__FINAL) // checking whether items are on the stage etc may not be needed in release, we can turn off specific checks here atArray CScaleformComplexObjectMgr::sm_ObjectArray; s32 CScaleformComplexObjectMgr::ms_iUniqueId = 0; #if __BANK bool CScaleformComplexObjectMgr::ms_bUseDetailedLogging = false; PARAM(complexObjectDetailedLogging, "Enable detailed logging for Complex Object operations"); #endif // __BANK #define MAX_COMPLEX_OBJECT_DEPTH (100000) // set a hard max to keep numbers used reasonable. There is a bug in AS which causes issues with very high depths so lets try to avoid it bool CComplexObject::IsActiveAndAttached() const { if (IsActive()) { CComplexObjectArrayItem const * const c_obj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if( c_obj ) { return ( (c_obj->IsActive()) && (!c_obj->IsPendingCreate()) && (!c_obj->IsPendingAttach()) && (!c_obj->IsPendingGet()) && (!c_obj->IsPendingGetRoot()) ); } } return false; } bool CComplexObject::HasInvokesPending() const { if (IsActive()) { CComplexObjectArrayItem const * const c_obj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if( c_obj ) { return (c_obj->IsPendingInvoke()); } } return false; } void CComplexObject::Release() { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { #if RSG_BANK if( CScaleformComplexObjectMgr::DetailedLogging() ) { int const c_movieId = pObj->GetMovieId(); sfDisplayf("CComplexObject::Release called on '" HASHFMT "' on movie %s (%d)", HASHOUT(pObj->GetObjectNameHash()), CScaleformMgr::GetMovieFilename( c_movieId ), c_movieId ); { sysStack::PrintStackTrace(); } } #endif // RSG_BANK CComplexObjectArrayItem::ReleaseObject(pObj, false); Clear(); } } void CComplexObject::SetPosition(Vector2 const& vPos) { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ( (!pObj->IsInitialised()) || (pObj->GetPosition().x != vPos.x || pObj->GetPosition().y != vPos.y) ) { pObj->SetPosition(vPos); } } } void CComplexObject::SetPositionInPixels(Vector2 const& vPixelPos) { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ( (!pObj->IsInitialised()) || (pObj->GetPositionInPixels().x != vPixelPos.x || pObj->GetPositionInPixels().y != vPixelPos.y) ) { pObj->SetPositionInPixels(vPixelPos); } } } void CComplexObject::SetPosition( Vec2f_In vPos ) { SetPosition( Vector2( vPos.GetX(), vPos.GetY() ) ); } void CComplexObject::SetPositionInPixels( Vec2f_In vPixelPos ) { SetPositionInPixels( Vector2( vPixelPos.GetX(), vPixelPos.GetY() ) ); } void CComplexObject::SetXPositionInPixels(float fPixelPos) { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ( !pObj->IsInitialised() || !AreNearlyEqual( pObj->GetXPositionInPixels(), fPixelPos ) ) { pObj->SetXPositionInPixels(fPixelPos); } } } void CComplexObject::SetYPositionInPixels( float fPixelPos ) { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ( (!pObj->IsInitialised()) || (pObj->GetYPositionInPixels() != fPixelPos) ) { pObj->SetYPositionInPixels(fPixelPos); } } } void CComplexObject::SetSize( Vec2f_In vScale ) { SetWidth( vScale.GetX() ); SetHeight( vScale.GetY() ); } void CComplexObject::SetSize( Vector2 const& vNewScale ) { SetWidth( vNewScale.x ); SetHeight( vNewScale.y ); } void CComplexObject::SetScale( Vec2f_In vScale ) { SetScale( Vector2( vScale.GetX(), vScale.GetY() ) ); } void CComplexObject::SetScale(Vector2 const& vNewScale) { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ( (!pObj->IsInitialised()) || (pObj->GetScale().x != vNewScale.x || pObj->GetScale().y != vNewScale.y) ) { pObj->SetScale(vNewScale); } } } void CComplexObject::SetXScale(float fScale) { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ( (!pObj->IsInitialised()) || (pObj->GetScale().x != fScale) ) { pObj->SetXScale(fScale); } } } void CComplexObject::SetRotation( float fRotation ) { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ( (!pObj->IsInitialised()) || (pObj->GetRotation() != fRotation) ) { pObj->SetRotation(fRotation); } } } void CComplexObject::SetMember( const char *pInstanceName, bool const c_value) { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { pObj->SetMember(pInstanceName, c_value); } } void CComplexObject::AdjustXPositionInPixels(float fPixels) { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if (fPixels != 0.0f) { pObj->AdjustXPositionInPixels(fPixels); } } } void CComplexObject::SetWidth(float fWidth) { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ( (!pObj->IsInitialised()) || (pObj->GetWidth() != fWidth) ) { pObj->SetWidth(fWidth); } } } void CComplexObject::SetHeight( float fHeight ) { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ( (!pObj->IsInitialised()) || (pObj->GetHeight() != fHeight) ) { pObj->SetHeight(fHeight); } } } void CComplexObject::SetVisible(bool bValue) { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ( (!pObj->IsInitialised()) || (pObj->IsVisible() != bValue) ) { pObj->SetVisible(bValue); } } } void CComplexObject::GotoFrame(s32 iFrame, bool const andPlay ) { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ( (!pObj->IsInitialised()) || (pObj->GetCurrentFrame() != iFrame) ) { pObj->GotoFrame(iFrame, andPlay ); } } } void CComplexObject::SetTextField(const char *pText) { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { pObj->SetTextField(pText); } } void CComplexObject::SetTextFieldHTML( const char *pHtmlText ) { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { pObj->SetTextFieldHTML(pHtmlText); } } void CComplexObject::SetColour(Color32 const &colour) { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ( (!pObj->IsInitialised()) || (pObj->GetColour() != colour) ) { pObj->SetColour(colour); } } } void CComplexObject::SetAlpha(u8 const c_alpha) { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { pObj->SetAlpha(c_alpha); } } void CComplexObject::SetDepth( s32 const c_depth ) { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ( (!pObj->IsInitialised()) || (pObj->GetDepth() != c_depth) ) { pObj->SetDepth(c_depth); } } } Vector2 CComplexObject::GetPosition() { Vector2 vRetPos(0,0); CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ((pObj->GetActionRequired() & CO_ACTION_UPDATE_POSITION_X) == 0 && (pObj->GetActionRequired() & CO_ACTION_UPDATE_POSITION_Y) == 0) { CScaleformComplexObjectMgr::CheckAndSetupIfUninitialised(objectId); } vRetPos = pObj->GetPosition(); } return vRetPos; } Vector2 CComplexObject::GetPositionInPixels() { Vector2 vRetPos(0,0); CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ((pObj->GetActionRequired() & CO_ACTION_UPDATE_POSITION_X) == 0 && (pObj->GetActionRequired() & CO_ACTION_UPDATE_POSITION_Y) == 0) { CScaleformComplexObjectMgr::CheckAndSetupIfUninitialised(objectId); } vRetPos = pObj->GetPositionInPixels(); } return vRetPos; } float CComplexObject::GetXPositionInPixels() { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ((pObj->GetActionRequired() & CO_ACTION_UPDATE_POSITION_X) == 0) { CScaleformComplexObjectMgr::CheckAndSetupIfUninitialised(objectId); } return pObj->GetXPositionInPixels(); } return 0.0f; } float CComplexObject::GetYPositionInPixels() { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ((pObj->GetActionRequired() & CO_ACTION_UPDATE_POSITION_Y) == 0) { CScaleformComplexObjectMgr::CheckAndSetupIfUninitialised(objectId); } return pObj->GetYPositionInPixels(); } return 0.0f; } Vector2 CComplexObject::GetSize() { Vector2 vRetSize(0,0); CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ( ((pObj->GetActionRequired() & CO_ACTION_UPDATE_WIDTH) == 0) || ((pObj->GetActionRequired() & CO_ACTION_UPDATE_HEIGHT) == 0) ) { CScaleformComplexObjectMgr::CheckAndSetupIfUninitialised(objectId); } vRetSize = Vector2(pObj->GetWidth() / (float)ACTIONSCRIPT_STAGE_SIZE_X, pObj->GetHeight() / (float)ACTIONSCRIPT_STAGE_SIZE_Y); } return vRetSize; } Vector2 CComplexObject::GetScale() { Vector2 vRetScale(0,0); CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ((pObj->GetActionRequired() & CO_ACTION_UPDATE_SCALE) == 0) { CScaleformComplexObjectMgr::CheckAndSetupIfUninitialised(objectId); } vRetScale = pObj->GetScale(); } return vRetScale; } float CComplexObject::GetRotation() { float rotation = 0.f; CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ((pObj->GetActionRequired() & CO_ACTION_UPDATE_ROTATION) == 0) { CScaleformComplexObjectMgr::CheckAndSetupIfUninitialised(objectId); } rotation = pObj->GetRotation(); } return rotation; } bool CComplexObject::GetMember(const char *pInstanceName, bool &out_bool) { float valueNumber; atString valueString; bool const c_success = GetMemberInternal(pInstanceName, out_bool, valueNumber, valueString); return c_success; } bool CComplexObject::GetMember(const char *pInstanceName, float &out_number) { bool valueBool; atString valueString; bool const c_success = GetMemberInternal(pInstanceName, valueBool, out_number, valueString); return c_success; } bool CComplexObject::GetMember(const char *pInstanceName, atString &out_string) { bool valueBool; float valueNumber; bool const c_success = GetMemberInternal(pInstanceName, valueBool, valueNumber, out_string); return c_success; } bool CComplexObject::GetMemberInternal(const char *pInstanceName, bool &out_valueBool, float &out_valueNumber, atString &out_valueString) { out_valueBool = false; out_valueNumber = 0.0f; out_valueString.Clear(); CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ((pObj->GetActionRequired() & CO_ACTION_UPDATE_MEMBERS) == 0) { CScaleformComplexObjectMgr::CheckAndSetupIfUninitialised(objectId); } eMemberValueType const c_typeUsed = pObj->GetMember(pInstanceName, out_valueBool, out_valueNumber, out_valueString); if (c_typeUsed == MEMBER_VALUE_TYPE_INVALID) // we didnt find a cached value so create it from the object itself { #if __SCALEFORM_CRITICAL_SECTIONS SYS_CS_SYNC(gs_ScaleformMovieCS[CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId)->GetMovieId()]); #endif GFxValue memberValue; pObj->m_asObject.GetMember(pInstanceName, &memberValue); if (memberValue.IsDefined() && (memberValue.GetType() == GFxValue::VT_Boolean || memberValue.GetType() == GFxValue::VT_Number || memberValue.GetType() == GFxValue::VT_String)) { sComplectObjectMembers *newSetMember = &(pObj->m_properties[CScaleformComplexObjectMgr::GetBuffer()].m_member).Grow(); newSetMember->m_instanceName = pInstanceName; newSetMember->m_update = false; switch (memberValue.GetType()) { case GFxValue::VT_Boolean: { out_valueBool = memberValue.GetBool(); newSetMember->value_bool = out_valueBool; newSetMember->m_type = MEMBER_VALUE_TYPE_BOOL; return true; } case GFxValue::VT_Number: { out_valueNumber = (float)memberValue.GetNumber(); newSetMember->value_number = out_valueNumber; newSetMember->m_type = MEMBER_VALUE_TYPE_NUMBER; return true; } case GFxValue::VT_String: { out_valueString = memberValue.GetString(); newSetMember->value_string = out_valueString; newSetMember->m_type = MEMBER_VALUE_TYPE_STRING; return true; } default: { // NOP } } } } else { return true; } } return false; } float CComplexObject::GetWidth() { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ((pObj->GetActionRequired() & CO_ACTION_UPDATE_WIDTH) == 0) { CScaleformComplexObjectMgr::CheckAndSetupIfUninitialised(objectId); } return pObj->GetWidth(); } return 0.0f; } float CComplexObject::GetHeight() { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ((pObj->GetActionRequired() & CO_ACTION_UPDATE_HEIGHT) == 0) { CScaleformComplexObjectMgr::CheckAndSetupIfUninitialised(objectId); } return pObj->GetHeight(); } return 0.0f; } bool CComplexObject::IsVisible() { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ((pObj->GetActionRequired() & CO_ACTION_UPDATE_VISIBILITY) == 0) { CScaleformComplexObjectMgr::CheckAndSetupIfUninitialised(objectId); } return pObj->IsVisible(); } return false; } s32 CComplexObject::GetCurrentFrame() { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ((pObj->GetActionRequired() & CO_ACTION_UPDATE_FRAME) == 0) { CScaleformComplexObjectMgr::CheckAndSetupIfUninitialised(objectId); } return pObj->GetCurrentFrame(); } return 1; } const char *CComplexObject::GetTextField() { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ((pObj->GetActionRequired() & CO_ACTION_UPDATE_TEXTFIELD) == 0) { CScaleformComplexObjectMgr::CheckAndSetupIfUninitialised(objectId); } return pObj->GetTextField(); } return NULL; } Color32 CComplexObject::GetColour() { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ((pObj->GetActionRequired() & CO_ACTION_UPDATE_COLOUR) == 0) { return pObj->GetColour(); } } return Color32(0,0,0,255); } u8 CComplexObject::GetAlpha() { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ((pObj->GetActionRequired() & CO_ACTION_UPDATE_ALPHA) == 0) { CScaleformComplexObjectMgr::CheckAndSetupIfUninitialised(objectId); } return pObj->GetAlpha(); } return 255; } s32 CComplexObject::GetDepth() { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { if ((pObj->GetActionRequired() & CO_ACTION_UPDATE_DEPTH) == 0) { CScaleformComplexObjectMgr::CheckAndSetupIfUninitialised(objectId); } return pObj->GetDepth(); } return 0; } atHashWithStringBank CComplexObject::GetObjectNameHash() { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { return pObj->GetObjectNameHash(); } return atHashWithStringBank::Null(); } s32 CComplexObject::GetMovieId() const { CComplexObjectArrayItem const * const c_obj = CScaleformComplexObjectMgr::FindObjectFromArrayIndexConst(objectId); return c_obj ? c_obj->GetMovieId() : INDEX_NONE; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::GetStageRoot // PURPOSE: gets the root object (stage) so we can add/get objects starting from here ///////////////////////////////////////////////////////////////////////////////////// CComplexObject CComplexObject::GetStageRoot(s32 iMovieId) { return CComplexObjectArrayItem::GetStageRoot(iMovieId); } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::GetObject // PURPOSE: returns pointer to the object requested. Will create an instance to use // if required or use an existing one previously set up. ///////////////////////////////////////////////////////////////////////////////////// CComplexObject CComplexObject::GetObject(const char *pMovieClipName1, const char *pMovieClipName2, const char *pMovieClipName3) { CComplexObject returnItem; CComplexObjectArrayItem * pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { #if __SCALEFORM_CRITICAL_SECTIONS SYS_CS_SYNC(gs_ScaleformMovieCS[pObj->GetMovieId()]); #endif CComplexObjectArrayItem *pNewObject = CScaleformComplexObjectMgr::FindOrCreateSlot(); // Grab again, as the "find or create" may grow our array, breaking the earlier pointer pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); returnItem.objectId = CComplexObjectArrayItem::GetObject(pObj, pNewObject, pMovieClipName1, pMovieClipName2, pMovieClipName3); } return returnItem; } //////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::CreateEmptyMovieClip // PURPOSE: creates an empty movie clip onto the stage at the specified depth. // Creates an object link to it and returns it. Name is the ref name ///////////////////////////////////////////////////////////////////////////////////// CComplexObject CComplexObject::CreateEmptyMovieClip(const char *pMovieClipName, s32 iDepth) { CComplexObject returnItem; CComplexObjectArrayItem * pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { #if __SCALEFORM_CRITICAL_SECTIONS SYS_CS_SYNC(gs_ScaleformMovieCS[pObj->GetMovieId()]); #endif CComplexObjectArrayItem *pNewObject = CScaleformComplexObjectMgr::FindOrCreateSlot(); // Grab again, as the "find or create" may grow our array, breaking the earlier pointer pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); returnItem.objectId = (CComplexObjectArrayItem::CreateEmptyMovieClip(pObj, pNewObject, pMovieClipName, iDepth)); } return returnItem; } //////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::AttachMovieClip // PURPOSE: attaches a movieclip onto the stage at the specified depth. Creates // an object link to it and returns it. Name is the ref name ///////////////////////////////////////////////////////////////////////////////////// CComplexObject CComplexObject::AttachMovieClip(const char *pMovieClipName, s32 iDepth) { CComplexObject returnItem; CComplexObjectArrayItem * pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { #if __SCALEFORM_CRITICAL_SECTIONS SYS_CS_SYNC(gs_ScaleformMovieCS[pObj->GetMovieId()]); #endif CComplexObjectArrayItem *pNewObject = CScaleformComplexObjectMgr::FindOrCreateSlot(); // Grab again, as the "find or create" may grow our array, breaking the earlier pointer pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (sfVerifyf(pMovieClipName, "AttachMovieClip requires a valid symbol name")) { returnItem.objectId = (CComplexObjectArrayItem::AttachMovieClip(pObj, pNewObject, pMovieClipName, iDepth)); } } return returnItem; } //////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::AttachMovieClip // PURPOSE: attaches a movieclip onto the stage at the specified depth. Creates // an object link to it and returns it. Name is the ref name ///////////////////////////////////////////////////////////////////////////////////// CComplexObject CComplexObject::AttachMovieClipInstance(const char *pMovieClipName, s32 iDepth) { CComplexObject returnItem; CComplexObjectArrayItem * pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { #if __SCALEFORM_CRITICAL_SECTIONS SYS_CS_SYNC(gs_ScaleformMovieCS[pObj->GetMovieId()]); #endif CComplexObjectArrayItem *pNewObject = CScaleformComplexObjectMgr::FindOrCreateSlot(); // Grab again, as the "find or create" may grow our array, breaking the earlier pointer pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (sfVerifyf(pMovieClipName, "AttachMovieClipInstance requires a valid symbol name")) { returnItem.objectId = (CComplexObjectArrayItem::AttachMovieClipInstance(pObj, pNewObject, pMovieClipName, iDepth)); } } return returnItem; } GFxValue *CComplexObject::GetComplexObjectGfxValue() { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(objectId); if (pObj) { return pObj->GetGfxValue(); } return NULL; } void CComplexObjectArrayItem::RemoveObject() { if (m_asObject.IsDefined()) { if (m_uState & CO_STATE_ATTACHED_BY_CODE) // only call removeMovieClip on objects that we attached { #if __BANK if (CScaleformComplexObjectMgr::DetailedLogging()) { sfDisplayf("COMPLEXOBJECT: removeMovieClip called on '%s' on movie %s (%d)", GetObjectNameHash().GetCStr(), CScaleformMgr::GetMovieFilename(m_iMovieId), m_iMovieId); } #endif // __BANK m_asObject.Invoke("removeMovieClip"); } m_asObject.SetUndefined(); } m_cPendingString[0] = NULL; m_cPendingString[1] = NULL; m_cPendingString[2] = NULL; for (s32 iBuf = 0; iBuf < MAX_CO_BUFFERS; iBuf++) { m_properties[iBuf].cTextfield = NULL; m_properties[iBuf].m_member.Reset(true); } m_bInitialised = false; m_uState = 0; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::CComplexObjectArrayItem // PURPOSE: constructor - initialise ///////////////////////////////////////////////////////////////////////////////////// CComplexObjectArrayItem::CComplexObjectArrayItem() : m_iPendingDepth( 0 ) , m_iPendingParentObjectUniqueId( INVALID_COMPLEX_OBJECT_ID ) , m_uState( 0 ) , m_iMovieId( -1 ) , m_iUniqueId( INVALID_COMPLEX_OBJECT_ID ) , m_bInitialised( false ) , m_bInitialisedEarly( false ) { InitProperties(); // default these } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::SetObject // PURPOSE: sets the GFxValue ///////////////////////////////////////////////////////////////////////////////////// void CComplexObjectArrayItem::SetObject(GFxValue newObject) { m_asObject = newObject; InitProperties(); m_bInitialised = true; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::SetUniqueId // PURPOSE: stores a unique identifier, used for checking later ///////////////////////////////////////////////////////////////////////////////////// void CComplexObjectArrayItem::SetUniqueId() { m_iUniqueId = CScaleformComplexObjectMgr::GetCurrentUniqueId(); } bool CComplexObjectArrayItem::IsActionRequiredOnEitherBuffer(u32 uflag) { for (s32 iBuf = 0; iBuf < MAX_CO_BUFFERS; iBuf++) { if (GetActionRequired(iBuf) & uflag) { return true; } } return false; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::InitProperties // PURPOSE: initialises the starting values of the properties on both buffers ///////////////////////////////////////////////////////////////////////////////////// void CComplexObjectArrayItem::InitProperties() { bool bObjectValid = (m_asObject.IsDefined() && m_asObject.IsDisplayObject()); GFxValue::DisplayInfo displayInfo; if (bObjectValid) m_asObject.GetDisplayInfo(&displayInfo); for (s32 iBuf = 0; iBuf < MAX_CO_BUFFERS; iBuf++) // initialise on both buffers unless (as nothing is using this yet) unless its been flagged for setting up { // initial values from the object itself: if (!IsActionRequiredOnEitherBuffer(CO_ACTION_UPDATE_POSITION_X)) { if (bObjectValid) m_properties[iBuf].vPosition.x = (float)displayInfo.GetX() / ACTIONSCRIPT_STAGE_SIZE_X; else m_properties[iBuf].vPosition.x = 0.0f; } if (!IsActionRequiredOnEitherBuffer(CO_ACTION_UPDATE_POSITION_Y)) { if (bObjectValid) m_properties[iBuf].vPosition.y = (float)displayInfo.GetY() / ACTIONSCRIPT_STAGE_SIZE_Y; else m_properties[iBuf].vPosition.y = 0.0f; } if (!IsActionRequiredOnEitherBuffer(CO_ACTION_UPDATE_SCALE)) { if (bObjectValid) m_properties[iBuf].vScale = Vector2((float)displayInfo.GetXScale(), (float)displayInfo.GetYScale()); else m_properties[iBuf].vScale = Vector2(100.0f, 100.0f); } if (!IsActionRequiredOnEitherBuffer(CO_ACTION_UPDATE_ROTATION)) { if (bObjectValid) m_properties[iBuf].fRotation = (float)displayInfo.GetRotation(); else m_properties[iBuf].fRotation = 0.f; } if (!IsActionRequiredOnEitherBuffer(CO_ACTION_UPDATE_MEMBERS)) { m_properties[iBuf].m_member.Reset(); } if (!IsActionRequiredOnEitherBuffer(CO_ACTION_UPDATE_WIDTH)) { if (bObjectValid) { GFxValue widthValue; m_asObject.GetMember("_width", &widthValue); m_properties[iBuf].fWidth = (float)widthValue.GetNumber(); } else { m_properties[iBuf].fWidth = 0.0f; } } if (!IsActionRequiredOnEitherBuffer(CO_ACTION_UPDATE_HEIGHT)) { if (bObjectValid) { GFxValue heightValue; m_asObject.GetMember("_height", &heightValue); m_properties[iBuf].fHeight = (float)heightValue.GetNumber(); } else { m_properties[iBuf].fHeight = 0.0f; } } if (!IsActionRequiredOnEitherBuffer(CO_ACTION_UPDATE_VISIBILITY)) { if (bObjectValid) { m_properties[iBuf].bVisible = displayInfo.GetVisible(); } else { m_properties[iBuf].bVisible = true; } } if (!IsActionRequiredOnEitherBuffer(CO_ACTION_UPDATE_FRAME)) { m_properties[iBuf].iFrame = 1; m_properties[iBuf].bFrameJumpPlay = false; } if ( (!IsActionRequiredOnEitherBuffer(CO_ACTION_UPDATE_TEXTFIELD)) && (!IsActionRequiredOnEitherBuffer(CO_ACTION_UPDATE_TEXTFIELD_HTML)) ) { m_properties[iBuf].cTextfield = NULL; } if (!IsActionRequiredOnEitherBuffer(CO_ACTION_UPDATE_COLOUR)) { m_properties[iBuf].colour.SetRed(0); m_properties[iBuf].colour.SetGreen(0); m_properties[iBuf].colour.SetBlue(0); if (!IsActionRequiredOnEitherBuffer(CO_ACTION_UPDATE_ALPHA)) m_properties[iBuf].colour.SetAlpha(s32( ( (float)displayInfo.GetAlpha() / 100.0f ) * 255.0f) ); } if( !IsActionRequiredOnEitherBuffer(CO_ACTION_UPDATE_DEPTH) ) { m_properties[iBuf].depth = 0; if (bObjectValid) { GFxValue result; if( m_asObject.Invoke("getDepth", &result ) ) { m_properties[iBuf].depth = (s32)result.GetNumber(); } } } } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::GetObject // PURPOSE: returns pointer to the object requested. Will create an instance to use // if required or use an existing one previously set up. ///////////////////////////////////////////////////////////////////////////////////// COMPLEX_OBJECT_ID CComplexObjectArrayItem::GetObject(CComplexObjectArrayItem *pObject, CComplexObjectArrayItem *pNewObject, const char *pMovieClipName1, const char *pMovieClipName2, const char *pMovieClipName3) { if (sfVerifyf(pObject, "CComplexObjectArrayItem::GetObject - object passed is invalid!")) { // just got to pass the parent object id into here and get it after the new one created instead OF calling it on it for it to work if (pNewObject) { pNewObject->SetMovieId(pObject->GetMovieId()); pNewObject->SetUniqueId(); pNewObject->SetObjectName(pMovieClipName1); for (s32 iBuf = 0; iBuf < MAX_CO_BUFFERS; iBuf++) { pNewObject->m_properties[iBuf].iActionRequired = 0; } if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) { pObject->GetObjectInternal(pNewObject, pMovieClipName1, pMovieClipName2, pMovieClipName3); } else { pNewObject->m_cPendingString[0] = NULL; pNewObject->m_cPendingString[1] = NULL; pNewObject->m_cPendingString[2] = NULL; s32 iIndex = 0; if (pMovieClipName1) pNewObject->m_cPendingString[iIndex++] = pMovieClipName1; if (pMovieClipName2) pNewObject->m_cPendingString[iIndex++] = pMovieClipName2; if (pMovieClipName3) pNewObject->m_cPendingString[iIndex++] = pMovieClipName3; pNewObject->m_iPendingParentObjectUniqueId = pObject->GetUniqueId(); pNewObject->m_uState |= CO_STATE_PENDING_GET_OBJECT; } return pNewObject->GetUniqueId(); } } return INVALID_COMPLEX_OBJECT_ID; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::GetObjectInternal // PURPOSE: returns pointer to the object requested. Will create an instance to use // if required or use an existing one previously set up. ///////////////////////////////////////////////////////////////////////////////////// CComplexObjectArrayItem *CComplexObjectArrayItem::GetObjectInternal(CComplexObjectArrayItem *pNewObject, const char *pMovieClipName1, const char *pMovieClipName2, const char *pMovieClipName3) { // // attach or get any items that this clip relies on now // if (IsPendingGetRoot()) { CComplexObjectArrayItem::GetStageRootInternal(this); } if (IsPendingCreate()) { if (m_iPendingParentObjectUniqueId != INVALID_COMPLEX_OBJECT_ID) { CComplexObjectArrayItem *pParentObject = CScaleformComplexObjectMgr::GetObjectFromUniqueId(m_iPendingParentObjectUniqueId); if (sfVerifyf(pParentObject, "CComplexObjectArrayItem::GetObjectInternal - Parent object with unique id %d not available to attach items to!", m_iPendingParentObjectUniqueId)) { pParentObject->CreateEmptyMovieClipInternal(this, m_iPendingDepth, m_cPendingString[0].c_str()); } } } if (IsPendingAttach()) { if (m_iPendingParentObjectUniqueId != INVALID_COMPLEX_OBJECT_ID) { CComplexObjectArrayItem *pParentObject = CScaleformComplexObjectMgr::GetObjectFromUniqueId(m_iPendingParentObjectUniqueId); if (sfVerifyf(pParentObject, "CComplexObjectArrayItem::GetObjectInternal - Parent object with unique id %d not available to attach items to!", m_iPendingParentObjectUniqueId)) { pParentObject->AttachMovieClipInternal(this, m_cPendingString[0].c_str(), m_iPendingDepth, m_cPendingString[1].c_str()); } } } if (IsPendingGet()) { if (m_iPendingParentObjectUniqueId != INVALID_COMPLEX_OBJECT_ID) { CComplexObjectArrayItem *pParentObject = CScaleformComplexObjectMgr::GetObjectFromUniqueId(m_iPendingParentObjectUniqueId); if (sfVerifyf(pParentObject, "CComplexObjectArrayItem::GetObjectInternal - Parent object with unique id %d not available to get items on!", m_iPendingParentObjectUniqueId)) { pParentObject->GetObjectInternal(this, m_cPendingString[0].c_str(), m_cPendingString[1].c_str(), m_cPendingString[2].c_str()); } } } // // get: // if (sfVerifyf(m_asObject.IsDefined(), "CComplexObjectArrayItem::GetObjectInternal - Parent object has an invalid GfxValue!")) { const char *pMovieClipName = NULL; if (pMovieClipName3 && pMovieClipName3[0] != '\0') { pMovieClipName = pMovieClipName3; } else if (pMovieClipName2 && pMovieClipName2[0] != '\0') { pMovieClipName = pMovieClipName2; } else if (pMovieClipName1 && pMovieClipName1[0] != '\0') { pMovieClipName = pMovieClipName1; } else { sfAssertf(0, "CComplexObjectArrayItem::GetObject: No valid movie clip passed"); return NULL; } if (pMovieClipName3 && pMovieClipName3[0] != '\0') { GFxValue pTempValue1, pTempValue2; m_asObject.GetMember(pMovieClipName1, &pTempValue1); pTempValue1.GetMember(pMovieClipName2, &pTempValue2); pTempValue2.GetMember(pMovieClipName3, &(pNewObject->m_asObject)); } else if (pMovieClipName2 && pMovieClipName2[0] != '\0') { GFxValue pTempValue; m_asObject.GetMember(pMovieClipName1, &pTempValue); pTempValue.GetMember(pMovieClipName2, &(pNewObject->m_asObject)); } else { m_asObject.GetMember(pMovieClipName1, &(pNewObject->m_asObject)); } if (sfVerifyf(pNewObject->m_asObject.IsDefined(), "CComplexObjectArrayItem::GetObjectInternal - object '%s' is not available on '%s'", pMovieClipName, GetObjectNameHash().GetCStr())) { #if __BANK if (CScaleformComplexObjectMgr::DetailedLogging()) { sfDisplayf("COMPLEXOBJECT: created object '%s' on movie %s (%d)", pMovieClipName, CScaleformMgr::GetMovieFilename(m_iMovieId), m_iMovieId); } #endif // __BANK pNewObject->m_uState &= ~CO_STATE_PENDING_GET_OBJECT; // empty any pending info here as we have now set it up pNewObject->m_cPendingString[0] = NULL; pNewObject->m_cPendingString[1] = NULL; pNewObject->m_cPendingString[2] = NULL; pNewObject->m_iPendingDepth = 0; pNewObject->m_iPendingParentObjectUniqueId = INVALID_COMPLEX_OBJECT_ID; pNewObject->m_uState |= CO_STATE_ACTIVE; pNewObject->InitProperties(); return pNewObject; } } return NULL; } void CComplexObjectArrayItem::SetToInvokeOnObject(bool bSet) { if (bSet) { m_uState |= CO_STATE_PENDING_INVOKE; } else { m_uState &= ~CO_STATE_PENDING_INVOKE; } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::ReleaseObjectInternal // PURPOSE: removes the object once finished with and deletes the entry from the // array ///////////////////////////////////////////////////////////////////////////////////// bool CComplexObjectArrayItem::ReleaseObjectInternal(s32 iIndex, bool bForce) { if (CSystem::IsThisThreadId(SYS_THREAD_RENDER) || bForce) // can only release on RT { if (sfVerifyf(iIndex < CScaleformComplexObjectMgr::sm_ObjectArray.GetCount(), "CComplexObjectArrayItem::ReleaseObject - Trying to remove object outside of array (%d/%d)", iIndex, CScaleformComplexObjectMgr::sm_ObjectArray.GetCount())) { #if __BANK if (CScaleformComplexObjectMgr::DetailedLogging()) { sfDisplayf("COMPLEXOBJECT: Object '%s' on movie %s (%d) has been removed", CScaleformComplexObjectMgr::sm_ObjectArray[iIndex].GetObjectNameHash().GetCStr(), CScaleformMgr::GetMovieFilename(CScaleformComplexObjectMgr::sm_ObjectArray[iIndex].GetMovieId()), CScaleformComplexObjectMgr::sm_ObjectArray[iIndex].GetMovieId()); } #endif // __BANK CComplexObjectArrayItem& currentObject = CScaleformComplexObjectMgr::sm_ObjectArray[iIndex]; /* // TODO - We could forcible remove invokes here rather than wait until later. // Another workaround was found that was less intrusive though if( currentObject.IsPendingInvoke() ) { CScaleformMgr::RemoveInvokesForComplexObject( currentObject.GetUniqueId() ); } */ currentObject.SetObjectName("\0"); currentObject.RemoveObject(); // if removing last in the array, then remove it, however if (iIndex == CScaleformComplexObjectMgr::sm_ObjectArray.GetCount()-1) { CScaleformComplexObjectMgr::sm_ObjectArray.Delete(iIndex); } return true; } } else { // flag to be released CScaleformComplexObjectMgr::sm_ObjectArray[iIndex].m_uState |= CO_STATE_FLAGGED_FOR_RELEASE; CScaleformComplexObjectMgr::sm_ObjectArray[iIndex].SetObjectName("\0"); } return false; } bool CComplexObjectArrayItem::ReleaseObject(CComplexObjectArrayItem *pObject, bool bForce) { if (CSystem::IsThisThreadId(SYS_THREAD_RENDER) || bForce) // can only release on RT { // this must be called within the safe zone s32 iIndex = CScaleformComplexObjectMgr::FindObjectIndex(pObject); if (iIndex >= 0) { return ReleaseObjectInternal(iIndex, bForce); } } else { // flag to be released pObject->m_uState |= CO_STATE_FLAGGED_FOR_RELEASE; } return false; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::FindOrCreateSlot // PURPOSE: reuse an empty slot or create a new one ///////////////////////////////////////////////////////////////////////////////////// CComplexObjectArrayItem *CScaleformComplexObjectMgr::FindOrCreateSlot() { for (s32 i = 0; i < CScaleformComplexObjectMgr::sm_ObjectArray.GetCount(); i++) { if (CScaleformComplexObjectMgr::sm_ObjectArray[i].IsUnused()) { CScaleformComplexObjectMgr::SetCurrentUniqueId(i); return (&CScaleformComplexObjectMgr::sm_ObjectArray[i]); } } CScaleformComplexObjectMgr::SetCurrentUniqueId(sm_ObjectArray.GetCount()); return &sm_ObjectArray.Grow(); } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::AttachMovieClip // PURPOSE: attaches a movieclip onto the stage at the specified depth. Creates // an object link to it and returns it. Name is the ref name ///////////////////////////////////////////////////////////////////////////////////// COMPLEX_OBJECT_ID CComplexObjectArrayItem::AttachMovieClip(CComplexObjectArrayItem *pObject, CComplexObjectArrayItem *pNewObject, const char *pMovieClipName, s32 iDepth) { if (sfVerifyf(pObject, "CComplexObjectArrayItem::AttachMovieClip - object passed is invalid!")) { if (pNewObject) { s32 const c_movieID = pObject->GetMovieId(); pNewObject->SetMovieId( c_movieID ); pNewObject->SetUniqueId(); char cInstanceName[64]; formatf(cInstanceName, "%s_%d", pMovieClipName, pNewObject->GetUniqueId(), NELEM(cInstanceName)); // unique instance name based on the unique id pNewObject->SetObjectName(cInstanceName); for (s32 iBuf = 0; iBuf < MAX_CO_BUFFERS; iBuf++) { pNewObject->m_properties[iBuf].iActionRequired = 0; } if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) { pObject->AttachMovieClipInternal(pNewObject, pMovieClipName, iDepth, cInstanceName); } else { pNewObject->m_cPendingString[0] = pMovieClipName; pNewObject->m_cPendingString[1] = cInstanceName; pNewObject->m_iPendingDepth = iDepth; pNewObject->m_iPendingParentObjectUniqueId = pObject->GetUniqueId(); pNewObject->m_uState |= CO_STATE_PENDING_ATTACH; } return pNewObject->GetUniqueId(); } } return INVALID_COMPLEX_OBJECT_ID; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::CreateEmptyMovieClip // PURPOSE: creates an empty movieclip onto the stage at the specified depth. Creates // an object link to it and returns it. Name is the ref name ///////////////////////////////////////////////////////////////////////////////////// COMPLEX_OBJECT_ID CComplexObjectArrayItem::CreateEmptyMovieClip(CComplexObjectArrayItem *pObject, CComplexObjectArrayItem *pNewObject, const char *pMovieClipName, s32 iDepth) { if (sfVerifyf(pObject, "CComplexObjectArrayItem::CreateEmptyMovieClip - object passed is invalid!")) { if (pNewObject) { s32 const c_movieID = pObject->GetMovieId(); pNewObject->SetMovieId( c_movieID ); pNewObject->SetUniqueId(); char cInstanceName[64]; formatf(cInstanceName, "%s_%d", pMovieClipName, pNewObject->GetUniqueId(), NELEM(cInstanceName)); // unique instance name based on the unique id pNewObject->SetObjectName(cInstanceName); for (s32 iBuf = 0; iBuf < MAX_CO_BUFFERS; iBuf++) { pNewObject->m_properties[iBuf].iActionRequired = 0; } if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) { pObject->CreateEmptyMovieClipInternal(pNewObject, iDepth, cInstanceName); } else { pNewObject->m_cPendingString[0] = cInstanceName; pNewObject->m_iPendingDepth = iDepth; pNewObject->m_iPendingParentObjectUniqueId = pObject->GetUniqueId(); pNewObject->m_uState |= CO_STATE_PENDING_CREATE; } return pNewObject->GetUniqueId(); } } return INVALID_COMPLEX_OBJECT_ID; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::AttachMovieClipInstance // PURPOSE: attaches a movieclip onto the stage at the specified depth. Creates // an object link to it and returns it - attaches it using the depth as // the ref name ///////////////////////////////////////////////////////////////////////////////////// COMPLEX_OBJECT_ID CComplexObjectArrayItem::AttachMovieClipInstance(CComplexObjectArrayItem *pObject, CComplexObjectArrayItem *pNewObject, const char *pMovieClipName, s32 iDepth) { if (sfVerifyf(pObject, "CComplexObjectArrayItem::GetObject - object passed is invalid!")) { if (pNewObject) { for (s32 iBuf = 0; iBuf < MAX_CO_BUFFERS; iBuf++) { pNewObject->m_properties[iBuf].iActionRequired = 0; } s32 const c_movieID = pObject->GetMovieId(); pNewObject->SetMovieId( c_movieID ); pNewObject->SetUniqueId(); char cInstanceName[64]; formatf(cInstanceName, "%s_%d", pMovieClipName, pNewObject->GetUniqueId(), NELEM(cInstanceName)); // unique instance name based on the unique id pNewObject->SetObjectName(cInstanceName); if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) { pObject->AttachMovieClipInternal(pNewObject, pMovieClipName, iDepth, cInstanceName); } else { pNewObject->m_cPendingString[0] = pMovieClipName; pNewObject->m_cPendingString[1] = cInstanceName; pNewObject->m_iPendingDepth = iDepth; pNewObject->m_iPendingParentObjectUniqueId = pObject->GetUniqueId(); pNewObject->m_uState |= CO_STATE_PENDING_ATTACH; } return pNewObject->GetUniqueId(); } } return INVALID_COMPLEX_OBJECT_ID; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::AttachMovieClipInternal // PURPOSE: attaches a movieclip onto the stage at the specified depth. ///////////////////////////////////////////////////////////////////////////////////// CComplexObjectArrayItem *CComplexObjectArrayItem::AttachMovieClipInternal(CComplexObjectArrayItem *pNewObject, const char *pMovieClipName, s32 iDepth, const char *pInstanceName) { // // attach or get any items that this clip relies on now // if (IsPendingGetRoot()) { CComplexObjectArrayItem::GetStageRootInternal(this); } if (IsPendingCreate()) { if (m_iPendingParentObjectUniqueId != INVALID_COMPLEX_OBJECT_ID) { CComplexObjectArrayItem *pParentObject = CScaleformComplexObjectMgr::GetObjectFromUniqueId(m_iPendingParentObjectUniqueId); if (sfVerifyf(pParentObject, "CComplexObjectArrayItem::AttachMovieClipInternal - Parent object with unique id %d not available to attach items to!", m_iPendingParentObjectUniqueId)) { pParentObject->CreateEmptyMovieClipInternal(this, m_iPendingDepth, m_cPendingString[0].c_str()); } } } if (IsPendingAttach()) { if (m_iPendingParentObjectUniqueId != INVALID_COMPLEX_OBJECT_ID) { CComplexObjectArrayItem *pParentObject = CScaleformComplexObjectMgr::GetObjectFromUniqueId(m_iPendingParentObjectUniqueId); if (sfVerifyf(pParentObject, "CComplexObjectArrayItem::AttachMovieClipInternal - Parent object with unique id %d not available to attach items to!", m_iPendingParentObjectUniqueId)) { pParentObject->AttachMovieClipInternal(this, m_cPendingString[0].c_str(), m_iPendingDepth, m_cPendingString[1].c_str()); } } } if (IsPendingGet()) { if (m_iPendingParentObjectUniqueId != INVALID_COMPLEX_OBJECT_ID) { CComplexObjectArrayItem *pParentObject = CScaleformComplexObjectMgr::GetObjectFromUniqueId(m_iPendingParentObjectUniqueId); if (sfVerifyf(pParentObject, "CComplexObjectArrayItem::AttachMovieClipInternal - Parent object with unique id %d not available to get items on!", m_iPendingParentObjectUniqueId)) { pParentObject->GetObjectInternal(this, m_cPendingString[0].c_str(), m_cPendingString[1].c_str(), m_cPendingString[2].c_str()); } } } // // attach: // if (sfVerifyf(m_asObject.IsDisplayObject(), "CComplexObjectArrayItem::AttachMovieClipInternal - Parent object has an invalid GfxValue!")) { #if __ASSERT #if __SCALEFORM_CRITICAL_SECTIONS SYS_CS_SYNC(gs_ScaleformMovieCS[GetMovieId()]); #endif if (sfVerifyf(!m_asObject.GFxValue::HasMember(pInstanceName), "CComplexObjectArrayItem::AttachMovieClipInternal - Trying to attach movieclip '%s' to object '%s' when it is already attached!", pMovieClipName, GetObjectNameHash().GetCStr())) #endif // __ASSERT { sfAssertf(iDepth < MAX_COMPLEX_OBJECT_DEPTH, "CComplexObjectArrayItem::AttachMovieClipInternal - Trying to attach an object at depth %d when max is %d", iDepth, MAX_COMPLEX_OBJECT_DEPTH); #if __ASSERT // // check if there is already an object at this depth: // GFxValue returnValue; GFxValue args[1]; args[0].SetNumber(iDepth); m_asObject.Invoke("getInstanceAtDepth", &returnValue, args, 1); if (returnValue.IsDefined()) { GFxValue instanceName; m_asObject.GetMember("_name", &instanceName); sfAssertf(0, "CComplexObjectArrayItem::AttachMovieClipInternal - Trying to attach %s at depth %d but '%s' object is already on the stage at this depth!", pMovieClipName, iDepth, instanceName.GetString()); } #endif // __ASSERT GFxValue asNewObject; if (sfVerifyf(m_asObject.AttachMovie(&asNewObject, pMovieClipName, pInstanceName, iDepth), "CComplexObjectArrayItem::AttachMovieClipInternal - Failed to attach symbol '%s', name '%s' to object '%s' - Object possibly not on stage", pMovieClipName, pInstanceName, GetObjectNameHash().GetCStr())) { pNewObject->SetObject(asNewObject); #if __BANK if (CScaleformComplexObjectMgr::DetailedLogging()) { sfDisplayf("COMPLEXOBJECT: attached object '%s' on movie %s (%d) at depth %d", GetObjectNameHash().GetCStr(), CScaleformMgr::GetMovieFilename(m_iMovieId), m_iMovieId, iDepth); } #endif // __BANK // now set it active pNewObject->m_uState &= ~CO_STATE_PENDING_ATTACH; // empty any pending info here as we have now set it up pNewObject->m_cPendingString[0] = NULL; pNewObject->m_cPendingString[1] = NULL; pNewObject->m_iPendingDepth = 0; pNewObject->m_iPendingParentObjectUniqueId = INVALID_COMPLEX_OBJECT_ID; pNewObject->m_uState |= CO_STATE_ACTIVE; pNewObject->m_uState |= CO_STATE_ATTACHED_BY_CODE; // flag that this was attached in code (so we can removemovieclip on it when we release this object) pNewObject->InitProperties(); return pNewObject; } } } return NULL; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::CreateEmptyMovieClipInternal // PURPOSE: creates an empty movieclip onto the stage at the specified depth. ///////////////////////////////////////////////////////////////////////////////////// CComplexObjectArrayItem *CComplexObjectArrayItem::CreateEmptyMovieClipInternal(CComplexObjectArrayItem *pNewObject, s32 iDepth, const char *pInstanceName) { // // attach or get any items that this clip relies on now // if (IsPendingGetRoot()) { CComplexObjectArrayItem::GetStageRootInternal(this); } if (IsPendingCreate()) { if (m_iPendingParentObjectUniqueId != INVALID_COMPLEX_OBJECT_ID) { CComplexObjectArrayItem *pParentObject = CScaleformComplexObjectMgr::GetObjectFromUniqueId(m_iPendingParentObjectUniqueId); if (sfVerifyf(pParentObject, "CComplexObjectArrayItem::CreateEmptyMovieClipInternal - Parent object with unique id %d not available to attach items to!", m_iPendingParentObjectUniqueId)) { pParentObject->CreateEmptyMovieClipInternal(this, m_iPendingDepth, m_cPendingString[0].c_str()); } } } if (IsPendingAttach()) { if (m_iPendingParentObjectUniqueId != INVALID_COMPLEX_OBJECT_ID) { CComplexObjectArrayItem *pParentObject = CScaleformComplexObjectMgr::GetObjectFromUniqueId(m_iPendingParentObjectUniqueId); if (sfVerifyf(pParentObject, "CComplexObjectArrayItem::CreateEmptyMovieClipInternal - Parent object with unique id %d not available to attach items to!", m_iPendingParentObjectUniqueId)) { pParentObject->AttachMovieClipInternal(this, m_cPendingString[0].c_str(), m_iPendingDepth, m_cPendingString[1].c_str()); } } } if (IsPendingGet()) { if (m_iPendingParentObjectUniqueId != INVALID_COMPLEX_OBJECT_ID) { CComplexObjectArrayItem *pParentObject = CScaleformComplexObjectMgr::GetObjectFromUniqueId(m_iPendingParentObjectUniqueId); if (sfVerifyf(pParentObject, "CComplexObjectArrayItem::CreateEmptyMovieClipInternal - Parent object with unique id %d not available to get items on!", m_iPendingParentObjectUniqueId)) { pParentObject->GetObjectInternal(this, m_cPendingString[0].c_str(), m_cPendingString[1].c_str(), m_cPendingString[2].c_str()); } } } // // create: // if (sfVerifyf(m_asObject.IsDisplayObject(), "CComplexObjectArrayItem::CreateEmptyMovieClipInternal - Parent object has an invalid GfxValue!")) { #if __ASSERT #if __SCALEFORM_CRITICAL_SECTIONS SYS_CS_SYNC(gs_ScaleformMovieCS[GetMovieId()]); #endif if (sfVerifyf(!m_asObject.GFxValue::HasMember(pInstanceName), "CComplexObjectArrayItem::CreateEmptyMovieClipInternal - Trying to create empty movieclip '%s' to object '%s' when it is already attached!", pInstanceName, GetObjectNameHash().GetCStr())) #endif { sfAssertf(iDepth < MAX_COMPLEX_OBJECT_DEPTH, "CComplexObjectArrayItem::CreateEmptyMovieClipInternal - Trying to create an empty movie clip object at depth %d when max is %d", iDepth, MAX_COMPLEX_OBJECT_DEPTH); #if __ASSERT // // check if there is already an object at this depth: // GFxValue returnValue; GFxValue args[1]; args[0].SetNumber(iDepth); m_asObject.Invoke("getInstanceAtDepth", &returnValue, args, 1); if (returnValue.IsDefined()) { GFxValue instanceName; m_asObject.GetMember("_name", &instanceName); sfAssertf(0, "CComplexObjectArrayItem::CreateEmptyMovieClipInternal - Trying to createEmptyMovieClip %s at depth %d but '%s' object is already on the stage at this depth!", pInstanceName, iDepth, instanceName.GetString()); } #endif // __ASSERT GFxValue asNewObject; if (sfVerifyf(m_asObject.CreateEmptyMovieClip(&asNewObject, pInstanceName, iDepth), "CComplexObjectArrayItem::CreateEmptyMovieClipInternal - Failed to createEmptyMovieClip '%s' to object '%s' - Object possibly not on stage", pInstanceName, GetObjectNameHash().GetCStr())) { pNewObject->SetObject(asNewObject); #if __BANK if (CScaleformComplexObjectMgr::DetailedLogging()) { sfDisplayf("COMPLEXOBJECT: created EmptyMovieClip object '%s' on movie %s (%d) at depth %d", GetObjectNameHash().GetCStr(), CScaleformMgr::GetMovieFilename(m_iMovieId), m_iMovieId, iDepth); } #endif // __BANK // now set it active pNewObject->m_uState &= ~CO_STATE_PENDING_CREATE; // empty any pending info here as we have now set it up pNewObject->m_cPendingString[0] = NULL; pNewObject->m_iPendingDepth = 0; pNewObject->m_iPendingParentObjectUniqueId = INVALID_COMPLEX_OBJECT_ID; pNewObject->m_uState |= CO_STATE_ACTIVE; pNewObject->m_uState |= CO_STATE_ATTACHED_BY_CODE; // flag that this was attached in code (so we can removemovieclip on it when we release this object) pNewObject->InitProperties(); return pNewObject; } } } return NULL; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::GetStageRoot // PURPOSE: gets the root object (stage) so we can add/get objects starting from here ///////////////////////////////////////////////////////////////////////////////////// CComplexObject CComplexObjectArrayItem::GetStageRoot(s32 iMovieId) { #if __SCALEFORM_CRITICAL_SECTIONS SYS_CS_SYNC(gs_ScaleformMovieCS[iMovieId]); #endif CComplexObjectArrayItem *pNewObject = CScaleformComplexObjectMgr::FindOrCreateSlot(); CComplexObject newItem; if (pNewObject) { pNewObject->SetMovieId(iMovieId); pNewObject->SetUniqueId(); pNewObject->SetObjectName("_root"); for (s32 iBuf = 0; iBuf < MAX_CO_BUFFERS; iBuf++) { pNewObject->m_properties[iBuf].iActionRequired = 0; } if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) { GetStageRootInternal(pNewObject); } else { pNewObject->m_uState |= CO_STATE_PENDING_GET_ROOT; } newItem.SetObjectId(pNewObject->GetUniqueId()); return newItem; } newItem.SetObjectId(INVALID_COMPLEX_OBJECT_ID); return newItem; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::GetStageRootInternal // PURPOSE: gets the root object (stage) so we can add/get objects starting from here ///////////////////////////////////////////////////////////////////////////////////// CComplexObjectArrayItem *CComplexObjectArrayItem::GetStageRootInternal(CComplexObjectArrayItem *pNewObject) { pNewObject->SetObject(CScaleformMgr::GetActionScriptObjectFromRoot(pNewObject->GetMovieId())); #if __BANK if (CScaleformComplexObjectMgr::DetailedLogging()) { sfDisplayf("COMPLEXOBJECT: created object '%s' on movie %s (%d)", pNewObject->GetObjectNameHash().GetCStr(), CScaleformMgr::GetMovieFilename(pNewObject->GetMovieId()), pNewObject->GetMovieId()); } #endif // __BANK // now set it active pNewObject->m_uState &= ~CO_STATE_PENDING_GET_ROOT; // empty any pending info here as we have now set it up pNewObject->m_cPendingString[0] = NULL; pNewObject->m_cPendingString[1] = NULL; pNewObject->m_iPendingDepth = 0; pNewObject->m_iPendingParentObjectUniqueId = INVALID_COMPLEX_OBJECT_ID; pNewObject->m_uState |= CO_STATE_ACTIVE; pNewObject->InitProperties(); return pNewObject; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::GotoFrame // PURPOSE: goto a frame of an object ///////////////////////////////////////////////////////////////////////////////////// void CComplexObjectArrayItem::GotoFrame(s32 iNewFrame, bool const andPlay) { s32 iThisBuffer = CScaleformComplexObjectMgr::GetBuffer(); if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) { #if __BANK if (CScaleformComplexObjectMgr::DetailedLogging()) { sfDisplayf("COMPLEXOBJECT: GotoAndStop(%d) called on object '%s' on movie %s (%d)", iNewFrame, GetObjectNameHash().GetCStr(), CScaleformMgr::GetMovieFilename(m_iMovieId), m_iMovieId); } #endif // __BANK if( andPlay ) { m_asObject.GotoAndPlay(iNewFrame); } else { m_asObject.GotoAndStop(iNewFrame); } } else { // update the position m_properties[iThisBuffer].iActionRequired |= CO_ACTION_UPDATE_FRAME; } m_properties[iThisBuffer].iFrame = iNewFrame; m_properties[iThisBuffer].bFrameJumpPlay = andPlay; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::GetCurrentFrame // PURPOSE: gets the current frame this object is set to ///////////////////////////////////////////////////////////////////////////////////// s32 CComplexObjectArrayItem::GetCurrentFrame() { return m_properties[CScaleformComplexObjectMgr::GetBuffer()].iFrame; } bool CComplexObjectArrayItem::PlayOnFrameJump() { return m_properties[CScaleformComplexObjectMgr::GetBuffer()].bFrameJumpPlay; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::GetTextField // PURPOSE: gets any text currently in the text field ///////////////////////////////////////////////////////////////////////////////////// const char *CComplexObjectArrayItem::GetTextField() { return m_properties[CScaleformComplexObjectMgr::GetBuffer()].cTextfield.c_str(); } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::GetTextFieldHTML // PURPOSE: gets any html text currently in the text field ///////////////////////////////////////////////////////////////////////////////////// const char * CComplexObjectArrayItem::GetTextFieldHTML() { return m_properties[CScaleformComplexObjectMgr::GetBuffer()].cTextfield.c_str(); } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::GetColour // PURPOSE: gets the current colour of the object ///////////////////////////////////////////////////////////////////////////////////// Color32 CComplexObjectArrayItem::GetColour() { return m_properties[CScaleformComplexObjectMgr::GetBuffer()].colour; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::GetColour // PURPOSE: gets the current colour of the object ///////////////////////////////////////////////////////////////////////////////////// u8 CComplexObjectArrayItem::GetAlpha() { return m_properties[CScaleformComplexObjectMgr::GetBuffer()].colour.GetAlpha(); } s32 CComplexObjectArrayItem::GetDepth() { return m_properties[CScaleformComplexObjectMgr::GetBuffer()].depth; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::SetTextField // PURPOSE: sets text in the text field on the object ///////////////////////////////////////////////////////////////////////////////////// void CComplexObjectArrayItem::SetTextField(const char *pText) { s32 iThisBuffer = CScaleformComplexObjectMgr::GetBuffer(); if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) { if (sfVerifyf(m_asObject.IsDefined(), "CComplexObjectArrayItem::SetTextField - Object '%s' gfxvalue is undefined!", GetObjectNameHash().GetCStr())) { #if __BANK if (CScaleformComplexObjectMgr::DetailedLogging()) { sfDisplayf("COMPLEXOBJECT: SetText(%s) called on object '%s' on movie %s (%d)", pText, GetObjectNameHash().GetCStr(), CScaleformMgr::GetMovieFilename(m_iMovieId), m_iMovieId); } #endif // __BANK m_asObject.SetText(pText); } } else { m_properties[iThisBuffer].iActionRequired |= CO_ACTION_UPDATE_TEXTFIELD; } m_properties[iThisBuffer].cTextfield = pText; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::SetTextFieldHTML // PURPOSE: sets html text in the text field on the object ///////////////////////////////////////////////////////////////////////////////////// void CComplexObjectArrayItem::SetTextFieldHTML( const char *pHtmlText ) { s32 iThisBuffer = CScaleformComplexObjectMgr::GetBuffer(); if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) { if (sfVerifyf(m_asObject.IsDefined(), "CComplexObjectArrayItem::SetTextFieldHTML - Object '%s' gfxvalue is undefined!", GetObjectNameHash().GetCStr())) { #if __BANK if (CScaleformComplexObjectMgr::DetailedLogging()) { sfDisplayf("COMPLEXOBJECT: SetText(%s) called on object '%s' on movie %s (%d)", pHtmlText, GetObjectNameHash().GetCStr(), CScaleformMgr::GetMovieFilename(m_iMovieId), m_iMovieId); } #endif // __BANK m_asObject.SetTextHTML(pHtmlText); } } else { m_properties[iThisBuffer].iActionRequired |= CO_ACTION_UPDATE_TEXTFIELD_HTML; } m_properties[iThisBuffer].cTextfield = pHtmlText; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::SetColour // PURPOSE: sets colour of the object ///////////////////////////////////////////////////////////////////////////////////// void CComplexObjectArrayItem::SetColour(Color32 const &colour) { s32 iThisBuffer = CScaleformComplexObjectMgr::GetBuffer(); if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) { if (sfVerifyf(m_asObject.IsDefined(), "CComplexObjectArrayItem::SetColour - Object '%s' gfxvalue is undefined!", GetObjectNameHash().GetCStr())) { #if __BANK if (CScaleformComplexObjectMgr::DetailedLogging()) { sfDisplayf("COMPLEXOBJECT: SetColour(%d,%d,%d,%d) called on object '%s' on movie %s (%d)", colour.GetRed(), colour.GetGreen(), colour.GetBlue(), colour.GetAlpha(), GetObjectNameHash().GetCStr(), CScaleformMgr::GetMovieFilename(m_iMovieId), m_iMovieId); } #endif // __BANK m_asObject.SetColorTransform(colour); GFxValue::DisplayInfo displayInfo; displayInfo.SetAlpha(colour.GetAlphaf() * 100.0f); m_asObject.SetDisplayInfo(displayInfo); } m_properties[iThisBuffer].colour.SetAlpha(colour.GetAlpha()); // set the alpha here as on RT the passed colour is the previously set 'SetAlpha' version of the alpha } else { m_properties[iThisBuffer].iActionRequired |= CO_ACTION_UPDATE_COLOUR; if (m_properties[iThisBuffer].iActionRequired & CO_ACTION_UPDATE_ALPHA) // no longer need to do alpha as we can do this during the colour { m_properties[iThisBuffer].iActionRequired &= ~CO_ACTION_UPDATE_ALPHA; } else { m_properties[iThisBuffer].colour.SetAlpha(colour.GetAlpha()); // if not set alpha then we use the alpha passed } } m_properties[iThisBuffer].colour.SetRed(colour.GetRed()); m_properties[iThisBuffer].colour.SetGreen(colour.GetGreen()); m_properties[iThisBuffer].colour.SetBlue(colour.GetBlue()); // do not set alpha here from the passed colour as we wish to retain whatever has been passed in as an alpha via SetAlpha } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::SetAlpha // PURPOSE: sets just the alpha of the object ///////////////////////////////////////////////////////////////////////////////////// void CComplexObjectArrayItem::SetAlpha( u8 const c_alpha ) { s32 const c_thisBuffer = CScaleformComplexObjectMgr::GetBuffer(); if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) { if (sfVerifyf(m_asObject.IsDefined(), "CComplexObjectArrayItem::SetAlpha - Object '%s' gfxvalue is undefined!", GetObjectNameHash().GetCStr())) { #if __BANK if (CScaleformComplexObjectMgr::DetailedLogging()) { sfDisplayf("COMPLEXOBJECT: SetAlpha(%u) called on object '%s' on movie %s (%d)", c_alpha, GetObjectNameHash().GetCStr(), CScaleformMgr::GetMovieFilename(m_iMovieId), m_iMovieId); } #endif // __BANK GFxValue::DisplayInfo displayInfo; displayInfo.SetAlpha(float((float)c_alpha / 255.0f) * 100.0f); m_asObject.SetDisplayInfo(displayInfo); } } else { if (m_properties[c_thisBuffer].iActionRequired & CO_ACTION_UPDATE_COLOUR) // if already pending colour, then adjust the alpha and set the colour again { m_properties[c_thisBuffer].colour.SetAlpha(c_alpha); SetColour(m_properties[c_thisBuffer].colour); return; } else { m_properties[c_thisBuffer].iActionRequired |= CO_ACTION_UPDATE_ALPHA; } } m_properties[c_thisBuffer].colour.SetAlpha(c_alpha); } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::SetDepth // PURPOSE: sets depth of the object ///////////////////////////////////////////////////////////////////////////////////// void CComplexObjectArrayItem::SetDepth( s32 const c_depth ) { s32 iThisBuffer = CScaleformComplexObjectMgr::GetBuffer(); if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) { if (sfVerifyf(m_asObject.IsDefined(), "CComplexObjectArrayItem::SetDepth - Object '%s' gfxvalue is undefined!", GetObjectNameHash().GetCStr())) { #if __BANK if (CScaleformComplexObjectMgr::DetailedLogging()) { sfDisplayf("COMPLEXOBJECT: SetDepth(%d) called on object '%s' on movie %s (%d)", c_depth, GetObjectNameHash().GetCStr(), CScaleformMgr::GetMovieFilename(m_iMovieId), m_iMovieId); } #endif // __BANK GFxValue args[1]; args[0].SetNumber(c_depth); GFxValue result; m_asObject.Invoke("swapDepths", &result, args, 1); } } else { m_properties[iThisBuffer].iActionRequired |= CO_ACTION_UPDATE_DEPTH; } m_properties[iThisBuffer].depth = c_depth; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::SetWidth // PURPOSE: sets the width of the object ///////////////////////////////////////////////////////////////////////////////////// void CComplexObjectArrayItem::SetWidth(float fNewWidth) { s32 iThisBuffer = CScaleformComplexObjectMgr::GetBuffer(); if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) { if (sfVerifyf(m_asObject.IsDefined(), "CComplexObjectArrayItem::SetWidth - Object '%s' gfxvalue is undefined!", GetObjectNameHash().GetCStr())) { #if __BANK if (CScaleformComplexObjectMgr::DetailedLogging()) { sfDisplayf("COMPLEXOBJECT: SetWidth(%0.2f) called on object '%s' on movie %s (%d)", fNewWidth, GetObjectNameHash().GetCStr(), CScaleformMgr::GetMovieFilename(m_iMovieId), m_iMovieId); } #endif // __BANK #if __FULL_SANITY_CHECKS if (sfVerifyf(m_asObject.HasMember("_width"), "CComplexObjectArrayItem::SetWidth - Cannot find member '_width'")) #endif // __FULL_SANITY_CHECKS { GFxValue widthValue; widthValue.SetNumber(fNewWidth); m_asObject.SetMember("_width", widthValue); } } } else { // update the position m_properties[iThisBuffer].iActionRequired |= CO_ACTION_UPDATE_WIDTH; } m_properties[iThisBuffer].fWidth = fNewWidth; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::SetHeight // PURPOSE: sets the height of the object ///////////////////////////////////////////////////////////////////////////////////// void CComplexObjectArrayItem::SetHeight( float fHeight ) { s32 iThisBuffer = CScaleformComplexObjectMgr::GetBuffer(); if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) { if (sfVerifyf(m_asObject.IsDefined(), "CComplexObjectArrayItem::SetHeight - Object '%s' gfxvalue is undefined!", GetObjectNameHash().GetCStr())) { #if __BANK if (CScaleformComplexObjectMgr::DetailedLogging()) { sfDisplayf("COMPLEXOBJECT: SetHeight(%0.2f) called on object '%s' on movie %s (%d)", fHeight, GetObjectNameHash().GetCStr(), CScaleformMgr::GetMovieFilename(m_iMovieId), m_iMovieId); } #endif // __BANK #if __FULL_SANITY_CHECKS if (sfVerifyf(m_asObject.HasMember("_height"), "CComplexObjectArrayItem::SetHeight - Cannot find member '_height'")) #endif // __FULL_SANITY_CHECKS { GFxValue heightValue; heightValue.SetNumber(fHeight); m_asObject.SetMember("_height", heightValue); } } } else { // update the position m_properties[iThisBuffer].iActionRequired |= CO_ACTION_UPDATE_HEIGHT; } m_properties[iThisBuffer].fHeight = fHeight; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::GetWidth // PURPOSE: returns the width of the object ///////////////////////////////////////////////////////////////////////////////////// float CComplexObjectArrayItem::GetWidth() { return m_properties[CScaleformComplexObjectMgr::GetBuffer()].fWidth; } float CComplexObjectArrayItem::GetHeight() { return m_properties[CScaleformComplexObjectMgr::GetBuffer()].fHeight; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::SetXScale // PURPOSE: Sets the X scale using a percentage value ///////////////////////////////////////////////////////////////////////////////////// void CComplexObjectArrayItem::SetXScale(float fScale) { SetScale(Vector2(fScale, GetScale().y)); } void CComplexObjectArrayItem::SetRotation( float const fRotation ) { s32 iThisBuffer = CScaleformComplexObjectMgr::GetBuffer(); if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) { if (sfVerifyf(m_asObject.IsDefined(), "CComplexObjectArrayItem::SetRotation - Object '%s' gfxvalue is undefined!", GetObjectNameHash().GetCStr())) { #if __BANK if (CScaleformComplexObjectMgr::DetailedLogging()) { sfDisplayf("COMPLEXOBJECT: SetRotation(%0.2f) called on object '%s' on movie %s (%d)", fRotation, GetObjectNameHash().GetCStr(), CScaleformMgr::GetMovieFilename(m_iMovieId), m_iMovieId); } #endif // __BANK GFxValue::DisplayInfo displayInfo; displayInfo.SetRotation( fRotation ); m_asObject.SetDisplayInfo(displayInfo); } } else { m_properties[iThisBuffer].iActionRequired |= CO_ACTION_UPDATE_ROTATION; } m_properties[iThisBuffer].fRotation = fRotation; } void CComplexObjectArrayItem::SetMember( const char *pInstanceName, bool const c_valueBool) { atString nullString; SetMemberInternal(pInstanceName, MEMBER_VALUE_TYPE_BOOL, c_valueBool, 0.0f, nullString); } void CComplexObjectArrayItem::SetMember( const char *pInstanceName, float const c_valueNumber) { atString nullString; SetMemberInternal(pInstanceName, MEMBER_VALUE_TYPE_BOOL, false, c_valueNumber, nullString); } void CComplexObjectArrayItem::SetMember( const char *pInstanceName, char const * const c_valueString) { SetMemberInternal(pInstanceName, MEMBER_VALUE_TYPE_BOOL, false, 0.0f, c_valueString); } void CComplexObjectArrayItem::SetMemberInternal(const char *pInstanceName, eMemberValueType const c_type, bool const c_valueBool, float const c_valueNumber, char const * const c_valueString) { s32 iThisBuffer = CScaleformComplexObjectMgr::GetBuffer(); if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) { if (sfVerifyf(m_asObject.IsDefined(), "CComplexObjectArrayItem::SetMember - Object '%s' gfxvalue is undefined!", GetObjectNameHash().GetCStr())) { #if __BANK if (CScaleformComplexObjectMgr::DetailedLogging()) { sfDisplayf("COMPLEXOBJECT: SetMember called on object '%s' on movie %s (%d)", GetObjectNameHash().GetCStr(), CScaleformMgr::GetMovieFilename(m_iMovieId), m_iMovieId); } #endif // __BANK GFxValue gfxValue; switch (c_type) { case MEMBER_VALUE_TYPE_BOOL: { gfxValue.SetBoolean(c_valueBool); break; } case MEMBER_VALUE_TYPE_NUMBER: { gfxValue.SetNumber((double)c_valueNumber); break; } case MEMBER_VALUE_TYPE_STRING: { gfxValue.SetString(c_valueString); break; } default: { // NOP } } m_asObject.SetMember(pInstanceName, gfxValue); } } else { m_properties[iThisBuffer].iActionRequired |= CO_ACTION_UPDATE_MEMBERS; } sComplectObjectMembers *newSetMember = NULL; const atHashString c_instanceNameHash = atHashString(pInstanceName); for (s32 i = 0; i < m_properties[iThisBuffer].m_member.GetCount(); i++) { const atHashString c_thisInstanceNameHash = atHashString(m_properties[iThisBuffer].m_member[i].m_instanceName); if (c_instanceNameHash == c_thisInstanceNameHash) { newSetMember = &m_properties[iThisBuffer].m_member[i]; break; } } if (!newSetMember) { newSetMember = &(m_properties[iThisBuffer].m_member).Grow(); } newSetMember->m_instanceName = pInstanceName; newSetMember->m_update = true; switch (c_type) { case MEMBER_VALUE_TYPE_BOOL: { newSetMember->value_bool = c_valueBool; newSetMember->m_type = MEMBER_VALUE_TYPE_BOOL; break; } case MEMBER_VALUE_TYPE_NUMBER: { newSetMember->value_number = c_valueNumber; newSetMember->m_type = MEMBER_VALUE_TYPE_NUMBER; break; } case MEMBER_VALUE_TYPE_STRING: { newSetMember->value_string = c_valueString; newSetMember->m_type = MEMBER_VALUE_TYPE_STRING; break; } default: { // NOP } } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::SetScale // PURPOSE: sets the scale based on a percentage ///////////////////////////////////////////////////////////////////////////////////// void CComplexObjectArrayItem::SetScale(Vector2 const& vNewScale) { s32 iThisBuffer = CScaleformComplexObjectMgr::GetBuffer(); if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) { if (sfVerifyf(m_asObject.IsDefined(), "CComplexObjectArrayItem::SetScale - Object '%s' gfxvalue is undefined!", GetObjectNameHash().GetCStr())) { #if __BANK if (CScaleformComplexObjectMgr::DetailedLogging()) { sfDisplayf("COMPLEXOBJECT: SetScale(%0.2f,%0.2f) called on object '%s' on movie %s (%d)", vNewScale.x, vNewScale.y, GetObjectNameHash().GetCStr(), CScaleformMgr::GetMovieFilename(m_iMovieId), m_iMovieId); } #endif // __BANK GFxValue::DisplayInfo displayInfo; displayInfo.SetScale(vNewScale.x, vNewScale.y); m_asObject.SetDisplayInfo(displayInfo); } } else { m_properties[iThisBuffer].iActionRequired |= CO_ACTION_UPDATE_SCALE; } m_properties[iThisBuffer].vScale = vNewScale; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::GetScale // PURPOSE: returns the current scale value of the object ///////////////////////////////////////////////////////////////////////////////////// Vector2 CComplexObjectArrayItem::GetScale() { s32 iThisBuffer = CScaleformComplexObjectMgr::GetBuffer(); return Vector2(m_properties[iThisBuffer].vScale.x, m_properties[iThisBuffer].vScale.y); } float CComplexObjectArrayItem::GetRotation() { s32 iThisBuffer = CScaleformComplexObjectMgr::GetBuffer(); return m_properties[iThisBuffer].fRotation; } eMemberValueType CComplexObjectArrayItem::GetMember(const char *pInstanceName, bool &out_valueBool, float &out_valueNumber, atString &out_valueString) { s32 const c_thisBuffer = CScaleformComplexObjectMgr::GetBuffer(); const atHashString c_instanceNameHash = atHashString(pInstanceName); for (s32 i = 0; i < m_properties[c_thisBuffer].m_member.GetCount(); i++) { const atHashString c_thisInstanceNameHash = atHashString(m_properties[c_thisBuffer].m_member[i].m_instanceName); if (c_instanceNameHash == c_thisInstanceNameHash) { switch (m_properties[c_thisBuffer].m_member[i].m_type) { case MEMBER_VALUE_TYPE_BOOL: { out_valueBool = m_properties[c_thisBuffer].m_member[i].value_bool; return m_properties[c_thisBuffer].m_member[i].m_type; } case MEMBER_VALUE_TYPE_NUMBER: { out_valueNumber = m_properties[c_thisBuffer].m_member[i].value_number; return m_properties[c_thisBuffer].m_member[i].m_type; } case MEMBER_VALUE_TYPE_STRING: { out_valueString = m_properties[c_thisBuffer].m_member[i].value_string; return m_properties[c_thisBuffer].m_member[i].m_type; } default: { // NOP } } break; } } return MEMBER_VALUE_TYPE_INVALID; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::SetPosition // PURPOSE: sets the pos of an object in 0-1 space. Does conversion to stage size // (assume standard 720p size for GTAV) here, so code can continue to // work in 0-1 ///////////////////////////////////////////////////////////////////////////////////// void CComplexObjectArrayItem::SetPosition(Vector2 const& vPos) { SetPositionInPixels(Vector2(vPos.x * ACTIONSCRIPT_STAGE_SIZE_X, vPos.y * ACTIONSCRIPT_STAGE_SIZE_Y)); } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::SetPositionInPixels // PURPOSE: sets the position of the object in pixels relative to the AS stage ///////////////////////////////////////////////////////////////////////////////////// void CComplexObjectArrayItem::SetPositionInPixels(Vector2 const& vPixelPos) { s32 iThisBuffer = CScaleformComplexObjectMgr::GetBuffer(); if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) { if (sfVerifyf(m_asObject.IsDefined(), "CComplexObjectArrayItem::SetPositionInPixels - Object '%s' gfxvalue is undefined!", GetObjectNameHash().GetCStr())) { #if __BANK if (CScaleformComplexObjectMgr::DetailedLogging()) { sfDisplayf("COMPLEXOBJECT: SetPosition(%0.2f,%0.2f) called on object '%s' on movie %s (%d)", vPixelPos.x, vPixelPos.y, GetObjectNameHash().GetCStr(), CScaleformMgr::GetMovieFilename(m_iMovieId), m_iMovieId); } #endif // __BANK GFxValue::DisplayInfo displayInfo; displayInfo.SetPosition(vPixelPos.x, vPixelPos.y); m_asObject.SetDisplayInfo(displayInfo); } } else { m_properties[iThisBuffer].iActionRequired |= CO_ACTION_UPDATE_POSITION_X; m_properties[iThisBuffer].iActionRequired |= CO_ACTION_UPDATE_POSITION_Y; } m_properties[iThisBuffer].vPosition.x = vPixelPos.x / ACTIONSCRIPT_STAGE_SIZE_X; m_properties[iThisBuffer].vPosition.y = vPixelPos.y / ACTIONSCRIPT_STAGE_SIZE_Y; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::GetPosition // PURPOSE: returns the position of the object on the screen in 0-1 space // this is currently relative to its parent, but we probably want to return // it in screen space to make this useful ///////////////////////////////////////////////////////////////////////////////////// Vector2 CComplexObjectArrayItem::GetPosition() { s32 iThisBuffer = CScaleformComplexObjectMgr::GetBuffer(); return Vector2(m_properties[iThisBuffer].vPosition.x, m_properties[iThisBuffer].vPosition.y); } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::GetPositionInPixels // PURPOSE: returns the position of the object in pixels relative to its parent // object ///////////////////////////////////////////////////////////////////////////////////// Vector2 CComplexObjectArrayItem::GetPositionInPixels() { return Vector2(m_properties[CScaleformComplexObjectMgr::GetBuffer()].vPosition.x * ACTIONSCRIPT_STAGE_SIZE_X, m_properties[CScaleformComplexObjectMgr::GetBuffer()].vPosition.y * ACTIONSCRIPT_STAGE_SIZE_Y); } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::GetXPositionInPixels // PURPOSE: returns the X position in pixels relative to its parent object ///////////////////////////////////////////////////////////////////////////////////// float CComplexObjectArrayItem::GetXPositionInPixels() { return m_properties[CScaleformComplexObjectMgr::GetBuffer()].vPosition.x * ACTIONSCRIPT_STAGE_SIZE_X; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::GetYPositionInPixels // PURPOSE: returns the Y position in pixels relative to its parent object ///////////////////////////////////////////////////////////////////////////////////// float CComplexObjectArrayItem::GetYPositionInPixels() { return m_properties[CScaleformComplexObjectMgr::GetBuffer()].vPosition.y * ACTIONSCRIPT_STAGE_SIZE_Y; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::SetXPositionInPixels // PURPOSE: sets the x position of the object in pixels relative to its parent object ///////////////////////////////////////////////////////////////////////////////////// void CComplexObjectArrayItem::SetXPositionInPixels(float fPixelPos) { s32 iThisBuffer = CScaleformComplexObjectMgr::GetBuffer(); if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) { if (sfVerifyf(m_asObject.IsDefined(), "CComplexObjectArrayItem::SetXPositionInPixels - Object '%s' gfxvalue is undefined!", GetObjectNameHash().GetCStr())) { #if __BANK if (CScaleformComplexObjectMgr::DetailedLogging()) { sfDisplayf("COMPLEXOBJECT: SetXPositionInPixels(%0.2f) called on object '%s' on movie %s (%d)", fPixelPos, GetObjectNameHash().GetCStr(), CScaleformMgr::GetMovieFilename(m_iMovieId), m_iMovieId); } #endif // __BANK GFxValue::DisplayInfo displayInfo; displayInfo.SetX( fPixelPos ); m_asObject.SetDisplayInfo(displayInfo); } } else { m_properties[iThisBuffer].iActionRequired |= CO_ACTION_UPDATE_POSITION_X; } m_properties[iThisBuffer].vPosition.x = fPixelPos / ACTIONSCRIPT_STAGE_SIZE_X; } void CComplexObjectArrayItem::SetYPositionInPixels( float fPixelPos ) { s32 iThisBuffer = CScaleformComplexObjectMgr::GetBuffer(); if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) { if (sfVerifyf(m_asObject.IsDefined(), "CComplexObjectArrayItem::SetYPositionInPixels - Object '%s' gfxvalue is undefined!", GetObjectNameHash().GetCStr())) { #if __BANK if (CScaleformComplexObjectMgr::DetailedLogging()) { sfDisplayf("COMPLEXOBJECT: SetYPositionInPixels(%0.2f) called on object '%s' on movie %s (%d)", fPixelPos, GetObjectNameHash().GetCStr(), CScaleformMgr::GetMovieFilename(m_iMovieId), m_iMovieId); } #endif // __BANK GFxValue::DisplayInfo displayInfo; displayInfo.SetY( fPixelPos ); m_asObject.SetDisplayInfo(displayInfo); } } else { m_properties[iThisBuffer].iActionRequired |= CO_ACTION_UPDATE_POSITION_Y; } m_properties[iThisBuffer].vPosition.y = fPixelPos / ACTIONSCRIPT_STAGE_SIZE_Y; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::AdjustXPositionInPixels // PURPOSE: increments/decrements the current position by X amount of pixels ///////////////////////////////////////////////////////////////////////////////////// void CComplexObjectArrayItem::AdjustXPositionInPixels(float fPixels) { if (fPixels == 0.0f) // if we are trying to adjust by 0.0f then lets not bother! return; s32 iThisBuffer = CScaleformComplexObjectMgr::GetBuffer(); if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) { if (sfVerifyf(m_asObject.IsDefined(), "CComplexObjectArrayItem::AdjustXPositionInPixels - Object '%s' gfxvalue is undefined!", GetObjectNameHash().GetCStr())) { GFxValue::DisplayInfo displayInfo; m_asObject.GetDisplayInfo(&displayInfo); #if __BANK if (CScaleformComplexObjectMgr::DetailedLogging()) { sfDisplayf("COMPLEXOBJECT: Adjusting X position from %0.2f by %0.2f resulting in %0.02f called on object '%s' on movie %s (%d)", displayInfo.GetX(), fPixels, displayInfo.GetX()+fPixels, GetObjectNameHash().GetCStr(), CScaleformMgr::GetMovieFilename(m_iMovieId), m_iMovieId); } #endif // __BANK displayInfo.SetX(displayInfo.GetX()+fPixels); m_asObject.SetDisplayInfo(displayInfo); } } else { m_properties[iThisBuffer].iActionRequired |= CO_ACTION_UPDATE_POSITION_X; } m_properties[iThisBuffer].vPosition.x += (fPixels / ACTIONSCRIPT_STAGE_SIZE_X); } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::SetVisible // PURPOSE: sets the object to be visible on the stage ///////////////////////////////////////////////////////////////////////////////////// void CComplexObjectArrayItem::SetVisible(bool bValue) { s32 iThisBuffer = CScaleformComplexObjectMgr::GetBuffer(); if (CSystem::IsThisThreadId(SYS_THREAD_RENDER)) { if (sfVerifyf(m_asObject.IsDefined(), "CComplexObjectArrayItem::SetVisible - Object '%s' gfxvalue is undefined!", GetObjectNameHash().GetCStr())) { #if __BANK if (CScaleformComplexObjectMgr::DetailedLogging()) { sfDisplayf("COMPLEXOBJECT: SetVisible(%s) called on object '%s' on movie %s (%d)", (bValue ? "TRUE" : "FALSE"), GetObjectNameHash().GetCStr(), CScaleformMgr::GetMovieFilename(m_iMovieId), m_iMovieId); } #endif // __BANK GFxValue::DisplayInfo displayInfo; displayInfo.SetVisible(bValue); m_asObject.SetDisplayInfo(displayInfo); } } else { #if __BANK if (CScaleformComplexObjectMgr::DetailedLogging()) { sfDisplayf("COMPLEXOBJECT: Wants to set visible to object '%s' on %s on movie %s (%d)", (bValue ? "TRUE" : "FALSE"), GetObjectNameHash().GetCStr(), CScaleformMgr::GetMovieFilename(m_iMovieId), m_iMovieId); } #endif m_properties[iThisBuffer].iActionRequired |= CO_ACTION_UPDATE_VISIBILITY; } m_properties[iThisBuffer].bVisible = bValue; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::IsVisible // PURPOSE: is this object currently visible on the stage? ///////////////////////////////////////////////////////////////////////////////////// bool CComplexObjectArrayItem::IsVisible() { return m_properties[CScaleformComplexObjectMgr::GetBuffer()].bVisible; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::GetActionRequired // PURPOSE: gets what action is required so we can process each object ///////////////////////////////////////////////////////////////////////////////////// u32 CComplexObjectArrayItem::GetActionRequired(s32 iBuf) { if (iBuf == -1) { return m_properties[CScaleformComplexObjectMgr::GetBuffer()].iActionRequired; } else { return m_properties[iBuf].iActionRequired; } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CComplexObjectArrayItem::CheckAndSetupIfUninitialised // PURPOSE: checks if uninitialised, and if so lock and initialise this object // and any parents it may have on the update thread ///////////////////////////////////////////////////////////////////////////////////// void CScaleformComplexObjectMgr::CheckAndSetupIfUninitialised(COMPLEX_OBJECT_ID objectId) { const s32 c_iIndex = (s32)objectId; if (sfVerifyf(c_iIndex >= 0 && c_iIndex < sm_ObjectArray.GetCount(), "CScaleformComplexObjectMgr::CheckAndSetupIfUninitialised - Object '%d' outside of sm_ObjectArray", c_iIndex)) { if ( (!sm_ObjectArray[c_iIndex].IsInitialised()) && (!CSystem::IsThisThreadId(SYS_THREAD_RENDER)) ) // if uninitialised, and called on the update thread, then set it up now { CScaleformComplexObjectMgr::AttachOrGetObjectOnStage(objectId); } } } void CComplexObjectArrayItem::SetObjectName(const char *pObjectName) { m_ObjectNameHash = atHashWithStringBank(pObjectName); } void CComplexObjectArrayItem::SetMovieId(s32 const iNewMovieId) { sfFatalAssertf( CScaleformMgr::IsMovieIdInRange( iNewMovieId ), "CComplexObjectArrayItem::SetMovieId - Attaching to invalid movie %d", iNewMovieId ); m_iMovieId = iNewMovieId; } void CScaleformComplexObjectMgr::Init() { sm_ObjectArray.Reset(); #if RSG_BANK ms_bUseDetailedLogging = PARAM_complexObjectDetailedLogging.Get(); #endif // RSG_BANK } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CScaleformComplexObjectMgr::FindObjectIndex // PURPOSE: returns the index in the array of the passed object ///////////////////////////////////////////////////////////////////////////////////// s32 CScaleformComplexObjectMgr::FindObjectIndex(CComplexObjectArrayItem *pObject) { for (s32 i = 0; i < sm_ObjectArray.GetCount(); i++) { if (sm_ObjectArray[i].GetUniqueId() == pObject->GetUniqueId()) { return i; } } sfAssertf(0, "CScaleformComplexObjectMgr::FindObjectIndex: Could not find index from the object!"); return -1; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CScaleformComplexObjectMgr::FindObjectIndex // PURPOSE: returns the object with the passed unique ID ///////////////////////////////////////////////////////////////////////////////////// CComplexObjectArrayItem const * CScaleformComplexObjectMgr::FindObjectFromArrayIndexConst( COMPLEX_OBJECT_ID const objectId ) { if (objectId != INVALID_COMPLEX_OBJECT_ID) { if (sfVerifyf(objectId >= 0 && objectId < sm_ObjectArray.GetCount(), "CScaleformComplexObjectMgr::FindObjectFromArrayIndex - Object '%d' outside of sm_ObjectArray", objectId)) { return &sm_ObjectArray[objectId]; } } return NULL; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CScaleformComplexObjectMgr::FindNumberOfObjectsInUseByMovie // PURPOSE: returns the number of objects that is currently set up under the passed // movie id. This allows us to detect left overs when a movie gets deleted ///////////////////////////////////////////////////////////////////////////////////// s32 CScaleformComplexObjectMgr::FindNumberOfObjectsInUseByMovie(s32 iScaleformMovieId) { s32 iCount = 0; for (s32 i = 0; i < sm_ObjectArray.GetCount(); i++) { if (sm_ObjectArray[i].GetMovieId() == iScaleformMovieId) { if (sm_ObjectArray[i].IsActive() && !sm_ObjectArray[i].IsPendingRelease() && !sm_ObjectArray[i].IsPendingFlaggedForRelease()) { iCount++; } } } return iCount; } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CScaleformComplexObjectMgr::AttachOrGetObjectOnStage // PURPOSE: attaches or gets an object on the stage ///////////////////////////////////////////////////////////////////////////////////// void CScaleformComplexObjectMgr::AttachOrGetObjectOnStage(COMPLEX_OBJECT_ID objectId) { #if __SCALEFORM_CRITICAL_SECTIONS SYS_CS_SYNC(gs_ScaleformMovieCS[sm_ObjectArray[objectId].GetMovieId()]); #endif if (sfVerifyf(objectId >= 0 && objectId < sm_ObjectArray.GetCount(), "CScaleformComplexObjectMgr::AttachOrGetObjectOnStage - Object '%d' outside of sm_ObjectArray", objectId)) { // // get any roots we need // if (sm_ObjectArray[objectId].IsPendingGetRoot()) { CComplexObjectArrayItem::GetStageRootInternal(&sm_ObjectArray[objectId]); } else if (sm_ObjectArray[objectId].IsPendingCreate()) { CComplexObjectArrayItem *pParentObject = CScaleformComplexObjectMgr::GetObjectFromUniqueId(sm_ObjectArray[objectId].m_iPendingParentObjectUniqueId); if (sfVerifyf(pParentObject, "CComplexObjectArrayItem::PerformAllOutstandingActionsOnRT - Parent object with unique id %d not available to createEmptyMovieClip items to!", sm_ObjectArray[objectId].m_iPendingParentObjectUniqueId)) { pParentObject->CreateEmptyMovieClipInternal(&sm_ObjectArray[objectId], sm_ObjectArray[objectId].m_iPendingDepth, sm_ObjectArray[objectId].m_cPendingString[0].c_str()); // if we are creating this early, then set visibility to false as we dont want to show it until its been fully set up if (sm_ObjectArray[objectId].m_asObject.IsDefined()) { sm_ObjectArray[objectId].m_bInitialised = true; GFxValue::DisplayInfo displayInfo; displayInfo.SetVisible(false); sm_ObjectArray[objectId].m_asObject.SetDisplayInfo(displayInfo); sm_ObjectArray[objectId].m_bInitialisedEarly = true; } } } else if (sm_ObjectArray[objectId].IsPendingAttach()) { CComplexObjectArrayItem *pParentObject = CScaleformComplexObjectMgr::GetObjectFromUniqueId(sm_ObjectArray[objectId].m_iPendingParentObjectUniqueId); if (sfVerifyf(pParentObject, "CComplexObjectArrayItem::PerformAllOutstandingActionsOnRT - Parent object with unique id %d not available to attach items to!", sm_ObjectArray[objectId].m_iPendingParentObjectUniqueId)) { pParentObject->AttachMovieClipInternal(&sm_ObjectArray[objectId], sm_ObjectArray[objectId].m_cPendingString[0].c_str(), sm_ObjectArray[objectId].m_iPendingDepth, sm_ObjectArray[objectId].m_cPendingString[1].c_str()); // if we are attaching this early, then set visibility to false as we dont want to show it until its been fully set up if (sm_ObjectArray[objectId].m_asObject.IsDefined()) { sm_ObjectArray[objectId].m_bInitialised = true; GFxValue::DisplayInfo displayInfo; displayInfo.SetVisible(false); sm_ObjectArray[objectId].m_asObject.SetDisplayInfo(displayInfo); sm_ObjectArray[objectId].m_bInitialisedEarly = true; } } } else if (sm_ObjectArray[objectId].IsPendingGet()) { CComplexObjectArrayItem *pParentObject = CScaleformComplexObjectMgr::GetObjectFromUniqueId(sm_ObjectArray[objectId].m_iPendingParentObjectUniqueId); if (sfVerifyf(pParentObject, "CComplexObjectArrayItem::PerformAllOutstandingActionsOnRT - Parent object with unique id %d not available to get items on!", sm_ObjectArray[objectId].m_iPendingParentObjectUniqueId)) { pParentObject->GetObjectInternal(&sm_ObjectArray[objectId], sm_ObjectArray[objectId].m_cPendingString[0].c_str(), sm_ObjectArray[objectId].m_cPendingString[1].c_str(), sm_ObjectArray[objectId].m_cPendingString[2].c_str()); // if we are getting this early, then set visibility to false as we dont want to show it until its been fully set up if (sm_ObjectArray[objectId].m_asObject.IsDefined()) { sm_ObjectArray[objectId].m_bInitialised = true; GFxValue::DisplayInfo displayInfo; displayInfo.SetVisible(false); sm_ObjectArray[objectId].m_asObject.SetDisplayInfo(displayInfo); sm_ObjectArray[objectId].m_bInitialisedEarly = true; } } } } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CScaleformComplexObjectMgr::PerformAllOutstandingActionsOnRT // PURPOSE: goes though each object and if we have actions that have been set on the // UT, we action these here on the RT ///////////////////////////////////////////////////////////////////////////////////// void CScaleformComplexObjectMgr::PerformAllOutstandingActionsOnRT() { s32 const c_buffer = GetBuffer(); sfAssertf( c_buffer == CO_BUFFER_RENDER, "Processing actions on wrong thread" ); // // if this was initialised early, then turn the visiblility back on now // for (s32 i = 0; i < sm_ObjectArray.GetCount(); i++) { CComplexObjectArrayItem& objRef = sm_ObjectArray[i]; #if __SCALEFORM_CRITICAL_SECTIONS int const c_movieId = objRef.GetMovieId(); SYS_CS_SYNC(gs_ScaleformMovieCS[ c_movieId ]); #endif if ( objRef.m_bInitialised && objRef.m_bInitialisedEarly && !objRef.IsPendingInvoke()) { if ( objRef.IsVisible()) // only set it to true if the object has been set to be visible otherwise simply keep it invisible { GFxValue::DisplayInfo displayInfo; displayInfo.SetVisible(true); sm_ObjectArray[i].m_asObject.SetDisplayInfo(displayInfo); } objRef.m_bInitialisedEarly = false; } } // // set depth of any items already on the stage 1st before we attach anything new (so we dont get new items on old items depths before they are updated) // for (s32 i = 0; i < sm_ObjectArray.GetCount(); i++) { #if __SCALEFORM_CRITICAL_SECTIONS SYS_CS_SYNC(gs_ScaleformMovieCS[sm_ObjectArray[i].GetMovieId()]); #endif CComplexObjectArrayItem& objRef = sm_ObjectArray[ i ]; if( objRef.IsActive() || objRef.IsPendingFlaggedForRelease() ) { if( objRef.GetActionRequired() != 0 ) { if (objRef.m_asObject.IsDefined()) { if (objRef.GetActionRequired() & CO_ACTION_UPDATE_DEPTH) { objRef.SetDepth(objRef.GetDepth()); objRef.m_properties[c_buffer ].iActionRequired &= ~CO_ACTION_UPDATE_DEPTH; } } } } } // // get any roots we need // for (s32 i = 0; i < sm_ObjectArray.GetCount(); i++) { #if __SCALEFORM_CRITICAL_SECTIONS SYS_CS_SYNC(gs_ScaleformMovieCS[sm_ObjectArray[i].GetMovieId()]); #endif CComplexObjectArrayItem& objRef = sm_ObjectArray[i]; if ( objRef.IsPendingGetRoot()) { CComplexObjectArrayItem::GetStageRootInternal(&objRef ); } } // // create the object on the stage // for (s32 i = 0; i < sm_ObjectArray.GetCount(); i++) { #if __SCALEFORM_CRITICAL_SECTIONS SYS_CS_SYNC(gs_ScaleformMovieCS[sm_ObjectArray[i].GetMovieId()]); #endif CComplexObjectArrayItem& objRef = sm_ObjectArray[i]; if ( objRef.IsPendingCreate()) { CComplexObjectArrayItem *pParentObject = CScaleformComplexObjectMgr::GetObjectFromUniqueId( objRef.m_iPendingParentObjectUniqueId); if (sfVerifyf(pParentObject, "CComplexObjectArrayItem::PerformAllOutstandingActionsOnRT - Parent object with unique id %d not available to attach items to!", sm_ObjectArray[i].m_iPendingParentObjectUniqueId)) { pParentObject->CreateEmptyMovieClipInternal(&objRef, objRef.m_iPendingDepth, objRef.m_cPendingString[0].c_str()); // if we are creating this early, then set visibility to false as we dont want to show it until its been fully set up if (sm_ObjectArray[i].m_asObject.IsDefined()) { GFxValue::DisplayInfo displayInfo; displayInfo.SetVisible(false); objRef.m_asObject.SetDisplayInfo(displayInfo); objRef.m_bInitialisedEarly = true; } } } } // // attach the object to the stage // for (s32 i = 0; i < sm_ObjectArray.GetCount(); i++) { #if __SCALEFORM_CRITICAL_SECTIONS SYS_CS_SYNC(gs_ScaleformMovieCS[sm_ObjectArray[i].GetMovieId()]); #endif CComplexObjectArrayItem& objRef = sm_ObjectArray[i]; if ( objRef.IsPendingAttach()) { CComplexObjectArrayItem *pParentObject = CScaleformComplexObjectMgr::GetObjectFromUniqueId( objRef.m_iPendingParentObjectUniqueId); if (sfVerifyf(pParentObject, "CComplexObjectArrayItem::PerformAllOutstandingActionsOnRT - Parent object with unique id %d not available to attach items to!", sm_ObjectArray[i].m_iPendingParentObjectUniqueId)) { pParentObject->AttachMovieClipInternal(&objRef, objRef.m_cPendingString[0].c_str(), objRef.m_iPendingDepth, objRef.m_cPendingString[1].c_str()); // if we are creating this early, then set visibility to false as we dont want to show it until its been fully set up if ( objRef.m_asObject.IsDefined()) { GFxValue::DisplayInfo displayInfo; displayInfo.SetVisible(false); objRef.m_asObject.SetDisplayInfo(displayInfo); objRef.m_bInitialisedEarly = true; } } } } // // get the object on the stage // for (s32 i = 0; i < sm_ObjectArray.GetCount(); i++) { #if __SCALEFORM_CRITICAL_SECTIONS SYS_CS_SYNC(gs_ScaleformMovieCS[sm_ObjectArray[i].GetMovieId()]); #endif CComplexObjectArrayItem& objRef = sm_ObjectArray[i]; if ( objRef.IsPendingGet()) { if ( objRef.m_iPendingParentObjectUniqueId != INVALID_COMPLEX_OBJECT_ID) { CComplexObjectArrayItem *pParentObject = CScaleformComplexObjectMgr::GetObjectFromUniqueId( objRef.m_iPendingParentObjectUniqueId); if (sfVerifyf(pParentObject, "CComplexObjectArrayItem::PerformAllOutstandingActionsOnRT - Parent object with unique id %d not available to get items on!", sm_ObjectArray[i].m_iPendingParentObjectUniqueId)) { pParentObject->GetObjectInternal(&objRef, objRef.m_cPendingString[0].c_str(), objRef.m_cPendingString[1].c_str(), objRef.m_cPendingString[2].c_str()); } } } } // // at this point, anything that needed setting up will be done, so we are free to set any properties on the object: // for (s32 i = 0; i < sm_ObjectArray.GetCount(); i++) { #if __SCALEFORM_CRITICAL_SECTIONS SYS_CS_SYNC(gs_ScaleformMovieCS[sm_ObjectArray[i].GetMovieId()]); #endif CComplexObjectArrayItem& objRef = sm_ObjectArray[ i ]; if( objRef.IsActive() || objRef.IsPendingFlaggedForRelease() ) { if( objRef.GetActionRequired() != 0 ) { if (objRef.m_asObject.IsDefined()) { if (objRef.GetActionRequired() & CO_ACTION_UPDATE_POSITION_X) { objRef.SetXPositionInPixels(objRef.GetXPositionInPixels()); } if (objRef.GetActionRequired() & CO_ACTION_UPDATE_POSITION_Y) { objRef.SetYPositionInPixels(objRef.GetYPositionInPixels()); } if (objRef.GetActionRequired() & CO_ACTION_UPDATE_WIDTH) { objRef.SetWidth(objRef.GetWidth()); } if (objRef.GetActionRequired() & CO_ACTION_UPDATE_HEIGHT) { objRef.SetHeight(objRef.GetHeight()); } if (objRef.GetActionRequired() & CO_ACTION_UPDATE_VISIBILITY) { objRef.SetVisible(objRef.IsVisible()); } if (objRef.GetActionRequired() & CO_ACTION_UPDATE_FRAME) { objRef.GotoFrame(objRef.GetCurrentFrame(), objRef.PlayOnFrameJump() ); } if (objRef.GetActionRequired() & CO_ACTION_UPDATE_TEXTFIELD) { objRef.SetTextField(objRef.GetTextField()); } if (objRef.GetActionRequired() & CO_ACTION_UPDATE_TEXTFIELD_HTML) { objRef.SetTextFieldHTML(objRef.GetTextFieldHTML()); } if (objRef.GetActionRequired() & CO_ACTION_UPDATE_SCALE) { objRef.SetScale(objRef.GetScale()); } if (objRef.GetActionRequired() & CO_ACTION_UPDATE_ROTATION) { objRef.SetRotation(objRef.GetRotation()); } if (objRef.GetActionRequired() & CO_ACTION_UPDATE_MEMBERS) { for (s32 i = 0; i < objRef.m_properties->m_member.GetCount(); i++) { if (objRef.m_properties->m_member[i].m_update) { if (objRef.m_properties->m_member[i].m_type == MEMBER_VALUE_TYPE_BOOL) { objRef.SetMember(objRef.m_properties->m_member[i].m_instanceName, objRef.m_properties->m_member[i].value_bool); } if (objRef.m_properties->m_member[i].m_type == MEMBER_VALUE_TYPE_NUMBER) { objRef.SetMember(objRef.m_properties->m_member[i].m_instanceName, objRef.m_properties->m_member[i].value_number); } if (objRef.m_properties->m_member[i].m_type == MEMBER_VALUE_TYPE_STRING) { objRef.SetMember(objRef.m_properties->m_member[i].m_instanceName, objRef.m_properties->m_member[i].value_string); } objRef.m_properties->m_member[i].m_update = false; } } } if (objRef.GetActionRequired() & CO_ACTION_UPDATE_COLOUR) { objRef.SetColour(objRef.GetColour()); } if (objRef.GetActionRequired() & CO_ACTION_UPDATE_ALPHA) { objRef.SetAlpha(objRef.GetAlpha()); } objRef.m_properties[c_buffer].iActionRequired = 0; // reset action flag once done } } } } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CScaleformComplexObjectMgr::ReleaseAnyFlaggedObjects // PURPOSE: goes though each object and if we have flagged it for removal, then do it ///////////////////////////////////////////////////////////////////////////////////// void CScaleformComplexObjectMgr::ReleaseAnyFlaggedObjects() { // // finally release anything we dont want anymore - only aslong as there are no pending invokes // for (s32 i = 0; i < sm_ObjectArray.GetCount(); i++) { #if __SCALEFORM_CRITICAL_SECTIONS SYS_CS_SYNC(gs_ScaleformMovieCS[sm_ObjectArray[i].GetMovieId()]); #endif if (sm_ObjectArray[i].IsPendingRelease()) { CComplexObjectArrayItem::ReleaseObjectInternal(i, false); continue; } if ( (sm_ObjectArray[i].GetActionRequired()) == 0 && (sm_ObjectArray[i].IsPendingFlaggedForRelease()) && (!sm_ObjectArray[i].IsPendingInvoke()) ) { sm_ObjectArray[i].m_uState |= CO_STATE_PENDING_RELEASE; } } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CScaleformComplexObjectMgr::ForceRemoveAllObjectsInUseByMovie // PURPOSE: goes though each object and remove it regardless of whether it was // flagged for removal ///////////////////////////////////////////////////////////////////////////////////// void CScaleformComplexObjectMgr::ForceRemoveAllObjectsInUseByMovie(s32 const iScaleformMovieId) { // // finally release anything we dont want anymore - only aslong as there are no pending invokes // for (s32 i = 0; i < sm_ObjectArray.GetCount(); i++) { #if __SCALEFORM_CRITICAL_SECTIONS SYS_CS_SYNC(gs_ScaleformMovieCS[sm_ObjectArray[i].GetMovieId()]); #endif if (sm_ObjectArray[i].GetMovieId() == iScaleformMovieId) { CComplexObjectArrayItem::ReleaseObjectInternal(i, true); } } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CScaleformComplexObjectMgr::ReleaseAllObjectsInUseByMovie // PURPOSE: goes though each object and if we have flagged it for removal, then do it ///////////////////////////////////////////////////////////////////////////////////// void CScaleformComplexObjectMgr::ReleaseAllObjectsInUseByMovie(s32 const iScaleformMovieId) { // // flag all objects used by this movie for removal // for (s32 i = 0; i < sm_ObjectArray.GetCount(); i++) { if (sm_ObjectArray[i].GetMovieId() == iScaleformMovieId) { CComplexObjectArrayItem *pObj = CScaleformComplexObjectMgr::FindObjectFromArrayIndex(i); if (pObj) { CComplexObjectArrayItem::ReleaseObject(pObj, false); } } } } ///////////////////////////////////////////////////////////////////////////////////// // NAME: CScaleformComplexObjectMgr::SyncBuffers // PURPOSE: flips the buffers and syncs them ///////////////////////////////////////////////////////////////////////////////////// void CScaleformComplexObjectMgr::SyncBuffers() { // copy contents of UT buffer to RT buffer and reset UT actions s32 const c_count = sm_ObjectArray.GetCount(); for( s32 i = 0; i < c_count; ++i ) { sComplexObjectProperties& rtProps = sm_ObjectArray[i].m_properties[ CO_BUFFER_RENDER ]; sComplexObjectProperties& utProps = sm_ObjectArray[i].m_properties[ CO_BUFFER_UPDATE ]; // Avoid an unecessary copy of properties if nothing has changed if( utProps.iActionRequired != 0 ) { // If someone calls SyncBuffers twice before we process actions, we need to ensure // we don't lose any buffered flags, so calculate the new set s32 const c_newFlags = rtProps.iActionRequired | utProps.iActionRequired; rtProps = utProps; // Reset flags on the UT and assign the coalesced flags for RT processing utProps.iActionRequired = 0; rtProps.iActionRequired = c_newFlags; } } } CComplexObjectArrayItem *CScaleformComplexObjectMgr::GetObjectFromUniqueId(COMPLEX_OBJECT_ID objectId) { if (objectId != INVALID_COMPLEX_OBJECT_ID) { for (s32 i = 0; i < sm_ObjectArray.GetCount(); i++) { if (sm_ObjectArray[i].GetUniqueId() == objectId) { return (&sm_ObjectArray[i]); } } } return NULL; } void CScaleformComplexObjectMgr::GetGfxValueFromUniqueIdForInvoke( COMPLEX_OBJECT_ID const objectId, GFxValue *& out_object, bool& out_canInvoke ) { out_object = nullptr; out_canInvoke = false; if (objectId != INVALID_COMPLEX_OBJECT_ID) { CComplexObjectArrayItem * const pObject = GetObjectFromUniqueId( objectId ); out_canInvoke = pObject && pObject->CanInvoke(); if( out_canInvoke ) // If we can't invoke, return null { out_object = pObject->GetGfxValue(); } } } #if __BANK ///////////////////////////////////////////////////////////////////////////////////// // NAME: CScaleformComplexObjectMgr::OutputMovieClipsInUseByMovieToLog // PURPOSE: outputs a list of objects in use by the passed movie id to the log for // debugging purposes. ///////////////////////////////////////////////////////////////////////////////////// void CScaleformComplexObjectMgr::OutputMovieClipsInUseByMovieToLog(s32 iScaleformMovieId) { s32 iCount = 0; sfDisplayf("COMPLEXOBJECT: Current movieclips active on movie on movie %s (%d):", CScaleformMgr::GetMovieFilename(iScaleformMovieId), iScaleformMovieId); for (s32 i = 0; i < sm_ObjectArray.GetCount(); i++) { if (sm_ObjectArray[i].GetMovieId() == iScaleformMovieId) { const char *c_namehash = sm_ObjectArray[i].GetObjectNameHash().GetCStr(); if (c_namehash) { sfDisplayf(" (%d) %s (state=%u)", iCount, sm_ObjectArray[i].GetObjectNameHash().GetCStr(), sm_ObjectArray[i].m_uState); } iCount++; } } sfDisplayf("COMPLEXOBJECT: (end)"); } #endif // __BANK // eof