// // Vrml 97 library // Copyright (C) 1998 Chris Morley // // ScriptJS.cpp // javascript script objects. // This needs a major clean up... // #include "config.h" #if HAVE_JAVASCRIPT #include "ScriptJS.h" #include #include #include "Doc.h" #include "MathUtils.h" #include "System.h" #include "VrmlNodeScript.h" #include "VrmlNamespace.h" #include "VrmlNodeType.h" #include "VrmlScene.h" #include "VrmlSFBool.h" #include "VrmlSFColor.h" #include "VrmlSFFloat.h" #include "VrmlSFImage.h" #include "VrmlSFInt.h" #include "VrmlSFNode.h" #include "VrmlSFRotation.h" #include "VrmlSFString.h" #include "VrmlSFTime.h" #include "VrmlSFVec2f.h" #include "VrmlSFVec3f.h" #include "VrmlMFColor.h" #include "VrmlMFFloat.h" #include "VrmlMFInt.h" #include "VrmlMFNode.h" #include "VrmlMFRotation.h" #include "VrmlMFString.h" #include "VrmlMFVec2f.h" #include "VrmlMFVec3f.h" // This is nominally a private include but I want to subclass Arrays... #include "jsarray.h" #define MAX_HEAP_BYTES 4L * 1024L * 1024L #define STACK_CHUNK_BYTES 4024L JSRuntime *ScriptJS::rt = 0; // Javascript runtime singleton object int ScriptJS::nInstances = 0; // Number of distinct script objects // Global class and functions static JSClass globalClass = { "global", 0, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub }; static JSBool Print(JSContext *, JSObject *, uintN, jsval *, jsval *); static VrmlField *jsvalToVrmlField( JSContext *cx, jsval v, VrmlField::VrmlFieldType expectType ); static JSFunctionSpec globalFunctions[] = { {"print", Print, 0}, { 0 } }; // Browser class and functions static JSClass browserClass = { "Browser", 0, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub }; static JSBool getName(JSContext*, JSObject*, uintN, jsval *, jsval *); static JSBool getVersion(JSContext*, JSObject*, uintN, jsval *, jsval *); static JSBool getCurrentSpeed(JSContext*, JSObject*, uintN, jsval *, jsval *); static JSBool getCurrentFrameRate(JSContext*, JSObject*, uintN, jsval*, jsval*); static JSBool getWorldURL(JSContext*, JSObject*, uintN, jsval *, jsval *); static JSBool replaceWorld(JSContext*, JSObject*, uintN, jsval *, jsval *); static JSBool createVrmlFromString(JSContext*, JSObject*, uintN, jsval *, jsval *); static JSBool createVrmlFromURL(JSContext*, JSObject*, uintN, jsval *, jsval *); static JSBool addRoute(JSContext*, JSObject*, uintN, jsval *, jsval *); static JSBool deleteRoute(JSContext*, JSObject*, uintN, jsval *, jsval *); static JSBool loadURL(JSContext*, JSObject*, uintN, jsval *, jsval *); static JSBool setDescription(JSContext*, JSObject*, uintN, jsval *, jsval *); static JSFunctionSpec browserFunctions[] = { {"getName", getName, 0}, {"getVersion", getVersion, 0}, {"getCurrentSpeed", getCurrentSpeed, 0}, {"getCurrentFrameRate", getCurrentFrameRate, 0}, {"getWorldURL", getWorldURL, 0}, {"replaceWorld", replaceWorld, 0}, {"createVrmlFromString", createVrmlFromString, 0}, {"createVrmlFromURL", createVrmlFromURL, 0}, {"addRoute", addRoute, 0}, {"deleteRoute", deleteRoute, 0}, {"loadURL", loadURL, 0}, {"setDescription", setDescription, 0}, {0} }; static void ErrorReporter(JSContext *, const char *, JSErrorReport *); // Construct from inline script ScriptJS::ScriptJS( VrmlNodeScript *node, const char *source ) : d_node(node), d_cx(0), d_globalObj(0), d_browserObj(0) { if (! rt) rt = JS_Init( MAX_HEAP_BYTES ); ++nInstances; if (rt) d_cx = JS_NewContext( rt, STACK_CHUNK_BYTES ); if (d_cx) { JS_SetErrorReporter(d_cx, ErrorReporter); // Define the global objects (builtins, Browser, SF*, MF*) ... d_globalObj = JS_NewObject( d_cx, &globalClass, 0, 0 ); JS_InitStandardClasses( d_cx, d_globalObj ); JS_DefineFunctions( d_cx, d_globalObj, globalFunctions ); // VRML-like TRUE, FALSE syntax if (! JS_DefineProperty( d_cx, d_globalObj, "FALSE", BOOLEAN_TO_JSVAL(false), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT )) theSystem->error("JS_DefineProp FALSE failed\n"); if (! JS_DefineProperty( d_cx, d_globalObj, "TRUE", BOOLEAN_TO_JSVAL(true), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT )) theSystem->error("JS_DefineProp TRUE failed\n"); if (! JS_DefineProperty( d_cx, d_globalObj, "_script", PRIVATE_TO_JSVAL(this), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT )) theSystem->error("JS_DefineProp _script failed\n"); // Browser object d_browserObj = JS_DefineObject( d_cx, d_globalObj, "Browser", &browserClass, 0, 0 ); if (! JS_DefineProperty( d_cx, d_browserObj, "_script", PRIVATE_TO_JSVAL(this), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT )) theSystem->error("JS_DefineProp _script failed\n"); if (! JS_DefineFunctions( d_cx, d_browserObj, browserFunctions )) theSystem->error("JS_DefineFunctions failed\n"); // Define SF*/MF* classes defineAPI(); // Define field/eventOut vars for this script defineFields(); /* These should indicate source location for diagnostics. */ char *filename = 0; uintN lineno = 0; jsval rval; if (! JS_EvaluateScript( d_cx, d_globalObj, source, strlen(source), filename, lineno, &rval)) theSystem->error("JS_EvaluateScript failed\n"); } } ScriptJS::~ScriptJS() { JS_DestroyContext(d_cx); if (--nInstances == 0) JS_Finish(rt); } static double s_timeStamp; // go away... // Run a specified script void ScriptJS::activate( double timeStamp, const char *fname, int argc, const VrmlField *argv[] ) { if (! d_cx) return; jsval fval, rval; if (! JS_LookupProperty( d_cx, d_globalObj, fname, &fval )) theSystem->error("JS_LookupProperty %s failed\n", fname); else if (! JSVAL_IS_VOID(fval)) { jsval jsargv[argc]; d_timeStamp = timeStamp; s_timeStamp = timeStamp; // this won't work for long... // convert VrmlField*'s to (gc-protected) jsvals for (int i=0; ifieldType(), argv[i], true ) : JSVAL_NULL; if (! JS_CallFunctionValue( d_cx, d_globalObj, fval, argc, jsargv, &rval)) theSystem->error("JS_CallFunctionName(%s) failed\n", fname); // Free up args for (int i=0; ibrowser(); } // Get a handle to the ScriptJS from the global object static ScriptJS *objToScript( JSContext *cx, JSObject *obj ) { jsval val; if (! JS_LookupProperty( cx, obj, "_script", &val )) theSystem->error("JS_LookupProperty _script failed\n"); else if (! JSVAL_IS_INT(val)) // Actually JSVAL_IS_PRIVATE theSystem->error("JS_LookupProperty _script failed- NULL _script\n"); return (ScriptJS*) JSVAL_TO_PRIVATE(val); } // Get a pointer to an eventOut from an object static char *objToEventOut( JSContext *cx, JSObject *obj ) { jsval val; if (JS_LookupProperty( cx, obj, "_eventOut", &val ) && JSVAL_IS_INT(val)) // Actually JSVAL_IS_PRIVATE return (char*) JSVAL_TO_PRIVATE(val); return 0; } // Check whether we are modifying a prop on an eventOut object, and if so, // notify the script. static void checkEventOut( JSContext *cx, JSObject *obj, VrmlField *val ) { char *eventOut = 0; ScriptJS *script = 0; if ((eventOut = objToEventOut( cx, obj )) != 0 && (script = objToScript( cx, JS_GetParent( cx, obj ))) != 0) { VrmlNodeScript *scriptNode = script->scriptNode(); scriptNode->setEventOut( eventOut, val ); } } // data converters static JSBool floatsToJSArray( int n, float *f, JSContext *cx, jsval *rval ) { const int MAX_FIXED = 20; jsval jsfixed[MAX_FIXED]; jsval *jsvec = (n > MAX_FIXED) ? new jsval[n] : jsfixed; int i; for (i=0; i MAX_FIXED) delete [] jsvec; return (i == n) ? JS_TRUE : JS_FALSE; } // Generic VrmlField finalize static void finalize(JSContext *cx, JSObject *obj) { VrmlField *f = (VrmlField *)JS_GetPrivate( cx, obj ); if (f) delete f; JS_SetPrivate( cx, obj, 0 ); } // Generic VrmlField toString #include static JSBool toString(JSContext *cx, JSObject *obj, uintN, jsval *, jsval *rval) { VrmlField *f = (VrmlField *)JS_GetPrivate( cx, obj ); if (f) { ostrstream os; os << (*f) << '\0'; const char *ss = os.str(); JSString *s = JS_NewStringCopyZ( cx, ss ); delete [] ss; if (s) { *rval = STRING_TO_JSVAL(s); return JS_TRUE; } } return JS_FALSE; } // // Classes precede the methods since the methods may access // objects of the various classes. // // SFColor class static JSBool SFColorCons(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *) { jsdouble r = 0.0, g = 0.0, b = 0.0; for (unsigned int i=0; ir())); break; case 1: *vp = DOUBLE_TO_JSVAL(JS_NewDouble( cx, c->g())); break; case 2: *vp = DOUBLE_TO_JSVAL(JS_NewDouble( cx, c->b())); break; default: return JS_FALSE; } return JS_TRUE; } static JSBool color_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { VrmlSFColor *c = (VrmlSFColor *)JS_GetPrivate( cx, obj ); jsdouble d; if (c && JSVAL_IS_INT(id) && JSVAL_TO_INT(id) >= 0 && JSVAL_TO_INT(id) < 3 && JS_ValueToNumber( cx, *vp, &d )) { c->get()[ JSVAL_TO_INT(id) ] = d; // very nice... checkEventOut( cx, obj, c ); return JS_TRUE; } return JS_FALSE; } static JSClass SFColorClass = { "SFColor", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, color_getProperty, color_setProperty, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, finalize }; // SFImage class // This is ugly because the spec requires an MFInt array for the pixel data // and because giving write access to the image size parameters can cause // the library code to crash unless they are validated somehow... static JSBool SFImageCons(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *) { int w = 0, h = 0, nc = 0; unsigned char *pixels = 0; jsdouble x; for (unsigned int i=0; i> (8*j); } } } break; default: /* Too many args */ break; } VrmlSFImage *c = new VrmlSFImage( w, h, nc, pixels ); JS_SetPrivate(cx, obj, c); return JS_TRUE; } static JSBool image_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { VrmlSFImage *c = (VrmlSFImage *)JS_GetPrivate( cx, obj ); if (! c) return JS_FALSE; if (JSVAL_IS_INT(id)) switch (JSVAL_TO_INT(id)) { case 0: *vp = INT_TO_JSVAL( c->width() ); break; case 1: *vp = INT_TO_JSVAL( c->height() ); break; case 2: *vp = INT_TO_JSVAL( c->nComponents() ); break; case 3: break; // *vp = convert pixels to MFInt... default: return JS_FALSE; } return JS_TRUE; } static JSBool image_setProperty(JSContext *, JSObject *, jsval , jsval *) { // ... return JS_FALSE; } static JSClass SFImageClass = { "SFImage", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, image_getProperty, image_setProperty, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, finalize }; // SFNode class static JSBool SFNodeCons(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *) { JSString *str; if (argc == 1 && JSVAL_IS_STRING(argv[0]) && (str = JSVAL_TO_STRING(argv[0])) != 0) { // If the nodes created contain scripts, they might want to access the // namespace... VrmlNamespace ns; VrmlMFNode *nodes = VrmlScene::readString( JS_GetStringBytes(str), &ns ); if (! nodes || nodes->size() == 0) return JS_FALSE; // If there are multiple top-level nodes, wrap them in a Group. SPEC? VrmlNode *n; if (nodes->size() == 1) n = nodes->get()[0]; else { VrmlNodeGroup *g = new VrmlNodeGroup(); g->addChildren( *nodes); n = g; } VrmlSFNode *sfnode = new VrmlSFNode(n); JS_SetPrivate(cx, obj, sfnode); delete nodes; return JS_TRUE; } return JS_FALSE; } // SFNode getProperty reads eventOut values, setProperty sends eventIns. static JSBool node_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { VrmlSFNode *n = (VrmlSFNode *)JS_GetPrivate( cx, obj ); JSString *str = 0; ScriptJS *script = 0; if (n && n->get() && JSVAL_IS_STRING(id) && ((str = JSVAL_TO_STRING(id)) != 0) && (script = objToScript( cx, JS_GetParent( cx, obj ))) != 0) { char *eventOut = JS_GetStringBytes(str); const VrmlField *fieldVal = n->get()->getEventOut( eventOut ); // convert event out value to jsval... if (fieldVal) { *vp = script->vrmlFieldToJSVal(fieldVal->fieldType(), fieldVal, false); return JS_TRUE; } theSystem->error("unrecognized exposedField/eventOut: node.getProperty(%s)\n", JS_GetStringBytes(str)); } return JS_FALSE; } static JSBool node_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { VrmlSFNode *sfn = (VrmlSFNode *)JS_GetPrivate( cx, obj ); VrmlNode *n = sfn ? sfn->get() : 0; if (n && JSVAL_IS_STRING(id)) { JSString *str = JSVAL_TO_STRING(id); char *eventIn = str ? JS_GetStringBytes(str) : 0; VrmlField::VrmlFieldType expect; expect = n->nodeType()->hasEventIn( eventIn ); if (expect && eventIn) // convert vp to field, send eventIn to n { VrmlField *f = jsvalToVrmlField( cx, *vp, expect ); // This should only happen if directOutput is set... #if DEBUG cout << "ScriptJS::node_setProperty sending " << eventIn << " (" << (*f) << ") to " << n->nodeType()->getName() << "::" << n->name() << endl; #endif // the timestamp should be stored as a global property and // looked up via obj somehow... ScriptJS *script = objToScript( cx, JS_GetParent( cx, obj )); if (script && script->browser()) script->browser()->queueEvent( s_timeStamp, f, n, eventIn ); } checkEventOut( cx, obj, sfn ); } return JS_TRUE; } static JSClass SFNodeClass = { "SFNode", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, node_getProperty, node_setProperty, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, finalize }; // SFRotation class static JSBool SFRotationCons(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *) { jsdouble x = 0.0, y = 1.0, z = 0.0, angle = 0.0; extern JSClass SFVec3fClass; if (argc > 0) { if ( JSVAL_IS_NUMBER(argv[0]) ) { JS_ValueToNumber( cx, argv[0], &x ); if (argc > 1) JS_ValueToNumber( cx, argv[1], &y ); if (argc > 2) JS_ValueToNumber( cx, argv[2], &z ); if (argc > 3) JS_ValueToNumber( cx, argv[3], &angle ); } else if (argc == 2 && JSVAL_IS_OBJECT(argv[0]) && &SFVec3fClass == JS_GetClass( JSVAL_TO_OBJECT(argv[0]) )) { JSObject *v1obj = JSVAL_TO_OBJECT(argv[0]); VrmlSFVec3f *v1 = (VrmlSFVec3f *)JS_GetPrivate( cx, v1obj ); if (JSVAL_IS_NUMBER( argv[1] )) { x = v1->x(); // axis/angle y = v1->y(); z = v1->z(); JS_ValueToNumber( cx, argv[1], &angle ); } else if ( JSVAL_IS_OBJECT(argv[1]) && &SFVec3fClass == JS_GetClass( JSVAL_TO_OBJECT(argv[1]) )) { JSObject *v2obj = JSVAL_TO_OBJECT(argv[1]); VrmlSFVec3f *v2 = (VrmlSFVec3f *)JS_GetPrivate( cx, v2obj ); VrmlSFVec3f v3(*v1); // find rotation that takes v1 to v2 v3.cross(v2); x = v3.x(); y = v3.y(); z = v3.z(); angle = acos( v1->dot(v2) / (v1->length() * v2->length()) ); } else return JS_FALSE; } else return JS_FALSE; } VrmlSFRotation *v = new VrmlSFRotation( x, y, z, angle ); JS_SetPrivate(cx, obj, v); return JS_TRUE; } static JSBool rot_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { VrmlSFRotation *v = (VrmlSFRotation *)JS_GetPrivate( cx, obj ); if (v && JSVAL_IS_INT(id)) switch (JSVAL_TO_INT(id)) { case 0: *vp = DOUBLE_TO_JSVAL(JS_NewDouble( cx, v->x())); break; case 1: *vp = DOUBLE_TO_JSVAL(JS_NewDouble( cx, v->y())); break; case 2: *vp = DOUBLE_TO_JSVAL(JS_NewDouble( cx, v->z())); break; case 3: *vp = DOUBLE_TO_JSVAL(JS_NewDouble( cx, v->r())); break; default: return JS_FALSE; } return JS_TRUE; } static JSBool rot_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { VrmlSFRotation *v = (VrmlSFRotation *)JS_GetPrivate( cx, obj ); jsdouble d; if (v && JSVAL_IS_INT(id) && JSVAL_TO_INT(id) >= 0 && JSVAL_TO_INT(id) < 4 && JS_ValueToNumber( cx, *vp, &d )) { v->get()[ JSVAL_TO_INT(id) ] = d; checkEventOut( cx, obj, v ); return JS_TRUE; } return JS_FALSE; } static JSClass SFRotationClass = { "SFRotation", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, rot_getProperty, rot_setProperty, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, finalize }; // SFVec2f class static JSBool SFVec2fCons(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *) { jsdouble x = 0.0, y = 0.0; if (argc > 0) JS_ValueToNumber( cx, argv[0], &x ); if (argc > 1) JS_ValueToNumber( cx, argv[1], &y ); VrmlSFVec2f *v = new VrmlSFVec2f( x, y ); JS_SetPrivate(cx, obj, v); return JS_TRUE; } static JSBool vec2f_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { VrmlSFVec2f *v = (VrmlSFVec2f *)JS_GetPrivate( cx, obj ); if (v && JSVAL_IS_INT(id)) switch (JSVAL_TO_INT(id)) { case 0: *vp = DOUBLE_TO_JSVAL(JS_NewDouble( cx, v->x())); break; case 1: *vp = DOUBLE_TO_JSVAL(JS_NewDouble( cx, v->y())); break; default: return JS_FALSE; } return JS_TRUE; } static JSBool vec2f_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { VrmlSFVec2f *v = (VrmlSFVec2f *)JS_GetPrivate( cx, obj ); jsdouble d; if (v && JSVAL_IS_INT(id) && JSVAL_TO_INT(id) >= 0 && JSVAL_TO_INT(id) < 2 && JS_ValueToNumber( cx, *vp, &d )) { v->get()[ JSVAL_TO_INT(id) ] = d; checkEventOut( cx, obj, v ); return JS_TRUE; } return JS_FALSE; } static JSClass SFVec2fClass = { "SFVec2f", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, vec2f_getProperty, vec2f_setProperty, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, finalize }; // SFVec3f class static JSBool SFVec3fCons(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *) { jsdouble x = 0.0, y = 0.0, z = 0.0; if (argc > 0) JS_ValueToNumber( cx, argv[0], &x ); if (argc > 1) JS_ValueToNumber( cx, argv[1], &y ); if (argc > 2) JS_ValueToNumber( cx, argv[2], &z ); VrmlSFVec3f *v = new VrmlSFVec3f( x, y, z ); JS_SetPrivate(cx, obj, v); return JS_TRUE; } static JSBool vec3f_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { VrmlSFVec3f *v = (VrmlSFVec3f *)JS_GetPrivate( cx, obj ); if (v && JSVAL_IS_INT(id)) switch (JSVAL_TO_INT(id)) { case 0: *vp = DOUBLE_TO_JSVAL(JS_NewDouble( cx, v->x())); break; case 1: *vp = DOUBLE_TO_JSVAL(JS_NewDouble( cx, v->y())); break; case 2: *vp = DOUBLE_TO_JSVAL(JS_NewDouble( cx, v->z())); break; default: return JS_FALSE; } return JS_TRUE; } static JSBool vec3f_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { VrmlSFVec3f *v = (VrmlSFVec3f *)JS_GetPrivate( cx, obj ); jsdouble d; if (v && JSVAL_IS_INT(id) && JSVAL_TO_INT(id) >= 0 && JSVAL_TO_INT(id) < 3 && JS_ValueToNumber( cx, *vp, &d )) { v->get()[ JSVAL_TO_INT(id) ] = d; checkEventOut( cx, obj, v ); return JS_TRUE; } return JS_FALSE; } static JSClass SFVec3fClass = { "SFVec3f", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, vec3f_getProperty, vec3f_setProperty, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, finalize }; // MFColor class static JSBool MFColorCons(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { obj = JS_NewArrayObject(cx, (jsint) argc, argv); *rval = OBJECT_TO_JSVAL(obj); return obj == 0 ? JS_FALSE : JS_TRUE; } static JSClass MFColorClass = { "MFColor", 0, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, }; // MFFloat class static JSBool MFFloatCons(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { obj = JS_NewArrayObject(cx, (jsint) argc, argv); *rval = OBJECT_TO_JSVAL(obj); return obj == 0 ? JS_FALSE : JS_TRUE; } static JSClass MFFloatClass = { "MFFloat", 0, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, }; // MFInt32 class static JSBool MFInt32Cons(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { obj = JS_NewArrayObject(cx, (jsint) argc, argv); *rval = OBJECT_TO_JSVAL(obj); return obj == 0 ? JS_FALSE : JS_TRUE; } static JSClass MFInt32Class = { "MFInt32", 0, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, }; // MFNode class static JSBool MFNodeCons(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { obj = JS_NewArrayObject(cx, (jsint) argc, argv); *rval = OBJECT_TO_JSVAL(obj); return obj == 0 ? JS_FALSE : JS_TRUE; } static JSClass MFNodeClass = { "MFNode", 0, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, }; // MFRotation class static JSBool MFRotationCons(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { obj = JS_NewArrayObject(cx, (jsint) argc, argv); *rval = OBJECT_TO_JSVAL(obj); return obj == 0 ? JS_FALSE : JS_TRUE; } static JSClass MFRotationClass = { "MFRotation", 0, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, }; // MFString class static JSBool MFStringCons(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { obj = JS_NewArrayObject(cx, (jsint) argc, argv); *rval = OBJECT_TO_JSVAL(obj); return obj == 0 ? JS_FALSE : JS_TRUE; } static JSClass MFStringClass = { "MFString", 0, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, }; // MFVec2f class static JSBool MFVec2fCons(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { obj = JS_NewArrayObject(cx, (jsint) argc, argv); *rval = OBJECT_TO_JSVAL(obj); return obj == 0 ? JS_FALSE : JS_TRUE; } static JSClass MFVec2fClass = { "MFVec2f", 0, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, }; // MFVec3f class static JSBool MFVec3fCons(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { obj = JS_NewArrayObject(cx, (jsint) argc, argv); *rval = OBJECT_TO_JSVAL(obj); return obj == 0 ? JS_FALSE : JS_TRUE; } static JSClass MFVec3fClass = { "MFVec3f", 0, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, }; // VrmlMatrix class ... // // Methods // // SFColor methods static JSBool color_setHSV(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *) { jsdouble h, s, v; VrmlSFColor *c = (VrmlSFColor *)JS_GetPrivate( cx, obj ); if ( c && argc == 3 && JS_ValueToNumber( cx, argv[0], &h ) && JS_ValueToNumber( cx, argv[1], &s ) && JS_ValueToNumber( cx, argv[2], &v ) ) { c->setHSV( h, s, v ); return JS_TRUE; } return JS_FALSE; } static JSBool color_getHSV(JSContext *cx, JSObject *obj, uintN , jsval *, jsval *rval) { VrmlSFColor *c = (VrmlSFColor *)JS_GetPrivate( cx, obj ); if ( c ) { float hsv[3]; c->getHSV( hsv[0], hsv[1], hsv[2] ); return floatsToJSArray( 3, hsv, cx, rval ); } return JS_FALSE; } // SFRotation methods static JSBool rot_getAxis(JSContext *cx, JSObject *obj, uintN , jsval *, jsval *rval) { VrmlSFRotation *r = (VrmlSFRotation *)JS_GetPrivate( cx, obj ); if ( r ) return floatsToJSArray( 3, r->get(), cx, rval ); return JS_FALSE; } static JSBool rot_inverse(JSContext *cx, JSObject *obj, uintN , jsval *, jsval *rval) { VrmlSFRotation *r = (VrmlSFRotation *)JS_GetPrivate( cx, obj ); JSObject *robj = 0; if (r && (robj = JS_NewObject( cx, &SFRotationClass, 0, JS_GetParent( cx, obj ) )) != 0) { VrmlSFRotation *r2 = (VrmlSFRotation*) (r->clone()); r2->invert(); JS_SetPrivate( cx, robj, r2 ); *rval = OBJECT_TO_JSVAL(robj); return JS_TRUE; } return JS_FALSE; } static JSBool rot_multiply(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { VrmlSFRotation *r1 = (VrmlSFRotation *)JS_GetPrivate( cx, obj ); VrmlSFRotation *r2 = 0; JSObject *r3obj = 0; // Verify that we have 2 SFRotation's && create a result if (r1 && argc > 0 && JSVAL_IS_OBJECT(argv[0]) && &SFRotationClass == JS_GetClass( JSVAL_TO_OBJECT(argv[0]) ) && (r2 = (VrmlSFRotation *)JS_GetPrivate( cx, JSVAL_TO_OBJECT(argv[0]))) && (((VrmlField*)r2)->fieldType() == VrmlField::SFROTATION) && (r3obj = JS_NewObject( cx, &SFRotationClass, 0, JS_GetParent( cx, obj ) )) != 0) { VrmlSFRotation *r3 = (VrmlSFRotation*) (r1->clone()); r3->multiply( r2 ); JS_SetPrivate( cx, r3obj, r3 ); *rval = OBJECT_TO_JSVAL(r3obj); return JS_TRUE; } return JS_FALSE; } static JSBool rot_multVec(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { VrmlSFRotation *r1 = (VrmlSFRotation *)JS_GetPrivate( cx, obj ); VrmlSFVec3f *v2 = 0; JSObject *v3obj = 0; // Verify that we have an SFVec3f arg && create a result if (r1 && argc > 0 && JSVAL_IS_OBJECT(argv[0]) && &SFVec3fClass == JS_GetClass( JSVAL_TO_OBJECT(argv[0]) ) && (v2 = (VrmlSFVec3f *)JS_GetPrivate( cx, JSVAL_TO_OBJECT(argv[0]))) && (((VrmlField*)v2)->fieldType() == VrmlField::SFVEC3F) && (v3obj = JS_NewObject( cx, &SFVec3fClass, 0, JS_GetParent( cx, obj ) )) != 0) { VrmlSFVec3f *v3 = new VrmlSFVec3f; // multiply v2 by rotation matrix... //Vmatrix( v3->get(), r1->getMatrix(), v2->get() ); JS_SetPrivate( cx, v3obj, v3 ); *rval = OBJECT_TO_JSVAL(v3obj); return JS_TRUE; } return JS_FALSE; } // Should this create a new object or modify obj?... static JSBool rot_setAxis(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { VrmlSFRotation *r1 = (VrmlSFRotation *)JS_GetPrivate( cx, obj ); VrmlSFVec3f *v2 = 0; // Verify that we have an SFVec3f arg && create a result if (r1 && argc > 0 && JSVAL_IS_OBJECT(argv[0]) && &SFVec3fClass == JS_GetClass( JSVAL_TO_OBJECT(argv[0]) ) && (v2 = (VrmlSFVec3f *)JS_GetPrivate( cx, JSVAL_TO_OBJECT(argv[0]))) && (((VrmlField*)v2)->fieldType() == VrmlField::SFVEC3F) ) { r1->set( v2->x(), v2->y(), v2->z(), r1->r() ); *rval = OBJECT_TO_JSVAL(obj); // return the same object return JS_TRUE; } return JS_FALSE; } static JSBool rot_slerp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { VrmlSFRotation *r1 = (VrmlSFRotation *)JS_GetPrivate( cx, obj ); VrmlSFRotation *r2 = 0; JSObject *r3obj = 0; // Verify that we have 2 SFRotation's, a number, & create a result if (r1 && argc > 1 && JSVAL_IS_OBJECT(argv[0]) && &SFRotationClass == JS_GetClass( JSVAL_TO_OBJECT(argv[0]) ) && (r2 = (VrmlSFRotation *)JS_GetPrivate( cx, JSVAL_TO_OBJECT(argv[0]))) && (((VrmlField*)r2)->fieldType() == VrmlField::SFROTATION) && JSVAL_IS_NUMBER(argv[1]) && (r3obj = JS_NewObject( cx, &SFRotationClass, 0, JS_GetParent( cx, obj ) )) != 0) { VrmlSFRotation *r3 = (VrmlSFRotation*) (r1->clone()); jsdouble factor; JS_ValueToNumber( cx, argv[1], &factor ); r3->slerp( r2, factor ); JS_SetPrivate( cx, r3obj, r3 ); *rval = OBJECT_TO_JSVAL(r3obj); return JS_TRUE; } return JS_FALSE; } // SFVec2f methods static JSBool vec2f_add(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { VrmlSFVec2f *v1 = (VrmlSFVec2f *)JS_GetPrivate( cx, obj ); VrmlSFVec2f *v2 = 0; JSObject *v3obj = 0; // Verify that we have 2 SFVec2f's && create a result if (v1 && argc > 0 && JSVAL_IS_OBJECT(argv[0]) && &SFVec2fClass == JS_GetClass( JSVAL_TO_OBJECT(argv[0]) ) && (v2 = (VrmlSFVec2f *)JS_GetPrivate( cx, JSVAL_TO_OBJECT(argv[0]))) && (((VrmlField*)v2)->fieldType() == VrmlField::SFVEC2F) && (v3obj = JS_NewObject( cx, &SFVec2fClass, 0, JS_GetParent( cx, obj ) )) != 0) { VrmlSFVec2f *v3 = (VrmlSFVec2f*) (v1->clone()); v3->add( v2 ); JS_SetPrivate( cx, v3obj, v3 ); *rval = OBJECT_TO_JSVAL(v3obj); return JS_TRUE; } return JS_FALSE; } static JSBool vec2f_divide(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { VrmlSFVec2f *v1 = (VrmlSFVec2f *)JS_GetPrivate( cx, obj ); jsdouble d = 0.0; JSObject *v3obj = 0; // Verify that we have a number && create a result if (v1 && argc > 0 && JS_ValueToNumber( cx, argv[0], &d ) && (v3obj = JS_NewObject( cx, &SFVec2fClass, 0, JS_GetParent( cx, obj ) )) != 0) { VrmlSFVec2f *v3 = (VrmlSFVec2f*) (v1->clone()); v3->divide( d ); JS_SetPrivate( cx, v3obj, v3 ); *rval = OBJECT_TO_JSVAL(v3obj); return JS_TRUE; } return JS_FALSE; } static JSBool vec2f_dot(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { VrmlSFVec2f *v1 = (VrmlSFVec2f *)JS_GetPrivate( cx, obj ); VrmlSFVec2f *v2 = 0; JSObject *v3obj = 0; // Verify that we have 2 SFVec2f's && create a result if (v1 && argc > 0 && JSVAL_IS_OBJECT(argv[0]) && &SFVec2fClass == JS_GetClass( JSVAL_TO_OBJECT(argv[0]) ) && (v2 = (VrmlSFVec2f *)JS_GetPrivate( cx, JSVAL_TO_OBJECT(argv[0]))) && (((VrmlField*)v2)->fieldType() == VrmlField::SFVEC2F) && (v3obj = JS_NewObject( cx, &SFVec2fClass, 0, JS_GetParent( cx, obj ) )) != 0) { VrmlSFVec2f *v3 = (VrmlSFVec2f*) (v1->clone()); v3->dot( v2 ); JS_SetPrivate( cx, v3obj, v3 ); *rval = OBJECT_TO_JSVAL(v3obj); return JS_TRUE; } return JS_FALSE; } static JSBool vec2f_length(JSContext *cx, JSObject *obj, uintN, jsval *, jsval *rval) { VrmlSFVec2f *v = (VrmlSFVec2f *)JS_GetPrivate( cx, obj ); if (v) { *rval = DOUBLE_TO_JSVAL(JS_NewDouble( cx, v->length())); return JS_TRUE; } return JS_FALSE; } static JSBool vec2f_multiply(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { VrmlSFVec2f *v1 = (VrmlSFVec2f *)JS_GetPrivate( cx, obj ); jsdouble d = 0.0; JSObject *v3obj = 0; // Verify that we have a number && create a result if (v1 && argc > 0 && JS_ValueToNumber( cx, argv[0], &d ) && (v3obj = JS_NewObject( cx, &SFVec2fClass, 0, JS_GetParent( cx, obj ) )) != 0) { VrmlSFVec2f *v3 = (VrmlSFVec2f*) (v1->clone()); v3->multiply( d ); JS_SetPrivate( cx, v3obj, v3 ); *rval = OBJECT_TO_JSVAL(v3obj); return JS_TRUE; } return JS_FALSE; } static JSBool vec2f_negate(JSContext *cx, JSObject *obj, uintN, jsval *, jsval *rval) { VrmlSFVec2f *v1 = (VrmlSFVec2f *)JS_GetPrivate( cx, obj ); JSObject *v3obj = 0; if (v1 && (v3obj = JS_NewObject( cx, &SFVec2fClass, 0, JS_GetParent( cx, obj ) )) != 0) { VrmlSFVec2f *v3 = (VrmlSFVec2f*) (v1->clone()); v3->multiply( -1.0 ); JS_SetPrivate( cx, v3obj, v3 ); *rval = OBJECT_TO_JSVAL(v3obj); return JS_TRUE; } return JS_FALSE; } static JSBool vec2f_normalize(JSContext *cx, JSObject *obj, uintN, jsval *, jsval *rval) { VrmlSFVec2f *v1 = (VrmlSFVec2f *)JS_GetPrivate( cx, obj ); JSObject *v3obj = 0; if (v1 && (v3obj = JS_NewObject( cx, &SFVec2fClass, 0, JS_GetParent( cx, obj ) )) != 0) { VrmlSFVec2f *v3 = (VrmlSFVec2f*) (v1->clone()); v3->normalize(); JS_SetPrivate( cx, v3obj, v3 ); *rval = OBJECT_TO_JSVAL(v3obj); return JS_TRUE; } return JS_FALSE; } static JSBool vec2f_subtract(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { VrmlSFVec2f *v1 = (VrmlSFVec2f *)JS_GetPrivate( cx, obj ); VrmlSFVec2f *v2 = 0; JSObject *v3obj = 0; // Verify that we have 2 SFVec2f's && create a result if (v1 && argc > 0 && JSVAL_IS_OBJECT(argv[0]) && &SFVec2fClass == JS_GetClass( JSVAL_TO_OBJECT(argv[0]) ) && (v2 = (VrmlSFVec2f *)JS_GetPrivate( cx, JSVAL_TO_OBJECT(argv[0]))) && (((VrmlField*)v2)->fieldType() == VrmlField::SFVEC2F) && (v3obj = JS_NewObject( cx, &SFVec2fClass, 0, JS_GetParent( cx, obj ) )) != 0) { VrmlSFVec2f *v3 = (VrmlSFVec2f*) (v1->clone()); v3->subtract( v2 ); JS_SetPrivate( cx, v3obj, v3 ); *rval = OBJECT_TO_JSVAL(v3obj); return JS_TRUE; } return JS_FALSE; } // SFVec3f methods static JSBool vec3f_add(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { VrmlSFVec3f *v1 = (VrmlSFVec3f *)JS_GetPrivate( cx, obj ); VrmlSFVec3f *v2 = 0; JSObject *v3obj = 0; // Verify that we have 2 SFVec3f's && create a result if (v1 && argc > 0 && JSVAL_IS_OBJECT(argv[0]) && &SFVec3fClass == JS_GetClass( JSVAL_TO_OBJECT(argv[0]) ) && (v2 = (VrmlSFVec3f *)JS_GetPrivate( cx, JSVAL_TO_OBJECT(argv[0]))) && (((VrmlField*)v2)->fieldType() == VrmlField::SFVEC3F) && (v3obj = JS_NewObject( cx, &SFVec3fClass, 0, JS_GetParent( cx, obj ) )) != 0) { VrmlSFVec3f *v3 = (VrmlSFVec3f*) (v1->clone()); v3->add( v2 ); JS_SetPrivate( cx, v3obj, v3 ); *rval = OBJECT_TO_JSVAL(v3obj); return JS_TRUE; } return JS_FALSE; } static JSBool vec3f_cross(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { VrmlSFVec3f *v1 = (VrmlSFVec3f *)JS_GetPrivate( cx, obj ); VrmlSFVec3f *v2 = 0; JSObject *v3obj = 0; // Verify that we have 2 SFVec3f's && create a result if (v1 && argc > 0 && JSVAL_IS_OBJECT(argv[0]) && &SFVec3fClass == JS_GetClass( JSVAL_TO_OBJECT(argv[0]) ) && (v2 = (VrmlSFVec3f *)JS_GetPrivate( cx, JSVAL_TO_OBJECT(argv[0]))) && (((VrmlField*)v2)->fieldType() == VrmlField::SFVEC3F) && (v3obj = JS_NewObject( cx, &SFVec3fClass, 0, JS_GetParent( cx, obj ) )) != 0) { VrmlSFVec3f *v3 = (VrmlSFVec3f*) (v1->clone()); v3->cross( v2 ); JS_SetPrivate( cx, v3obj, v3 ); *rval = OBJECT_TO_JSVAL(v3obj); return JS_TRUE; } return JS_FALSE; } static JSBool vec3f_divide(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { VrmlSFVec3f *v1 = (VrmlSFVec3f *)JS_GetPrivate( cx, obj ); jsdouble d = 0.0; JSObject *v3obj = 0; // Verify that we have a number && create a result if (v1 && argc > 0 && JS_ValueToNumber( cx, argv[0], &d ) && (v3obj = JS_NewObject( cx, &SFVec3fClass, 0, JS_GetParent( cx, obj ) )) != 0) { VrmlSFVec3f *v3 = (VrmlSFVec3f*) (v1->clone()); v3->divide( d ); JS_SetPrivate( cx, v3obj, v3 ); *rval = OBJECT_TO_JSVAL(v3obj); return JS_TRUE; } return JS_FALSE; } static JSBool vec3f_dot(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { VrmlSFVec3f *v1 = (VrmlSFVec3f *)JS_GetPrivate( cx, obj ); VrmlSFVec3f *v2 = 0; JSObject *v3obj = 0; // Verify that we have 2 SFVec3f's && create a result if (v1 && argc > 0 && JSVAL_IS_OBJECT(argv[0]) && &SFVec3fClass == JS_GetClass( JSVAL_TO_OBJECT(argv[0]) ) && (v2 = (VrmlSFVec3f *)JS_GetPrivate( cx, JSVAL_TO_OBJECT(argv[0]))) && (((VrmlField*)v2)->fieldType() == VrmlField::SFVEC3F) && (v3obj = JS_NewObject( cx, &SFVec3fClass, 0, JS_GetParent( cx, obj ) )) != 0) { VrmlSFVec3f *v3 = (VrmlSFVec3f*) (v1->clone()); v3->dot( v2 ); JS_SetPrivate( cx, v3obj, v3 ); *rval = OBJECT_TO_JSVAL(v3obj); return JS_TRUE; } return JS_FALSE; } static JSBool vec3f_length(JSContext *cx, JSObject *obj, uintN, jsval *, jsval *rval) { VrmlSFVec3f *v = (VrmlSFVec3f *)JS_GetPrivate( cx, obj ); if (v) { *rval = DOUBLE_TO_JSVAL(JS_NewDouble( cx, v->length())); return JS_TRUE; } return JS_FALSE; } static JSBool vec3f_multiply(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { VrmlSFVec3f *v1 = (VrmlSFVec3f *)JS_GetPrivate( cx, obj ); jsdouble d = 0.0; JSObject *v3obj = 0; // Verify that we have a number && create a result if (v1 && argc > 0 && JS_ValueToNumber( cx, argv[0], &d ) && (v3obj = JS_NewObject( cx, &SFVec3fClass, 0, JS_GetParent( cx, obj ) )) != 0) { VrmlSFVec3f *v3 = (VrmlSFVec3f*) (v1->clone()); v3->multiply( d ); JS_SetPrivate( cx, v3obj, v3 ); *rval = OBJECT_TO_JSVAL(v3obj); return JS_TRUE; } return JS_FALSE; } static JSBool vec3f_negate(JSContext *cx, JSObject *obj, uintN, jsval *, jsval *rval) { VrmlSFVec3f *v1 = (VrmlSFVec3f *)JS_GetPrivate( cx, obj ); JSObject *v3obj = 0; if (v1 && (v3obj = JS_NewObject( cx, &SFVec3fClass, 0, JS_GetParent( cx, obj ) )) != 0) { VrmlSFVec3f *v3 = (VrmlSFVec3f*) (v1->clone()); v3->multiply( -1.0 ); JS_SetPrivate( cx, v3obj, v3 ); *rval = OBJECT_TO_JSVAL(v3obj); return JS_TRUE; } return JS_FALSE; } static JSBool vec3f_normalize(JSContext *cx, JSObject *obj, uintN, jsval *, jsval *rval) { VrmlSFVec3f *v1 = (VrmlSFVec3f *)JS_GetPrivate( cx, obj ); JSObject *v3obj = 0; if (v1 && (v3obj = JS_NewObject( cx, &SFVec3fClass, 0, JS_GetParent( cx, obj ) )) != 0) { VrmlSFVec3f *v3 = (VrmlSFVec3f*) (v1->clone()); v3->normalize(); JS_SetPrivate( cx, v3obj, v3 ); *rval = OBJECT_TO_JSVAL(v3obj); return JS_TRUE; } return JS_FALSE; } static JSBool vec3f_subtract(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { VrmlSFVec3f *v1 = (VrmlSFVec3f *)JS_GetPrivate( cx, obj ); VrmlSFVec3f *v2 = 0; JSObject *v3obj = 0; // Verify that we have 2 SFVec3f's && create a result if (v1 && argc > 0 && JSVAL_IS_OBJECT(argv[0]) && &SFVec3fClass == JS_GetClass( JSVAL_TO_OBJECT(argv[0]) ) && (v2 = (VrmlSFVec3f *)JS_GetPrivate( cx, JSVAL_TO_OBJECT(argv[0]))) && (((VrmlField*)v2)->fieldType() == VrmlField::SFVEC3F) && (v3obj = JS_NewObject( cx, &SFVec3fClass, 0, JS_GetParent( cx, obj ) )) != 0) { VrmlSFVec3f *v3 = (VrmlSFVec3f*) (v1->clone()); v3->subtract( v2 ); JS_SetPrivate( cx, v3obj, v3 ); *rval = OBJECT_TO_JSVAL(v3obj); return JS_TRUE; } return JS_FALSE; } // Create class objects for the non-scalar field types. // Move toString to a prototype object? void ScriptJS::defineAPI() { // SFColor static JSPropertySpec SFColorProps[] = { {"r", 0, JSPROP_ENUMERATE}, {"g", 1, JSPROP_ENUMERATE}, {"b", 2, JSPROP_ENUMERATE}, {0} }; static JSFunctionSpec SFColorMethods[] = { /* name native nargs */ {"setHSV", color_setHSV, 3}, {"getHSV", color_getHSV, 0}, {"toString", toString, 0}, {0} }; if (! JS_InitClass( d_cx, d_globalObj, 0, &SFColorClass, SFColorCons, 0, // constructor function, min arg count SFColorProps, SFColorMethods, 0, 0)) // static properties and methods theSystem->error("JS_InitClass SFColor failed\n"); // SFImage static JSPropertySpec SFImageProps[] = { {"x", 0, JSPROP_ENUMERATE}, {"y", 1, JSPROP_ENUMERATE}, {"comp", 2, JSPROP_ENUMERATE}, {"array", 3, JSPROP_ENUMERATE}, {0} }; static JSFunctionSpec SFImageMethods[] = { /* name native nargs */ {"toString", toString, 0}, {0} }; if (! JS_InitClass( d_cx, d_globalObj, 0, &SFImageClass, SFImageCons, 0, // constructor function, min arg count SFImageProps, SFImageMethods, 0, 0)) // static properties and methods theSystem->error("JS_InitClass SFImage failed\n"); // SFNode static JSFunctionSpec SFNodeMethods[] = { /* name native nargs */ {"toString", toString, 0}, {0} }; if (! JS_InitClass( d_cx, d_globalObj, 0, &SFNodeClass, SFNodeCons, 1, // constructor function, min arg count 0, SFNodeMethods, 0, 0)) // static properties and methods theSystem->error("JS_InitClass SFNode failed\n"); // SFRotation static JSPropertySpec SFRotationProps[] = { {"x", 0, JSPROP_ENUMERATE}, {"y", 1, JSPROP_ENUMERATE}, {"z", 2, JSPROP_ENUMERATE}, {"angle", 3, JSPROP_ENUMERATE}, {0} }; static JSFunctionSpec SFRotationMethods[] = { /* name native nargs */ {"getAxis", rot_getAxis, 0}, {"inverse", rot_inverse, 0}, {"multiply", rot_multiply, 1}, {"multVec", rot_multVec, 1}, {"setAxis", rot_setAxis, 1}, {"slerp", rot_slerp, 2}, {"toString", toString, 0}, {0} }; if (! JS_InitClass( d_cx, d_globalObj, 0, &SFRotationClass, SFRotationCons, 0, // constructor function, min arg count SFRotationProps, SFRotationMethods, 0, 0)) // static properties and methods theSystem->error("JS_InitClass SFRotation failed\n"); // SFVec2f static JSPropertySpec SFVec2fProps[] = { {"x", 0, JSPROP_ENUMERATE}, {"y", 1, JSPROP_ENUMERATE}, {0} }; static JSFunctionSpec SFVec2fMethods[] = { /* name native nargs */ {"add", vec2f_add, 1}, {"divide", vec2f_divide, 1}, {"dot", vec2f_dot, 1}, {"length", vec2f_length, 0}, {"multiply", vec2f_multiply, 1}, {"negate", vec2f_negate, 0}, {"normalize", vec2f_normalize,0}, {"subtract", vec2f_subtract, 1}, {"toString", toString, 0}, {0} }; if (! JS_InitClass( d_cx, d_globalObj, 0, &SFVec2fClass, SFVec2fCons, 0, // constructor function, min arg count SFVec2fProps, SFVec2fMethods, 0, 0)) // static properties and methods theSystem->error("JS_InitClass SFVec2f failed\n"); // SFVec3f static JSPropertySpec SFVec3fProps[] = { {"x", 0, JSPROP_ENUMERATE}, {"y", 1, JSPROP_ENUMERATE}, {"z", 2, JSPROP_ENUMERATE}, {0} }; static JSFunctionSpec SFVec3fMethods[] = { /* name native nargs */ {"add", vec3f_add, 1}, {"cross", vec3f_cross, 1}, {"divide", vec3f_divide, 1}, {"dot", vec3f_dot, 1}, {"length", vec3f_length, 0}, {"multiply", vec3f_multiply, 1}, {"negate", vec3f_negate, 0}, {"normalize", vec3f_normalize,0}, {"subtract", vec3f_subtract, 1}, {"toString", toString, 0}, {0} }; if (! JS_InitClass( d_cx, d_globalObj, 0, &SFVec3fClass, SFVec3fCons, 0, // constructor function, min arg count SFVec3fProps, SFVec3fMethods, 0, 0)) // static properties and methods theSystem->error("JS_InitClass SFVec3f failed\n"); // All the MF* classes are subclassed from Array JSObject *array_proto = js_InitArrayClass( d_cx, d_globalObj ); // MFColor class if (! JS_InitClass( d_cx, d_globalObj, array_proto, &MFColorClass, MFColorCons, 0, // constructor function, min arg count 0, 0, 0, 0)) // static properties and methods theSystem->error("JS_InitClass MFColor failed\n"); // MFFloat class if (! JS_InitClass( d_cx, d_globalObj, array_proto, &MFFloatClass, MFFloatCons, 0, // constructor function, min arg count 0, 0, 0, 0)) // static properties and methods theSystem->error("JS_InitClass MFFloat failed\n"); // MFInt32 class if (! JS_InitClass( d_cx, d_globalObj, array_proto, &MFInt32Class, MFInt32Cons, 0, // constructor function, min arg count 0, 0, 0, 0)) // static properties and methods theSystem->error("JS_InitClass MFInt32 failed\n"); // MFNode class if (! JS_InitClass( d_cx, d_globalObj, array_proto, &MFNodeClass, MFNodeCons, 0, // constructor function, min arg count 0, 0, 0, 0)) // static properties and methods theSystem->error("JS_InitClass MFNode failed\n"); // MFRotation class if (! JS_InitClass( d_cx, d_globalObj, array_proto, &MFRotationClass, MFRotationCons, 0, // constructor function, min arg count 0, 0, 0, 0)) // static properties and methods theSystem->error("JS_InitClass MFRotation failed\n"); // MFString class if (! JS_InitClass( d_cx, d_globalObj, array_proto, &MFStringClass, MFStringCons, 0, // constructor function, min arg count 0, 0, 0, 0)) // static properties and methods theSystem->error("JS_InitClass MFString failed\n"); // MFVec2f class if (! JS_InitClass( d_cx, d_globalObj, array_proto, &MFVec2fClass, MFVec2fCons, 0, // constructor function, min arg count 0, 0, 0, 0)) // static properties and methods theSystem->error("JS_InitClass MFVec2f failed\n"); // MFVec3f class if (! JS_InitClass( d_cx, d_globalObj, array_proto, &MFVec3fClass, MFVec3fCons, 0, // constructor function, min arg count 0, 0, 0, 0)) // static properties and methods theSystem->error("JS_InitClass MFVec3f failed\n"); } // Convert a VrmlField value to a jsval, optionally protect from gc. jsval ScriptJS::vrmlFieldToJSVal( VrmlField::VrmlFieldType type, const VrmlField *f, bool protect ) { switch (type) { case VrmlField::SFBOOL: { return BOOLEAN_TO_JSVAL( f ? f->toSFBool()->get() : 0 ); } case VrmlField::SFCOLOR: { JSObject *obj = JS_NewObject( d_cx, &SFColorClass, 0, d_globalObj ); if (! obj) return JSVAL_NULL; if (protect) JS_AddRoot( d_cx, obj ); JS_SetPrivate( d_cx, obj, f ? f->clone() : new VrmlSFColor() ); return OBJECT_TO_JSVAL(obj); } case VrmlField::SFFLOAT: { jsdouble *d = JS_NewDouble( d_cx, f ? f->toSFFloat()->get() : 0.0 ); if (protect) JS_AddRoot( d_cx, d ); return DOUBLE_TO_JSVAL( d ); } case VrmlField::SFIMAGE: { JSObject *obj = JS_NewObject( d_cx, &SFImageClass, 0, d_globalObj ); if (! obj) return JSVAL_NULL; if (protect) JS_AddRoot( d_cx, obj ); JS_SetPrivate( d_cx, obj, f ? f->clone() : new VrmlSFImage() ); return OBJECT_TO_JSVAL(obj); } case VrmlField::SFINT32: { return INT_TO_JSVAL( f ? f->toSFInt()->get() : 0 ); } case VrmlField::SFNODE: { JSObject *obj = JS_NewObject( d_cx, &SFNodeClass, 0, d_globalObj ); if (! obj) return JSVAL_NULL; if (protect) JS_AddRoot( d_cx, obj ); JS_SetPrivate( d_cx, obj, f ? f->clone() : new VrmlSFNode() ); return OBJECT_TO_JSVAL(obj); } case VrmlField::SFROTATION: { JSObject *obj = JS_NewObject( d_cx, &SFRotationClass, 0, d_globalObj ); if (! obj) return JSVAL_NULL; if (protect) JS_AddRoot( d_cx, obj ); JS_SetPrivate( d_cx, obj, f ? f->clone() : new VrmlSFRotation() ); return OBJECT_TO_JSVAL(obj); } case VrmlField::SFSTRING: { JSString *s = JS_NewStringCopyZ( d_cx, f ? f->toSFString()->get() : "" ); if (protect) JS_AddRoot( d_cx, s ); return STRING_TO_JSVAL( s ); } case VrmlField::SFTIME: { jsdouble *d = JS_NewDouble( d_cx, f ? f->toSFTime()->get() : 0 ); if (protect) JS_AddRoot( d_cx, d ); return DOUBLE_TO_JSVAL( d ); } case VrmlField::SFVEC2F: { JSObject *obj = JS_NewObject( d_cx, &SFVec2fClass, 0, d_globalObj ); if (! obj) return JSVAL_NULL; if (protect) JS_AddRoot( d_cx, obj ); JS_SetPrivate( d_cx, obj, f ? f->clone() : new VrmlSFVec2f() ); return OBJECT_TO_JSVAL(obj); } case VrmlField::SFVEC3F: { JSObject *obj = JS_NewObject( d_cx, &SFVec3fClass, 0, d_globalObj ); if (! obj) return JSVAL_NULL; if (protect) JS_AddRoot( d_cx, obj ); JS_SetPrivate( d_cx, obj, f ? f->clone() : new VrmlSFVec3f() ); return OBJECT_TO_JSVAL(obj); } // MF* case VrmlField::MFCOLOR: { VrmlMFColor *mf = f ? ((VrmlMFColor*) (f->toMFColor())) : 0; int i, n = mf ? mf->size() : 0; JSObject *obj = JS_NewArrayObject( d_cx, (jsint)n, 0 ); if (! obj) return JSVAL_NULL; JS_AddRoot( d_cx, obj ); float *fn = mf ? mf->get() : 0; for (i=0; itoMFFloat())) : 0; int i, n = mf ? mf->size() : 0; JSObject *obj = JS_NewArrayObject( d_cx, (jsint)n, 0 ); if (! obj) return JSVAL_NULL; JS_AddRoot( d_cx, obj ); float *fn = mf ? mf->get() : 0; for (i=0; itoMFInt())) : 0; int i, n = mf ? mf->size() : 0; JSObject *obj = JS_NewArrayObject( d_cx, (jsint)n, 0 ); if (! obj) return JSVAL_NULL; if (protect) JS_AddRoot( d_cx, obj ); int *fn = mf ? mf->get() : 0; for (i=0; itoMFNode())) : 0; int i, n = mf ? mf->size() : 0; JSObject *obj = JS_NewArrayObject( d_cx, (jsint)n, 0 ); if (! obj) return JSVAL_NULL; JS_AddRoot( d_cx, obj ); for (i=0; iget(i) ) ); JS_DefineElement( d_cx, obj, (jsint)i, OBJECT_TO_JSVAL(elt), JS_PropertyStub, JS_PropertyStub, JSPROP_ENUMERATE ); } if (! protect) JS_RemoveRoot( d_cx, obj ); return OBJECT_TO_JSVAL(obj); } case VrmlField::MFROTATION: { VrmlMFRotation *mf = f ? ((VrmlMFRotation*) (f->toMFRotation())) : 0; int i, n = mf ? mf->size() : 0; JSObject *obj = JS_NewArrayObject( d_cx, (jsint)n, 0 ); if (! obj) return JSVAL_NULL; JS_AddRoot( d_cx, obj ); float *fn = mf ? mf->get() : 0; for (i=0; itoMFString()); n = mf ? mf->size() : 0; if (n > 0) jsvec = new jsval[n]; for (i=0; iget(i) ); jsvec[i] = STRING_TO_JSVAL( s ); } } JSObject *obj = JS_NewArrayObject( d_cx, (jsint)n, jsvec ); if (jsvec) delete [] jsvec; if (! obj) return JSVAL_NULL; if (protect) JS_AddRoot( d_cx, obj ); return OBJECT_TO_JSVAL(obj); } case VrmlField::MFVEC2F: { VrmlMFVec2f *mf = f ? ((VrmlMFVec2f*) (f->toMFVec2f())) : 0; int i, n = mf ? mf->size() : 0; JSObject *obj = JS_NewArrayObject( d_cx, (jsint)n, 0 ); if (! obj) return JSVAL_NULL; JS_AddRoot( d_cx, obj ); float *fn = mf ? mf->get() : 0; for (i=0; itoMFVec3f())) : 0; int i, n = mf ? mf->size() : 0; JSObject *obj = JS_NewArrayObject( d_cx, (jsint)n, 0 ); if (! obj) return JSVAL_NULL; JS_AddRoot( d_cx, obj ); float *fn = mf ? mf->get() : 0; for (i=0; ierror("vrmlFieldToJSVal: unhandled type (%d)\n", (int) type); return BOOLEAN_TO_JSVAL( false ); // oops... } } // Convert a jsval to a (new) VrmlField static VrmlField *jsvalToVrmlField( JSContext *cx, jsval v, VrmlField::VrmlFieldType expectType ) { if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) return 0; else if (JSVAL_IS_BOOLEAN(v) && expectType == VrmlField::SFBOOL) return new VrmlSFBool( JSVAL_TO_BOOLEAN(v) ); else if (JSVAL_IS_INT(v) && expectType == VrmlField::SFINT32) return new VrmlSFInt( JSVAL_TO_INT(v) ); else if (JSVAL_IS_NUMBER(v) && expectType == VrmlField::SFFLOAT) { jsdouble d; JS_ValueToNumber( cx, v, &d ); return new VrmlSFFloat( d ); } else if (JSVAL_IS_NUMBER(v) && expectType == VrmlField::SFTIME) { jsdouble d; JS_ValueToNumber( cx, v, &d ); return new VrmlSFTime( d ); } else if (JSVAL_IS_STRING(v) && expectType == VrmlField::SFSTRING) { JSString *str = JSVAL_TO_STRING(v); return new VrmlSFString( str ? JS_GetStringBytes(str) : "" ); } else if (JSVAL_IS_OBJECT(v) && ((expectType == VrmlField::SFCOLOR && &SFColorClass == JS_GetClass( JSVAL_TO_OBJECT(v) )) || (expectType == VrmlField::SFIMAGE && &SFImageClass == JS_GetClass( JSVAL_TO_OBJECT(v) )) || (expectType == VrmlField::SFNODE && &SFNodeClass == JS_GetClass( JSVAL_TO_OBJECT(v) )) || (expectType == VrmlField::SFROTATION && &SFRotationClass == JS_GetClass( JSVAL_TO_OBJECT(v) )) || (expectType == VrmlField::SFVEC2F && &SFVec2fClass == JS_GetClass( JSVAL_TO_OBJECT(v) )) || (expectType == VrmlField::SFVEC3F && &SFVec3fClass == JS_GetClass( JSVAL_TO_OBJECT(v) )) )) { VrmlField *f = (VrmlField *)JS_GetPrivate( cx, JSVAL_TO_OBJECT(v) ); if (! f) return 0; return f->clone(); } // MFColor else if (JSVAL_IS_OBJECT(v) && JS_IsArrayObject( cx, JSVAL_TO_OBJECT(v) ) && expectType == VrmlField::MFCOLOR) { jsuint len; JS_GetArrayLength( cx, JSVAL_TO_OBJECT(v), &len ); float *data = new float[ 3*len ]; memset(data, 0, 3*len*sizeof(float)); for (int i=0; i<(int)len; ++i) { jsval elt; JS_GetElement( cx, JSVAL_TO_OBJECT(v), (jsint) i, &elt ); if (JSVAL_IS_OBJECT(elt)) { JSObject *obj = JSVAL_TO_OBJECT(elt); VrmlField *vf = obj ? (VrmlField *)JS_GetPrivate( cx, obj ) : 0; VrmlSFColor *c = vf ? vf->toSFColor() : 0; if (c) { data[3*i] = c->get()[0]; data[3*i+1] = c->get()[1]; data[3*i+2] = c->get()[2]; } } } VrmlMFColor *f = new VrmlMFColor( (int)len, data ); delete [] data; return f; } // MFFloat else if (JSVAL_IS_OBJECT(v) && JS_IsArrayObject( cx, JSVAL_TO_OBJECT(v) ) && expectType == VrmlField::MFFLOAT) { jsuint len; JS_GetArrayLength( cx, JSVAL_TO_OBJECT(v), &len ); float *data = new float[ len ]; memset(data, 0, len*sizeof(float)); for (int i=0; i<(int)len; ++i) { jsval elt; JS_GetElement( cx, JSVAL_TO_OBJECT(v), (jsint) i, &elt ); if (JSVAL_IS_NUMBER(elt)) { jsdouble factor; JS_ValueToNumber( cx, elt, &factor ); data[i] = (float) factor; } } VrmlMFFloat *f = new VrmlMFFloat( (int)len, data ); delete [] data; return f; } // MFInt else if (JSVAL_IS_OBJECT(v) && JS_IsArrayObject( cx, JSVAL_TO_OBJECT(v) ) && expectType == VrmlField::MFINT32) { jsuint len; JS_GetArrayLength( cx, JSVAL_TO_OBJECT(v), &len ); int *data = new int[ len ]; memset(data, 0, len*sizeof(int)); for (int i=0; i<(int)len; ++i) { jsval elt; JS_GetElement( cx, JSVAL_TO_OBJECT(v), (jsint) i, &elt ); if (JSVAL_IS_NUMBER(elt)) { jsdouble factor; JS_ValueToNumber( cx, elt, &factor ); data[i] = (int) factor; } } VrmlMFInt *f = new VrmlMFInt( (int)len, data ); delete [] data; return f; } // MFNode else if (JSVAL_IS_OBJECT(v) && JS_IsArrayObject( cx, JSVAL_TO_OBJECT(v) ) && expectType == VrmlField::MFNODE) { jsuint len; JS_GetArrayLength( cx, JSVAL_TO_OBJECT(v), &len ); VrmlMFNode *f = new VrmlMFNode( (int) len, 0 ); VrmlNode **nodes = f->get(); for (int i=0; i<(int)len; ++i) { jsval elt; JS_GetElement( cx, JSVAL_TO_OBJECT(v), (jsint) i, &elt ); VrmlSFNode *child = 0; if (JSVAL_IS_OBJECT(elt) && &SFNodeClass == JS_GetClass( JSVAL_TO_OBJECT(elt) )) child = (VrmlSFNode *)JS_GetPrivate( cx, JSVAL_TO_OBJECT(elt) ); nodes[i] = child ? child->get()->reference() : 0; } return f; } // MFRotation else if (JSVAL_IS_OBJECT(v) && JS_IsArrayObject( cx, JSVAL_TO_OBJECT(v) ) && expectType == VrmlField::MFROTATION) { jsuint len; JS_GetArrayLength( cx, JSVAL_TO_OBJECT(v), &len ); float *data = new float[ 4*len ]; memset(data, 0, 4*len*sizeof(float)); for (int i=0; i<(int)len; ++i) { jsval elt; JS_GetElement( cx, JSVAL_TO_OBJECT(v), (jsint) i, &elt ); if (JSVAL_IS_OBJECT(elt)) { JSObject *obj = JSVAL_TO_OBJECT(elt); VrmlField *vf = obj ? (VrmlField *)JS_GetPrivate( cx, obj ) : 0; VrmlSFRotation *c = vf ? vf->toSFRotation() : 0; if (c) { data[3*i] = c->get()[0]; data[3*i+1] = c->get()[1]; data[3*i+2] = c->get()[2]; data[3*i+3] = c->get()[3]; } } } VrmlMFRotation *f = new VrmlMFRotation( (int)len, data ); delete [] data; return f; } // MFString else if (JSVAL_IS_OBJECT(v) && JS_IsArrayObject( cx, JSVAL_TO_OBJECT(v) ) && expectType == VrmlField::MFSTRING) { jsuint len; JS_GetArrayLength( cx, JSVAL_TO_OBJECT(v), &len ); char **s = new char*[ len ]; for (int i=0; i<(int)len; ++i) { jsval elt; JS_GetElement( cx, JSVAL_TO_OBJECT(v), (jsint) i, &elt ); JSString *str = 0; if (JSVAL_IS_STRING(elt) && (str = JSVAL_TO_STRING(elt)) != 0) s[i] = JS_GetStringBytes(str); else s[i] = 0; } VrmlMFString *f = new VrmlMFString( (int)len, s ); delete [] s; return f; } // MFVec2f else if (JSVAL_IS_OBJECT(v) && JS_IsArrayObject( cx, JSVAL_TO_OBJECT(v) ) && expectType == VrmlField::MFVEC2F) { jsuint len; JS_GetArrayLength( cx, JSVAL_TO_OBJECT(v), &len ); float *data = new float[ 2*len ]; memset(data, 0, 2*len*sizeof(float)); for (int i=0; i<(int)len; ++i) { jsval elt; JS_GetElement( cx, JSVAL_TO_OBJECT(v), (jsint) i, &elt ); if (JSVAL_IS_OBJECT(elt)) { JSObject *obj = JSVAL_TO_OBJECT(elt); VrmlField *vf = obj ? (VrmlField *)JS_GetPrivate( cx, obj ) : 0; VrmlSFVec2f *c = vf ? vf->toSFVec2f() : 0; if (c) { data[3*i] = c->get()[0]; data[3*i+1] = c->get()[1]; } } } VrmlMFVec2f *f = new VrmlMFVec2f( (int)len, data ); delete [] data; return f; } // MFVec3f else if (JSVAL_IS_OBJECT(v) && JS_IsArrayObject( cx, JSVAL_TO_OBJECT(v) ) && expectType == VrmlField::MFVEC3F) { jsuint len; JS_GetArrayLength( cx, JSVAL_TO_OBJECT(v), &len ); float *data = new float[ 3*len ]; memset(data, 0, 3*len*sizeof(float)); for (int i=0; i<(int)len; ++i) { jsval elt; JS_GetElement( cx, JSVAL_TO_OBJECT(v), (jsint) i, &elt ); if (JSVAL_IS_OBJECT(elt)) { JSObject *obj = JSVAL_TO_OBJECT(elt); VrmlField *vf = obj ? (VrmlField *)JS_GetPrivate( cx, obj ) : 0; VrmlSFVec3f *c = vf ? vf->toSFVec3f() : 0; if (c) { data[3*i] = c->get()[0]; data[3*i+1] = c->get()[1]; data[3*i+2] = c->get()[2]; } } } VrmlMFVec3f *f = new VrmlMFVec3f( (int)len, data ); delete [] data; return f; } else { theSystem->error("jsvalToVrmlField: unhandled type (expected %d)\n", expectType); JSString *str = JS_ValueToString(cx, v); if (str) theSystem->error("%s", JS_GetStringBytes(str)); return 0; } } // Must assign the proper type to eventOuts static JSBool eventOut_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *val) { JSString *str = JS_ValueToString(cx, id); if (! str) return JS_FALSE; const char *eventName = JS_GetStringBytes(str); // The ScriptJS object pointer is stored as a global property value: ScriptJS *script = objToScript( cx, obj ); if (! script) return JS_FALSE; VrmlNodeScript *scriptNode = script->scriptNode(); // Validate the type VrmlField::VrmlFieldType t = scriptNode->hasEventOut( eventName ) ; if (! t) return JS_FALSE; // Convert to a vrmlField and set the eventOut value VrmlField *f = jsvalToVrmlField( cx, *val, t ); if (! f) { theSystem->error("Error: invalid type in assignment to eventOut %s\n", eventName ); return JS_FALSE; } scriptNode->setEventOut( eventName, f ); if (f) delete f; // Don't overwrite the property value. if (JSVAL_IS_OBJECT(*val) && JSVAL_TO_OBJECT(*val) != 0 && ! JS_DefineProperty( cx, JSVAL_TO_OBJECT(*val), "_eventOut", PRIVATE_TO_JSVAL((long int)eventName), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT )) theSystem->error("JS_DefineProp _eventOut failed\n"); return JS_TRUE; } // Define objects corresponding to fields/eventOuts void ScriptJS::defineFields() { VrmlNodeScript::FieldList::iterator i, end = d_node->fields().end(); for (i=d_node->fields().begin(); i!=end; ++i) { jsval val = vrmlFieldToJSVal( (*i)->type, (*i)->value, false ); #if DEBUG if ( (*i)->value ) cout << "field " << (*i)->name << " value " << *((*i)->value) << endl; else cout << "field " << (*i)->name << " \n"; #endif if (! JS_DefineProperty( d_cx, d_globalObj, (*i)->name, val, //getter, setter, ... 0, 0, JSPROP_PERMANENT )) theSystem->error("JS_DefineProp %s failed\n", (*i)->name ); } end = d_node->eventOuts().end(); for (i=d_node->eventOuts().begin(); i!=end; ++i) { jsval val = vrmlFieldToJSVal( (*i)->type, (*i)->value, false ); if (JSVAL_IS_OBJECT(val) && JSVAL_TO_OBJECT(val) != 0 && ! JS_DefineProperty( d_cx, JSVAL_TO_OBJECT(val), "_eventOut", PRIVATE_TO_JSVAL((long int)((*i)->name)), 0, 0, JSPROP_READONLY | JSPROP_PERMANENT )) theSystem->error("JS_DefineProp _eventOut failed\n"); if (! JS_DefineProperty( d_cx, d_globalObj, (*i)->name, val, //getter, setter 0, eventOut_setProperty, JSPROP_PERMANENT )) theSystem->error("JS_DefineProp %s failed\n", (*i)->name ); } } // Global functions static JSBool Print(JSContext *cx, JSObject *, uintN argc, jsval *argv, jsval *) { uintN i; for (i = 0; i < argc; i++) { JSString *str = JS_ValueToString(cx, argv[i]); if (!str) return JS_FALSE; printf("%s%s", i ? " " : "", JS_GetStringBytes(str)); } putchar('\n'); return JS_TRUE; } // Browser functions static JSBool getName(JSContext *cx, JSObject *b, uintN , jsval *, jsval *rval) { jsval p; if (! JS_GetProperty( cx, b, "_script", &p )) return JS_FALSE; ScriptJS *s = (ScriptJS *)JSVAL_TO_PRIVATE(p); if (! s || ! s->browser() ) return JS_FALSE; const char *name = s->browser()->getName(); *rval = STRING_TO_JSVAL(JS_InternString( cx, name )); return JS_TRUE; } static JSBool getVersion(JSContext *cx, JSObject *b, uintN , jsval *, jsval *rval) { jsval p; if (! JS_GetProperty( cx, b, "_script", &p )) return JS_FALSE; ScriptJS *s = (ScriptJS *)JSVAL_TO_PRIVATE(p); if (! s || ! s->browser() ) return JS_FALSE; const char *version = s->browser()->getVersion(); *rval = STRING_TO_JSVAL(JS_InternString( cx, version )); return JS_TRUE; } static JSBool getCurrentSpeed(JSContext *cx, JSObject*, uintN, jsval *, jsval *rval) { *rval = DOUBLE_TO_JSVAL(JS_NewDouble( cx, 0.0 )); //... return JS_TRUE; } static JSBool getCurrentFrameRate(JSContext *cx, JSObject* b, uintN, jsval*, jsval *rval) { jsval p; if (! JS_GetProperty( cx, b, "_script", &p )) return JS_FALSE; ScriptJS *s = (ScriptJS *)JSVAL_TO_PRIVATE(p); if (! s || ! s->browser() ) return JS_FALSE; *rval = DOUBLE_TO_JSVAL(JS_NewDouble( cx, s->browser()->getFrameRate() )); return JS_TRUE; } static JSBool getWorldURL(JSContext *cx, JSObject *b, uintN, jsval *, jsval *rval) { jsval p; if (! JS_GetProperty( cx, b, "_script", &p )) return JS_FALSE; ScriptJS *s = (ScriptJS *)JSVAL_TO_PRIVATE(p); if (! s || ! s->browser() ) return JS_FALSE; const char *url = 0; if (s->browser()->urlDoc()) url = s->browser()->urlDoc()->url(); if (! url) url = ""; *rval = STRING_TO_JSVAL(JS_InternString( cx, url )); return JS_TRUE; } // No events will be processed after loadURL. static JSBool loadURL(JSContext* cx, JSObject* b, uintN argc, jsval *argv, jsval *) { if ((int)argc < 1) return JS_FALSE; jsval p; if (! JS_GetProperty( cx, b, "_script", &p )) return JS_FALSE; ScriptJS *s = (ScriptJS *)JSVAL_TO_PRIVATE(p); if (! s || ! s->browser() ) return JS_FALSE; // Get 2 arguments MFString url, MFString parameters VrmlMFString *url, *parameters = 0; url = (VrmlMFString*) jsvalToVrmlField( cx, argv[0], VrmlField::MFSTRING ); if (! url) return JS_TRUE; // empty URL if ((int)argc > 1) parameters = (VrmlMFString*) jsvalToVrmlField( cx, argv[1], VrmlField::MFSTRING ); s->browser()->queueLoadUrl( url, parameters ); return JS_TRUE; } // This does return, but no events will be processed after it is called. static JSBool replaceWorld(JSContext *cx, JSObject *b, uintN argc, jsval *argv, jsval *) { if ((int)argc < 1) return JS_FALSE; jsval p; if (! JS_GetProperty( cx, b, "_script", &p )) return JS_FALSE; ScriptJS *s = (ScriptJS *)JSVAL_TO_PRIVATE(p); if (! s || ! s->browser() ) return JS_FALSE; // Get 1 argument MFNode nodes VrmlMFNode *nodes = (VrmlMFNode*) jsvalToVrmlField( cx, argv[0], VrmlField::MFNODE ); if (nodes) { VrmlNamespace *ns = new VrmlNamespace(); // should be stored with nodes... s->browser()->queueReplaceNodes( nodes, ns ); } return JS_TRUE; } static JSBool createVrmlFromString(JSContext *cx, JSObject* bobj, uintN argc, jsval *argv, jsval *rval) { JSString *str; if (argc == 1 && JSVAL_IS_STRING(argv[0]) && (str = JSVAL_TO_STRING(argv[0])) != 0) { char *vrmlString = JS_GetStringBytes(str); VrmlNamespace ns; VrmlMFNode *kids; if (! (kids = VrmlScene::readString( vrmlString, &ns )) ) return JS_FALSE; // Put the children from g into an MFNode and return in rval. // should store the namespace as well... int i, n = kids->size(); jsval *jsvec = new jsval[n]; VrmlNode **k = kids->get(); for (i=0; ireference() : 0); jsvec[i] = OBJECT_TO_JSVAL(obj); } *rval = OBJECT_TO_JSVAL(JS_NewArrayObject(cx, (jsint)n, jsvec)); delete [] jsvec; delete kids; return JS_TRUE; } return JS_FALSE; } // createVrmlFromURL( MFString url, SFNode node, SFString event ) static JSBool createVrmlFromURL(JSContext* cx, JSObject* b, uintN argc, jsval *argv, jsval *) { if ((int)argc != 3) return JS_FALSE; Doc *relative = 0; jsval p; ScriptJS *s = 0; // egcs warning if (JS_GetProperty( cx, b, "_script", &p ) && (s = (ScriptJS *)JSVAL_TO_PRIVATE(p)) != 0 && s->browser() != 0) relative = s->browser()->urlDoc(); VrmlMFString *url = 0; VrmlField *f; if (JSVAL_IS_STRING(argv[0])) { JSString *str = JSVAL_TO_STRING(argv[0]); url = new VrmlMFString( JS_GetStringBytes(str) ); } else if ((f = jsvalToVrmlField( cx, argv[0], VrmlField::MFSTRING )) != 0) { url = f->toMFString(); } if (url) { VrmlSFNode *node = 0; // egcs warning JSString *str = 0; // egcs warning f = jsvalToVrmlField( cx, argv[1], VrmlField::SFNODE ); if ( f != 0 && (node = f->toSFNode()) != 0 && JSVAL_IS_STRING(argv[2]) && (str = JSVAL_TO_STRING(argv[2])) != 0) { char *event = JS_GetStringBytes(str); VrmlNamespace ns; // this is a problem... VrmlMFNode *kids = VrmlScene::readWrl( url, relative, &ns ); VrmlNode *nn = node->get(); if (nn) nn->eventIn( s_timeStamp, // fix me... event, kids ); delete node; delete kids; delete url; return JS_TRUE; } delete url; delete f; } return JS_FALSE; } // addRoute(SFNode fromNode, String fromEventOut, SFNode toNode, String toEvent) static JSBool addRoute(JSContext* cx, JSObject*, uintN argc, jsval *argv, jsval *) { if ((int)argc != 4 || ! JSVAL_IS_STRING(argv[1]) || ! JSVAL_IS_STRING(argv[3])) return JS_FALSE; JSString *str = JS_ValueToString(cx, argv[1]); if (! str) return JS_FALSE; char *eventOut = JS_GetStringBytes( str ); str = JS_ValueToString(cx, argv[3]); if (! str) return JS_FALSE; char *eventIn = JS_GetStringBytes( str ); if (! eventOut || ! eventIn) return JS_FALSE; VrmlField *f = jsvalToVrmlField( cx, argv[0], VrmlField::SFNODE ); VrmlSFNode *from = f ? f->toSFNode() : 0; f = jsvalToVrmlField( cx, argv[2], VrmlField::SFNODE ); VrmlSFNode *to = f ? f->toSFNode() : 0; if (! to || !to->get() || !from || !from->get()) return JS_FALSE; theSystem->debug("addRoute(%s::%s::%s, %s::%s::%s)\n", from->get()->nodeType()->getName(), from->get()->name(), eventOut, to->get()->nodeType()->getName(), to->get()->name(), eventIn); (from->get())->addRoute( eventOut, to->get(), eventIn ); return JS_TRUE; } // deleteRoute(SFNode fromNode, String fromEventOut, SFNode toNode, String toEvent) static JSBool deleteRoute(JSContext* cx, JSObject*, uintN argc, jsval *argv, jsval *) { if ((int)argc != 4 || ! JSVAL_IS_STRING(argv[1]) || ! JSVAL_IS_STRING(argv[3])) return JS_FALSE; JSString *str = JS_ValueToString(cx, argv[1]); if (! str) return JS_FALSE; char *eventOut = JS_GetStringBytes( str ); str = JS_ValueToString(cx, argv[3]); if (! str) return JS_FALSE; char *eventIn = JS_GetStringBytes( str ); if (! eventOut || ! eventIn) return JS_FALSE; VrmlField *f = jsvalToVrmlField( cx, argv[0], VrmlField::SFNODE ); VrmlSFNode *from = f ? f->toSFNode() : 0; f = jsvalToVrmlField( cx, argv[2], VrmlField::SFNODE ); VrmlSFNode *to = f ? f->toSFNode() : 0; if (! to || !to->get() || !from || !from->get()) return JS_FALSE; (from->get())->deleteRoute( eventOut, to->get(), eventIn ); return JS_TRUE; } static JSBool setDescription(JSContext *cx, JSObject*, uintN argc, jsval *argv, jsval *) { if (argc < 1) return JS_FALSE; JSString *str = JS_ValueToString(cx, argv[0]); if (!str) return JS_FALSE; theSystem->inform("%s", JS_GetStringBytes(str)); return JS_TRUE; } // static void ErrorReporter(JSContext *, const char *message, JSErrorReport *report) { int i, j, k, n; theSystem->error("javascript: "); if (!report) { theSystem->error("%s\n", message); return; } if (report->filename) theSystem->error("%s, ", report->filename); if (report->lineno) theSystem->error("line %u: ", report->lineno); theSystem->error(message); if (!report->linebuf) { theSystem->error("\n"); return; } theSystem->error(":\n%s\n", report->linebuf); n = report->tokenptr - report->linebuf; for (i = j = 0; i < n; i++) { if (report->linebuf[i] == '\t') { for (k = (j + 8) & ~7; j < k; j++) theSystem->error("."); continue; } theSystem->error("."); j++; } theSystem->error("\n"); } #endif // HAVE_JAVASCRIPT