1786 lines
60 KiB
C++
1786 lines
60 KiB
C++
/**********************************************************************
|
|
|
|
Filename : GFxValueImpl.cpp
|
|
Content : Complex Objects API Implementation
|
|
Created :
|
|
Authors : Prasad Silva
|
|
|
|
Copyright : (c) 2009 Scaleform Corp. All Rights Reserved.
|
|
|
|
Notes : Contains GFxMovieRoot, GFxValue::ObjectInterface and
|
|
GFxValue method definitions.
|
|
|
|
Licensees may use this file in accordance with the valid Scaleform
|
|
Commercial License Agreement provided with the software.
|
|
|
|
This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
|
|
THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR ANY PURPOSE.
|
|
|
|
**********************************************************************/
|
|
|
|
#include <GFxPlayer.h>
|
|
#include "GFxPlayerImpl.h"
|
|
#include "GFxSprite.h"
|
|
#include "GFxText.h"
|
|
#include "AS/GASObject.h"
|
|
#include "AS/GASArrayObject.h"
|
|
#include "AMP/GFxAmpViewStats.h"
|
|
|
|
// Helper macro to determine the offset of a member. The 16 value is an
|
|
// arbitrary number used as a pointer. The commonly used pointer, NULL,
|
|
// produces warnings on some compilers, so 16 is used.
|
|
#define OFFSETOF(st, m) ((size_t) ( (char *)&((st *)(16))->m - (char *)16 ))
|
|
|
|
// RAGE - add some diag context for actionscript calls
|
|
#include "../../../../base/src/diag/output.h"
|
|
|
|
// ***** Custom AS2 function object
|
|
|
|
// Custom GASFunctionObject that wraps the function context as well as
|
|
// the user data.
|
|
class GASUserDefinedFunctionObject : public GASFunctionObject
|
|
{
|
|
friend class GASFunctionProto;
|
|
friend class GASFunctionCtorFunction;
|
|
friend class GASCustomFunctionObject;
|
|
friend class GASFunctionRefBase;
|
|
protected:
|
|
GPtr<GFxFunctionHandler> pContext;
|
|
void* pUserData;
|
|
|
|
GASUserDefinedFunctionObject(GASStringContext* psc) : GASFunctionObject(psc) { GUNUSED(psc); }
|
|
GASUserDefinedFunctionObject(GASEnvironment* penv) : GASFunctionObject(penv) { GUNUSED(penv); }
|
|
|
|
#ifndef GFC_NO_GC
|
|
|
|
// PPS: We may need to link up ForEachChild_GC via a visitor interface
|
|
// later on to somewhat automate the cleaning up of any GFxValues
|
|
// held by the function context.
|
|
|
|
virtual void Finalize_GC()
|
|
{
|
|
pContext = NULL;
|
|
GASFunctionObject::Finalize_GC();
|
|
}
|
|
#endif // GFC_NO_GC
|
|
public:
|
|
GASUserDefinedFunctionObject(GASStringContext* psc, GFxFunctionHandler* pcontext, void* puserData)
|
|
: GASFunctionObject(psc), pContext(pcontext), pUserData(puserData)
|
|
{
|
|
Set__proto__(psc, psc->pContext->GetPrototype(GASBuiltin_Function));
|
|
}
|
|
virtual ~GASUserDefinedFunctionObject() {}
|
|
|
|
virtual GASEnvironment* GetEnvironment(const GASFnCall& fn, GPtr<GFxASCharacter>* ptargetCh)
|
|
{
|
|
GUNUSED(ptargetCh);
|
|
return fn.Env;
|
|
}
|
|
virtual void Invoke (const GASFnCall& fn, GASLocalFrame*, const char* pmethodName);
|
|
|
|
virtual bool IsNull () const { return 0 == pContext; }
|
|
virtual bool IsEqual(const GASFunctionObject& f) const
|
|
{
|
|
GUNUSED(f);
|
|
return false; // AB wants it returning false
|
|
}
|
|
|
|
// returns number of arguments expected by this function;
|
|
// returns -1 if number of arguments is unknown (for C functions)
|
|
int GetNumArgs() const { return -1; }
|
|
|
|
private:
|
|
void InvokeImpl(const GASFnCall& fn);
|
|
};
|
|
|
|
|
|
void GASUserDefinedFunctionObject::Invoke(const GASFnCall& fn, GASLocalFrame*, const char* BANK_ONLY(methodName))
|
|
{
|
|
if (0 != pContext) {
|
|
DIAG_CONTEXT_MESSAGE("AS UserFn: %s", methodName);
|
|
GASObjectInterface* pthis = fn.ThisPtr;
|
|
if (pthis && pthis->IsSuper())
|
|
{
|
|
GASObjectInterface* prealThis = static_cast<GASSuperObject*>(pthis)->GetRealThis();
|
|
GASFnCall fn2(fn.Result, prealThis, fn.Env, fn.NArgs, fn.FirstArgBottomIndex);
|
|
InvokeImpl(fn2);
|
|
static_cast<GASSuperObject*>(pthis)->ResetAltProto(); // reset alternative proto, if set
|
|
}
|
|
else
|
|
InvokeImpl(fn);
|
|
}
|
|
}
|
|
|
|
void GASUserDefinedFunctionObject::InvokeImpl(const GASFnCall& fn)
|
|
{
|
|
GASEnvironment* penv = fn.Env;
|
|
GASSERT(penv);
|
|
GArrayCPP<GFxValue> args;
|
|
|
|
GFxValue thisVal, retVal;
|
|
GASValue thisAS;
|
|
if (fn.ThisPtr) thisAS.SetAsObjectInterface(fn.ThisPtr);
|
|
else thisAS.SetNull();
|
|
penv->GetMovieRoot()->ASValue2GFxValue(penv, thisAS, &thisVal);
|
|
args.PushBack(thisVal); // Used to pack 'this' on callback
|
|
|
|
for (int i=0; i < fn.NArgs; i++)
|
|
{
|
|
GFxValue arg;
|
|
penv->GetMovieRoot()->ASValue2GFxValue(penv, fn.Arg(i), &arg);
|
|
args.PushBack(arg);
|
|
}
|
|
|
|
GFxFunctionHandler::Params params;
|
|
params.pMovie = penv->GetMovieRoot();
|
|
params.pRetVal = &retVal;
|
|
params.pThis = &thisVal;
|
|
params.pArgs = fn.NArgs > 0 ? &args[1] : NULL;
|
|
params.pArgsWithThisRef = &args[0];
|
|
params.ArgCount = (UInt)args.GetSize() - 1;
|
|
params.pUserData = pUserData;
|
|
pContext->Call(params);
|
|
|
|
if (!retVal.IsUndefined())
|
|
penv->GetMovieRoot()->GFxValue2ASValue(retVal, fn.Result);
|
|
}
|
|
|
|
|
|
// ***** GFxMovieRoot definitions
|
|
|
|
// Convert a GFxValue to an internal GASValue representation
|
|
void GFxMovieRoot::GFxValue2ASValue(const GFxValue& gfxVal, GASValue* pdestVal) const
|
|
{
|
|
GASSERT(pdestVal);
|
|
switch(gfxVal.GetType())
|
|
{
|
|
case GFxValue::VT_Undefined: pdestVal->SetUndefined(); break;
|
|
case GFxValue::VT_Boolean: pdestVal->SetBool(gfxVal.GetBool()); break;
|
|
case GFxValue::VT_Null: pdestVal->SetNull(); break;
|
|
case GFxValue::VT_Number: pdestVal->SetNumber(gfxVal.GetNumber()); break;
|
|
case GFxValue::VT_String:
|
|
{
|
|
if (gfxVal.IsManagedValue())
|
|
{
|
|
size_t memberOffset = OFFSETOF(GASStringNode, pData);
|
|
// Must be an assignment of a string from the same movie root
|
|
GASSERT(gfxVal.pObjectInterface->IsSameContext(pObjectInterface));
|
|
GASStringNode* strnode = (GASStringNode*)(((UByte*)gfxVal.Value.pStringManaged) - memberOffset);
|
|
GASString str(strnode);
|
|
pdestVal->SetString(str);
|
|
}
|
|
else
|
|
pdestVal->SetString(pGlobalContext->CreateString(gfxVal.GetString()));
|
|
}
|
|
break;
|
|
case GFxValue::VT_StringW:
|
|
{
|
|
if (gfxVal.IsManagedValue())
|
|
{
|
|
size_t memberOffset = OFFSETOF(GFxMovieRoot::WideStringStorage, pData);
|
|
// Must be an assignment of a string from the same movie root
|
|
GASSERT(gfxVal.pObjectInterface->IsSameContext(pObjectInterface));
|
|
WideStringStorage* wstr = (WideStringStorage*)(((UByte*)gfxVal.Value.pStringW) - memberOffset);
|
|
GASString str(wstr->pNode);
|
|
pdestVal->SetString(str);
|
|
}
|
|
else
|
|
pdestVal->SetString(pGlobalContext->CreateString(gfxVal.GetStringW()));
|
|
}
|
|
break;
|
|
case GFxValue::VT_Array:
|
|
case GFxValue::VT_Object:
|
|
{
|
|
// Must be an assignment of an object from the same movie root
|
|
GASSERT(gfxVal.pObjectInterface->IsSameContext(pObjectInterface));
|
|
GASObjectInterface* pifc = (GASObjectInterface*)gfxVal.Value.pData;
|
|
pdestVal->SetAsObject((GASObject*) pifc);
|
|
}
|
|
break;
|
|
case GFxValue::VT_DisplayObject:
|
|
{
|
|
// Must be an assignment of an object from the same movie root
|
|
GASSERT(gfxVal.pObjectInterface->IsSameContext(pObjectInterface));
|
|
GFxCharacterHandle* pifc = (GFxCharacterHandle*)gfxVal.Value.pData;
|
|
pdestVal->SetAsCharacterHandle(pifc);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Convert a GASValue to GFxValue representation
|
|
void GFxMovieRoot::ASValue2GFxValue(GASEnvironment* penv, const GASValue& value, GFxValue* pdestVal) const
|
|
{
|
|
GASSERT(pdestVal);
|
|
int toType;
|
|
if (pdestVal->GetType() & GFxValue::VTC_ConvertBit)
|
|
toType = pdestVal->GetType() & (~GFxValue::VTC_ConvertBit);
|
|
else
|
|
{
|
|
switch(value.GetType())
|
|
{
|
|
case GASValue::UNSET:
|
|
case GASValue::UNDEFINED: toType = GFxValue::VT_Undefined; break;
|
|
case GASValue::BOOLEAN: toType = GFxValue::VT_Boolean; break;
|
|
case GASValue::NULLTYPE: toType = GFxValue::VT_Null; break;
|
|
case GASValue::INTEGER:
|
|
case GASValue::NUMBER: toType = GFxValue::VT_Number; break;
|
|
case GASValue::OBJECT:
|
|
case GASValue::FUNCTION:
|
|
toType = GFxValue::VT_Object; break;
|
|
case GASValue::CHARACTER: toType = GFxValue::VT_DisplayObject; break;
|
|
// GASValue::PROPERTY is returned as a string
|
|
default: toType = GFxValue::VT_String; break;
|
|
}
|
|
}
|
|
|
|
// Clear existing ref
|
|
if (pdestVal->IsManagedValue()) pdestVal->ReleaseManagedValue();
|
|
|
|
switch(toType)
|
|
{
|
|
case GFxValue::VT_Undefined:
|
|
case GFxValue::VT_Null:
|
|
{
|
|
pdestVal->Type = GFxValue::ValueType(toType);
|
|
}
|
|
break;
|
|
case GFxValue::VT_Boolean:
|
|
{
|
|
pdestVal->Type = GFxValue::ValueType(toType);
|
|
pdestVal->Value.BValue = value.ToBool(penv);
|
|
}
|
|
break;
|
|
case GFxValue::VT_Number:
|
|
{
|
|
pdestVal->Type = GFxValue::ValueType(toType);
|
|
pdestVal->Value.NValue = value.ToNumber(penv);
|
|
}
|
|
break;
|
|
case GFxValue::VT_String:
|
|
{
|
|
size_t memberOffset = OFFSETOF(GASStringNode, pData);
|
|
GASString str = value.ToString(penv);
|
|
GASStringNode* strNode = str.GetNode();
|
|
pdestVal->Type = GFxValue::ValueType(GFxValue::VT_String | GFxValue::VTC_ManagedBit);
|
|
pdestVal->Value.pStringManaged = (const char**)(((UByte*)strNode) + memberOffset);
|
|
pdestVal->pObjectInterface = pObjectInterface;
|
|
pObjectInterface->ObjectAddRef(pdestVal, pdestVal->Value.pData);
|
|
}
|
|
break;
|
|
case GFxValue::VT_StringW:
|
|
{
|
|
size_t memberOffset = OFFSETOF(GFxMovieRoot::WideStringStorage, pData);
|
|
GASString str = value.ToString(penv);
|
|
GASStringNode* strNode = str.GetNode();
|
|
UInt len = str.GetLength() + 1;
|
|
void* pdata = GHEAP_ALLOC(pHeap, sizeof(WideStringStorage) - sizeof(UByte) + (sizeof(wchar_t) * len), GFxStatMV_Other_Mem);
|
|
pdestVal->Type = GFxValue::ValueType(GFxValue::VT_StringW | GFxValue::VTC_ManagedBit);
|
|
GPtr<WideStringStorage> wstr = *::new(pdata) WideStringStorage(strNode, len);
|
|
pdestVal->Value.pStringW = (const wchar_t*)(((UByte*)wstr.GetPtr()) + memberOffset);
|
|
pdestVal->pObjectInterface = pObjectInterface;
|
|
pObjectInterface->ObjectAddRef(pdestVal, pdestVal->Value.pData);
|
|
}
|
|
break;
|
|
case GFxValue::VT_Object:
|
|
{
|
|
GFxValue::ValueType type = GFxValue::VT_Object;
|
|
GASObjectInterface* pifc = (GASObjectInterface*)value.ToObjectInterface(penv);
|
|
if (pifc->IsASObject())
|
|
{
|
|
GASObject* pobj = pifc->ToASObject();
|
|
if (pobj->GetObjectType() == GASObjectInterface::Object_Array)
|
|
type = GFxValue::VT_Array;
|
|
}
|
|
pdestVal->Type = GFxValue::ValueType(type | GFxValue::VTC_ManagedBit);
|
|
pdestVal->Value.pData = pifc;
|
|
pdestVal->pObjectInterface = pObjectInterface;
|
|
pObjectInterface->ObjectAddRef(pdestVal, pdestVal->Value.pData);
|
|
}
|
|
break;
|
|
case GFxValue::VT_DisplayObject:
|
|
{
|
|
GASObjectInterface* pifc = (GASObjectInterface*)value.ToObjectInterface(penv);
|
|
if (pifc) // RAGE: The code below fails when we're converting a character handle that points to a deleted movieclip into GFxValue
|
|
{
|
|
GFxASCharacter* aschar = pifc->ToASCharacter();
|
|
pdestVal->Type = GFxValue::ValueType(GFxValue::VT_DisplayObject | GFxValue::VTC_ManagedBit);
|
|
pdestVal->Value.pData = aschar->GetCharacterHandle();
|
|
pdestVal->pObjectInterface = pObjectInterface;
|
|
pObjectInterface->ObjectAddRef(pdestVal, pdestVal->Value.pData);
|
|
}
|
|
else
|
|
{
|
|
pdestVal->Type = GFxValue::VT_Undefined;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void GFxMovieRoot::CreateString(GFxValue* pvalue, const char* pstring)
|
|
{
|
|
GASEnvironment* penv = pLevel0Movie->GetASEnvironment();
|
|
GASStringContext* psc = penv->GetSC();
|
|
GASString asstr = psc->CreateString(pstring);
|
|
ASValue2GFxValue(penv, asstr, pvalue);
|
|
}
|
|
|
|
void GFxMovieRoot::CreateStringW(GFxValue* pvalue, const wchar_t* pstring)
|
|
{
|
|
GASEnvironment* penv = pLevel0Movie->GetASEnvironment();
|
|
GASStringContext* psc = penv->GetSC();
|
|
GASString asstr = psc->CreateString(pstring);
|
|
pvalue->SetConvertStringW();
|
|
ASValue2GFxValue(penv, asstr, pvalue);
|
|
}
|
|
|
|
void GFxMovieRoot::CreateObject(GFxValue* pvalue, const char* className, const GFxValue* pargs, UInt nargs)
|
|
{
|
|
GASEnvironment* penv = pLevel0Movie->GetASEnvironment();
|
|
GPtr<GASObject> pobj;
|
|
|
|
if (className)
|
|
{
|
|
// Push params to stack
|
|
if (nargs > 0)
|
|
{
|
|
for (SInt i=(nargs-1); i > -1; --i)
|
|
{
|
|
GASValue asval;
|
|
GFxValue2ASValue(pargs[i], &asval);
|
|
penv->Push(asval);
|
|
}
|
|
}
|
|
|
|
// Check if the className is part of a package (has '.')
|
|
const char* p = strchr(className, '.');
|
|
if (p)
|
|
{
|
|
// For package resolution
|
|
GASStringContext* psc = penv->GetSC();
|
|
char buf[256];
|
|
const char* pname = className;
|
|
GPtr<GASObject> parent = penv->GetGC()->pGlobal;
|
|
|
|
while(pname)
|
|
{
|
|
const char* p = strchr(pname, '.');
|
|
UPInt sz;
|
|
if (p)
|
|
sz = p++ - pname + 1;
|
|
else
|
|
break; // class name found
|
|
|
|
GASSERT(sz <= sizeof(buf));
|
|
if (sz > sizeof(buf))
|
|
sz = sizeof(buf);
|
|
|
|
memcpy(buf, pname, sz-1);
|
|
buf[sz-1] = '\0';
|
|
|
|
pname = p;
|
|
|
|
GASValue pkgObjVal;
|
|
GPtr<GASObject> pkgObj;
|
|
GASString memberName(psc->CreateString(buf));
|
|
|
|
if (parent->GetMemberRaw(psc, memberName, &pkgObjVal))
|
|
pkgObj = pkgObjVal.ToObject(NULL);
|
|
else
|
|
{
|
|
pvalue->SetUndefined();
|
|
return; // Package in path not found; bail
|
|
}
|
|
|
|
parent = pkgObj;
|
|
}
|
|
|
|
pobj = *penv->OperatorNew(parent, penv->CreateString(pname), nargs);
|
|
}
|
|
else
|
|
pobj = *penv->OperatorNew(penv->CreateString(className), nargs);
|
|
|
|
if (pobj)
|
|
ASValue2GFxValue(penv, GASValue(pobj), pvalue);
|
|
else
|
|
pvalue->SetUndefined();
|
|
|
|
// Cleanup; pop params from stack
|
|
if (nargs > 0)
|
|
penv->Drop(nargs);
|
|
}
|
|
else
|
|
{
|
|
pobj = *penv->OperatorNew(penv->GetBuiltin(GASBuiltin_Object));
|
|
ASValue2GFxValue(penv, GASValue(pobj), pvalue);
|
|
}
|
|
}
|
|
|
|
void GFxMovieRoot::CreateArray(GFxValue* pvalue)
|
|
{
|
|
GASEnvironment* penv = pLevel0Movie->GetASEnvironment();
|
|
GPtr<GASArrayObject> parr = *static_cast<GASArrayObject*>(penv->OperatorNew(penv->GetBuiltin(GASBuiltin_Array)));
|
|
GASValue asval(parr);
|
|
ASValue2GFxValue(penv, asval, pvalue);
|
|
}
|
|
|
|
void GFxMovieRoot::CreateFunction(GFxValue* pvalue, GFxFunctionHandler* pfc, void* puserData /* = NULL */)
|
|
{
|
|
GASEnvironment* penv = pLevel0Movie->GetASEnvironment();
|
|
GASStringContext* psc = penv->GetSC();
|
|
GASValue asval;
|
|
GPtr<GASUserDefinedFunctionObject> pfuncObj = *GHEAP_NEW(psc->GetHeap()) GASUserDefinedFunctionObject(psc, pfc, puserData);
|
|
asval.SetAsFunction( GASFunctionRef(pfuncObj.GetPtr()) );
|
|
ASValue2GFxValue(penv, asval, pvalue);
|
|
}
|
|
|
|
// ***** GFxValue definitions
|
|
|
|
GString GFxValue::ToString() const
|
|
{
|
|
GString retVal;
|
|
|
|
switch(GetType())
|
|
{
|
|
case VT_Undefined:
|
|
{
|
|
retVal = GString("undefined");
|
|
}
|
|
break;
|
|
case VT_Null:
|
|
{
|
|
retVal = GString("null");
|
|
}
|
|
break;
|
|
case VT_Boolean:
|
|
{
|
|
retVal = GString(Value.BValue ? "true" : "false");
|
|
}
|
|
break;
|
|
case VT_Number:
|
|
{
|
|
char buf[GASNumberUtil::TOSTRING_BUF_SIZE];
|
|
retVal = GString(GASNumberUtil::ToString(Value.NValue, buf, sizeof(buf))); // Precision is 10 by default.
|
|
}
|
|
break;
|
|
case VT_String:
|
|
{
|
|
retVal = GString(GetString());
|
|
}
|
|
break;
|
|
case VT_StringW:
|
|
{
|
|
retVal = GString(GetStringW());
|
|
}
|
|
break;
|
|
case VT_Object:
|
|
case VT_Array:
|
|
case VT_DisplayObject:
|
|
{
|
|
pObjectInterface->ToString(&retVal, *this);
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
retVal = "<bad type>";
|
|
GASSERT(0);
|
|
}
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
const wchar_t* GFxValue::ToStringW(wchar_t* pwstr, UPInt len) const
|
|
{
|
|
switch(GetType())
|
|
{
|
|
case VT_StringW:
|
|
{
|
|
G_wcscpy(pwstr, len, GetStringW());
|
|
return pwstr;
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
GUTF8Util::DecodeString(pwstr, ToString().ToCStr(), len);
|
|
}
|
|
break;
|
|
}
|
|
return pwstr;
|
|
}
|
|
|
|
|
|
// ***** GFxValue::ObjectInterface definitions
|
|
|
|
#ifdef GFC_BUILD_DEBUG
|
|
void GFxValue::ObjectInterface::DumpTaggedValues() const
|
|
{
|
|
GFC_DEBUG_MESSAGE(1, "** Begin Tagged GFxValues Dump **");
|
|
const GFxValue* data = ExternalObjRefs.GetFirst();
|
|
while (!ExternalObjRefs.IsNull(data))
|
|
{
|
|
const char* ptypestr = NULL;
|
|
switch (data->GetType())
|
|
{
|
|
case GFxValue::VT_Array: ptypestr = "Array"; break;
|
|
case GFxValue::VT_DisplayObject: ptypestr = "DispObj"; break;
|
|
default: ptypestr = "Object";
|
|
}
|
|
GFC_DEBUG_MESSAGE2(1, "> [%s] : %p", ptypestr, data);
|
|
data = ExternalObjRefs.GetNext(data);
|
|
}
|
|
GFC_DEBUG_MESSAGE(1, "** End Tagged GFxValues Dump **");
|
|
}
|
|
#endif
|
|
|
|
void GFxValue::ObjectInterface::ObjectAddRef(GFxValue* val, void* pobj)
|
|
{
|
|
// Addref complex object
|
|
switch (val->GetType())
|
|
{
|
|
case GFxValue::VT_String:
|
|
{
|
|
// pobj points to const char**
|
|
size_t memberOffset = OFFSETOF(GASStringNode, pData);
|
|
GASStringNode* ps = (GASStringNode*)(((UByte*)pobj) - memberOffset);
|
|
ps->AddRef();
|
|
}
|
|
break;
|
|
case GFxValue::VT_StringW:
|
|
{
|
|
// pobj points to const wchar_t*
|
|
size_t memberOffset = OFFSETOF(GFxMovieRoot::WideStringStorage, pData);
|
|
GFxMovieRoot::WideStringStorage* pws = (GFxMovieRoot::WideStringStorage*)(((UByte*)pobj) - memberOffset);
|
|
pws->AddRef();
|
|
}
|
|
break;
|
|
case GFxValue::VT_DisplayObject:
|
|
{
|
|
GFxCharacterHandle* pifc = (GFxCharacterHandle*)pobj;
|
|
pifc->AddRef();
|
|
}
|
|
break;
|
|
case GFxValue::VT_Object:
|
|
case GFxValue::VT_Array:
|
|
{
|
|
GASObjectInterface* pifc = (GASObjectInterface*)pobj;
|
|
pifc->ToASObject()->AddRef();
|
|
}
|
|
break;
|
|
default:
|
|
GASSERT(0);
|
|
}
|
|
|
|
#ifdef GFC_BUILD_DEBUG
|
|
ExternalObjRefs.PushBack(val);
|
|
#endif
|
|
}
|
|
void GFxValue::ObjectInterface::ObjectRelease(GFxValue* val, void* pobj)
|
|
{
|
|
// NOTE: The next statements may cause an access violation exception
|
|
// if the GFxMovie containing the AS object has been released. To
|
|
// avoid this issue, make sure to release any GFxValues holding
|
|
// references to AS objects before the movie that holds those objects
|
|
// is released.
|
|
|
|
switch (val->GetType())
|
|
{
|
|
case GFxValue::VT_String:
|
|
{
|
|
// pobj points to const char**
|
|
size_t memberOffset = OFFSETOF(GASStringNode, pData);
|
|
GASStringNode* ps = (GASStringNode*)(((UByte*)pobj) - memberOffset);
|
|
ps->Release();
|
|
}
|
|
break;
|
|
case GFxValue::VT_StringW:
|
|
{
|
|
// pobj points to const wchar_t*
|
|
size_t memberOffset = OFFSETOF(GFxMovieRoot::WideStringStorage, pData);
|
|
GFxMovieRoot::WideStringStorage* pws = (GFxMovieRoot::WideStringStorage*)(((UByte*)pobj) - memberOffset);
|
|
pws->Release();
|
|
}
|
|
break;
|
|
case GFxValue::VT_DisplayObject:
|
|
{
|
|
GFxCharacterHandle* pifc = (GFxCharacterHandle*)pobj;
|
|
pifc->Release();
|
|
}
|
|
break;
|
|
case GFxValue::VT_Object:
|
|
case GFxValue::VT_Array:
|
|
{
|
|
GASObjectInterface* pifc = (GASObjectInterface*)pobj;
|
|
pifc->ToASObject()->Release();
|
|
}
|
|
break;
|
|
default:
|
|
GASSERT(0);
|
|
}
|
|
|
|
#ifdef GFC_BUILD_DEBUG
|
|
ExternalObjRefs.Remove(val);
|
|
#endif
|
|
}
|
|
|
|
bool GFxValue::ObjectInterface::HasMember(void* pdata, const char* name, bool isdobj) const
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_HasMember, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
GASObjectInterface* pthis = static_cast<GASObjectInterface*>(pdata);
|
|
if (isdobj)
|
|
{
|
|
GFxCharacterHandle* pch = static_cast<GFxCharacterHandle*>(pdata);
|
|
pthis = pch->ResolveCharacter(pMovieRoot);
|
|
if (!pthis) return false;
|
|
}
|
|
GASValue asval;
|
|
GASEnvironment* penv = pMovieRoot->pLevel0Movie->GetASEnvironment();
|
|
GASStringContext* psc = penv->GetSC();
|
|
|
|
// Look for member
|
|
GASValue member;
|
|
// PPS: We are using GetMember instead of FindMember because certain GASObjectInterface
|
|
// subclasses do not implement FindMember (such as Sprite). GetMember has guaranteed
|
|
// behavior.
|
|
if (!pthis->GetMember(penv, psc->CreateConstString(name), &member))
|
|
{
|
|
// Member not found
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool GFxValue::ObjectInterface::GetMember(void* pdata, const char* name, GFxValue* pval, bool isdobj) const
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_GetMember, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
GASObjectInterface* pthis = static_cast<GASObjectInterface*>(pdata);
|
|
if (isdobj)
|
|
{
|
|
GFxCharacterHandle* pch = static_cast<GFxCharacterHandle*>(pdata);
|
|
pthis = pch->ResolveCharacter(pMovieRoot);
|
|
if (!pthis)
|
|
{
|
|
if (pval) pval->SetUndefined();
|
|
return false;
|
|
}
|
|
}
|
|
GASValue asval;
|
|
GASEnvironment* penv = pMovieRoot->pLevel0Movie->GetASEnvironment();
|
|
|
|
// Look for member
|
|
if (!pthis->GetMember(penv, penv->CreateString(name), &asval))
|
|
{
|
|
// Member not found
|
|
if (pval) pval->SetUndefined();
|
|
return false;
|
|
}
|
|
|
|
// Resolve property if required
|
|
if (asval.IsProperty())
|
|
{
|
|
GASObjectInterface* pobj = NULL;
|
|
GFxASCharacter* paschar = NULL;
|
|
if (pthis->IsASObject())
|
|
pobj = pthis->ToASObject();
|
|
if (pthis->IsASCharacter())
|
|
paschar = pthis->ToASCharacter();
|
|
asval.GetPropertyValue(penv, paschar?(GASObjectInterface*)paschar:pobj, &asval);
|
|
}
|
|
|
|
// Found the member
|
|
pMovieRoot->ASValue2GFxValue(penv, asval, pval);
|
|
return true;
|
|
}
|
|
|
|
bool GFxValue::ObjectInterface::SetMember(void* pdata, const char* name, const GFxValue& value, bool isdobj)
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_SetMember, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
GASObjectInterface* pthis = static_cast<GASObjectInterface*>(pdata);
|
|
if (isdobj)
|
|
{
|
|
GFxCharacterHandle* pch = static_cast<GFxCharacterHandle*>(pdata);
|
|
pthis = pch->ResolveCharacter(pMovieRoot);
|
|
if (!pthis) return false;
|
|
}
|
|
GASEnvironment* penv = pMovieRoot->pLevel0Movie->GetASEnvironment();
|
|
|
|
GASValue asval;
|
|
pMovieRoot->GFxValue2ASValue(value, &asval);
|
|
|
|
// Call SetMember to resolve properties
|
|
return pthis->SetMember(penv, penv->GetSC()->CreateString(name), asval);
|
|
}
|
|
|
|
bool GFxValue::ObjectInterface::Invoke(void* pdata, GFxValue* presult, const char* name, const GFxValue* pargs, UPInt nargs, bool isdobj)
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_Invoke, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
GASObjectInterface* pthis = static_cast<GASObjectInterface*>(pdata);
|
|
if (isdobj)
|
|
{
|
|
GFxCharacterHandle* pch = static_cast<GFxCharacterHandle*>(pdata);
|
|
pthis = pch->ResolveCharacter(pMovieRoot);
|
|
if (!pthis) return false;
|
|
}
|
|
GASEnvironment* penv = pMovieRoot->pLevel0Movie->GetASEnvironment();
|
|
GASValue member, result;
|
|
|
|
// Look for member
|
|
if (!pthis->GetConstMemberRaw(penv->GetSC(), name, &member))
|
|
{
|
|
// Warn?
|
|
return false;
|
|
}
|
|
|
|
GASValue asArg;
|
|
for (SInt i=SInt(nargs-1); i > -1; i--)
|
|
{
|
|
pMovieRoot->GFxValue2ASValue(pargs[i], &asArg);
|
|
penv->Push(asArg);
|
|
}
|
|
bool retVal = GAS_Invoke(member, &result, pthis, penv, UInt(nargs), penv->GetTopIndex(), NULL);
|
|
penv->Drop(UInt(nargs));
|
|
|
|
// Process the return value if needed
|
|
if (presult)
|
|
pMovieRoot->ASValue2GFxValue(penv, result, presult);
|
|
|
|
return retVal;
|
|
}
|
|
|
|
bool GFxValue::ObjectInterface::DeleteMember(void* pdata, const char* name, bool isdobj)
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_DeleteMember, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
GASObjectInterface* pthis = static_cast<GASObjectInterface*>(pdata);
|
|
if (isdobj)
|
|
{
|
|
GFxCharacterHandle* pch = static_cast<GFxCharacterHandle*>(pdata);
|
|
pthis = pch->ResolveCharacter(pMovieRoot);
|
|
if (!pthis) return false;
|
|
}
|
|
GASEnvironment* penv = pMovieRoot->pLevel0Movie->GetASEnvironment();
|
|
GASStringContext* psc = penv->GetSC();
|
|
|
|
return pthis->DeleteMember(psc, GASString(psc->CreateConstString(name)));
|
|
}
|
|
|
|
void GFxValue::ObjectInterface::VisitMembers(void* pdata, GFxValue::ObjectVisitor* visitor, bool isdobj) const
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_VisitMembers, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
const GASObjectInterface* pthis = static_cast<const GASObjectInterface*>(pdata);
|
|
if (isdobj)
|
|
{
|
|
GFxCharacterHandle* pch = static_cast<GFxCharacterHandle*>(pdata);
|
|
pthis = pch->ResolveCharacter(pMovieRoot);
|
|
if (!pthis) return;
|
|
}
|
|
GASEnvironment* penv = pMovieRoot->pLevel0Movie->GetASEnvironment();
|
|
GASStringContext* psc = penv->GetSC();
|
|
|
|
class VisitorProxy : public GASObjectInterface::MemberVisitor
|
|
{
|
|
public:
|
|
VisitorProxy(GFxMovieRoot* pmovieRoot, GFxValue::ObjectVisitor* visitor)
|
|
: pMovieRoot(pmovieRoot), pVisitor(visitor)
|
|
{
|
|
pEnv = pMovieRoot->pLevel0Movie->GetASEnvironment();
|
|
}
|
|
void Visit(const GASString& name, const GASValue& val, UByte flags)
|
|
{
|
|
GUNUSED(flags);
|
|
GFxValue v;
|
|
pMovieRoot->ASValue2GFxValue(pEnv, val, &v);
|
|
pVisitor->Visit(name.ToCStr(), v);
|
|
};
|
|
private:
|
|
GFxMovieRoot* pMovieRoot;
|
|
GASEnvironment* pEnv;
|
|
GFxValue::ObjectVisitor* pVisitor;
|
|
} visitorProxy(pMovieRoot, visitor);
|
|
|
|
pthis->VisitMembers(psc, &visitorProxy, GASObjectInterface::VisitMember_Prototype | GASObjectInterface::VisitMember_ChildClips);
|
|
}
|
|
|
|
UInt GFxValue::ObjectInterface::GetArraySize(void* pdata) const
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_GetArraySize, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
GASObjectInterface* pobj = static_cast<GASObjectInterface*>(pdata);
|
|
const GASArrayObject* parr = static_cast<const GASArrayObject*>(pobj);
|
|
|
|
return (UInt)parr->GetSize();
|
|
}
|
|
|
|
bool GFxValue::ObjectInterface::SetArraySize(void* pdata, UInt sz)
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_SetArraySize, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
GASObjectInterface* pobj = static_cast<GASObjectInterface*>(pdata);
|
|
GASArrayObject* parr = static_cast<GASArrayObject*>(pobj);
|
|
|
|
parr->Resize(sz);
|
|
return true;
|
|
}
|
|
|
|
bool GFxValue::ObjectInterface::GetElement(void* pdata, UInt idx, GFxValue *pval) const
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_GetElement, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
GASObjectInterface* pobj = static_cast<GASObjectInterface*>(pdata);
|
|
const GASArrayObject* parr = static_cast<const GASArrayObject*>(pobj);
|
|
|
|
pval->SetUndefined();
|
|
if (idx >= (UInt)parr->GetSize()) return false;
|
|
|
|
const GASValue* pelem = parr->GetElementPtr(idx);
|
|
if (!pelem) return false;
|
|
|
|
GASEnvironment* penv = pMovieRoot->pLevel0Movie->GetASEnvironment();
|
|
pMovieRoot->ASValue2GFxValue(penv, *pelem, pval);
|
|
return true;
|
|
}
|
|
|
|
bool GFxValue::ObjectInterface::SetElement(void* pdata, UInt idx, const GFxValue& value)
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_SetElement, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
GASObjectInterface* pobj = static_cast<GASObjectInterface*>(pdata);
|
|
GASArrayObject* parr = static_cast<GASArrayObject*>(pobj);
|
|
|
|
GASValue asval;
|
|
pMovieRoot->GFxValue2ASValue(value, &asval);
|
|
parr->SetElementSafe(idx, asval);
|
|
return true;
|
|
}
|
|
|
|
void GFxValue::ObjectInterface::VisitElements(void* pdata, GFxValue::ArrayVisitor* visitor, UInt idx, SInt count) const
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_VisitElements, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
GASObjectInterface* pobj = static_cast<GASObjectInterface*>(pdata);
|
|
GASArrayObject* parr = static_cast<GASArrayObject*>(pobj);
|
|
GASEnvironment* penv = pMovieRoot->pLevel0Movie->GetASEnvironment();
|
|
GFxValue val;
|
|
|
|
UInt sz = (UInt)parr->GetSize();
|
|
if (idx >= sz) return;
|
|
if (count < 0) { count = (sz - idx); }
|
|
|
|
UInt eidx = G_Min(sz, idx + count);
|
|
for (UInt i=idx; i < eidx; i++)
|
|
{
|
|
const GASValue* pelem = parr->GetElementPtr(i);
|
|
if (pelem)
|
|
pMovieRoot->ASValue2GFxValue(penv, *pelem, &val);
|
|
else
|
|
val.SetUndefined();
|
|
visitor->Visit(i, val);
|
|
}
|
|
}
|
|
|
|
bool GFxValue::ObjectInterface::PushBack(void *pdata, const GFxValue &value)
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_PushBack, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
GASObjectInterface* pobj = static_cast<GASObjectInterface*>(pdata);
|
|
GASArrayObject* parr = static_cast<GASArrayObject*>(pobj);
|
|
|
|
GASValue asval;
|
|
pMovieRoot->GFxValue2ASValue(value, &asval);
|
|
parr->PushBack(asval);
|
|
return true;
|
|
}
|
|
|
|
bool GFxValue::ObjectInterface::PopBack(void* pdata, GFxValue* pval)
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_PopBack, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
GASObjectInterface* pobj = static_cast<GASObjectInterface*>(pdata);
|
|
GASArrayObject* parr = static_cast<GASArrayObject*>(pobj);
|
|
GASEnvironment* penv = pMovieRoot->pLevel0Movie->GetASEnvironment();
|
|
|
|
int sz = parr->GetSize();
|
|
if (sz <= 0)
|
|
{
|
|
if (pval) pval->SetUndefined();
|
|
return false;
|
|
}
|
|
|
|
if (pval)
|
|
{
|
|
GASValue* pasval = parr->GetElementPtr(sz - 1);
|
|
pMovieRoot->ASValue2GFxValue(penv, *pasval, pval);
|
|
}
|
|
|
|
parr->PopBack();
|
|
return true;
|
|
}
|
|
|
|
bool GFxValue::ObjectInterface::RemoveElements(void *pdata, UInt idx, SInt count)
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_RemoveElements, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
GASObjectInterface* pobj = static_cast<GASObjectInterface*>(pdata);
|
|
GASArrayObject* parr = static_cast<GASArrayObject*>(pobj);
|
|
|
|
UInt sz = (UInt)parr->GetSize();
|
|
if (idx >= sz) return false;
|
|
if (count < 0) { count = (sz - idx); }
|
|
|
|
parr->RemoveElements(idx, G_Min(sz - idx, (UInt)count));
|
|
return true;
|
|
}
|
|
|
|
bool GFxValue::ObjectInterface::GetDisplayMatrix(void* pdata, GMatrix2D* pmat) const
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_GetDisplayMatrix, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
GFxCharacterHandle* pch = static_cast<GFxCharacterHandle*>(pdata);
|
|
GFxASCharacter* pchar = pch->ResolveCharacter(pMovieRoot);
|
|
if (!pchar) return false;
|
|
|
|
GMatrix2D m = pchar->GetMatrix();
|
|
m.M_[1][2] = TwipsToPixels(m.M_[0][2]);
|
|
m.M_[0][2] = TwipsToPixels(m.M_[1][2]);
|
|
*pmat = m;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool GFxValue::ObjectInterface::SetDisplayMatrix(void* pdata, const GMatrix2D& mat)
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_SetDisplayMatrix, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
GFxCharacterHandle* pch = static_cast<GFxCharacterHandle*>(pdata);
|
|
GFxASCharacter* pchar = pch->ResolveCharacter(pMovieRoot);
|
|
if (!pchar) return false;
|
|
|
|
// Extra checks
|
|
if (!mat.IsValid())
|
|
{
|
|
GFC_DEBUG_WARNING(1, "GFxValue::SetDisplayMatrix called with an invalid matrix.\n"
|
|
"At least one of the matrix values is invalid (non-finite).\n");
|
|
return false;
|
|
}
|
|
|
|
GMatrix2D m = mat;
|
|
m.M_[0][2] = PixelsToTwips(m.M_[0][2]);
|
|
m.M_[1][2] = PixelsToTwips(m.M_[1][2]);
|
|
pchar->SetMatrix(m);
|
|
|
|
// Also set the geom data structure to reflect changes for the runtime
|
|
GFxASCharacter::GeomDataType geomData;
|
|
pchar->GetGeomData(geomData);
|
|
geomData.X = int(mat.GetX());
|
|
geomData.Y = int(mat.GetY());
|
|
geomData.XScale = mat.GetXScale()*(Double)100.;
|
|
geomData.YScale = mat.GetYScale()*(Double)100.;
|
|
geomData.Rotation = (mat.GetRotation()*(Double)180.)/GFC_MATH_PI;
|
|
pchar->SetGeomData(geomData);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool GFxValue::ObjectInterface::GetMatrix3D(void* pdata, GMatrix3D* pmat) const
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_GetMatrix3D, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
#ifndef GFC_NO_3D
|
|
GFxCharacterHandle* pch = static_cast<GFxCharacterHandle*>(pdata);
|
|
GFxASCharacter* pchar = pch->ResolveCharacter(pMovieRoot);
|
|
if (!pchar) return false;
|
|
|
|
GMatrix3D m = pchar->GetMatrix3D() ? *pchar->GetMatrix3D() : GMatrix3D::Identity;
|
|
m.SetX(TwipsToPixels(m.GetX()));
|
|
m.SetY(TwipsToPixels(m.GetY()));
|
|
*pmat = m;
|
|
|
|
return true;
|
|
#else
|
|
GUNUSED2(pdata, pmat);
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
bool GFxValue::ObjectInterface::SetMatrix3D(void* pdata, const GMatrix3D& mat)
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_SetMatrix3D, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
#ifndef GFC_NO_3D
|
|
GFxCharacterHandle* pch = static_cast<GFxCharacterHandle*>(pdata);
|
|
GFxASCharacter* pchar = pch->ResolveCharacter(pMovieRoot);
|
|
if (!pchar) return false;
|
|
|
|
// Extra checks
|
|
if (!mat.IsValid())
|
|
{
|
|
GFC_DEBUG_WARNING(1, "GFxValue::SetDisplayMatrix called with an invalid matrix.\n"
|
|
"At least one of the matrix values is invalid (non-finite).\n");
|
|
return false;
|
|
}
|
|
|
|
GMatrix3D m = mat;
|
|
// m.SetX(PixelsToTwips(m.GetX()));
|
|
// m.SetY(PixelsToTwips(m.GetY()));
|
|
pchar->SetMatrix3D(m);
|
|
|
|
// Also set the geom data structure to reflect changes for the runtime
|
|
GFxASCharacter::GeomDataType geomData;
|
|
pchar->GetGeomData(geomData);
|
|
geomData.Z = mat.GetZ();
|
|
geomData.ZScale = mat.GetZScale()*(Double)100.;
|
|
|
|
float xr, yr;
|
|
mat.GetRotation(&xr, &yr, NULL);
|
|
geomData.XRotation = GFC_RADTODEG(xr);
|
|
geomData.YRotation = GFC_RADTODEG(yr);
|
|
|
|
pchar->SetGeomData(geomData);
|
|
|
|
return true;
|
|
#else
|
|
GUNUSED2(pdata, mat);
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
bool GFxValue::ObjectInterface::IsDisplayObjectActive(void* pdata) const
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_IsDisplayObjectActive, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
GFxCharacterHandle* pch = static_cast<GFxCharacterHandle*>(pdata);
|
|
GFxASCharacter* pchar = pch->ResolveCharacter(pMovieRoot);
|
|
return pchar != NULL;
|
|
}
|
|
|
|
bool GFxValue::ObjectInterface::GetDisplayInfo(void* pdata, DisplayInfo* pinfo) const
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_GetDisplayInfo, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
// The getter code was lifted from GFxASCharacter::GetStandardMember
|
|
|
|
GFxCharacterHandle* pch = static_cast<GFxCharacterHandle*>(pdata);
|
|
GFxASCharacter* pchar = pch->ResolveCharacter(pMovieRoot);
|
|
if (!pchar) return false;
|
|
|
|
GFxASCharacter::GeomDataType geomData;
|
|
pchar->GetGeomData(geomData);
|
|
if (pchar->GetObjectType() == GASObjectInterface::Object_TextField)
|
|
{
|
|
// Special case for TextField
|
|
GASTextField* ptf = static_cast<GASTextField*>(pchar);
|
|
ptf->GetPosition(pinfo);
|
|
}
|
|
else
|
|
{
|
|
Double x = TwipsToPixels(Double(geomData.X));
|
|
Double y = TwipsToPixels(Double(geomData.Y));
|
|
Double rotation = geomData.Rotation;
|
|
Double xscale = geomData.XScale;
|
|
Double yscale = geomData.YScale;
|
|
Double alpha = pchar->GetCxform().M_[3][0] * 100.F;
|
|
bool visible = pchar->GetVisible();
|
|
#ifndef GFC_NO_3D
|
|
Double xrotation = geomData.XRotation;
|
|
Double yrotation = geomData.YRotation;
|
|
Double zscale = geomData.ZScale;
|
|
Double z = geomData.Z;
|
|
pinfo->Set(x, y, rotation, xscale, yscale, alpha, visible, z, xrotation, yrotation, zscale);
|
|
pinfo->SetPerspFOV(pchar->GetPerspectiveFOV());
|
|
pinfo->SetPerspective3D(pchar->GetPerspective3D());
|
|
pinfo->SetView3D(pchar->GetView3D());
|
|
#else
|
|
pinfo->Set(x, y, rotation, xscale, yscale, alpha, visible, 0,0,0,0);
|
|
#endif
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#ifndef GFC_NO_3D
|
|
void GFxValue_UpdateTransform(GFxASCharacter* pchar)
|
|
{
|
|
GMatrix3D rotXMat, transMat, scaleMat, rotYMat;
|
|
|
|
// build new matrix
|
|
transMat.SetZ((Float)pchar->pGeomData->Z);
|
|
scaleMat.SetZScale((Float)pchar->pGeomData->ZScale/100.f);
|
|
|
|
rotXMat.RotateX((Float)GFC_DEGTORAD(pchar->pGeomData->XRotation));
|
|
rotYMat.RotateY((Float)GFC_DEGTORAD(pchar->pGeomData->YRotation));
|
|
|
|
// Apply transforms in SRT order
|
|
GMatrix3D m(scaleMat);
|
|
m.Append(rotXMat);
|
|
m.Append(rotYMat);
|
|
m.Append(transMat);
|
|
|
|
if (m.IsValid())
|
|
pchar->SetMatrix3D(m);
|
|
}
|
|
#endif
|
|
|
|
bool GFxValue::ObjectInterface::SetDisplayInfo(void *pdata, const DisplayInfo &cinfo)
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_SetDisplayInfo, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
// The getter code was lifted from GFxASCharacter::SetStandardMember, however
|
|
// some logic was compressed for efficiency (e.g.: set the matrix once, instead
|
|
// of 5 different times - worst case)
|
|
|
|
GFxCharacterHandle* pch = static_cast<GFxCharacterHandle*>(pdata);
|
|
GFxASCharacter* pchar = pch->ResolveCharacter(pMovieRoot);
|
|
if (!pchar) return false;
|
|
|
|
// Check for TextField special case:
|
|
bool istf = (pchar->GetObjectType() == GASObjectInterface::Object_TextField);
|
|
GASTextField* ptf = static_cast<GASTextField*>(pchar);
|
|
|
|
if (cinfo.IsFlagSet(DisplayInfo::V_alpha))
|
|
{
|
|
if (!GASNumberUtil::IsNaN(cinfo.GetAlpha()))
|
|
{
|
|
// Set alpha modulate, in percent.
|
|
GFxASCharacter::Cxform cx = pchar->GetCxform();
|
|
cx.M_[3][0] = Float(cinfo.GetAlpha() / 100.);
|
|
pchar->SetCxform(cx);
|
|
pchar->SetAcceptAnimMoves(0);
|
|
}
|
|
}
|
|
if (cinfo.IsFlagSet(DisplayInfo::V_visible))
|
|
{
|
|
pchar->SetVisible(cinfo.GetVisible());
|
|
}
|
|
|
|
#ifndef GFC_NO_3D
|
|
bool UpdateTransforms = false;
|
|
|
|
if (cinfo.IsFlagSet(DisplayInfo::V_z))
|
|
{
|
|
GASNumber zval = cinfo.GetZ();
|
|
if (GASNumberUtil::IsNaN(zval))
|
|
zval = 0;
|
|
if (GASNumberUtil::IsNEGATIVE_INFINITY(zval) || GASNumberUtil::IsPOSITIVE_INFINITY(zval))
|
|
zval = 0;
|
|
|
|
pchar->EnsureGeomDataCreated(); // let timeline anim continue
|
|
GASSERT(pchar->pGeomData);
|
|
|
|
if (zval != pchar->pGeomData->Z)
|
|
{
|
|
pchar->pGeomData->Z = zval;
|
|
|
|
UpdateTransforms = true;
|
|
}
|
|
}
|
|
|
|
if (cinfo.IsFlagSet(DisplayInfo::V_zscale))
|
|
{
|
|
GASNumber newZScale = cinfo.GetZScale();
|
|
if (GASNumberUtil::IsNaN(newZScale) ||
|
|
GASNumberUtil::IsNEGATIVE_INFINITY(newZScale) || GASNumberUtil::IsPOSITIVE_INFINITY(newZScale))
|
|
{
|
|
newZScale = 100.;
|
|
}
|
|
|
|
pchar->EnsureGeomDataCreated(); // let timeline anim continue
|
|
GASSERT(pchar->pGeomData);
|
|
|
|
if (pchar->pGeomData->ZScale != newZScale)
|
|
{
|
|
pchar->pGeomData->ZScale = newZScale;
|
|
|
|
UpdateTransforms = true;
|
|
}
|
|
}
|
|
|
|
if (cinfo.IsFlagSet(DisplayInfo::V_xrotation))
|
|
{
|
|
GASNumber rval = cinfo.GetXRotation();
|
|
|
|
pchar->EnsureGeomDataCreated(); // let timeline anim continue
|
|
GASSERT(pchar->pGeomData);
|
|
|
|
if (rval != pchar->pGeomData->XRotation)
|
|
{
|
|
Double r = fmod((Double)rval, (Double)360.);
|
|
if (r > 180)
|
|
r -= 360;
|
|
else if (r < -180)
|
|
r += 360;
|
|
|
|
pchar->pGeomData->XRotation = r;
|
|
|
|
UpdateTransforms = true;
|
|
}
|
|
}
|
|
|
|
if (cinfo.IsFlagSet(DisplayInfo::V_yrotation))
|
|
{
|
|
GASNumber rval = cinfo.GetYRotation();
|
|
|
|
pchar->EnsureGeomDataCreated(); // let timeline anim continue
|
|
GASSERT(pchar->pGeomData);
|
|
|
|
if (rval != pchar->pGeomData->YRotation)
|
|
{
|
|
Double r = fmod((Double)rval, (Double)360.);
|
|
if (r > 180)
|
|
r -= 360;
|
|
else if (r < -180)
|
|
r += 360;
|
|
|
|
pchar->pGeomData->YRotation= r;
|
|
|
|
UpdateTransforms = true;
|
|
}
|
|
}
|
|
|
|
if (UpdateTransforms)
|
|
GFxValue_UpdateTransform(pchar);
|
|
|
|
if (cinfo.IsFlagSet(DisplayInfo::V_perspFOV))
|
|
{
|
|
GASNumber rval = cinfo.GetPerspFOV();
|
|
if (rval != pchar->GetPerspectiveFOV())
|
|
{
|
|
Double r = fmod((Double)rval, (Double)180.);
|
|
pchar->SetPerspectiveFOV((float)r);
|
|
}
|
|
}
|
|
|
|
if (cinfo.IsFlagSet(DisplayInfo::V_perspMatrix3D))
|
|
{
|
|
pchar->SetPerspective3D(*cinfo.GetPerspective3D());
|
|
}
|
|
|
|
if (cinfo.IsFlagSet(DisplayInfo::V_viewMatrix3D))
|
|
{
|
|
pchar->SetView3D(*cinfo.GetView3D());
|
|
}
|
|
#endif
|
|
|
|
if (cinfo.IsFlagSet(DisplayInfo::V_x) || cinfo.IsFlagSet(DisplayInfo::V_y) || cinfo.IsFlagSet(DisplayInfo::V_rotation) ||
|
|
cinfo.IsFlagSet(DisplayInfo::V_xscale) || cinfo.IsFlagSet(DisplayInfo::V_yscale))
|
|
{
|
|
// Special case for TextField:
|
|
if (istf && (cinfo.IsFlagSet(DisplayInfo::V_xscale) ||
|
|
cinfo.IsFlagSet(DisplayInfo::V_yscale) ||
|
|
cinfo.IsFlagSet(DisplayInfo::V_rotation)))
|
|
ptf->SetNeedToUpdateGeomData();
|
|
|
|
pchar->SetAcceptAnimMoves(0);
|
|
GASSERT(pchar->pGeomData);
|
|
|
|
GFxASCharacter::Matrix m = pchar->GetMatrix();
|
|
|
|
GPointD pt;
|
|
// Special case for TextField:
|
|
if (istf && (cinfo.IsFlagSet(DisplayInfo::V_x) || cinfo.IsFlagSet(DisplayInfo::V_y)))
|
|
{
|
|
GPointF tpt = ptf->TransformToTextRectSpace(cinfo);
|
|
pt.x = tpt.x;
|
|
pt.y = tpt.y;
|
|
}
|
|
else
|
|
{
|
|
if (cinfo.IsFlagSet(GFxValue::DisplayInfo::V_x))
|
|
pt.x = cinfo.GetX();
|
|
if (cinfo.IsFlagSet(GFxValue::DisplayInfo::V_y))
|
|
pt.y = cinfo.GetY();
|
|
}
|
|
|
|
if (cinfo.IsFlagSet(DisplayInfo::V_rotation) || cinfo.IsFlagSet(DisplayInfo::V_xscale) || cinfo.IsFlagSet(DisplayInfo::V_yscale))
|
|
{
|
|
GFxASCharacter::Matrix om = pchar->pGeomData->OrigMatrix;
|
|
om.M_[0][2] = m.M_[0][2];
|
|
om.M_[1][2] = m.M_[1][2];
|
|
|
|
Double origRotation = om.GetRotation();
|
|
Double origXScale = om.GetXScale();
|
|
Double origYScale = om.GetYScale();
|
|
|
|
Double newXScale = pchar->pGeomData->XScale / 100;
|
|
Double newYScale = pchar->pGeomData->YScale / 100;
|
|
Double newRotation = GFC_DEGTORAD(pchar->pGeomData->Rotation);
|
|
|
|
// _rotation
|
|
GASNumber rval = cinfo.IsFlagSet(DisplayInfo::V_rotation) ? cinfo.GetRotation() : GASNumberUtil::NaN();
|
|
if (!GASNumberUtil::IsNaN(rval))
|
|
{
|
|
newRotation = fmod((Double)rval, (Double)360.);
|
|
if (newRotation > 180)
|
|
newRotation -= 360;
|
|
else if (newRotation < -180)
|
|
newRotation += 360;
|
|
pchar->pGeomData->Rotation = newRotation;
|
|
newRotation = GFC_DEGTORAD(newRotation); // Convert to rads
|
|
}
|
|
// _xscale
|
|
Double nx = cinfo.IsFlagSet(DisplayInfo::V_xscale) ? (cinfo.GetXScale()/100) : GASNumberUtil::NaN();
|
|
if (!(GASNumberUtil::IsNaN(nx) ||
|
|
GASNumberUtil::IsNEGATIVE_INFINITY(nx) || GASNumberUtil::IsPOSITIVE_INFINITY(nx)) && (nx != newXScale))
|
|
{
|
|
pchar->pGeomData->XScale = cinfo.GetXScale();
|
|
if (origXScale == 0 || nx > 1E+16)
|
|
{
|
|
nx = 0;
|
|
origXScale = 1;
|
|
}
|
|
newXScale = nx;
|
|
}
|
|
// _yscale
|
|
Double ny = cinfo.IsFlagSet(DisplayInfo::V_yscale) ? (cinfo.GetYScale()/100) : GASNumberUtil::NaN();
|
|
if (!(GASNumberUtil::IsNaN(ny) ||
|
|
GASNumberUtil::IsNEGATIVE_INFINITY(ny) || GASNumberUtil::IsPOSITIVE_INFINITY(ny)) && (ny != newYScale))
|
|
{
|
|
pchar->pGeomData->YScale = cinfo.GetYScale();
|
|
if (origYScale == 0 || ny > 1E+16)
|
|
{
|
|
ny = 0;
|
|
origYScale = 1;
|
|
}
|
|
newYScale = ny;
|
|
}
|
|
|
|
// remove old rotation by rotate back and add new one
|
|
GFxASCharacter_MatrixScaleAndRotate2x2(om,
|
|
Float(newXScale/origXScale),
|
|
Float(newYScale/origYScale),
|
|
Float(newRotation - origRotation));
|
|
|
|
m = om;
|
|
}
|
|
|
|
|
|
|
|
// _x
|
|
GASNumber xval = cinfo.IsFlagSet(DisplayInfo::V_x) ? pt.x : GASNumberUtil::NaN();
|
|
if (!GASNumberUtil::IsNaN(xval))
|
|
{
|
|
if (GASNumberUtil::IsNEGATIVE_INFINITY(xval) || GASNumberUtil::IsPOSITIVE_INFINITY(xval))
|
|
xval = 0;
|
|
pchar->pGeomData->X = int(floor(PixelsToTwips(xval)));
|
|
m.M_[0][2] = (Float) pchar->pGeomData->X;
|
|
}
|
|
// _y
|
|
GASNumber yval = cinfo.IsFlagSet(DisplayInfo::V_y) ? pt.y : GASNumberUtil::NaN();
|
|
if (!GASNumberUtil::IsNaN(yval))
|
|
{
|
|
if (GASNumberUtil::IsNEGATIVE_INFINITY(yval) || GASNumberUtil::IsPOSITIVE_INFINITY(yval))
|
|
yval = 0;
|
|
pchar->pGeomData->Y = int(floor(PixelsToTwips(yval)));
|
|
m.M_[1][2] = (Float) pchar->pGeomData->Y;
|
|
}
|
|
|
|
if (m.IsValid())
|
|
pchar->SetMatrix(m);
|
|
|
|
// Special case for TextField:
|
|
if (istf)
|
|
{
|
|
if (cinfo.IsFlagSet(GFxValue::DisplayInfo::V_x))
|
|
pchar->pGeomData->X = G_IRound(PixelsToTwips(pt.x));
|
|
if (cinfo.IsFlagSet(GFxValue::DisplayInfo::V_y))
|
|
pchar->pGeomData->Y = G_IRound(PixelsToTwips(pt.y));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool GFxValue::ObjectInterface::SetText(void *pdata, const char *ptext, bool reqHtml)
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_SetText, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
GFxCharacterHandle* pch = static_cast<GFxCharacterHandle*>(pdata);
|
|
GFxASCharacter* pchar = pch->ResolveCharacter(pMovieRoot);
|
|
if (!pchar)
|
|
return false;
|
|
|
|
if (pchar->GetObjectType() != GASObjectInterface::Object_TextField)
|
|
return SetMember(pdata, (reqHtml) ? "htmlText" : "text", ptext, true);
|
|
else
|
|
{
|
|
GASTextField* ptf = static_cast<GASTextField*>(pchar);
|
|
ptf->SetText(ptext, reqHtml);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool GFxValue::ObjectInterface::SetText(void *pdata, const wchar_t *ptext, bool reqHtml)
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_SetText, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
GFxCharacterHandle* pch = static_cast<GFxCharacterHandle*>(pdata);
|
|
GFxASCharacter* pchar = pch->ResolveCharacter(pMovieRoot);
|
|
if (!pchar)
|
|
return false;
|
|
|
|
if (pchar->GetObjectType() != GASObjectInterface::Object_TextField)
|
|
return SetMember(pdata, (reqHtml) ? "htmlText" : "text", ptext, true);
|
|
else
|
|
{
|
|
GASTextField* ptf = static_cast<GASTextField*>(pchar);
|
|
ptf->SetText(ptext, reqHtml);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool GFxValue::ObjectInterface::GetText(void* pdata, GFxValue* pval, bool reqHtml) const
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_GetText, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
GFxCharacterHandle* pch = static_cast<GFxCharacterHandle*>(pdata);
|
|
GFxASCharacter* pchar = pch->ResolveCharacter(pMovieRoot);
|
|
if (!pchar)
|
|
return false;
|
|
|
|
if (pchar->GetObjectType() != GASObjectInterface::Object_TextField)
|
|
return GetMember(pdata, (reqHtml) ? "htmlText" : "text", pval, true);
|
|
else
|
|
{
|
|
GASEnvironment* penv = pMovieRoot->pLevel0Movie->GetASEnvironment();
|
|
GASTextField* ptf = static_cast<GASTextField*>(pchar);
|
|
GASString astext = ptf->GetText(penv, reqHtml);
|
|
pMovieRoot->ASValue2GFxValue(penv, astext, pval);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool GFxValue::ObjectInterface::GotoAndPlay(void *pdata, const char *frame, bool stop)
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_GotoAndPlay, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
GFxCharacterHandle* pch = static_cast<GFxCharacterHandle*>(pdata);
|
|
GFxASCharacter* pchar = pch->ResolveCharacter(pMovieRoot);
|
|
if (!pchar || !pchar->IsSprite())
|
|
return false;
|
|
|
|
UInt frameNum;
|
|
if (pchar->GetLabeledFrame(frame, &frameNum))
|
|
{
|
|
pchar->GotoFrame(frameNum);
|
|
pchar->SetPlayState(stop ? GFxMovie::Stopped : GFxMovie::Playing);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool GFxValue::ObjectInterface::GotoAndPlay(void *pdata, UInt frame, bool stop)
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_GotoAndPlay, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
GFxCharacterHandle* pch = static_cast<GFxCharacterHandle*>(pdata);
|
|
GFxASCharacter* pchar = pch->ResolveCharacter(pMovieRoot);
|
|
if (!pchar || !pchar->IsSprite())
|
|
return false;
|
|
|
|
// Incoming frame number is 1-based, but internally GFx is 0 based.
|
|
pchar->GotoFrame(frame-1);
|
|
pchar->SetPlayState(stop ? GFxMovie::Stopped : GFxMovie::Playing);
|
|
return true;
|
|
}
|
|
|
|
bool GFxValue::ObjectInterface::GetCxform(void *pdata, GRenderer::Cxform *pcx) const
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_GetCxform, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
GFxCharacterHandle* pch = static_cast<GFxCharacterHandle*>(pdata);
|
|
GFxASCharacter* pchar = pch->ResolveCharacter(pMovieRoot);
|
|
if (!pchar) return false;
|
|
|
|
*pcx = pchar->GetCxform();
|
|
return true;
|
|
}
|
|
|
|
bool GFxValue::ObjectInterface::SetCxform(void *pdata, const GRenderer::Cxform &cx)
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_SetCxform, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
GFxCharacterHandle* pch = static_cast<GFxCharacterHandle*>(pdata);
|
|
GFxASCharacter* pchar = pch->ResolveCharacter(pMovieRoot);
|
|
if (!pchar) return false;
|
|
|
|
pchar->SetCxform(cx);
|
|
pchar->SetAcceptAnimMoves(false);
|
|
return true;
|
|
}
|
|
|
|
bool GFxValue::ObjectInterface::CreateEmptyMovieClip(void* pdata, GFxValue* pmc,
|
|
const char* instanceName, SInt depth)
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_CreateEmptyMovieClip, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
GFxCharacterHandle* pch = static_cast<GFxCharacterHandle*>(pdata);
|
|
GFxASCharacter* pchar = pch->ResolveCharacter(pMovieRoot);
|
|
if (!pchar || !pchar->IsSprite())
|
|
return false;
|
|
|
|
GFxSprite* psprite = (GFxSprite*)pchar;
|
|
GASEnvironment* penv = pMovieRoot->pLevel0Movie->GetASEnvironment();
|
|
|
|
// Check for specified depth; else get next highest depth
|
|
if (depth < 0)
|
|
depth = G_Max<SInt>(0, psprite->GetLargestDepthInUse() - 16384 + 1);
|
|
|
|
// Create a new object and add it.
|
|
GFxCharPosInfo pos = GFxCharPosInfo( GFxResourceId(GFxCharacterDef::CharId_EmptyMovieClip),
|
|
depth + 16384,
|
|
1, GRenderer::Cxform::Identity, 1, GRenderer::Matrix::Identity);
|
|
// Bounds check depth.
|
|
if ((pos.Depth < 0) || (pos.Depth > (2130690045 + 16384)))
|
|
return false;
|
|
|
|
GPtr<GFxCharacter> newCh = psprite->AddDisplayObject(
|
|
pos, penv->CreateString(instanceName), NULL, NULL, GFC_MAX_UINT,
|
|
GFxDisplayList::Flags_ReplaceIfDepthIsOccupied);
|
|
if (newCh)
|
|
{
|
|
newCh->SetAcceptAnimMoves(false);
|
|
|
|
// Return newly created clip.
|
|
GFxASCharacter* pspriteCh = newCh->CharToASCharacter();
|
|
GASSERT (pspriteCh != 0);
|
|
GASValue asval(pspriteCh);
|
|
pMovieRoot->ASValue2GFxValue(penv, asval, pmc);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool GFxValue::ObjectInterface::AttachMovie(void* pdata, GFxValue* pmc,
|
|
const char* symbolName, const char* instanceName,
|
|
SInt depth, const GFxValue* initObj)
|
|
{
|
|
#ifdef GFX_AMP_SERVER
|
|
ScopeFunctionTimer timer(pMovieRoot->AdvanceStats, NativeCodeSwdHandle, Func_GFxValue_ObjectInterface_AttachMovie, Amp_Profile_Level_Low);
|
|
#endif
|
|
|
|
GFxCharacterHandle* pch = static_cast<GFxCharacterHandle*>(pdata);
|
|
GFxASCharacter* pchar = pch->ResolveCharacter(pMovieRoot);
|
|
if (!pchar || !pchar->IsSprite())
|
|
{
|
|
//RAGE
|
|
GFC_DEBUG_MESSAGE2(true, "GFxValue::ObjectInterface::AttachMovie returning false - pChar=%d, isSprite=%d", pchar, pchar ? pchar->IsSprite() : -1);
|
|
return false;
|
|
}
|
|
|
|
GFxSprite* psprite = (GFxSprite*)pchar;
|
|
GASEnvironment* penv = pMovieRoot->pLevel0Movie->GetASEnvironment();
|
|
|
|
GFxResourceBindData resBindData;
|
|
if (!pMovieRoot->FindExportedResource(psprite->GetResourceMovieDef(), &resBindData, symbolName))
|
|
{
|
|
psprite->LogScriptWarning("Error: %s.attachMovie() failed - export name \"%s\" is not found.\n",
|
|
psprite->GetCharacterHandle()->GetNamePath().ToCStr(), symbolName);
|
|
//RAGE
|
|
GFC_DEBUG_MESSAGE(true, "GFxValue::ObjectInterface::AttachMovie returning false - !pMovieRoot->FindExportedResource");
|
|
return false;
|
|
}
|
|
|
|
GASSERT(resBindData.pResource.GetPtr() != 0); // MA TBD: Could this be true?
|
|
if (!(resBindData.pResource->GetResourceType() & GFxResource::RT_CharacterDef_Bit))
|
|
{
|
|
psprite->LogScriptWarning("Error: %s.attachMovie() failed - \"%s\" is not a movieclip.\n",
|
|
psprite->GetCharacterHandle()->GetNamePath().ToCStr(), symbolName);
|
|
//RAGE
|
|
GFC_DEBUG_MESSAGE(true, "GFxValue::ObjectInterface::AttachMovie returning false - !(resBindData.pResource->GetResourceType() & GFxResource::RT_CharacterDef_Bit)");
|
|
return false;
|
|
}
|
|
|
|
GFxCharacterCreateInfo ccinfo;
|
|
ccinfo.pCharDef = (GFxCharacterDef*) resBindData.pResource.GetPtr();
|
|
ccinfo.pBindDefImpl = resBindData.pBinding->GetOwnerDefImpl();
|
|
|
|
// Check for specified depth; else get next highest depth
|
|
if (depth < 0)
|
|
depth = G_Max<SInt>(0, psprite->GetLargestDepthInUse() - 16384 + 1);
|
|
|
|
// Create a new object and add it.
|
|
GFxCharPosInfo pos( ccinfo.pCharDef->GetId(), depth + 16384,
|
|
1, GRenderer::Cxform::Identity, 1, GRenderer::Matrix::Identity);
|
|
// Bounds check depth.
|
|
if ((pos.Depth < 0) || (pos.Depth > (2130690045 + 16384)))
|
|
{
|
|
psprite->LogScriptWarning("Error: %s.attachMovie(\"%s\") failed - depth (%d) must be >= 0\n",
|
|
psprite->GetCharacterHandle()->GetNamePath().ToCStr(), symbolName, pos.Depth);
|
|
//RAGE
|
|
GFC_DEBUG_MESSAGE1(true, "GFxValue::ObjectInterface::AttachMovie returning false - depth = %d", pos.Depth);
|
|
return false;
|
|
}
|
|
|
|
// Check for init obj
|
|
GASObjectInterface* pinitobj = NULL;
|
|
if (initObj)
|
|
{
|
|
GASValue oa;
|
|
pMovieRoot->GFxValue2ASValue(*initObj, &oa);
|
|
pinitobj = oa.ToObjectInterface(penv);
|
|
}
|
|
|
|
// We pass pchDef to make sure that symbols from nested imports use
|
|
// the right definition scope, which might be different from that of psprite.
|
|
GPtr<GFxCharacter> newCh = psprite->AddDisplayObject(
|
|
pos, penv->CreateString(instanceName), 0,
|
|
pinitobj, GFC_MAX_UINT,
|
|
GFxDisplayList::Flags_ReplaceIfDepthIsOccupied, &ccinfo);
|
|
if (newCh)
|
|
{
|
|
newCh->SetAcceptAnimMoves(false);
|
|
|
|
//!AB: attachMovie in Flash 6 and above should return newly created clip
|
|
if (psprite->GetVersion() >= 6)
|
|
{
|
|
GFxASCharacter* pspriteCh = newCh->CharToASCharacter();
|
|
GASSERT (pspriteCh != 0);
|
|
GASValue asval(pspriteCh);
|
|
pMovieRoot->ASValue2GFxValue(penv, asval, pmc);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void GFxValue::ObjectInterface::ToString(GString* pstr, const GFxValue& thisVal) const
|
|
{
|
|
GASEnvironment* penv = pMovieRoot->pLevel0Movie->GetASEnvironment();
|
|
|
|
GASValue asVal;
|
|
penv->GetMovieRoot()->GFxValue2ASValue(thisVal, &asVal);
|
|
|
|
*pstr = GString(asVal.ToString(penv).ToCStr());
|
|
}
|
|
|
|
|
|
#ifndef GFC_NO_FXPLAYER_AS_USERDATA
|
|
|
|
GFxASUserData* GFxValue::ObjectInterface::GetUserData(void* pdata, bool isdobj) const
|
|
{
|
|
GASObjectInterface* pthis = static_cast<GASObjectInterface*>(pdata);
|
|
if (isdobj)
|
|
{
|
|
GFxCharacterHandle* pch = static_cast<GFxCharacterHandle*>(pdata);
|
|
pthis = pch->ResolveCharacter(pMovieRoot);
|
|
if (!pthis) return NULL;
|
|
}
|
|
|
|
return pthis->GetUserData();
|
|
}
|
|
|
|
void GFxValue::ObjectInterface::SetUserData(void* pdata, GFxASUserData* puserdata, bool isdobj)
|
|
{
|
|
GASObjectInterface* pthis = static_cast<GASObjectInterface*>(pdata);
|
|
if (isdobj)
|
|
{
|
|
GFxCharacterHandle* pch = static_cast<GFxCharacterHandle*>(pdata);
|
|
pthis = pch->ResolveCharacter(pMovieRoot);
|
|
if (!pthis) return;
|
|
}
|
|
|
|
return pthis->SetUserData(pMovieRoot, puserdata, isdobj);
|
|
}
|
|
|
|
|
|
void GFxASUserData::SetLastObjectValue(GFxValue::ObjectInterface* pobjIfc, void* pdata, bool isdobj)
|
|
{
|
|
pLastObjectInterface = pobjIfc;
|
|
pLastData = pdata;
|
|
IsLastDispObj = isdobj;
|
|
}
|
|
|
|
bool GFxASUserData::GetLastObjectValue(GFxValue* value) const
|
|
{
|
|
if (!pLastObjectInterface || !pLastData || !value) return false;
|
|
|
|
GFxValue::ValueType type = GFxValue::VT_Object;
|
|
GASObjectInterface* pifc = static_cast<GASObjectInterface*>(pLastData);
|
|
if (IsLastDispObj)
|
|
{
|
|
type = GFxValue::VT_DisplayObject;
|
|
GFxCharacterHandle* pch = static_cast<GFxCharacterHandle*>(pLastData);
|
|
GFxMovieRoot* pmovieRoot = pLastObjectInterface->GetMovieRoot();
|
|
GASSERT(pmovieRoot);
|
|
pifc = pch->ResolveCharacter(pmovieRoot);
|
|
}
|
|
else
|
|
{
|
|
GASObject* pobj = pifc->ToASObject();
|
|
if (pobj->GetObjectType() == GASObjectInterface::Object_Array)
|
|
type = GFxValue::VT_Array;
|
|
}
|
|
|
|
// Clear existing managed ref first
|
|
if (value->IsManagedValue()) value->ReleaseManagedValue();
|
|
value->Type = GFxValue::ValueType(type | GFxValue::VTC_ManagedBit);
|
|
value->Value.pData = pLastData;
|
|
value->pObjectInterface = pLastObjectInterface;
|
|
// Make sure to add-ref before returning
|
|
pLastObjectInterface->ObjectAddRef(value, pLastData);
|
|
|
|
return true;
|
|
}
|
|
|
|
#endif // GFC_NO_FXPLAYER_AS_USERDATA
|