Changeset View
Changeset View
Standalone View
Standalone View
source/simulation2/scripting/EngineScriptConversions.cpp
Show All 25 Lines | |||||
#include "ps/CLogger.h" | #include "ps/CLogger.h" | ||||
#include "ps/Shapes.h" | #include "ps/Shapes.h" | ||||
#include "ps/utf16string.h" | #include "ps/utf16string.h" | ||||
#include "simulation2/helpers/CinemaPath.h" | #include "simulation2/helpers/CinemaPath.h" | ||||
#include "simulation2/helpers/Grid.h" | #include "simulation2/helpers/Grid.h" | ||||
#include "simulation2/system/IComponent.h" | #include "simulation2/system/IComponent.h" | ||||
#include "simulation2/system/ParamNode.h" | #include "simulation2/system/ParamNode.h" | ||||
#define FAIL(msg) STMT(JS_ReportError(rq.cx, msg); return false) | #define FAIL(msg) STMT(LOGERROR(msg); return false) | ||||
#define FAIL_VOID(msg) STMT(JS_ReportError(rq.cx, msg); return) | #define FAIL_VOID(msg) STMT(ScriptException::Raise(rq, msg); return) | ||||
template<> void ScriptInterface::ToJSVal<IComponent*>(const Request& rq, JS::MutableHandleValue ret, IComponent* const& val) | template<> void ScriptInterface::ToJSVal<IComponent*>(const ScriptRequest& rq, JS::MutableHandleValue ret, IComponent* const& val) | ||||
{ | { | ||||
if (val == NULL) | if (val == NULL) | ||||
{ | { | ||||
ret.setNull(); | ret.setNull(); | ||||
return; | return; | ||||
} | } | ||||
// If this is a scripted component, just return the JS object directly | // If this is a scripted component, just return the JS object directly | ||||
Show All 14 Lines | if (!val->NewJSObject(*ScriptInterface::GetScriptInterfaceAndCBData(rq.cx)->pScriptInterface, &obj)) | ||||
ret.setUndefined(); | ret.setUndefined(); | ||||
return; | return; | ||||
} | } | ||||
JS_SetPrivate(obj, static_cast<void*>(val)); | JS_SetPrivate(obj, static_cast<void*>(val)); | ||||
ret.setObject(*obj); | ret.setObject(*obj); | ||||
} | } | ||||
template<> void ScriptInterface::ToJSVal<CParamNode>(const Request& rq, JS::MutableHandleValue ret, CParamNode const& val) | template<> void ScriptInterface::ToJSVal<CParamNode>(const ScriptRequest& rq, JS::MutableHandleValue ret, CParamNode const& val) | ||||
{ | { | ||||
val.ToJSVal(rq, true, ret); | val.ToJSVal(rq, true, ret); | ||||
// Prevent modifications to the object, so that it's safe to share between | // Prevent modifications to the object, so that it's safe to share between | ||||
// components and to reconstruct on deserialization | // components and to reconstruct on deserialization | ||||
if (ret.isObject()) | if (ret.isObject()) | ||||
{ | { | ||||
JS::RootedObject obj(rq.cx, &ret.toObject()); | JS::RootedObject obj(rq.cx, &ret.toObject()); | ||||
JS_DeepFreezeObject(rq.cx, obj); | JS_DeepFreezeObject(rq.cx, obj); | ||||
} | } | ||||
} | } | ||||
template<> void ScriptInterface::ToJSVal<const CParamNode*>(const Request& rq, JS::MutableHandleValue ret, const CParamNode* const& val) | template<> void ScriptInterface::ToJSVal<const CParamNode*>(const ScriptRequest& rq, JS::MutableHandleValue ret, const CParamNode* const& val) | ||||
{ | { | ||||
if (val) | if (val) | ||||
ToJSVal(rq, ret, *val); | ToJSVal(rq, ret, *val); | ||||
else | else | ||||
ret.setUndefined(); | ret.setUndefined(); | ||||
} | } | ||||
template<> bool ScriptInterface::FromJSVal<CColor>(const Request& rq, JS::HandleValue v, CColor& out) | template<> bool ScriptInterface::FromJSVal<CColor>(const ScriptRequest& rq, JS::HandleValue v, CColor& out) | ||||
{ | { | ||||
if (!v.isObject()) | if (!v.isObject()) | ||||
FAIL("CColor has to be an object"); | FAIL("CColor has to be an object"); | ||||
JS::RootedObject obj(rq.cx, &v.toObject()); | JS::RootedObject obj(rq.cx, &v.toObject()); | ||||
JS::RootedValue r(rq.cx); | JS::RootedValue r(rq.cx); | ||||
JS::RootedValue g(rq.cx); | JS::RootedValue g(rq.cx); | ||||
JS::RootedValue b(rq.cx); | JS::RootedValue b(rq.cx); | ||||
JS::RootedValue a(rq.cx); | JS::RootedValue a(rq.cx); | ||||
if (!JS_GetProperty(rq.cx, obj, "r", &r) || !FromJSVal(rq, r, out.r)) | if (!JS_GetProperty(rq.cx, obj, "r", &r) || !FromJSVal(rq, r, out.r)) | ||||
FAIL("Failed to get property CColor.r"); | FAIL("Failed to get property CColor.r"); | ||||
if (!JS_GetProperty(rq.cx, obj, "g", &g) || !FromJSVal(rq, g, out.g)) | if (!JS_GetProperty(rq.cx, obj, "g", &g) || !FromJSVal(rq, g, out.g)) | ||||
FAIL("Failed to get property CColor.g"); | FAIL("Failed to get property CColor.g"); | ||||
if (!JS_GetProperty(rq.cx, obj, "b", &b) || !FromJSVal(rq, b, out.b)) | if (!JS_GetProperty(rq.cx, obj, "b", &b) || !FromJSVal(rq, b, out.b)) | ||||
FAIL("Failed to get property CColor.b"); | FAIL("Failed to get property CColor.b"); | ||||
if (!JS_GetProperty(rq.cx, obj, "a", &a) || !FromJSVal(rq, a, out.a)) | if (!JS_GetProperty(rq.cx, obj, "a", &a) || !FromJSVal(rq, a, out.a)) | ||||
FAIL("Failed to get property CColor.a"); | FAIL("Failed to get property CColor.a"); | ||||
return true; | return true; | ||||
} | } | ||||
template<> void ScriptInterface::ToJSVal<CColor>(const Request& rq, JS::MutableHandleValue ret, CColor const& val) | template<> void ScriptInterface::ToJSVal<CColor>(const ScriptRequest& rq, JS::MutableHandleValue ret, CColor const& val) | ||||
{ | { | ||||
CreateObject( | CreateObject( | ||||
rq, | rq, | ||||
ret, | ret, | ||||
"r", val.r, | "r", val.r, | ||||
"g", val.g, | "g", val.g, | ||||
"b", val.b, | "b", val.b, | ||||
"a", val.a); | "a", val.a); | ||||
} | } | ||||
template<> bool ScriptInterface::FromJSVal<fixed>(const Request& rq, JS::HandleValue v, fixed& out) | template<> bool ScriptInterface::FromJSVal<fixed>(const ScriptRequest& rq, JS::HandleValue v, fixed& out) | ||||
{ | { | ||||
double ret; | double ret; | ||||
if (!JS::ToNumber(rq.cx, v, &ret)) | if (!JS::ToNumber(rq.cx, v, &ret)) | ||||
return false; | return false; | ||||
out = fixed::FromDouble(ret); | out = fixed::FromDouble(ret); | ||||
// double can precisely represent the full range of fixed, so this is a non-lossy conversion | // double can precisely represent the full range of fixed, so this is a non-lossy conversion | ||||
return true; | return true; | ||||
} | } | ||||
template<> void ScriptInterface::ToJSVal<fixed>(const Request& UNUSED(rq), JS::MutableHandleValue ret, const fixed& val) | template<> void ScriptInterface::ToJSVal<fixed>(const ScriptRequest& UNUSED(rq), JS::MutableHandleValue ret, const fixed& val) | ||||
{ | { | ||||
ret.set(JS::NumberValue(val.ToDouble())); | ret.set(JS::NumberValue(val.ToDouble())); | ||||
} | } | ||||
template<> bool ScriptInterface::FromJSVal<CFixedVector3D>(const Request& rq, JS::HandleValue v, CFixedVector3D& out) | template<> bool ScriptInterface::FromJSVal<CFixedVector3D>(const ScriptRequest& rq, JS::HandleValue v, CFixedVector3D& out) | ||||
{ | { | ||||
if (!v.isObject()) | if (!v.isObject()) | ||||
return false; // TODO: report type error | return false; // TODO: report type error | ||||
JS::RootedObject obj(rq.cx, &v.toObject()); | JS::RootedObject obj(rq.cx, &v.toObject()); | ||||
JS::RootedValue p(rq.cx); | JS::RootedValue p(rq.cx); | ||||
if (!JS_GetProperty(rq.cx, obj, "x", &p)) return false; // TODO: report type errors | if (!JS_GetProperty(rq.cx, obj, "x", &p)) return false; // TODO: report type errors | ||||
if (!FromJSVal(rq, p, out.X)) return false; | if (!FromJSVal(rq, p, out.X)) return false; | ||||
if (!JS_GetProperty(rq.cx, obj, "y", &p)) return false; | if (!JS_GetProperty(rq.cx, obj, "y", &p)) return false; | ||||
if (!FromJSVal(rq, p, out.Y)) return false; | if (!FromJSVal(rq, p, out.Y)) return false; | ||||
if (!JS_GetProperty(rq.cx, obj, "z", &p)) return false; | if (!JS_GetProperty(rq.cx, obj, "z", &p)) return false; | ||||
if (!FromJSVal(rq, p, out.Z)) return false; | if (!FromJSVal(rq, p, out.Z)) return false; | ||||
return true; | return true; | ||||
} | } | ||||
template<> void ScriptInterface::ToJSVal<CFixedVector3D>(const Request& rq, JS::MutableHandleValue ret, const CFixedVector3D& val) | template<> void ScriptInterface::ToJSVal<CFixedVector3D>(const ScriptRequest& rq, JS::MutableHandleValue ret, const CFixedVector3D& val) | ||||
{ | { | ||||
JS::RootedObject global(rq.cx, rq.glob); | JS::RootedObject global(rq.cx, rq.glob); | ||||
JS::RootedValue valueVector3D(rq.cx); | JS::RootedValue valueVector3D(rq.cx); | ||||
if (!JS_GetProperty(rq.cx, global, "Vector3D", &valueVector3D)) | if (!JS_GetProperty(rq.cx, global, "Vector3D", &valueVector3D)) | ||||
FAIL_VOID("Failed to get Vector3D constructor"); | FAIL_VOID("Failed to get Vector3D constructor"); | ||||
JS::AutoValueArray<3> args(rq.cx); | JS::AutoValueArray<3> args(rq.cx); | ||||
args[0].setNumber(val.X.ToDouble()); | args[0].setNumber(val.X.ToDouble()); | ||||
args[1].setNumber(val.Y.ToDouble()); | args[1].setNumber(val.Y.ToDouble()); | ||||
args[2].setNumber(val.Z.ToDouble()); | args[2].setNumber(val.Z.ToDouble()); | ||||
if (!JS::Construct(rq.cx, valueVector3D, args, ret)) | if (!JS::Construct(rq.cx, valueVector3D, args, ret)) | ||||
FAIL_VOID("Failed to construct Vector3D object"); | FAIL_VOID("Failed to construct Vector3D object"); | ||||
} | } | ||||
template<> bool ScriptInterface::FromJSVal<CFixedVector2D>(const Request& rq, JS::HandleValue v, CFixedVector2D& out) | template<> bool ScriptInterface::FromJSVal<CFixedVector2D>(const ScriptRequest& rq, JS::HandleValue v, CFixedVector2D& out) | ||||
{ | { | ||||
if (!v.isObject()) | if (!v.isObject()) | ||||
return false; // TODO: report type error | return false; // TODO: report type error | ||||
JS::RootedObject obj(rq.cx, &v.toObject()); | JS::RootedObject obj(rq.cx, &v.toObject()); | ||||
JS::RootedValue p(rq.cx); | JS::RootedValue p(rq.cx); | ||||
if (!JS_GetProperty(rq.cx, obj, "x", &p)) return false; // TODO: report type errors | if (!JS_GetProperty(rq.cx, obj, "x", &p)) return false; // TODO: report type errors | ||||
if (!FromJSVal(rq, p, out.X)) return false; | if (!FromJSVal(rq, p, out.X)) return false; | ||||
if (!JS_GetProperty(rq.cx, obj, "y", &p)) return false; | if (!JS_GetProperty(rq.cx, obj, "y", &p)) return false; | ||||
if (!FromJSVal(rq, p, out.Y)) return false; | if (!FromJSVal(rq, p, out.Y)) return false; | ||||
return true; | return true; | ||||
} | } | ||||
template<> void ScriptInterface::ToJSVal<CFixedVector2D>(const Request& rq, JS::MutableHandleValue ret, const CFixedVector2D& val) | template<> void ScriptInterface::ToJSVal<CFixedVector2D>(const ScriptRequest& rq, JS::MutableHandleValue ret, const CFixedVector2D& val) | ||||
{ | { | ||||
JS::RootedObject global(rq.cx, rq.glob); | JS::RootedObject global(rq.cx, rq.glob); | ||||
JS::RootedValue valueVector2D(rq.cx); | JS::RootedValue valueVector2D(rq.cx); | ||||
if (!JS_GetProperty(rq.cx, global, "Vector2D", &valueVector2D)) | if (!JS_GetProperty(rq.cx, global, "Vector2D", &valueVector2D)) | ||||
FAIL_VOID("Failed to get Vector2D constructor"); | FAIL_VOID("Failed to get Vector2D constructor"); | ||||
JS::AutoValueArray<2> args(rq.cx); | JS::AutoValueArray<2> args(rq.cx); | ||||
args[0].setNumber(val.X.ToDouble()); | args[0].setNumber(val.X.ToDouble()); | ||||
args[1].setNumber(val.Y.ToDouble()); | args[1].setNumber(val.Y.ToDouble()); | ||||
if (!JS::Construct(rq.cx, valueVector2D, args, ret)) | if (!JS::Construct(rq.cx, valueVector2D, args, ret)) | ||||
FAIL_VOID("Failed to construct Vector2D object"); | FAIL_VOID("Failed to construct Vector2D object"); | ||||
} | } | ||||
template<> void ScriptInterface::ToJSVal<Grid<u8> >(const Request& rq, JS::MutableHandleValue ret, const Grid<u8>& val) | template<> void ScriptInterface::ToJSVal<Grid<u8> >(const ScriptRequest& rq, JS::MutableHandleValue ret, const Grid<u8>& val) | ||||
{ | { | ||||
u32 length = (u32)(val.m_W * val.m_H); | u32 length = (u32)(val.m_W * val.m_H); | ||||
u32 nbytes = (u32)(length * sizeof(u8)); | u32 nbytes = (u32)(length * sizeof(u8)); | ||||
JS::RootedObject objArr(rq.cx, JS_NewUint8Array(rq.cx, length)); | JS::RootedObject objArr(rq.cx, JS_NewUint8Array(rq.cx, length)); | ||||
// Copy the array data and then remove the no-GC check to allow further changes to the JS data | // Copy the array data and then remove the no-GC check to allow further changes to the JS data | ||||
{ | { | ||||
JS::AutoCheckCannotGC nogc; | JS::AutoCheckCannotGC nogc; | ||||
bool sharedMemory; | bool sharedMemory; | ||||
memcpy((void*)JS_GetUint8ArrayData(objArr, &sharedMemory, nogc), val.m_Data, nbytes); | memcpy((void*)JS_GetUint8ArrayData(objArr, &sharedMemory, nogc), val.m_Data, nbytes); | ||||
} | } | ||||
JS::RootedValue data(rq.cx, JS::ObjectValue(*objArr)); | JS::RootedValue data(rq.cx, JS::ObjectValue(*objArr)); | ||||
CreateObject( | CreateObject( | ||||
rq, | rq, | ||||
ret, | ret, | ||||
"width", val.m_W, | "width", val.m_W, | ||||
"height", val.m_H, | "height", val.m_H, | ||||
"data", data); | "data", data); | ||||
} | } | ||||
template<> void ScriptInterface::ToJSVal<Grid<u16> >(const Request& rq, JS::MutableHandleValue ret, const Grid<u16>& val) | template<> void ScriptInterface::ToJSVal<Grid<u16> >(const ScriptRequest& rq, JS::MutableHandleValue ret, const Grid<u16>& val) | ||||
{ | { | ||||
u32 length = (u32)(val.m_W * val.m_H); | u32 length = (u32)(val.m_W * val.m_H); | ||||
u32 nbytes = (u32)(length * sizeof(u16)); | u32 nbytes = (u32)(length * sizeof(u16)); | ||||
JS::RootedObject objArr(rq.cx, JS_NewUint16Array(rq.cx, length)); | JS::RootedObject objArr(rq.cx, JS_NewUint16Array(rq.cx, length)); | ||||
// Copy the array data and then remove the no-GC check to allow further changes to the JS data | // Copy the array data and then remove the no-GC check to allow further changes to the JS data | ||||
{ | { | ||||
JS::AutoCheckCannotGC nogc; | JS::AutoCheckCannotGC nogc; | ||||
bool sharedMemory; | bool sharedMemory; | ||||
memcpy((void*)JS_GetUint16ArrayData(objArr, &sharedMemory, nogc), val.m_Data, nbytes); | memcpy((void*)JS_GetUint16ArrayData(objArr, &sharedMemory, nogc), val.m_Data, nbytes); | ||||
} | } | ||||
JS::RootedValue data(rq.cx, JS::ObjectValue(*objArr)); | JS::RootedValue data(rq.cx, JS::ObjectValue(*objArr)); | ||||
CreateObject( | CreateObject( | ||||
rq, | rq, | ||||
ret, | ret, | ||||
"width", val.m_W, | "width", val.m_W, | ||||
"height", val.m_H, | "height", val.m_H, | ||||
"data", data); | "data", data); | ||||
} | } | ||||
template<> bool ScriptInterface::FromJSVal<TNSpline>(const Request& rq, JS::HandleValue v, TNSpline& out) | template<> bool ScriptInterface::FromJSVal<TNSpline>(const ScriptRequest& rq, JS::HandleValue v, TNSpline& out) | ||||
{ | { | ||||
if (!v.isObject()) | if (!v.isObject()) | ||||
FAIL("Argument must be an object"); | FAIL("Argument must be an object"); | ||||
JS::RootedObject obj(rq.cx, &v.toObject()); | JS::RootedObject obj(rq.cx, &v.toObject()); | ||||
bool isArray; | bool isArray; | ||||
if (!JS_IsArrayObject(rq.cx, obj, &isArray) || !isArray) | if (!JS_IsArrayObject(rq.cx, obj, &isArray) || !isArray) | ||||
FAIL("Argument must be an array"); | FAIL("Argument must be an array"); | ||||
Show All 20 Lines | template<> bool ScriptInterface::FromJSVal<TNSpline>(const ScriptRequest& rq, JS::HandleValue v, TNSpline& out) | ||||
} | } | ||||
if (out.GetAllNodes().empty()) | if (out.GetAllNodes().empty()) | ||||
FAIL("Spline must contain at least one node"); | FAIL("Spline must contain at least one node"); | ||||
return true; | return true; | ||||
} | } | ||||
template<> bool ScriptInterface::FromJSVal<CCinemaPath>(const Request& rq, JS::HandleValue v, CCinemaPath& out) | template<> bool ScriptInterface::FromJSVal<CCinemaPath>(const ScriptRequest& rq, JS::HandleValue v, CCinemaPath& out) | ||||
{ | { | ||||
if (!v.isObject()) | if (!v.isObject()) | ||||
FAIL("Argument must be an object"); | FAIL("Argument must be an object"); | ||||
JS::RootedObject obj(rq.cx, &v.toObject()); | JS::RootedObject obj(rq.cx, &v.toObject()); | ||||
CCinemaData pathData; | CCinemaData pathData; | ||||
TNSpline positionSpline, targetSpline; | TNSpline positionSpline, targetSpline; | ||||
Show All 33 Lines |
Wildfire Games · Phabricator