00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <iostream>
00012 #include <algorithm>
00013 #include <string>
00014 #include <vector>
00015 #include <stdio.h>
00016 #include <string.h>
00017 #include <jsapi.h>
00018
00019 #include "../../core/src/kernel.h"
00020 #include "jsenvironment.h"
00021 #include "jshandler.h"
00022 #include "jsprivate.h"
00023 #include "scriptexception.h"
00024 #include "scriptscenemanager.h"
00025 #include "scriptscene.h"
00026 #include "scriptnode.h"
00027
00028 using namespace VRUT;
00029 using namespace std;
00030
00031 #ifdef _WINDOWS
00032 #pragma warning(disable:4312)
00033 #pragma warning(disable:4311)
00034 #endif
00035
00036 #include "jsevents.h"
00037 #include "jsmemory.h"
00038
00040 #define MATRIX_SIZE 16
00041
00043 #define VECTOR_SIZE 3
00044
00046 #define JSE_FS {NULL, NULL, 0, 0, 0}
00048 #define JSE_PS {NULL, 0, 0, NULL, NULL}
00049
00051 #define JSE_LOG_TO_CONSOLE 0
00052
00053 #define JSE_TEST_DD 1
00054
00055 #if JSE_TEST_DD
00056 #include "../../core/src/evtstructs.h"
00057 #endif
00058
00059
00061 enum TRANS_TYPE {TRANSLATE_ABS, TRANSLATE, ROTATE, SCALE};
00062
00063
00065 static JSHandler *jsHandler;
00066
00068 static Kernel *kernel;
00069
00071 static ScriptSceneManager *ssm = NULL;
00072
00074 static bool realError;
00075
00076
00077
00078
00079
00080
00082 static void reportError(JSContext *cx, const char *asciiMsg, JSErrorReport *report);
00083
00085 static JSBool globalLog(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00086
00088 static JSBool globalWarning(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00089
00091 static JSBool globalError(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00092
00094 static JSBool globalExit(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00095
00097 static JSBool globalInclude(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00098
00100 static JSBool globalSleep(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00101
00103 static JSBool sceneGetID(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00104
00106 static JSBool sceneGetRoot(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00107
00109 static JSBool sceneGetRootID(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00110
00112 static JSBool sceneGetNode(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00113
00115 static JSBool sceneGetNodeID(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00116
00118 static JSBool sceneGetNodeIDs(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00119
00121 static JSBool sceneSetTransformation(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00122
00124 static JSBool sceneTransform(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00125
00127 static JSBool sceneTranslateAbs(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00128
00130 static JSBool sceneTranslate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00131
00133 static JSBool sceneRotate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00134
00136 static JSBool sceneScale(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00137
00139 static JSBool sceneUpdateTransformation(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00140
00142 static JSBool sceneGetScene(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00143
00145 static JSBool sceneGetSceneIDs(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00146
00148 static JSBool sceneToString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00149
00151 static void scene_Finalize(JSContext *cx, JSObject *obj);
00152
00154 static JSBool nodeGetName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00155
00157 static JSBool nodeGetUid(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00158
00160 static JSBool nodeGetID(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00161
00163 static JSBool nodeGetLocalTransMatrix(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00164
00166 static JSBool nodeGetWorldTransMatrix(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00167
00169 static JSBool nodeGetChildren(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00170
00172 static JSBool nodeGetChildrenIDs(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00173
00175 static JSBool nodeGetParent(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00176
00178 static JSBool nodeGetParentID(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00179
00181 static JSBool nodeIsValid(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00182
00184 static JSBool nodeIsActive(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00185
00187 static JSBool nodeGetType(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00188
00190 static JSBool nodeIsOfType(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00191
00193 static JSBool nodeToString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00194
00196 static JSBool node_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
00197
00199 static void node_Finalize(JSContext *cx, JSObject *obj);
00200
00202 static JSBool matrixConstructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00203
00205 static JSBool matrixToString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00206
00208 static void matrix_Finalize(JSContext *cx, JSObject *obj);
00209
00211 static JSBool vectorConstructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00212
00214 static JSBool vectorToString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00215
00217 static void vector_Finalize(JSContext *cx, JSObject *obj);
00218
00220 static JSBool eventPost(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00221
00223 static JSBool eventPostToKernel(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00224
00226 static JSBool eventGetArgument(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00227
00229 static JSBool eventSetArgument(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00230
00232 static JSBool eventGet(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00233
00235 static JSBool eventWait(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00236
00238 static JSBool eventToString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00239
00241 static JSBool event_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
00242
00244 static void event_Finalize(JSContext *cx, JSObject *obj);
00245
00247 static JSBool memorySlice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00248
00250 static JSBool memoryAlloc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00251
00253 static JSBool memoryToString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00254
00256 static JSBool memory_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
00257
00259 static void memory_Finalize(JSContext *cx, JSObject *obj);
00260
00262 static JSBool chunkGetType(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00263
00265 static JSBool chunkToString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval);
00266
00268 static JSBool chunkValueGetter(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
00269
00271 static JSBool chunkValueSetter(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
00272
00274 static void chunk_Finalize(JSContext *cx, JSObject *obj);
00275
00276
00277
00279 static JSFunctionSpec globalFunctions[] = {
00280 {"log", globalLog, 0, 0, 0},
00281 {"warning", globalWarning, 0, 0, 0},
00282 {"error", globalError, 0, 0, 0},
00283 {"exit", globalExit, 0, 0, 0},
00284 {"include", globalInclude, 0, 0, 0},
00285 {"sleep", globalSleep, 0, 0, 0},
00286 JSE_FS
00287 };
00288
00290 static JSFunctionSpec sceneFunctions[] = {
00291 {"GetID", sceneGetID, 0, 0, 0},
00292 {"GetRoot", sceneGetRoot, 0, 0, 0},
00293 {"GetRootID", sceneGetRootID, 0, 0, 0},
00294 {"GetNode", sceneGetNode, 0, 0, 0},
00295 {"GetNodeID", sceneGetNodeID , 0, 0, 0},
00296 {"GetNodeIDs", sceneGetNodeIDs , 0, 0, 0},
00297 {"SetTransformation", sceneSetTransformation, 0, 0, 0},
00298 {"Transform", sceneTransform, 0, 0, 0},
00299 {"UpdateTransformation", sceneUpdateTransformation, 0, 0, 0},
00300 {"TranslateAbs", sceneTranslateAbs, 0, 0, 0},
00301 {"Translate", sceneTranslate, 0, 0, 0},
00302 {"Rotate", sceneRotate, 0, 0, 0},
00303 {"Scale", sceneScale, 0, 0, 0},
00304 {"toString", sceneToString, 0, 0, 0},
00305 JSE_FS
00306 };
00307
00309 static JSFunctionSpec sceneStaticFunctions[] = {
00310 {"GetScene", sceneGetScene, 0, 0, 0},
00311 {"GetSceneIDs", sceneGetSceneIDs, 0, 0, 0},
00312 JSE_FS
00313 };
00314
00316 static JSFunctionSpec nodeFunctions[] = {
00317 {"GetID", nodeGetID, 0, 0, 0},
00318 {"GetName", nodeGetName, 0, 0, 0},
00319 {"GetUid", nodeGetUid, 0, 0, 0},
00320 {"GetLocalTransMatrix", nodeGetLocalTransMatrix, 0, 0, 0},
00321 {"GetWorldTransMatrix", nodeGetWorldTransMatrix, 0, 0, 0},
00322 {"GetChildren", nodeGetChildren, 0, 0, 0},
00323 {"GetChildrenIDs", nodeGetChildrenIDs, 0, 0, 0},
00324 {"GetParent", nodeGetParent, 0, 0, 0},
00325 {"GetParentID", nodeGetParentID, 0, 0, 0},
00326 {"IsValid", nodeIsValid, 0, 0, 0},
00327 {"IsActive", nodeIsActive, 0, 0, 0},
00328 {"GetType", nodeGetType, 0, 0, 0},
00329 {"IsOfType", nodeIsOfType, 0, 0, 0},
00330 {"toString", nodeToString, 0, 0, 0},
00331 JSE_FS
00332 };
00333
00335 static JSFunctionSpec matrixFunctions[] = {
00336 {"toString", matrixToString, 0, 0, 0},
00337 JSE_FS
00338 };
00339
00341 static JSFunctionSpec vectorFunctions[] = {
00342 {"toString", vectorToString, 0, 0, 0},
00343 JSE_FS
00344 };
00345
00347 static JSFunctionSpec eventFunctions[] = {
00348 {"Post", eventPost, 0, 0, 0},
00349 {"PostToKernel", eventPostToKernel, 0, 0, 0},
00350 {"GetArgument", eventGetArgument, 0, 0, 0},
00351 {"SetArgument", eventSetArgument, 0, 0, 0},
00352 {"toString", eventToString, 0, 0, 0},
00353 JSE_FS
00354 };
00355
00357 static JSFunctionSpec eventStaticFunctions[] = {
00358 {"Get", eventGet, 0, 0, 0},
00359 {"Wait", eventWait, 0, 0, 0},
00360 JSE_FS
00361 };
00362
00364 static JSFunctionSpec memoryFunctions[] = {
00365 {"Slice", memorySlice, 0, 0, 0},
00366 {"toString", memoryToString, 0, 0, 0},
00367 JSE_FS
00368 };
00369
00371 static JSFunctionSpec memoryStaticFunctions[] = {
00372 {"Alloc", memoryAlloc, 0, 0, 0},
00373 JSE_FS
00374 };
00375
00377 static JSFunctionSpec chunkFunctions[] = {
00378 {"GetType", chunkGetType, 0, 0, 0},
00379 JSE_FS
00380 };
00381
00382
00383
00385
00387 static JSPropertySpec nodeStaticProps[] = {
00388 {"ASSEMBLY", SceneNode::ASSEMBLY, JSPROP_READONLY, NULL, NULL},
00389 {"ROOT", SceneNode::ROOT, JSPROP_READONLY, NULL, NULL},
00390 {"CAMERA", SceneNode::CAMERA, JSPROP_READONLY, NULL, NULL},
00391 {"GEOMETRY", SceneNode::GEOMETRY, JSPROP_READONLY, NULL, NULL},
00392 {"LIGHT", SceneNode::LIGHT, JSPROP_READONLY, NULL, NULL},
00393 JSE_PS
00394 };
00395
00397 static JSPropertySpec eventStaticProps[JSEVT_ARG_COUNT + JSEVT_EVT_COUNT + 1];
00398
00400 static JSPropertySpec memoryStaticProps[JSMEM_TYPES_COUNT + 1];
00401
00403 static JSPropertySpec chunkProps[] = {
00404 {"value", 1, JSPROP_ENUMERATE, chunkValueGetter, chunkValueSetter},
00405 JSE_PS
00406 };
00407
00408
00409
00410
00412 static JSClass GlobalClass = {
00413 "VRUT", JSCLASS_GLOBAL_FLAGS,
00414 JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
00415 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
00416 JSCLASS_NO_OPTIONAL_MEMBERS
00417 };
00418
00420 static JSClass SceneClass = {
00421 "Scene", JSCLASS_HAS_PRIVATE,
00422 JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
00423 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, scene_Finalize,
00424 JSCLASS_NO_OPTIONAL_MEMBERS
00425 };
00426
00428 static JSClass NodeClass = {
00429 "Node", JSCLASS_HAS_PRIVATE,
00430 JS_PropertyStub, JS_PropertyStub, node_GetProperty, JS_PropertyStub,
00431 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, node_Finalize,
00432 JSCLASS_NO_OPTIONAL_MEMBERS
00433 };
00434
00436 static JSClass MatrixClass = {
00437 "Matrix", JSCLASS_HAS_PRIVATE ,
00438 JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
00439 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, matrix_Finalize,
00440 JSCLASS_NO_OPTIONAL_MEMBERS
00441 };
00442
00444 static JSClass VectorClass = {
00445 "Vector", JSCLASS_HAS_PRIVATE ,
00446 JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
00447 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, vector_Finalize,
00448 JSCLASS_NO_OPTIONAL_MEMBERS
00449 };
00450
00452 static JSClass EventClass = {
00453 "Event", JSCLASS_HAS_PRIVATE,
00454 JS_PropertyStub, JS_PropertyStub, event_GetProperty, JS_PropertyStub,
00455 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, event_Finalize,
00456 JSCLASS_NO_OPTIONAL_MEMBERS
00457 };
00458
00460 static JSClass MemoryClass = {
00461 "Memory", JSCLASS_HAS_PRIVATE,
00462 JS_PropertyStub, JS_PropertyStub, memory_GetProperty, JS_PropertyStub,
00463 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, memory_Finalize,
00464 JSCLASS_NO_OPTIONAL_MEMBERS
00465 };
00466
00467 static JSClass ChunkClass = {
00468 "Chunk", JSCLASS_HAS_PRIVATE,
00469 JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
00470 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, chunk_Finalize,
00471 JSCLASS_NO_OPTIONAL_MEMBERS
00472 };
00473
00474
00475
00476
00477
00478
00480 static void log(int type, const char *asciiMsg)
00481 {
00482 wxString msg(asciiMsg, wxConvUTF8);
00483 VRUT::FlexiLog::LogMessageFlexi(wxT("<JSScriptingModule>") + msg, type);
00484 }
00485
00487 #define logMsg(_msg) log(wxLOG_Message, _msg)
00488
00490 #define logError(_msg) log(wxLOG_Error, _msg)
00491
00493 #define logWarning(_msg) log(wxLOG_Warning, _msg)
00494
00495 static JSString *getJSString(JSContext *cx, const char *str)
00496 {
00497 JSString *jsStr = JS_NewStringCopyZ(cx, str);
00498 if (!jsStr)
00499 JS_ReportError(cx, "The String object cannot be created");
00500 return jsStr;
00501 }
00502
00503 static void fillArray(float *a, unsigned size, uintN argc, jsval *argv)
00504 {
00505 unsigned i, count = int((argc > size)? size: argc);
00506 for (i = 0; i < count; i++)
00507 {
00508 if (JSVAL_IS_DOUBLE(argv[i]))
00509 {
00510 jsdouble *value = JSVAL_TO_DOUBLE(argv[i]);
00511 a[i] = float(*value);
00512 }
00513 else if (JSVAL_IS_INT(argv[i]))
00514 a[i] = float(JSVAL_TO_INT(argv[i]));
00515 else
00516 a[i] = 0;
00517 }
00519 for (; i < size; i++)
00520 a[i] = 0;
00521 }
00522
00524 static VECTOR3 makeVector(JSContext *cx, uintN argc, jsval *argv) throw(ScriptException)
00525 {
00527 if (JSVAL_IS_OBJECT(argv[0]))
00528 {
00529 JSObject *vectorObj = JSVAL_TO_OBJECT(argv[0]);
00530 if (!JS_InstanceOf(cx, vectorObj, &VectorClass, NULL))
00531 throw(ScriptException("Second argument in function %s isn't Vector or Number instance"));
00532 VectorData *data = (VectorData *) JS_GetPrivate(cx, vectorObj);
00533 if (!data)
00534 throw(ScriptException("Second argurment in function %s is incorrect Vector object"));
00535 return data->v;
00536 }
00537 else
00538 {
00539 jsdouble x, y, z;
00540 if (!JS_ConvertArguments(cx, argc, argv, "ddd", &x, &y, &z))
00541 throw(ScriptException("Bad arguments in function %s"));
00542
00543 return VECTOR3(float(x), float(y), float(z));
00544 }
00545 }
00546
00547 static void *getMemoryAddr(JSContext *cx, JSObject *obj)
00548 {
00549 MemoryData *data = (MemoryData *) JS_GetPrivate(cx, obj);
00550 if (!data)
00551 {
00552 JS_ReportWarning(cx, "Memory object doesn't have private data (it was probably explicitly created)");
00553 return NULL;
00554 }
00555 return data->memAddr;
00556 }
00557
00558
00559
00561 static void reportError(JSContext *cx, const char *asciiMsg, JSErrorReport *report)
00562 {
00563 wxString msg(asciiMsg, wxConvUTF8);
00564 wxString fileName = (report->filename? wxString(report->filename, wxConvUTF8): wxT("console"));
00565 wxString line = wxString::Format(wxT(":%d:"), report->lineno);
00566
00567 VRUT::FlexiLog::LogMessageFlexi(wxT("<JSScriptingModule>") + fileName + line + msg,
00568 JSREPORT_IS_WARNING(report->flags)? wxLOG_Warning: wxLOG_Error);
00569
00570 #if JSE_LOG_TO_CONSOLE
00571 cerr << (report->filename? report->filename: "<no filename>")
00572 << ':' << report->lineno << ':' << asciiMsg << endl;
00573 #endif
00574
00575 }
00576
00577
00578
00580 static JSBool globalLog(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
00581 {
00582 *rval = JSVAL_VOID;
00583
00585 if (argc == 0)
00586 return JS_TRUE;
00587
00588 char *asciiMsg;
00589 if (!JS_ConvertArguments(cx, argc, argv, "s", &asciiMsg))
00590 {
00591 JS_ReportError(cx, "Function log requires string argument");
00592 return JS_FALSE;
00593 }
00594
00595 logMsg(asciiMsg);
00596
00597 #if JSE_LOG_TO_CONSOLE
00598 cout << asciiMsg << endl;
00599 #endif
00600
00601 return JS_TRUE;
00602 }
00603
00605 static JSBool globalWarning(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
00606 {
00607 *rval = JSVAL_VOID;
00608
00610 if (argc == 0)
00611 return JS_TRUE;
00612
00613 char *asciiMsg;
00614 if (!JS_ConvertArguments(cx, argc, argv, "s", &asciiMsg))
00615 {
00616 JS_ReportError(cx, "Function warning requires string argument");
00617 return JS_FALSE;
00618 }
00619
00620 logWarning(asciiMsg);
00621
00622 #if JSE_LOG_TO_CONSOLE
00623 cout << asciiMsg << endl;
00624 #endif
00625
00626 return JS_TRUE;
00627 }
00628
00630 static JSBool globalError(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
00631 {
00632 realError = false;
00633
00635 if (argc == 0)
00636 return JS_FALSE;
00637
00638 char *asciiMsg;
00639 if (!JS_ConvertArguments(cx, argc, argv, "s", &asciiMsg))
00640 {
00641 JS_ReportError(cx, "Function error requires a string argument");
00642 return JS_FALSE;
00643 }
00644
00645 logError(asciiMsg);
00646
00647 #if JSE_LOG_TO_CONSOLE
00648 cerr << asciiMsg << endl;
00649 #endif
00650
00651 return JS_FALSE;
00652 }
00653
00655 static JSBool globalExit(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
00656 {
00657 realError = false;
00658 return JS_FALSE;
00659 }
00660
00661
00663 static JSBool globalInclude(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
00664 {
00665 if (argc == 0)
00666 {
00667 *rval = JSVAL_VOID;
00668 return JS_TRUE;
00669 }
00670
00671 char *filePath;
00672 if (!JS_ConvertArguments(cx, argc, argv, "s", &filePath))
00673 {
00674 JS_ReportError(cx, "Function include requires a string with file path");
00675 return JS_FALSE;
00676 }
00677
00678 FILE *file = fopen(filePath, "r");
00679 if (file == NULL)
00680 {
00681 JS_ReportError(cx, "File %s not found or cannot be read", filePath);
00682 return JS_FALSE;
00683 }
00684
00686 bool rc = true;
00687
00689 JSScript *script = JS_CompileFileHandle(cx, JS_GetGlobalObject(cx), filePath, file);
00690 if (!script)
00691 {
00692 JS_ReportError(cx, "The file %s with included script cannot be compilated", filePath);
00693 return JS_FALSE;
00694 }
00696 JSObject *scriptObj = JS_NewScriptObject(cx, script);
00697 if (scriptObj == NULL)
00698 {
00699 JS_DestroyScript(cx, script);
00700 JS_ReportError(cx, "The included script object cannot be created");
00701 return JS_FALSE;
00702 }
00704 if (!JS_AddNamedRoot(cx, &scriptObj, "IncludedScript"))
00705 {
00706 JS_ReportError(cx, "The included script object cannot be added to root");
00707 return JS_FALSE;
00708 }
00709
00710 rc = JS_ExecuteScript(cx, JS_GetGlobalObject(cx), script, rval) == JS_TRUE;
00711 JS_RemoveRoot(cx, &scriptObj);
00712 if (!rc)
00713 {
00714 JS_ReportError(cx, "Unsuccessfull executing the script file %s", filePath);
00715 return JS_FALSE;
00716 }
00717
00718 return JS_TRUE;
00719 }
00720
00722 static JSBool globalSleep(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
00723 {
00724 if (argc == 0)
00725 {
00726 JS_ReportError(cx, "The function sleep needs one argument (sleeping time in milis)");
00727 return JS_FALSE;
00728 }
00729
00730 uint32 jsTime;
00731 if (!JS_ConvertArguments(cx, argc, argv, "u", &jsTime))
00732 {
00733 JS_ReportError(cx, "The function sleep requires a number argument");
00734 return JS_FALSE;
00735 }
00736
00737 if (!jsHandler->Sleep(jsTime))
00738 {
00739 logError("Script was terminated");
00740 return JS_FALSE;
00741 }
00742
00743 return JS_TRUE;
00744 }
00745
00746
00747
00748
00750 static SCENE_ID getSceneID(JSContext *cx, JSObject *obj)
00751 {
00752 SceneData *sceneData = (SceneData *) JS_GetPrivate(cx, obj);
00753 if (!sceneData)
00754 {
00755 JS_ReportWarning(cx, "Scene object doesn't have private data (it was probably explicitly created)");
00756 return SCENE_ID_NONE;
00757 }
00758 return sceneData->GetSceneID();
00759 }
00760
00762 static ScriptScene *getScene(JSContext *cx, JSObject *obj, SCENE_ID *idp = NULL)
00763 {
00764 SCENE_ID sceneID = getSceneID(cx, obj);
00765 if (idp)
00766 *idp = sceneID;
00767 if (sceneID == SCENE_ID_NONE)
00768 return NULL;
00769
00770 ScriptScene *scene = ssm->GetScene(sceneID);
00771 if (scene)
00772 return scene;
00773
00774 JS_ReportWarning(cx, "Invalid scene ID");
00775 return NULL;
00776 }
00777
00778
00780 static JSBool sceneGetID(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
00781 {
00782 SCENE_ID sceneID = getSceneID(cx, obj);
00783 if (sceneID == SCENE_ID_NONE)
00784 {
00785 *rval = JSVAL_VOID;
00786 return JS_TRUE;
00787 }
00788 *rval = INT_TO_JSVAL(int(sceneID));
00789 return JS_TRUE;
00790 }
00791
00793 static JSBool sceneGetRoot(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
00794 {
00795 try
00796 {
00797 SCENE_ID sceneID;
00798 ScriptScene *scene = getScene(cx, obj, &sceneID);
00799
00800 if (!scene)
00801 {
00802 *rval = JSVAL_VOID;
00803 return JS_TRUE;
00804 }
00805
00806 NODE_ID rootID = scene->GetRootID();
00807 if (rootID == NODE_ID_NONE)
00808 {
00809 *rval = JSVAL_NULL;
00810 return JS_TRUE;
00811 }
00812
00813 JSObject *rootObj = JS_NewObject(cx, &NodeClass, NULL, NULL);
00814 if (!JS_SetPrivate(cx, rootObj, (void *) new NodeData(sceneID, rootID)))
00815 throw ScriptException("Node data cannot be set");
00816
00817 *rval = OBJECT_TO_JSVAL(rootObj);
00818 }
00819 catch (ScriptException & exc)
00820 {
00821 JS_ReportError(cx, exc.what());
00822 return JS_FALSE;
00823 }
00824
00825 return JS_TRUE;
00826 }
00827
00829 static JSBool sceneGetRootID(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
00830 {
00831 try
00832 {
00833 ScriptScene *scene = getScene(cx, obj);
00834 if (!scene)
00835 {
00836 *rval = JSVAL_VOID;
00837 return JS_TRUE;
00838 }
00839
00840 NODE_ID rootID = scene->GetRootID();
00841 if (rootID == NODE_ID_NONE)
00842 {
00843 *rval = JSVAL_NULL;
00844 return JS_TRUE;
00845 }
00846
00847 *rval = INT_TO_JSVAL(int(rootID));
00848 }
00849 catch (ScriptException & exc)
00850 {
00851 JS_ReportError(cx, exc.what());
00852 return JS_FALSE;
00853 }
00854
00855 return JS_TRUE;
00856 }
00857
00859 static JSBool sceneGetNode(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
00860 {
00861 try
00862 {
00863 if (argc == 0)
00864 throw ScriptException("The function GetNodeID needs argument (node uid or node id)");
00865
00867 SCENE_ID sceneID;
00868 ScriptScene *scene = getScene(cx, obj, &sceneID);
00869 if (!scene)
00870 {
00871 *rval = JSVAL_VOID;
00872 return JS_TRUE;
00873 }
00874
00876 NODE_ID nodeID;
00877 if (JSVAL_IS_STRING(argv[0]))
00878 {
00879 char *asciiUid = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
00880 wxString uid(asciiUid, wxConvUTF8);
00881 nodeID = scene->GetNodeID(uid);
00882 }
00883 else if (JSVAL_IS_INT(argv[0]))
00884 nodeID = NODE_ID(JSVAL_TO_INT(argv[0]));
00885 else
00886 throw ScriptException("Function Scene.GetNode() requires a string argument");
00887
00888 if (!scene->GetNode(NODE_ID(nodeID)))
00889 {
00890 *rval = JSVAL_NULL;
00891 return JS_TRUE;
00892 }
00893
00894 JSObject *nodeObj = JS_NewObject(cx, &NodeClass, NULL, NULL);
00895 if (!JS_SetPrivate(cx, nodeObj, (void *) new NodeData(sceneID, nodeID)))
00896 throw ScriptException("Node data cannot be set");
00897
00898 *rval = OBJECT_TO_JSVAL(nodeObj);
00899
00900 }
00901 catch (ScriptException & exc)
00902 {
00903 JS_ReportError(cx, exc.what());
00904 return JS_FALSE;
00905 }
00906
00907 return JS_TRUE;
00908 }
00909
00911 static JSBool sceneGetNodeID(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
00912 {
00913 try
00914 {
00915 if (argc == 0)
00916 throw ScriptException("The function Scene.GetNodeID needs one argument");
00917
00918 ScriptScene *scene = getScene(cx, obj);
00919 if (!scene)
00920 {
00921 *rval = JSVAL_VOID;
00922 return JS_TRUE;
00923 }
00924
00925 char *asciiUid;
00926 if (!JS_ConvertArguments(cx, argc, argv, "s", &asciiUid))
00927 throw ScriptException("Function Scene.GetNode() requires a string argument");
00928
00929 wxString uid(asciiUid, wxConvUTF8);
00930 NODE_ID nodeID = scene->GetNodeID(uid);
00931
00932 *rval = INT_TO_JSVAL(int(nodeID));
00933 }
00934 catch (ScriptException & exc)
00935 {
00936 JS_ReportError(cx, exc.what());
00937 return JS_FALSE;
00938 }
00939
00940 return JS_TRUE;
00941 }
00942
00944 static JSBool sceneGetNodeIDs(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
00945 {
00946 try
00947 {
00948 ScriptScene *scene = getScene(cx, obj);
00949 if (!scene)
00950 {
00951 *rval = JSVAL_VOID;
00952 return JS_TRUE;
00953 }
00954
00956 vector<NODE_ID> nodeIDs;
00957 scene->GetNodeIDs(&nodeIDs);
00958 if (nodeIDs.size())
00959 {
00960 JSObject *nodesObj = JS_NewArrayObject(cx, 0, NULL);
00961 if (!nodesObj)
00962 throw ScriptException("Nodes array object cannot be created");
00963
00964 for (unsigned i = 0; i < nodeIDs.size(); i++)
00965 {
00966 jsval id = INT_TO_JSVAL(int(nodeIDs[i]));
00967 if (!JS_SetElement(cx, nodesObj, i, &id))
00968 throw ScriptException("Scenes array object cannot be created");
00969 }
00970 *rval = OBJECT_TO_JSVAL(nodesObj);
00971 }
00972 else
00973 *rval = JSVAL_NULL;
00974 }
00975 catch (ScriptException & exc)
00976 {
00977 JS_ReportError(cx, exc.what());
00978 return JS_FALSE;
00979 }
00980
00981 return JS_TRUE;
00982 }
00983
00985 static JSBool sceneUpdateTransformation(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
00986 {
00987 try
00988 {
00989 *rval = JSVAL_VOID;
00990
00991 if (argc == 0 || !JSVAL_IS_INT(argv[0]))
00992 throw ScriptException("Invalid arguments in function Scene.UpdateTransformation");
00993
00994 NODE_ID nodeID = NODE_ID(JSVAL_TO_INT(argv[0]));
00995
00997 ScriptScene *scene = getScene(cx, obj);
00998 if (!scene)
00999 return JS_TRUE;
01000
01001 scene->UpdateTransformation(nodeID);
01002 }
01003 catch (ScriptException & exc)
01004 {
01005 JS_ReportError(cx, exc.what());
01006 return JS_FALSE;
01007 }
01008
01009 return JS_TRUE;
01010 }
01011
01013 static JSBool _sceneTransMatrix(bool isTransform, JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01014 {
01015 *rval = JSVAL_VOID;
01016 JSObject *matrixObj;
01017
01019 if (argc <= 1 || !JSVAL_IS_INT(argv[0]) || !JSVAL_IS_OBJECT(argv[1])
01020 || !JS_InstanceOf(cx, matrixObj = JSVAL_TO_OBJECT(argv[1]), &MatrixClass, NULL))
01021 {
01022 JS_ReportError(cx, "Invalid arguments for function Scene.%s",
01023 isTransform? "Transform": "SetTransformation");
01024 return JS_FALSE;
01025 }
01026 NODE_ID nodeID = NODE_ID(JSVAL_TO_INT(argv[0]));
01027
01028 try
01029 {
01031 ScriptScene *scene = getScene(cx, obj);
01032 if (!scene)
01033 return JS_TRUE;
01034
01035 MatrixData *data = (MatrixData *) JS_GetPrivate(cx, matrixObj);
01036 if (data && isTransform)
01037 scene->Transform(nodeID, data->m);
01038 else if (data && !isTransform)
01039 scene->SetTransformation(nodeID, data->m);
01040 else
01041 JS_ReportWarning(cx, "Private data for Matrix object wasn't set");
01042 }
01043 catch (ScriptException & exc)
01044 {
01045 JS_ReportError(cx, exc.what());
01046 return JS_FALSE;
01047 }
01048
01049 return JS_TRUE;
01050 }
01051
01053 static JSBool sceneSetTransformation(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01054 {
01055 return _sceneTransMatrix(false, cx, obj, argc, argv, rval);
01056 }
01057
01059 static JSBool sceneTransform(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01060 {
01061 return _sceneTransMatrix(true, cx, obj, argc, argv, rval);
01062 }
01063
01064
01066 static JSBool _sceneTransVector(TRANS_TYPE type, const char *fceName,
01067 JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01068 {
01069 *rval = JSVAL_VOID;
01070
01072 if (int(argc) <= ((type == ROTATE)? 2: 1) || !JSVAL_IS_INT(argv[0]))
01073 {
01074 JS_ReportError(cx, "Invalid arguments in function %s", fceName);
01075 return JS_FALSE;
01076 }
01077
01078 NODE_ID nodeID = NODE_ID(JSVAL_TO_INT(argv[0]));
01079
01080 try
01081 {
01083 ScriptScene *scene = getScene(cx, obj);
01084 if (!scene)
01085 return JS_TRUE;
01086
01087 if (type == TRANSLATE_ABS)
01088 {
01089 scene->TranslateAbs(nodeID, makeVector(cx, argc-1, argv+1));
01090 return JS_TRUE;
01091 }
01092
01093 ScriptNode *node = scene->GetNode(nodeID);
01094 if (!node)
01095 {
01096 JS_ReportWarning(cx, "No node with ID %u", unsigned(nodeID));
01097 return JS_TRUE;
01098 }
01099
01100 MATRIX m;
01101 switch (type)
01102 {
01103 case TRANSLATE:
01104 m.Translate(makeVector(cx, argc-1, argv+1));
01105 break;
01106 case SCALE:
01107 m.Scale(makeVector(cx, argc-1, argv+1));
01108 break;
01109 case ROTATE:
01110 float angle;
01111 if (JSVAL_IS_DOUBLE(argv[1]))
01112 {
01113 jsdouble *jsAngle = JSVAL_TO_DOUBLE(argv[1]);
01114 angle = float(*jsAngle);
01115 }
01116 else if (JSVAL_IS_INT(argv[1]))
01117 angle = float(JSVAL_TO_INT(argv[1]));
01118 else
01119 break;
01120
01121 angle = angle * M_PI / 180;
01122
01123 m = m.RotationAxis(makeVector(cx, argc-2, argv+2), angle);
01124 break;
01125 }
01126 scene->Transform(nodeID, m);
01127 scene->UpdateTransformation(nodeID);
01128
01129 }
01130 catch (ScriptException & exc)
01131 {
01132 JS_ReportError(cx, exc.what(), fceName);
01133 return JS_FALSE;
01134 }
01135
01136 return JS_TRUE;
01137 }
01138
01140 static JSBool sceneTranslateAbs(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01141 {
01142 return _sceneTransVector(TRANSLATE_ABS, "Scene.TranslateAbs", cx, obj, argc, argv, rval);
01143 }
01144
01146 static JSBool sceneTranslate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01147 {
01148 return _sceneTransVector(TRANSLATE, "Scene.Translate", cx, obj, argc, argv, rval);
01149 }
01150
01152 static JSBool sceneRotate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01153 {
01154 return _sceneTransVector(ROTATE, "Scene.Rotate", cx, obj, argc, argv, rval);
01155 }
01156
01158 static JSBool sceneScale(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01159 {
01160 return _sceneTransVector(SCALE, "Scene.Scale", cx, obj, argc, argv, rval);
01161 }
01162
01163
01165 static JSBool sceneGetScene(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01166 {
01167 if (argc == 0 || !JSVAL_IS_INT(argv[0]))
01168 {
01169 JS_ReportError(cx, "Invalid arguments in static function Scene.GetScene");
01170 return JS_FALSE;
01171 }
01172 SCENE_ID sceneID = SCENE_ID(JSVAL_TO_INT(argv[0]));
01173
01174 vector<SCENE_ID> sceneIDs;
01175 size_t size = kernel->sceneManager->GetSceneIDs(sceneIDs);
01176 if (size == 0 || find(sceneIDs.begin(), sceneIDs.end(), sceneID) == sceneIDs.end())
01177 {
01178 JS_ReportWarning(cx, "No scene with ID %u", unsigned(sceneID));
01179 *rval = JSVAL_NULL;
01180 return JS_TRUE;
01181 }
01182
01183 JSObject *sceneObj = JS_NewObject(cx, &SceneClass, NULL, NULL);
01184 if (!sceneObj || !JS_SetPrivate(cx, sceneObj, (void *) new SceneData(sceneID)))
01185 {
01186 JS_ReportError(cx, "Scene object cannot be created");
01187 return JS_FALSE;
01188 }
01189
01190 *rval = OBJECT_TO_JSVAL(sceneObj);
01191 return JS_TRUE;
01192 }
01193
01195 static JSBool sceneGetSceneIDs(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01196 {
01197 vector<SCENE_ID> sceneIDs;
01198 size_t size = kernel->sceneManager->GetSceneIDs(sceneIDs);
01199 if (size)
01200 {
01201 JSObject *scenesObj = JS_NewArrayObject(cx, 0, NULL);
01202 if (!scenesObj)
01203 {
01204 JS_ReportError(cx, "Scenes array object cannot be created");
01205 return JS_FALSE;
01206 }
01207 for (unsigned i = 0; i < size; i++)
01208 {
01209 jsval id = INT_TO_JSVAL((int) sceneIDs[i]);
01210 if (!JS_SetElement(cx, scenesObj, i, &id))
01211 {
01212 JS_ReportError(cx, "Scenes array object cannot be created");
01213 return JS_FALSE;
01214 }
01215 }
01216 *rval = OBJECT_TO_JSVAL(scenesObj);
01217 }
01218 else
01219 *rval = JSVAL_NULL;
01220 return JS_TRUE;
01221 }
01222
01224 static JSBool sceneToString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01225 {
01226 char buff[64];
01227 SCENE_ID id = getSceneID(cx, obj);
01228 if (id == SCENE_ID_NONE)
01229 strcpy(buff, "[object Scene(sceneId=undefined)]");
01230 else
01231 sprintf(buff, "[object Scene(sceneId=%u)]", unsigned(id));
01232
01233 JSString *msgStr = getJSString(cx, buff);
01234 if (!msgStr)
01235 return JS_FALSE;
01236
01237 *rval = STRING_TO_JSVAL(msgStr);
01238
01239 return JS_TRUE;
01240 }
01241
01243 static void scene_Finalize(JSContext *cx, JSObject *obj)
01244 {
01245 SceneData *data = (SceneData *) JS_GetPrivate(cx, obj);
01246 if (data)
01247 delete data;
01248 }
01249
01250
01251
01252
01254 static NodeData *getNodeData(JSContext *cx, JSObject *obj)
01255 {
01256 NodeData *nodeData = (NodeData *) JS_GetPrivate(cx, obj);
01257 if (!nodeData)
01258 {
01259 JS_ReportWarning(cx, "Node object doesn't have the private data (it was probably explicitly created)");
01260 return NULL;
01261 }
01262 return nodeData;
01263 }
01264
01266 static ScriptNode *getNode(JSContext *cx, JSObject *obj, SCENE_ID *sid = NULL, NODE_ID *nid = NULL)
01267 throw(ScriptException)
01268 {
01269 NodeData *nodeData = getNodeData(cx, obj);
01270 if (!nodeData)
01271 return NULL;
01272
01273 SCENE_ID sceneID = nodeData->GetSceneID();
01274 NODE_ID nodeID = nodeData->GetNodeID();
01275 if (sid)
01276 *sid = sceneID;
01277 if (nid)
01278 *nid = nodeID;
01279
01280 ScriptScene *scene = ssm->GetScene(sceneID);
01281 if (!scene)
01282 throw ScriptException("Invalid scene ID");
01283
01284 ScriptNode *node = scene->GetNode(nodeID);
01285 if (!node)
01286 throw ScriptException("Invalid node ID");
01287
01288 return node;
01289
01290 }
01291
01293 static JSBool nodeGetName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01294 {
01295 try
01296 {
01297 ScriptNode *node = getNode(cx, obj);
01298 if (!node)
01299 {
01300 *rval = JSVAL_VOID;
01301 return JS_TRUE;
01302 }
01303
01304 JSString *nameStr = getJSString(cx, node->GetName().mb_str());
01305 if (!nameStr)
01306 return JS_FALSE;
01307
01308 *rval = STRING_TO_JSVAL(nameStr);
01309 }
01310 catch (ScriptException & exc)
01311 {
01312 JS_ReportError(cx, exc.what());
01313 return JS_FALSE;
01314 }
01315
01316 return JS_TRUE;
01317 }
01318
01320 static JSBool nodeGetUid(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01321 {
01322 try
01323 {
01324 ScriptNode *node = getNode(cx, obj);
01325 if (!node)
01326 {
01327 *rval = JSVAL_VOID;
01328 return JS_TRUE;
01329 }
01330
01331 JSString *uidStr = getJSString(cx, node->GetUid().mb_str());
01332 if (!uidStr)
01333 return JS_FALSE;
01334
01335 *rval = STRING_TO_JSVAL(uidStr);
01336 }
01337 catch (ScriptException & exc)
01338 {
01339 JS_ReportError(cx, exc.what());
01340 return JS_FALSE;
01341 }
01342
01343 return JS_TRUE;
01344 }
01345
01347 static JSBool nodeGetID(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01348 {
01349 try
01350 {
01351
01352 ScriptNode *node = getNode(cx, obj);
01353 if (!node)
01354 {
01355 *rval = JSVAL_VOID;
01356 return JS_TRUE;
01357 }
01358 *rval = INT_TO_JSVAL(int(node->GetID()));
01359 }
01360 catch (ScriptException & exc)
01361 {
01362 JS_ReportError(cx, exc.what());
01363 return JS_FALSE;
01364 }
01365
01366 return JS_TRUE;
01367 }
01368
01369 static JSBool _nodeGetTransMatrix(bool isLocal, JSContext *cx, JSObject *obj, jsval *rval)
01370 {
01371 try
01372 {
01373 ScriptNode *node = getNode(cx, obj);
01374 if (!node)
01375 {
01376 *rval = JSVAL_VOID;
01377 return JS_TRUE;
01378 }
01379
01380 MATRIX m(*(isLocal? node->GetLocalTransMatrix(): node->GetWorldTransMatrix()));
01381 JSObject *matrixObj = JS_NewObject(cx, &MatrixClass, NULL, NULL);
01382 if (!matrixObj || !JS_SetPrivate(cx, matrixObj, (void *) new MatrixData(m)))
01383 throw ScriptException("Matrix object cannot be created");
01384
01385 *rval = OBJECT_TO_JSVAL(matrixObj);
01386 }
01387 catch (ScriptException & exc)
01388 {
01389 JS_ReportError(cx, exc.what());
01390 return JS_FALSE;
01391 }
01392
01393 return JS_TRUE;
01394 }
01395
01397 static JSBool nodeGetLocalTransMatrix(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01398 {
01399 return _nodeGetTransMatrix(true, cx, obj, rval);
01400 }
01401
01403 static JSBool nodeGetWorldTransMatrix(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01404 {
01405 return _nodeGetTransMatrix(false, cx, obj, rval);
01406 }
01407
01409 static JSBool nodeGetChildren(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01410 {
01411 try
01412 {
01413
01414 SCENE_ID sceneID;
01415 const SceneNode::NodeIDList *children;
01416 ScriptNode *node = getNode(cx, obj, &sceneID);
01417 if (!node || !(children = node->GetChildren()))
01418 {
01419 *rval = JSVAL_NULL;
01420 return JS_TRUE;
01421 }
01422
01423 JSObject *childrenObj = JS_NewArrayObject(cx, 0, NULL);
01424 if (!childrenObj)
01425 throw ScriptException("The array with node's children cannot be created");
01426
01427 SceneNode::NodeIDList::const_iterator it = children->begin();
01428 for (jsint i = 0; it != children->end(); it++, i++)
01429 {
01430 JSObject *childObj = JS_NewObject(cx, &NodeClass, NULL, NULL);
01431 if (!childObj || !JS_SetPrivate(cx, childObj, new NodeData(sceneID, *it)))
01432 throw ScriptException("Node child object cannot be create");
01433
01434 jsval value = OBJECT_TO_JSVAL(childObj);
01435 if (!JS_SetElement(cx, childrenObj, i, &value))
01436 throw ScriptException("Node child object element cannot be set");
01437 }
01438
01439 *rval = OBJECT_TO_JSVAL(childrenObj);
01440 }
01441 catch (ScriptException & exc)
01442 {
01443 JS_ReportError(cx, exc.what());
01444 return JS_FALSE;
01445 }
01446
01447 return JS_TRUE;
01448 }
01449
01451 static JSBool nodeGetChildrenIDs(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01452 {
01453 try
01454 {
01455 const SceneNode::NodeIDList *children;
01456 ScriptNode *node = getNode(cx, obj);
01457 if (!node || !(children = node->GetChildren()))
01458 {
01459 *rval = JSVAL_NULL;
01460 return JS_TRUE;
01461 }
01462 JSObject *childrenObj = JS_NewArrayObject(cx, 0, NULL);
01463 if (!childrenObj)
01464 throw ScriptException("The array with node's children cannot be created");
01465
01466 SceneNode::NodeIDList::const_iterator it = children->begin();
01467 for (jsint i = 0; it != children->end(); it++, i++)
01468 {
01469 jsval value = INT_TO_JSVAL(*it);
01470 if (!JS_SetElement(cx, childrenObj, i, &value))
01471 throw ScriptException("Children ID element cannot be created");
01472 }
01473
01474 *rval = OBJECT_TO_JSVAL(childrenObj);
01475 }
01476 catch (ScriptException & exc)
01477 {
01478 JS_ReportError(cx, exc.what());
01479 return JS_FALSE;
01480 }
01481
01482 return JS_TRUE;
01483 }
01484
01486 static JSBool nodeGetParent(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01487 {
01488 try
01489 {
01490 SCENE_ID sceneID;
01491 ScriptNode *node = getNode(cx, obj, &sceneID);
01492 if (!node || node->GetParent() == NODE_ID_NONE)
01493 {
01494 *rval = JSVAL_NULL;
01495 return JS_TRUE;
01496 }
01497
01498 JSObject *parentObj = JS_NewObject(cx, &NodeClass, NULL, NULL);
01499 if (!parentObj || !JS_SetPrivate(cx, parentObj, new NodeData(sceneID, node->GetParent())))
01500 throw ScriptException("Parent object cannot be created");
01501
01502 *rval = OBJECT_TO_JSVAL(parentObj);
01503 }
01504 catch (ScriptException & exc)
01505 {
01506 JS_ReportError(cx, exc.what());
01507 return JS_FALSE;
01508 }
01509
01510 return JS_TRUE;
01511 }
01512
01514 static JSBool nodeGetParentID(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01515 {
01516 try
01517 {
01518 ScriptNode *node = getNode(cx, obj);
01519 *rval = (node && node->GetParent() != NODE_ID_NONE)? INT_TO_JSVAL(node->GetParent()): JSVAL_NULL;
01520 }
01521 catch (ScriptException & exc)
01522 {
01523 JS_ReportError(cx, exc.what());
01524 return JS_FALSE;
01525 }
01526
01527 return JS_TRUE;
01528 }
01529
01531 static JSBool nodeIsValid(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01532 {
01533 try
01534 {
01535 ScriptNode *node = getNode(cx, obj);
01536 *rval = (node && node->IsValid())? JSVAL_TRUE: JSVAL_FALSE;
01537 }
01538 catch (ScriptException & exc)
01539 {
01540 JS_ReportError(cx, exc.what());
01541 return JS_FALSE;
01542 }
01543
01544 return JS_TRUE;
01545 }
01546
01548 static JSBool nodeIsActive(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01549 {
01550 try
01551 {
01552 ScriptNode *node = getNode(cx, obj);
01553 *rval = (node && node->IsActive())? JSVAL_TRUE: JSVAL_FALSE;
01554 }
01555 catch (ScriptException & exc)
01556 {
01557 JS_ReportError(cx, exc.what());
01558 return JS_FALSE;
01559 }
01560 return JS_TRUE;
01561 }
01562
01564 static JSBool nodeGetType(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01565 {
01566 try
01567 {
01568 ScriptNode *node = getNode(cx, obj);
01569 *rval = (node)? INT_TO_JSVAL(node->GetType()): JSVAL_NULL;
01570 }
01571 catch (ScriptException & exc)
01572 {
01573 JS_ReportError(cx, exc.what());
01574 return JS_FALSE;
01575 }
01576
01577 return JS_TRUE;
01578 }
01579
01581 static JSBool nodeIsOfType(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01582 {
01583 try
01584 {
01585 ScriptNode *node;
01586 *rval = (argc > 0 && JSVAL_IS_INT(argv[0]) && (node = getNode(cx, obj))
01587 && node->IsOfType(SceneNode::SCENENODE_TYPE(JSVAL_TO_INT(argv[0]))))? JSVAL_TRUE: JSVAL_FALSE;
01588 }
01589 catch (ScriptException & exc)
01590 {
01591 JS_ReportError(cx, exc.what());
01592 return JS_FALSE;
01593 }
01594
01595 return JS_TRUE;
01596 }
01597
01599 static JSBool nodeToString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01600 {
01601 char buff[64];
01602 NodeData *data = getNodeData(cx, obj);
01603 if (!data)
01604 strcpy(buff, "[object Node(sceneId=undefined, nodeId=undefined)]");
01605 else
01606 {
01607 sprintf(buff, "[object Node(sceneId=%u, nodeId=%u)]",
01608 unsigned(data->GetSceneID()), unsigned(data->GetNodeID()));
01609 }
01610
01611 JSString *msgStr = getJSString(cx, buff);
01612 if (!msgStr)
01613 return JS_FALSE;
01614
01615 *rval = STRING_TO_JSVAL(msgStr);
01616
01617 return JS_TRUE;
01618 }
01619
01621 static JSBool node_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
01622 {
01623 if (JSVAL_IS_INT(id))
01624 {
01625 switch (JSVAL_TO_INT(id))
01626 {
01627 case SceneNode::ASSEMBLY:
01628 *vp = INT_TO_JSVAL(int(SceneNode::ASSEMBLY));
01629 break;
01630 case SceneNode::ROOT:
01631 *vp = INT_TO_JSVAL(int(SceneNode::ROOT));
01632 break;
01633 case SceneNode::CAMERA:
01634 *vp = INT_TO_JSVAL(int(SceneNode::CAMERA));
01635 break;
01636 case SceneNode::GEOMETRY:
01637 *vp = INT_TO_JSVAL(int(SceneNode::GEOMETRY));
01638 break;
01639 case SceneNode::LIGHT:
01640 *vp = INT_TO_JSVAL(int(SceneNode::LIGHT));
01641 break;
01642 }
01643 }
01644 return JS_TRUE;
01645 }
01646
01648 static void node_Finalize(JSContext *cx, JSObject *obj)
01649 {
01650 NodeData *data = (NodeData *) JS_GetPrivate(cx, obj);
01651 delete data;
01652 }
01653
01654
01655
01656
01658 static JSBool matrixConstructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01659 {
01660 float m[MATRIX_SIZE];
01661 fillArray(m, MATRIX_SIZE, argc, argv);
01662
01663 if (!JS_SetPrivate(cx, obj, new MatrixData(m)))
01664 {
01665 JS_ReportError(cx, "Matrix data couldn't be set");
01666 return JS_FALSE;
01667 }
01668
01669 return JS_TRUE;
01670 }
01671
01673 static JSBool matrixToString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01674 {
01675 JSString *msg;
01676 MatrixData *data = (MatrixData *) JS_GetPrivate(cx, obj);
01677 if (data)
01678 {
01679 wxString str(wxT("[object Matrix(\n") + data->m.ToString() + wxT(")]"));
01680 msg = getJSString(cx, str.mb_str());
01681 }
01682 else
01683 msg = getJSString(cx, "[object Matrix(undefined)]");
01684
01685 if (!msg)
01686 return FALSE;
01687
01688 *rval = STRING_TO_JSVAL(msg);
01689 return JS_TRUE;
01690 }
01691
01693 static void matrix_Finalize(JSContext *cx, JSObject *obj)
01694 {
01695 MatrixData *data = (MatrixData *) JS_GetPrivate(cx, obj);
01696 delete data;
01697 }
01698
01699
01700
01701
01703 static JSBool vectorConstructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01704 {
01705 float v[VECTOR_SIZE];
01706 fillArray(v, VECTOR_SIZE, argc, argv);
01707
01708 if (!JS_SetPrivate(cx, obj, new VectorData(v)))
01709 {
01710 JS_ReportError(cx, "Vector data couldn't be set");
01711 return JS_FALSE;
01712 }
01713
01714 return JS_TRUE;
01715 }
01716
01718 static JSBool vectorToString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01719 {
01720 JSString *msg;
01721 VectorData *data = (VectorData *) JS_GetPrivate(cx, obj);
01722 if (data)
01723 {
01724 wxString str(wxT("[object Vector") + data->v.ToString() + wxT("]"));
01725 msg = getJSString(cx, str.mb_str());
01726 }
01727 else
01728 msg = getJSString(cx, "[object Vecto(undefined)]");
01729
01730 if (!msg)
01731 return JS_FALSE;
01732
01733 *rval = STRING_TO_JSVAL(msg);
01734 return JS_TRUE;
01735 }
01736
01738 static void vector_Finalize(JSContext *cx, JSObject *obj)
01739 {
01740 VectorData *data = (VectorData *) JS_GetPrivate(cx, obj);
01741 delete data;
01742 }
01743
01744
01745
01746
01748 static JSBool eventPost(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01749 {
01750 *rval = JSVAL_VOID;
01751 EventData *data = (EventData *) JS_GetPrivate(cx, obj);
01752 if (!data)
01753 return JS_TRUE;
01754
01755 jsHandler->PostEvent(*data->evt);
01756
01757 return JS_TRUE;
01758 }
01759
01761 static JSBool eventPostToKernel(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01762 {
01763 *rval = JSVAL_VOID;
01764 EventData *data = (EventData *) JS_GetPrivate(cx, obj);
01765 if (!data)
01766 return JS_TRUE;
01767
01768 jsHandler->PostToKernel(*data->evt);
01769
01770 return JS_TRUE;
01771 }
01772
01774 static int getArgumentType(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, EventData **data) throw(ScriptException)
01775 {
01776 *data = (EventData *) JS_GetPrivate(cx, obj);
01777 if (!data)
01778 throw ScriptException("The method %s is called in the incorrect Event object (no private data)");
01779
01780 int argType;
01781 if (!JSVAL_IS_INT(argv[0]) || getEventArgIdxByType(argType = JSVAL_TO_INT(argv[0])) < 0)
01782 throw ScriptException("The first argument for %s method isn't argument type");
01783
01784 unsigned nparams = (*data)->info->nparams;
01785 JSEVT_PARAM_TYPE *params = (*data)->info->params;
01786 bool correct = false;
01787 for (unsigned i = 0; i < nparams; i++)
01788 {
01789
01790 if (params[i] == argType)
01791 {
01792 correct = true;
01793 break;
01794 }
01795 }
01796 if (!correct)
01797 throw ScriptException("The first argument for %s method isn't correct argument type");
01798
01799 return argType;
01800 }
01801
01803 static JSBool eventGetArgument(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01804 {
01805 try
01806 {
01807 if (argc == 0)
01808 throw ScriptException("The method %s needs one argument");
01809
01810 EventData *data;
01811 int argType = getArgumentType(cx, obj, argc, argv, &data);
01812
01813 if (JSEVT_PARAM_IS_JSSTRING(argType))
01814 {
01815 JSString *str = getJSString(cx, data->evt->GetString().mb_str());
01816 if (!str)
01817 return JS_FALSE;
01818 *rval = STRING_TO_JSVAL(str);
01819 }
01820 else if (JSEVT_PARAM_IS_JSBOOL(argType))
01821 *rval = (data->evt->GetInt()? JSVAL_TRUE: JSVAL_FALSE);
01822 else if (JSEVT_PARAM_IS_JSINT(argType))
01823 {
01824 int value;
01825 if (JSEVT_PARAM_IS_ID(argType))
01826 value = data->evt->GetId();
01827 else if (JSEVT_PARAM_IS_INT(argType))
01828 value = value = data->evt->GetInt();
01829 else
01830 throw ScriptException("Unknown JSINT type in method %s");
01831 *rval = INT_TO_JSVAL(value);
01832 }
01833 else if (JSEVT_PARAM_IS_JSMEMORY(argType))
01834 {
01835 void *addr = data->evt->GetClientData();
01836 if (!addr)
01837 throw ScriptException("NULL client data in method %s");
01838
01839 MemoryData *memData = new MemoryData(addr);
01840 JSObject *memObj = JS_NewObject(cx, &MemoryClass, NULL, NULL);
01841 if (!memObj || !JS_SetPrivate(cx, memObj, (void *) memData))
01842 {
01843 JS_ReportError(cx, "Memory object cannot be correctly created");
01844 return JS_FALSE;
01845 }
01846
01847 *rval = OBJECT_TO_JSVAL(memObj);
01848 }
01849 else
01850 throw ScriptException("Not supported EVT_PARAM_TYPE type in method %s");
01851
01852 }
01853 catch (ScriptException & exc)
01854 {
01855 JS_ReportWarning(cx, exc.what(), "GetArgument");
01856 *rval = JSVAL_NULL;
01857 }
01858
01859 return JS_TRUE;
01860 }
01861
01863 static JSBool eventSetArgument(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01864 {
01865 *rval = JSVAL_TRUE;
01866
01867 try
01868 {
01869 if (argc < 2)
01870 throw ScriptException("The method %s needs two arguments");
01871
01872 EventData *data;
01873 int argType = getArgumentType(cx, obj, argc, argv, &data);
01874
01875 if (JSEVT_PARAM_IS_JSINT(argType))
01876 {
01877 if (!JSVAL_IS_INT(argv[1]))
01878 {
01879 JS_ReportError(cx, "It is required integer second argument");
01880 return JS_FALSE;
01881 }
01882 if (JSEVT_PARAM_IS_ID(argType))
01883 data->evt->SetId(JSVAL_TO_INT(argv[1]));
01884 else if (JSEVT_PARAM_IS_INT(argType))
01885 data->evt->SetInt(JSVAL_TO_INT(argv[1]));
01886 else
01887 throw ScriptException("Unknown JSINT type in method %s");
01888
01889 }
01890 else if (JSEVT_PARAM_IS_JSSTRING(argType))
01891 {
01892 char *asciiStr;
01893 if (!JS_ConvertArguments(cx, 1, argv + 1, "s", &asciiStr))
01894 {
01895 JS_ReportError(cx, "It is required string second argument");
01896 return JS_FALSE;
01897 }
01898 wxString str(asciiStr, wxConvUTF8);
01899 data->evt->SetString(str);
01900 }
01901 else if (JSEVT_PARAM_IS_JSBOOL(argType))
01902 {
01903 if (!JSVAL_IS_BOOLEAN(argv[1]))
01904 {
01905 JS_ReportError(cx, "It is required boolean second argument");
01906 return JS_FALSE;
01907 }
01908 data->evt->SetInt(int(argv[1] == JSVAL_TRUE));
01909 }
01910 else if (JSEVT_PARAM_IS_JSMEMORY(argType))
01911 {
01912 JSObject *memObj;
01913 if (!JSVAL_IS_OBJECT(argv[1])
01914 || !JS_InstanceOf(cx, memObj = JSVAL_TO_OBJECT(argv[1]), &MemoryClass, NULL))
01915 {
01916 JS_ReportError(cx, "It is required Memory object as second argument");
01917 return JS_FALSE;
01918 }
01919
01920 void *memAddr = getMemoryAddr(cx, memObj);
01921 if (!memAddr)
01922 {
01923 *rval = JSVAL_FALSE;
01924 return JS_TRUE;
01925 }
01926 data->evt->SetClientData(memAddr);
01927 }
01928 else
01929 {
01930 JS_ReportError(cx, "Invalid type of the second argument");
01931 return JS_FALSE;
01932 }
01933
01934 }
01935 catch (ScriptException & exc)
01936 {
01937 JS_ReportWarning(cx, exc.what(), "SetArgument");
01938 *rval = JSVAL_FALSE;
01939 }
01940
01941 return JS_TRUE;
01942 }
01943
01945 static JSBool eventGet(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
01946 {
01947 if (argc == 0)
01948 return JS_TRUE;
01949
01950 int idx;
01951 if (!JSVAL_IS_INT(argv[0]) || (idx = getEventIdxByType(JSVAL_TO_INT(argv[0]))) < 0)
01952 {
01953 JS_ReportError(cx, "The first argument in Event constructor must be correct EVENT_TYPE");
01954 return JS_FALSE;
01955 }
01956
01957 if (argc <= events[idx].nparams)
01958 {
01959 JS_ReportError(cx, "The event %s requires %u arguments", events[idx].name, events[idx].nparams);
01960 return JS_FALSE;
01961 }
01962
01963 wxCommandEvent *evt = new wxCommandEvent(events[idx].type);
01964
01965 for (unsigned i = 0; i < events[idx].nparams; i++)
01966 {
01967 if (JSEVT_PARAM_IS_JSINT(events[idx].params[i]))
01968 {
01969 if (!JSVAL_IS_INT(argv[i+1]))
01970 {
01971 JS_ReportError(cx, "The argument %u for event %s must be integer", i, events[idx].name);
01972 return JS_FALSE;
01973 }
01974 if (JSEVT_PARAM_IS_ID(events[idx].params[i]))
01975 evt->SetId(JSVAL_TO_INT(argv[i+1]));
01976 else if (JSEVT_PARAM_IS_INT(events[idx].params[i]))
01977 evt->SetInt(JSVAL_TO_INT(argv[i+1]));
01978 else
01979 JS_ReportWarning(cx, "The argument %u for event %s is undefined integer type", i, events[idx].name);
01980
01981 }
01982 else if (JSEVT_PARAM_IS_JSSTRING(events[idx].params[i]))
01983 {
01984 char *asciiStr;
01985 if (!JS_ConvertArguments(cx, 1, argv + 1 + i, "s", &asciiStr))
01986 {
01987 JS_ReportError(cx, "The argument %u for event %s must be string", i, events[idx].name);
01988 return JS_FALSE;
01989 }
01990 wxString str(asciiStr, wxConvUTF8);
01991 evt->SetString(str);
01992 }
01993 else if (JSEVT_PARAM_IS_JSBOOL(events[idx].params[i]))
01994 {
01995 if (!JSVAL_IS_BOOLEAN(argv[i+1]))
01996 {
01997 JS_ReportError(cx, "The argument %u for event %s must be boolean", i, events[idx].name);
01998 return JS_FALSE;
01999 }
02000 evt->SetInt(int(argv[i+1] == JSVAL_TRUE));
02001 }
02002 else if (JSEVT_PARAM_IS_JSMEMORY(events[idx].params[i]))
02003 {
02004 JSObject *memObj;
02005 if (!JSVAL_IS_OBJECT(argv[i+1])
02006 || !JS_InstanceOf(cx, memObj = JSVAL_TO_OBJECT(argv[i+1]), &MemoryClass, NULL))
02007 {
02008 JS_ReportError(cx, "It is required Memory object as second argument");
02009 return JS_FALSE;
02010 }
02011
02012 void *memAddr = getMemoryAddr(cx, memObj);
02013 if (!memAddr)
02014 {
02015 *rval = JSVAL_FALSE;
02016 return JS_TRUE;
02017 }
02018 evt->SetClientData(memAddr);
02019 }
02020 else
02021 {
02022 JS_ReportError(cx, "The argument %u for event %s is invalid type", i, events[idx].name);
02023 return JS_FALSE;
02024 }
02025 }
02026
02028 JSObject *eventObj = JS_NewObject(cx, &EventClass, NULL, NULL);
02029 if (!eventObj)
02030 {
02031 JS_ReportError(cx, "Event object cannot be created");
02032 return JS_FALSE;
02033 }
02034
02035 EventData *data = new EventData(evt, &events[idx]);
02036 if (!JS_SetPrivate(cx, eventObj, (void *) data))
02037 {
02038 JS_ReportError(cx, "The private data for event object cannot be set");
02039 return JS_FALSE;
02040 }
02041
02042 *rval = OBJECT_TO_JSVAL(eventObj);
02043
02044 return JS_TRUE;
02045 }
02046
02048 static JSBool eventWait(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
02049 {
02050 int idx;
02051 if (argc == 0 || !JSVAL_IS_INT(argv[0]) || (idx = getEventIdxByType(JSVAL_TO_INT(argv[0]))) < 0)
02052 {
02053 *rval = JSVAL_NULL;
02054 return JS_TRUE;
02055 }
02056
02057 unsigned long milis = 0;
02058 bool waitFromNow = false;
02059 if (argc > 1)
02060 {
02061 if (JSVAL_IS_INT(argv[1]))
02062 milis = (unsigned long) JSVAL_TO_INT(argv[1]);
02063 if (argc > 2 && JSVAL_IS_BOOLEAN(argv[2]))
02064 waitFromNow = (JSVAL_TRUE == argv[2]);
02065 }
02066
02067 wxCommandEvent *evt = jsHandler->WaitForEvent(events[idx].type, milis, waitFromNow);
02068 if (jsHandler->IsEnd())
02069 {
02070 logError("Script was terminated");
02071 return JS_FALSE;
02072 }
02073
02074
02076 JSObject *eventObj = JS_NewObject(cx, &EventClass, NULL, NULL);
02077 if (!eventObj)
02078 {
02079 JS_ReportError(cx, "Event object cannot be created");
02080 return JS_FALSE;
02081 }
02082
02084 EventData *data = new EventData(evt, &events[idx]);
02085 if (!JS_SetPrivate(cx, eventObj, (void *) data))
02086 {
02087 JS_ReportError(cx, "The private data for event object cannot be set");
02088 return JS_FALSE;
02089 }
02090 return JS_TRUE;
02091 }
02092
02093
02095 static JSBool eventToString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
02096 {
02097 JSString *msg;
02098 char ptr[16];
02099 EventData *data = (EventData *) JS_GetPrivate(cx, obj);
02100 if (data)
02101 {
02102 JSEventStruct *es = data->info;
02103 stringstream oss;
02104 oss << "[object Event(" << es->name;
02105 for (unsigned i = 0; i < es->nparams; i++)
02106 {
02107 if (JSEVT_PARAM_IS_ID(es->params[i]))
02108 oss << "," << data->evt->GetId();
02109 else if (JSEVT_PARAM_IS_INT(es->params[i]))
02110 oss << "," << data->evt->GetInt();
02111 else if (JSEVT_PARAM_IS_STRING(es->params[i]))
02112 oss << "," << data->evt->GetString().mb_str();
02113 else if (JSEVT_PARAM_IS_CD(es->params[i]))
02114 {
02115 sprintf(ptr, "%p", data->evt->GetClientData());
02116 oss << "," << ptr;
02117 }
02118 else
02119 JS_ReportWarning(cx, "Unknown event argument");
02120 }
02121 oss << ")]";
02122 msg = getJSString(cx, oss.str().c_str());
02123 }
02124 else
02125 msg = getJSString(cx, "[object Event(undefined)]");
02126
02127 if (!msg)
02128 {
02129 JS_ReportWarning(cx, "String couldn't be created");
02130 *rval = JSVAL_NULL;
02131 return JS_TRUE;
02132 }
02133
02134 *rval = STRING_TO_JSVAL(msg);
02135
02136 return JS_TRUE;
02137 }
02138
02140 static JSBool event_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
02141 {
02142 if (JSVAL_IS_INT(id))
02143 {
02144 int i = getEventIdxById(JSVAL_TO_INT(id));
02145 if (i >= 0)
02146 *vp = INT_TO_JSVAL(int(events[i].type));
02147 else if ((i = getEventArgIdxById(JSVAL_TO_INT(id))) >= 0)
02148 *vp = INT_TO_JSVAL(int(eventArgs[i].type));
02149 }
02150 return JS_TRUE;
02151 }
02152
02154 static void event_Finalize(JSContext *cx, JSObject *obj)
02155 {
02156 EventData *data = (EventData *) JS_GetPrivate(cx, obj);
02157 delete data;
02158 }
02159
02160
02161
02162
02164 static JSBool memorySlice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
02165 {
02166 void *mAddr, *chAddr;
02167 if (argc == 0 || !(mAddr = chAddr = getMemoryAddr(cx, obj)))
02168 {
02169 *rval = JSVAL_NULL;
02170 return JS_TRUE;
02171 }
02172
02173 try
02174 {
02175 JSObject *chunksObj = JS_NewArrayObject(cx, 0, NULL);
02176 if (!chunksObj)
02177 throw ScriptException("Chunks array cannot be created");
02178
02179 for (unsigned i = 0; i < argc; i++)
02180 {
02181 JSMemoryStruct *mType;
02182 if (!JSVAL_IS_INT(argv[i]) || !(mType = getMemoryType(JSVAL_TO_INT(argv[i]))))
02183 throw ScriptException("Incorrect memory type");
02184
02185 JSObject *chunkObj = JS_NewObject(cx, &ChunkClass, NULL, NULL);
02186 if (!chunkObj)
02187 throw ScriptException("Chunk object cannot be created");
02188
02189 ChunkData *chunkData = new ChunkData(mAddr, chAddr, mType);
02190 if (!chunkData || !JS_SetPrivate(cx, chunkObj, (void *) chunkData))
02191 throw ScriptException("Chunk private data cannot be set");
02192
02193 jsval chunkVal = OBJECT_TO_JSVAL(chunkObj);
02194 if (!JS_SetElement(cx, chunksObj, i, &chunkVal))
02195 throw ScriptException("Chunk element cannot be set to chunks array");
02196
02197 chAddr = (void *) ((char *) chAddr + mType->size);
02198 }
02199 *rval = OBJECT_TO_JSVAL(chunksObj);
02200 }
02201 catch (ScriptException & exc)
02202 {
02203 JS_ReportError(cx, exc.what());
02204 return JS_FALSE;
02205 }
02206
02207 return JS_TRUE;
02208 }
02209
02210
02212 static JSBool memoryAlloc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
02213 {
02214 int size;
02215 #if JSE_TEST_DD
02216 if (argc == 0)
02217 {
02218 try
02219 {
02220 DeviceData *dd = new DeviceData;
02221 dd->id = 1;
02222 dd->type = 2;
02223 dd->matrix = MATRIX();
02224 dd->buttons = 3;
02225 dd->control1 = 1.2;
02226 dd->control2 = 2.3;
02227
02228 MemoryData *dataTest = new MemoryData((void *) dd);
02229 if (!dataTest || !dd)
02230 throw ScriptException("The memory cannot be allocated");
02231
02232 JSObject *memTestObj = JS_NewObject(cx, &MemoryClass, NULL, NULL);
02233 if (!memTestObj || !JS_SetPrivate(cx, memTestObj, (void *) dataTest))
02234 throw ScriptException("Memory object cannot be created");
02235
02236 *rval = OBJECT_TO_JSVAL(memTestObj);
02237 return JS_TRUE;
02238 }
02239 catch (ScriptException & exc)
02240 {
02241 JS_ReportError(cx, exc.what());
02242 return JS_FALSE;
02243 }
02244 }
02245 else if (!JSVAL_IS_INT(argv[0]) || !(size = JSVAL_TO_INT(argv[0])))
02246 #else
02247 if (argc == 0 || !JSVAL_IS_INT(argv[0]) || !(size = JSVAL_TO_INT(argv[0])))
02248 #endif
02249 {
02250 *rval = JSVAL_NULL;
02251 return JS_TRUE;
02252 }
02253
02254 try
02255 {
02256 void *addr = new char[size];
02257 MemoryData *data = new MemoryData(addr);
02258 if (!data || !addr)
02259 throw ScriptException("The memory cannot be allocated");
02260
02261 JSObject *memObj = JS_NewObject(cx, &MemoryClass, NULL, NULL);
02262 if (!memObj || !JS_SetPrivate(cx, memObj, (void *) data))
02263 throw ScriptException("Memory object cannot be created");
02264
02265 *rval = OBJECT_TO_JSVAL(memObj);
02266 }
02267 catch (ScriptException & exc)
02268 {
02269 JS_ReportError(cx, exc.what());
02270 return JS_FALSE;
02271 }
02272
02273 return JS_TRUE;
02274 }
02275
02277 static JSBool memoryToString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
02278 {
02279 JSString *str;
02280 MemoryData *data = (MemoryData *) JS_GetPrivate(cx, obj);
02281 if (data)
02282 {
02283 char ptr[32];
02284 sprintf(ptr, "[object Memory(%p)]", data->memAddr);
02285 str = getJSString(cx, ptr);
02286 }
02287 else
02288 str = getJSString(cx, "[object Memory(undefined)]");
02289
02290 *rval = (str? STRING_TO_JSVAL(str): JSVAL_NULL);
02291
02292 return JS_TRUE;
02293 }
02294
02296 static JSBool memory_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
02297 {
02298 if (JSVAL_IS_INT(id) && IS_JSMEM_TYPE(JSVAL_TO_INT(id)))
02299 {
02300 *vp = id;
02301 }
02302 return JS_TRUE;
02303 }
02304
02306 static void memory_Finalize(JSContext *cx, JSObject *obj)
02307 {
02308 MemoryData *data = (MemoryData *) JS_GetPrivate(cx, obj);
02309 delete data;
02310 }
02311
02312
02313
02314
02316 static ChunkData *getChunkData(JSContext *cx, JSObject *obj)
02317 {
02318 ChunkData *data = (ChunkData *) JS_GetPrivate(cx, obj);
02319 if (!data)
02320 JS_ReportWarning(cx, "Chunk object doesn't have private data (it was probably explicitly created)");
02321 return data;
02322 }
02323
02325 static JSBool chunkGetType(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
02326 {
02327 ChunkData *data = getChunkData(cx, obj);
02328
02329 *rval = (data? INT_TO_JSVAL(data->info->type): JSVAL_NULL);
02330
02331 return JS_TRUE;
02332 }
02333
02335 static JSBool chunkToString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
02336 {
02337 JSString *str;
02338 ChunkData *data = getChunkData(cx, obj);
02339 if (data)
02340 {
02341 ostringstream oss;
02342 oss << "[object Chunk(" << data->info->name << ")]";
02343 str = getJSString(cx, oss.str().c_str());
02344 }
02345 else
02346 str = getJSString(cx, "[object Chunk(undefined)]");
02347
02348 if (str)
02349 {
02350 *rval = STRING_TO_JSVAL(str);
02351 return JS_TRUE;
02352 }
02353 else
02354 return JS_FALSE;
02355 }
02356
02358 static JSBool chunkValueGetter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
02359 {
02360 ChunkData *data = getChunkData(cx, obj);
02361 if (!data)
02362 return JS_TRUE;
02363
02364 try
02365 {
02366 switch (data->info->type)
02367 {
02368 case JSMEM_INT:
02369 int iValue;
02370 memcpy(&iValue, data->chunkAddr, data->info->size);
02371 *vp = INT_TO_JSVAL(iValue);
02372 break;
02373 case JSMEM_FLOAT:
02374 float fValue;
02375 jsdouble dValue;
02376 memcpy(&fValue, data->chunkAddr, 4);
02377 dValue = jsdouble(fValue);
02378 if (!JS_NewNumberValue(cx, dValue, vp))
02379 ScriptException("Double value wasn't correctly converted");
02380 break;
02381 case JSMEM_MATRIX:
02382 MATRIX m;
02383 memcpy(&m, data->chunkAddr, data->info->size);
02384
02385 JSObject *matrixObj = JS_NewObject(cx, &MatrixClass, NULL, NULL);
02386 if (!matrixObj || !JS_SetPrivate(cx, matrixObj, new MatrixData(m)))
02387 ScriptException("Matrix object cannot be correctly created");
02388
02389 *vp = OBJECT_TO_JSVAL(matrixObj);
02390 break;
02391 }
02392 }
02393 catch (ScriptException & exc)
02394 {
02395 JS_ReportError(cx, exc.what());
02396 return JS_FALSE;
02397 }
02398
02399 return JS_TRUE;
02400 }
02401
02403 static JSBool chunkValueSetter(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
02404 {
02405 ChunkData *data = getChunkData(cx, obj);
02406 if (!data)
02407 return JS_TRUE;
02408
02409 try
02410 {
02411 int iValue;
02412 switch (data->info->type)
02413 {
02414 case JSMEM_INT:
02415 if (!JSVAL_IS_INT(*vp))
02416 ScriptException("This chunk value has to be integer");
02417 iValue = JSVAL_TO_INT(*vp);
02418 memcpy(data->chunkAddr, &iValue, data->info->size);
02419 break;
02420 case JSMEM_FLOAT:
02421 if (!JSVAL_IS_NUMBER(*vp))
02422 ScriptException("This chunk value has to be float");
02423
02424 float fValue;
02425 if (JSVAL_IS_INT(*vp))
02426 fValue = float(JSVAL_TO_INT(*vp));
02427 else if (JSVAL_IS_DOUBLE(*vp))
02428 {
02429 jsdouble *dValue = JSVAL_TO_DOUBLE(*vp);
02430 fValue = float(*dValue);
02431 }
02432 else
02433 ScriptException("Unknown number value");
02434
02435 memcpy(data->chunkAddr, &fValue, data->info->size);
02436 break;
02437 case JSMEM_MATRIX:
02438 JSObject *matrixObj;
02439 if (!JSVAL_IS_OBJECT(*vp) || !JS_InstanceOf(cx, matrixObj = JSVAL_TO_OBJECT(*vp), &MatrixClass, NULL))
02440 ScriptException("This chunk value has to be Matrix object");
02441 MatrixData *matrixData = (MatrixData *) JS_GetPrivate(cx, matrixObj);
02442 if (!matrixData)
02443 ScriptException("Matrix object doesn't have private data, it's not possible to set it");
02444 memcpy(data->chunkAddr, &matrixData->m, data->info->size);
02445 break;
02446 }
02447 }
02448 catch (ScriptException & exc)
02449 {
02450 JS_ReportWarning(cx, exc.what());
02451 }
02452
02453 return JS_TRUE;
02454 }
02455
02457 static void chunk_Finalize(JSContext *cx, JSObject *obj)
02458 {
02459 ChunkData *data = (ChunkData *) JS_GetPrivate(cx, obj);
02460 delete data;
02461 }
02462
02463
02464
02465
02466
02468 static void initJSEvents()
02469 {
02470 unsigned i, evtCount = JSEVT_EVT_COUNT, argCount = JSEVT_ARG_COUNT;
02472 for (i = 0; i < evtCount; i++)
02473 {
02474 eventStaticProps[i].name = events[i].name;
02475 eventStaticProps[i].tinyid = events[i].id = i + 1;
02476 eventStaticProps[i].flags = JSPROP_READONLY;
02477 eventStaticProps[i].getter = NULL;
02478 eventStaticProps[i].setter = NULL;
02479 }
02481 for (unsigned j = 0; j < argCount; i++, j++)
02482 {
02483 eventStaticProps[i].name = eventArgs[j].name;
02484 eventStaticProps[i].tinyid = eventArgs[j].id = i + 1;
02485 eventStaticProps[i].flags = JSPROP_READONLY;
02486 eventStaticProps[i].getter = NULL;
02487 eventStaticProps[i].setter = NULL;
02488 }
02490 eventStaticProps[i].name = NULL;
02491 eventStaticProps[i].tinyid = 0;
02492 eventStaticProps[i].flags = 0;
02493 eventStaticProps[i].getter = NULL;
02494 eventStaticProps[i].setter = NULL;
02495 }
02496
02498 static void initJSMemory()
02499 {
02500 unsigned i;
02501 for (i = 0; i < JSMEM_TYPES_COUNT; i++)
02502 {
02503 memoryStaticProps[i].name = memoryTypes[i].name;
02504 memoryStaticProps[i].tinyid = memoryTypes[i].type;
02505 memoryStaticProps[i].flags = JSPROP_READONLY;
02506 memoryStaticProps[i].getter = NULL;
02507 memoryStaticProps[i].setter = NULL;
02508 }
02510 memoryStaticProps[i].name = NULL;
02511 memoryStaticProps[i].tinyid = 0;
02512 memoryStaticProps[i].flags = 0;
02513 memoryStaticProps[i].getter = NULL;
02514 memoryStaticProps[i].setter = NULL;
02515 }
02516
02517 JSEnvironment::JSEnvironment(JSHandler *_handler)
02518 {
02520 rt = JS_NewRuntime(8L * 1024L * 1024L);
02521
02523 jsHandler = handler = _handler;
02524 kernel = NULL;
02525
02526 initJSEvents();
02527 initJSMemory();
02528
02529 }
02530
02531 JSEnvironment::~JSEnvironment()
02532 {
02533 JS_DestroyRuntime(rt);
02534 JS_ShutDown();
02535 }
02536
02537
02538 void JSEnvironment::initJSClasses() throw(ScriptException)
02539 {
02541 if (!JS_InitClass(cx, globalObj, NULL, &SceneClass,
02542 NULL, 0,
02543 NULL, sceneFunctions,
02544 NULL, sceneStaticFunctions ))
02545 throw ScriptException("The Scene class cannot be created");
02546
02548 if (!JS_InitClass(cx, globalObj, NULL, &NodeClass,
02549 NULL, 0,
02550 NULL, nodeFunctions,
02551 nodeStaticProps, NULL ))
02552 throw ScriptException("The Scene class cannot be created");
02553
02555 if (!JS_InitClass(cx, globalObj, NULL, &MatrixClass,
02556 matrixConstructor, MATRIX_SIZE,
02557 NULL, matrixFunctions,
02558 NULL, NULL ))
02559 throw ScriptException("The Scene class cannot be created");
02560
02562 if (!JS_InitClass(cx, globalObj, NULL, &VectorClass,
02563 vectorConstructor, VECTOR_SIZE,
02564 NULL, vectorFunctions,
02565 NULL, NULL ))
02566 throw ScriptException("The Scene class cannot be created");
02567
02569
02570
02571
02572
02573
02574 if (!JS_InitClass(cx, globalObj, NULL, &EventClass,
02575 NULL, 0,
02576 NULL, eventFunctions,
02577 eventStaticProps, eventStaticFunctions ))
02578 throw ScriptException("The Event class cannot be created");
02579
02581 if (!JS_InitClass(cx, globalObj, NULL, &MemoryClass,
02582 NULL, 0,
02583 NULL, memoryFunctions,
02584 memoryStaticProps, memoryStaticFunctions ))
02585 throw ScriptException("The Memory class cannot be created");
02586
02588 if (!JS_InitClass(cx, globalObj, NULL, &ChunkClass,
02589 NULL, 0,
02590 chunkProps, chunkFunctions,
02591 NULL, NULL ))
02592 throw ScriptException("The Chunk class cannot be created");
02593 }
02594
02595 bool JSEnvironment::RunScript(Kernel *_kernel, const char *fileName, SCENE_ID sceneID)
02596 {
02597 if (rt == NULL || _kernel == NULL)
02598 return false;
02599
02600 FILE *file = fopen(fileName, "r");
02601 if (file == NULL)
02602 {
02603 logError("File couldn't be read");
02604 return false;
02605 }
02606
02608 if ((cx = JS_NewContext(rt, 8192)) == NULL)
02609 return false;
02610
02611 JS_SetOptions(cx, JSOPTION_VAROBJFIX);
02612 JS_SetVersion(cx, JSVERSION_1_7);
02613 JS_SetErrorReporter(cx, reportError);
02614
02616 bool rc = true;
02617 realError = true;
02618
02620 kernel = _kernel;
02621
02623 ssm = new ScriptSceneManager(_kernel);
02624
02625 try
02626 {
02628 globalObj = JS_NewObject(cx, &GlobalClass, NULL, NULL);
02629 if (globalObj == NULL || !JS_InitStandardClasses(cx, globalObj))
02630 throw ScriptException("The global object can't be created");
02631
02633 if (!JS_DefineFunctions(cx, globalObj, globalFunctions))
02634 throw ScriptException("The global functions can't be defined");
02635
02636 initJSClasses();
02637
02638 if (sceneID != SCENE_ID_NONE) {
02640 if (!(sceneObj = JS_DefineObject(cx, globalObj, "scene", &SceneClass, NULL, JSPROP_ENUMERATE)))
02641 throw ScriptException("The scene object cannot be created");
02642
02643 if (!JS_SetPrivate(cx, sceneObj, (void *) new SceneData(sceneID)))
02644 throw ScriptException("The scene data cannot be set");
02645 }
02646 else {
02647 if (!JS_DefineProperty(cx, globalObj, "scene",
02648 JSVAL_VOID, NULL, NULL, 0))
02649 {
02650 throw ScriptException(
02651 "The scene object cannot be created");
02652 }
02653 }
02655 JSScript *script = JS_CompileFileHandle(cx, globalObj, fileName, file);
02656 if (!script)
02657 throw ScriptException("The script cannot be compilated");
02659 JSObject *scriptObj = JS_NewScriptObject(cx, script);
02660 if (scriptObj == NULL) {
02661 JS_DestroyScript(cx, script);
02662 throw ScriptException("The script object cannot be created");
02663 }
02665 if (!JS_AddNamedRoot(cx, &scriptObj, "mainScript"))
02666 throw ScriptException("The script object cannot be added to root");
02667
02668 jsval rval;
02669 rc = JS_ExecuteScript(cx, globalObj, script, &rval) == JS_TRUE;
02670 JS_RemoveRoot(cx, &scriptObj);
02671 if (!rc && realError)
02672 throw ScriptException("Unsuccessfull executing the script");
02673 }
02674 catch (const ScriptException & exc)
02675 {
02676 rc = false;
02677 logError(exc.what());
02678
02679 #if JSE_LOG_TO_CONSOLE
02680 cerr << exc.what() << endl;
02681 #endif
02682 }
02683
02684 JS_DestroyContext(cx);
02685 delete ssm;
02686
02687 return rc;
02688 }
02689