Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
EngineScriptConversions.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2012 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "precompiled.h"
19 
21 #include "scriptinterface/ScriptExtraHeaders.h" // for typed arrays
22 
23 #include "maths/Fixed.h"
24 #include "maths/FixedVector2D.h"
25 #include "maths/FixedVector3D.h"
26 #include "ps/CLogger.h"
27 #include "ps/Overlay.h"
28 #include "ps/utf16string.h"
32 
33 #define FAIL(msg) STMT(JS_ReportError(cx, msg); return false)
34 
35 template<> jsval ScriptInterface::ToJSVal<IComponent*>(JSContext* cx, IComponent* const& val)
36 {
37  if (val == NULL)
38  return JSVAL_NULL;
39 
40  // If this is a scripted component, just return the JS object directly
41  jsval instance = val->GetJSInstance();
42  if (!JSVAL_IS_NULL(instance))
43  return instance;
44 
45  // Otherwise we need to construct a wrapper object
46  // (TODO: cache wrapper objects?)
47  JSClass* cls = val->GetJSClass();
48  if (!cls)
49  {
50  // Report as an error, since scripts really shouldn't try to use unscriptable interfaces
51  LOGERROR(L"IComponent does not have a scriptable interface");
52  return JSVAL_VOID;
53  }
54 
55  JSObject* obj = JS_NewObject(cx, cls, NULL, NULL);
56  if (!obj)
57  {
58  LOGERROR(L"Failed to construct IComponent script object");
59  return JSVAL_VOID;
60  }
61  JS_SetPrivate(cx, obj, static_cast<void*>(val));
62 
63  return OBJECT_TO_JSVAL(obj);
64 }
65 
66 template<> jsval ScriptInterface::ToJSVal<CParamNode>(JSContext* cx, CParamNode const& val)
67 {
68  jsval rval = val.ToJSVal(cx, true);
69 
70  // Prevent modifications to the object, so that it's safe to share between
71  // components and to reconstruct on deserialization
72  if (JSVAL_IS_OBJECT(rval))
73  JS_DeepFreezeObject(cx, JSVAL_TO_OBJECT(rval));
74 
75  return rval;
76 }
77 
78 template<> jsval ScriptInterface::ToJSVal<const CParamNode*>(JSContext* cx, const CParamNode* const& val)
79 {
80  if (val)
81  return ToJSVal(cx, *val);
82  else
83  return JSVAL_VOID;
84 }
85 
86 template<> bool ScriptInterface::FromJSVal<CColor>(JSContext* cx, jsval v, CColor& out)
87 {
88  if (!JSVAL_IS_OBJECT(v))
89  FAIL("jsval not an object");
90 
91  JSObject* obj = JSVAL_TO_OBJECT(v);
92 
93  jsval r, g, b, a;
94  if (!JS_GetProperty(cx, obj, "r", &r) || !FromJSVal(cx, r, out.r))
95  FAIL("Failed to get property CColor.r");
96  if (!JS_GetProperty(cx, obj, "g", &g) || !FromJSVal(cx, g, out.g))
97  FAIL("Failed to get property CColor.g");
98  if (!JS_GetProperty(cx, obj, "b", &b) || !FromJSVal(cx, b, out.b))
99  FAIL("Failed to get property CColor.b");
100  if (!JS_GetProperty(cx, obj, "a", &a) || !FromJSVal(cx, a, out.a))
101  FAIL("Failed to get property CColor.a");
102  // TODO: this probably has GC bugs if a getter returns an unrooted value
103 
104  return true;
105 }
106 
107 template<> jsval ScriptInterface::ToJSVal<CColor>(JSContext* cx, CColor const& val)
108 {
109  JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL);
110  if (!obj)
111  return JSVAL_VOID;
112 
113  jsval r = ToJSVal(cx, val.r);
114  jsval g = ToJSVal(cx, val.g);
115  jsval b = ToJSVal(cx, val.b);
116  jsval a = ToJSVal(cx, val.a);
117 
118  JS_SetProperty(cx, obj, "r", &r);
119  JS_SetProperty(cx, obj, "g", &g);
120  JS_SetProperty(cx, obj, "b", &b);
121  JS_SetProperty(cx, obj, "a", &a);
122 
123  return OBJECT_TO_JSVAL(obj);
124 }
125 
126 template<> bool ScriptInterface::FromJSVal<fixed>(JSContext* cx, jsval v, fixed& out)
127 {
128  jsdouble ret;
129  if (!JS_ValueToNumber(cx, v, &ret))
130  return false;
131  out = fixed::FromDouble(ret);
132  // double can precisely represent the full range of fixed, so this is a non-lossy conversion
133 
134  return true;
135 }
136 
137 template<> jsval ScriptInterface::ToJSVal<fixed>(JSContext* cx, const fixed& val)
138 {
139  jsval rval = JSVAL_VOID;
140  JS_NewNumberValue(cx, val.ToDouble(), &rval); // ignore return value
141  return rval;
142 }
143 
144 template<> bool ScriptInterface::FromJSVal<CFixedVector3D>(JSContext* cx, jsval v, CFixedVector3D& out)
145 {
146  if (!JSVAL_IS_OBJECT(v))
147  return false; // TODO: report type error
148  JSObject* obj = JSVAL_TO_OBJECT(v);
149 
150  jsval p;
151 
152  if (!JS_GetProperty(cx, obj, "x", &p)) return false; // TODO: report type errors
153  if (!FromJSVal(cx, p, out.X)) return false;
154 
155  if (!JS_GetProperty(cx, obj, "y", &p)) return false;
156  if (!FromJSVal(cx, p, out.Y)) return false;
157 
158  if (!JS_GetProperty(cx, obj, "z", &p)) return false;
159  if (!FromJSVal(cx, p, out.Z)) return false;
160 
161  return true;
162 }
163 
164 template<> jsval ScriptInterface::ToJSVal<CFixedVector3D>(JSContext* cx, const CFixedVector3D& val)
165 {
166  JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL);
167  if (!obj)
168  return JSVAL_VOID;
169 
170  jsval x = ToJSVal(cx, val.X);
171  jsval y = ToJSVal(cx, val.Y);
172  jsval z = ToJSVal(cx, val.Z);
173 
174  JS_SetProperty(cx, obj, "x", &x);
175  JS_SetProperty(cx, obj, "y", &y);
176  JS_SetProperty(cx, obj, "z", &z);
177 
178  return OBJECT_TO_JSVAL(obj);
179 }
180 
181 template<> bool ScriptInterface::FromJSVal<CFixedVector2D>(JSContext* cx, jsval v, CFixedVector2D& out)
182 {
183  if (!JSVAL_IS_OBJECT(v))
184  return false; // TODO: report type error
185  JSObject* obj = JSVAL_TO_OBJECT(v);
186 
187  jsval p;
188 
189  if (!JS_GetProperty(cx, obj, "x", &p)) return false; // TODO: report type errors
190  if (!FromJSVal(cx, p, out.X)) return false;
191 
192  if (!JS_GetProperty(cx, obj, "y", &p)) return false;
193  if (!FromJSVal(cx, p, out.Y)) return false;
194 
195  return true;
196 }
197 
198 template<> jsval ScriptInterface::ToJSVal<CFixedVector2D>(JSContext* cx, const CFixedVector2D& val)
199 {
200  JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL);
201  if (!obj)
202  return JSVAL_VOID;
203 
204  jsval x = ToJSVal(cx, val.X);
205  jsval y = ToJSVal(cx, val.Y);
206 
207  JS_SetProperty(cx, obj, "x", &x);
208  JS_SetProperty(cx, obj, "y", &y);
209 
210  return OBJECT_TO_JSVAL(obj);
211 }
212 
213 template<jsint atype, typename T> jsval ToJSVal_Grid(JSContext* cx, const Grid<T>& val)
214 {
215  JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL);
216  if (!obj)
217  return JSVAL_VOID;
218 
219  jsuint len = val.m_W * val.m_H;
220  JSObject *darray = js_CreateTypedArray(cx, atype, len);
221  if (!darray)
222  return JSVAL_VOID;
223 
224  js::TypedArray *tdest = js::TypedArray::fromJSObject(darray);
225  ENSURE(tdest->byteLength == len*sizeof(T));
226 
227  memcpy(tdest->data, val.m_Data, tdest->byteLength);
228 
229  jsval w = ScriptInterface::ToJSVal(cx, val.m_W);
230  jsval h = ScriptInterface::ToJSVal(cx, val.m_H);
231  jsval data = OBJECT_TO_JSVAL(darray);
232 
233  JS_SetProperty(cx, obj, "width", &w);
234  JS_SetProperty(cx, obj, "height", &h);
235  JS_SetProperty(cx, obj, "data", &data);
236 
237  return OBJECT_TO_JSVAL(obj);
238 }
239 
240 template<> jsval ScriptInterface::ToJSVal<Grid<u8> >(JSContext* cx, const Grid<u8>& val)
241 {
242  return ToJSVal_Grid<js::TypedArray::TYPE_UINT8>(cx, val);
243 }
244 
245 template<> jsval ScriptInterface::ToJSVal<Grid<u16> >(JSContext* cx, const Grid<u16>& val)
246 {
247  return ToJSVal_Grid<js::TypedArray::TYPE_UINT16>(cx, val);
248 }
An entity initialisation parameter node.
Definition: ParamNode.h:112
A simple fixed-point number class.
Definition: Fixed.h:115
jsval ToJSVal_Grid(JSContext *cx, const Grid< T > &val)
#define LOGERROR
Definition: CLogger.h:35
Definition: Overlay.h:34
u16 m_H
Definition: Grid.h:101
static void out(const wchar_t *fmt,...)
Definition: wdbg_sym.cpp:419
Basic 2D array, intended for storing tile data, plus support for lazy updates by ICmpObstructionManag...
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
#define FAIL(msg)
static jsval ToJSVal(JSContext *cx, T const &val)
Convert a C++ type to a jsval.
#define T(string_literal)
Definition: secure_crt.cpp:70
T * m_Data
Definition: Grid.h:102
jsval ToJSVal(T &Native)
Definition: JSConversions.h:87
u16 m_W
Definition: Grid.h:101
static CFixed FromDouble(double n)
Definition: Fixed.h:149