This file is part of MXE. See LICENSE.md for licensing information. Contains ad hoc patches for cross building. From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Tony Theodore Date: Sat, 18 Nov 2017 20:43:52 +1100 Subject: [PATCH 1/2] fixes This patch has been taken from: https://bitbucket.org/msys2/coin/commits/69e9990b05cee506f5fa16c6edad02a7808bc610/raw/ It was modified to work with Coin 3.1.3. (The order of the template arguments of SbHash was switched.) diff --git a/include/Inventor/C/glue/spidermonkey.h b/include/Inventor/C/glue/spidermonkey.h index 1111111..2222222 100644 --- a/include/Inventor/C/glue/spidermonkey.h +++ b/include/Inventor/C/glue/spidermonkey.h @@ -47,7 +47,7 @@ extern "C" { Structs and defines. */ typedef int JSBool; -typedef long jsword; +typedef intmax_t jsword; typedef jsword jsval; typedef jsword jsid; typedef int intN; diff --git a/include/Inventor/C/glue/spidermonkey.h.orig b/include/Inventor/C/glue/spidermonkey.h.orig new file mode 100644 index 1111111..2222222 --- /dev/null +++ b/include/Inventor/C/glue/spidermonkey.h.orig @@ -0,0 +1,470 @@ +#ifndef COIN_GLUE_SPIDERMONKEY_H +#define COIN_GLUE_SPIDERMONKEY_H + +/**************************************************************************\ + * + * This file is part of the Coin 3D visualization library. + * Copyright (C) by Kongsberg Oil & Gas Technologies. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * ("GPL") version 2 as published by the Free Software Foundation. + * See the file LICENSE.GPL at the root directory of this source + * distribution for additional information about the GNU GPL. + * + * For using Coin with software that can not be combined with the GNU + * GPL, and for taking advantage of the additional benefits of our + * support services, please contact Kongsberg Oil & Gas Technologies + * about acquiring a Coin Professional Edition License. + * + * See http://www.coin3d.org/ for more information. + * + * Kongsberg Oil & Gas Technologies, Bygdoy Alle 5, 0257 Oslo, NORWAY. + * http://www.sim.no/ sales@sim.no coin-support@coin3d.org + * +\**************************************************************************/ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#if 0 /* to get proper auto-indentation in emacs */ +} +#endif /* emacs indentation */ + + +/* + This is used to detect whether the 'jsapi.h' was included by the + user or not. The JSVERSION_IS_ECMA is defined in the 'jspubtd.h' + file in the SpiderMonkey header directory. +*/ +#ifndef JSVERSION_IS_ECMA + + +/* + Structs and defines. +*/ +typedef int JSBool; +typedef long jsword; +typedef jsword jsval; +typedef jsword jsid; +typedef int intN; +typedef unsigned int uintN; +typedef uint16_t jschar; + +typedef int32_t jsrefcount; +typedef uint8_t jsbytecode; +typedef uint32_t JSHashNumber; +typedef uint32_t jsatomid; + +typedef enum JSType { + JSTYPE_VOID, + JSTYPE_OBJECT, + JSTYPE_FUNCTION, + JSTYPE_STRING, + JSTYPE_NUMBER, + JSTYPE_BOOLEAN, + JSTYPE_LIMIT +} JSType; + +typedef enum JSAccessMode { + JSACC_PROTO = 0, + JSACC_PARENT = 1, + JSACC_IMPORT = 2, + JSACC_WATCH = 3, + JSACC_READ = 4, + JSACC_WRITE = 8, + JSACC_LIMIT +} JSAccessMode; + +typedef enum JSGCStatus { + JSGC_BEGIN, + JSGC_END, + JSGC_MARK_END, + JSGC_FINALIZE_END +} JSGCStatus; + +struct JSIdArray { + int32_t length; + jsid vector[1]; +}; + +typedef void JSRuntime; +typedef void JSContext; +typedef void JSObject; +typedef void JSObjectOps; +typedef void JSXDRState; +typedef void JSString; +typedef struct JSClass JSClass; +typedef struct JSPropertySpec JSPropertySpec; +typedef int JSVersion; +typedef void JSFunction; +typedef struct JSFunctionSpec JSFunctionSpec; +typedef struct JSErrorReport JSErrorReport; +typedef void JSScript; + +#define JS_DLL_CALLBACK /* FIXME: set up this define properly. 20050601 mortene. */ + +typedef JSBool (* JS_DLL_CALLBACK JSPropertyOp)(JSContext *, JSObject *, jsval, jsval *); +typedef JSBool (* JS_DLL_CALLBACK JSEnumerateOp)(JSContext *, JSObject *); +typedef JSBool (* JS_DLL_CALLBACK JSResolveOp)(JSContext *, JSObject *, jsval); +typedef JSBool (* JS_DLL_CALLBACK JSConvertOp)(JSContext *, JSObject *, JSType, jsval *); +typedef void (* JS_DLL_CALLBACK JSFinalizeOp)(JSContext *, JSObject *); +typedef JSObjectOps * (* JS_DLL_CALLBACK JSGetObjectOps)(JSContext *, JSClass *); +typedef JSBool (* JS_DLL_CALLBACK JSCheckAccessOp)(JSContext *, JSObject *, jsval, JSAccessMode, jsval *); +typedef JSBool (* JS_DLL_CALLBACK JSNative)(JSContext *, JSObject *, uintN, jsval *, jsval *); +typedef JSBool (* JS_DLL_CALLBACK JSXDRObjectOp)(JSXDRState *, JSObject **); +typedef JSBool (* JS_DLL_CALLBACK JSHasInstanceOp)(JSContext *, JSObject *, jsval, JSBool *); +typedef uint32_t (* JS_DLL_CALLBACK JSMarkOp)(JSContext *, JSObject *, void *); + +struct JSClass { + const char * name; + uint32_t flags; + JSPropertyOp addProperty; + JSPropertyOp delProperty; + JSPropertyOp getProperty; + JSPropertyOp setProperty; + JSEnumerateOp enumerate; + JSResolveOp resolve; + JSConvertOp convert; + JSFinalizeOp finalize; + JSGetObjectOps getObjectOps; + JSCheckAccessOp checkAccess; + JSNative call; + JSNative construct; + JSXDRObjectOp xdrObject; + JSHasInstanceOp hasInstance; + JSMarkOp mark; + jsword spare; +}; + +struct JSPropertySpec { + const char * name; + int8_t tinyid; + uint8_t flags; + JSPropertyOp getter; + JSPropertyOp setter; +}; + +struct JSFunctionSpec { + const char *name; + JSNative call; + uint8_t nargs; + uint8_t flags; + uint16_t extra; +}; + +struct JSErrorReport { + const char * filename; + uintN lineno; + const char * linebuf; + const char * tokenptr; + const jschar * uclinebuf; + const jschar * uctokenptr; + uintN flags; + uintN errorNumber; + const jschar * ucmessage; + const jschar ** messageArgs; +}; + + +/* Defines and macros. ************************************************** */ + +#define JSVAL_OBJECT 0x0 +#define JSVAL_INT 0x1 +#define JSVAL_DOUBLE 0x2 +#define JSVAL_STRING 0x4 +#define JSVAL_BOOLEAN 0x6 + +#define JS_BIT(n) ((uint32_t)1 << (n)) +#define JS_BITMASK(n) (JS_BIT(n) - 1) + +#define JSVAL_TAGBITS 3 +#define JSVAL_TAGMASK JS_BITMASK(JSVAL_TAGBITS) +#define JSVAL_TAG(v) ((v) & JSVAL_TAGMASK) +#define JSVAL_SETTAG(v,t) ((v) | (t)) +#define JSVAL_CLRTAG(v) ((v) & ~(jsval)JSVAL_TAGMASK) + +#define JSVAL_IS_PRIMITIVE(v) (!JSVAL_IS_OBJECT(v) || JSVAL_IS_NULL(v)) +#define JSVAL_IS_OBJECT(v) (JSVAL_TAG(v) == JSVAL_OBJECT) +#define JSVAL_IS_NUMBER(v) (JSVAL_IS_INT(v) || JSVAL_IS_DOUBLE(v)) +#define JSVAL_IS_INT(v) (((v) & JSVAL_INT) && (v) != JSVAL_VOID) +#define JSVAL_IS_DOUBLE(v) (JSVAL_TAG(v) == JSVAL_DOUBLE) +#define JSVAL_IS_STRING(v) (JSVAL_TAG(v) == JSVAL_STRING) +#define JSVAL_IS_BOOLEAN(v) (JSVAL_TAG(v) == JSVAL_BOOLEAN) +#define JSVAL_IS_NULL(v) ((v) == JSVAL_NULL) +#define JSVAL_IS_VOID(v) ((v) == JSVAL_VOID) + +#define BOOLEAN_TO_JSVAL(b) JSVAL_SETTAG((jsval)(b) << JSVAL_TAGBITS, JSVAL_BOOLEAN) +#define JSVAL_TO_BOOLEAN(v) ((JSBool)((v) >> JSVAL_TAGBITS)) + +#define JSVAL_INT_BITS 31 +#define JSVAL_INT_POW2(n) ((jsval)1 << (n)) +#define JSVAL_INT_MIN ((jsval)1 - JSVAL_INT_POW2(30)) +#define JSVAL_INT_MAX (JSVAL_INT_POW2(30) - 1) +#define INT_FITS_IN_JSVAL(i) ((uint32_t)((i)+JSVAL_INT_MAX) <= 2*JSVAL_INT_MAX) +#define JSVAL_TO_INT(v) ((int32_t)(v) >> 1) +#define INT_TO_JSVAL(i) (((jsval)(i) << 1) | JSVAL_INT) + +#define JSVAL_TO_GCTHING(v) ((void *)JSVAL_CLRTAG(v)) +#define JSVAL_TO_OBJECT(v) ((JSObject *)JSVAL_TO_GCTHING(v)) +#define JSVAL_TO_DOUBLE(v) ((double *)JSVAL_TO_GCTHING(v)) +#define JSVAL_TO_STRING(v) ((JSString *)JSVAL_TO_GCTHING(v)) +#define OBJECT_TO_JSVAL(obj) ((jsval)(obj)) +#define DOUBLE_TO_JSVAL(dp) JSVAL_SETTAG((jsval)(dp), JSVAL_DOUBLE) +#define STRING_TO_JSVAL(str) JSVAL_SETTAG((jsval)(str), JSVAL_STRING) +#define JSVAL_TO_PRIVATE(v) ((void *)((v) & ~JSVAL_INT)) +#define PRIVATE_TO_JSVAL(p) ((jsval)(p) | JSVAL_INT) + +#define JSPROP_ENUMERATE 0x01 +#define JSPROP_READONLY 0x02 +#define JSPROP_PERMANENT 0x04 +#define JSPROP_EXPORTED 0x08 +#define JSPROP_GETTER 0x10 +#define JSPROP_SETTER 0x20 +#define JSPROP_SHARED 0x40 +#define JSPROP_INDEX 0x80 + +#define JS_FALSE (int)0 +#define JS_TRUE (int)1 + +#define JSVAL_VOID INT_TO_JSVAL(0 - JSVAL_INT_POW2(30)) +#define JSVAL_NULL OBJECT_TO_JSVAL(0) +#define JSVAL_ZERO INT_TO_JSVAL(0) +#define JSVAL_ONE INT_TO_JSVAL(1) +#define JSVAL_FALSE BOOLEAN_TO_JSVAL(JS_FALSE) +#define JSVAL_TRUE BOOLEAN_TO_JSVAL(JS_TRUE) + +#define JSCLASS_HAS_PRIVATE (1<<0) +#define JSCLASS_NEW_ENUMERATE (1<<1) +#define JSCLASS_NEW_RESOLVE (1<<2) +#define JSCLASS_PRIVATE_IS_NSISUPPORTS (1<<3) +#define JSCLASS_SHARE_ALL_PROPERTIES (1<<4) +#define JSCLASS_NEW_RESOLVE_GETS_START (1<<5) + +#define JSFUN_BOUND_METHOD 0x40 + +#define JSOPTION_STRICT JS_BIT(0) +#define JSOPTION_WERROR JS_BIT(1) +#define JSOPTION_VAROBJFIX JS_BIT(2) +#define JSOPTION_PRIVATE_IS_NSISUPPORTS JS_BIT(3) +#define JSOPTION_COMPILE_N_GO JS_BIT(4) + + +/* Function typedefs. *************************************************** */ + +typedef void (* JS_DLL_CALLBACK JSErrorReporter)(JSContext *, const char *, JSErrorReport *); +typedef JSBool (* JS_DLL_CALLBACK JSGCCallback)(JSContext *, JSGCStatus); + +#endif /* !JSVERSION_IS_ECMA */ + +typedef JSBool (* JS_EvaluateScript_t)(JSContext *, JSObject *, const char *, uintN, const char *, uintN, jsval *); +typedef JSString * (* JS_ValueToString_t)(JSContext *, jsval); +typedef char * (* JS_GetStringBytes_t)(JSString *); +typedef JSBool (* JS_SetProperty_t)(JSContext *, JSObject *, const char *, jsval *); +typedef JSBool (* JS_GetProperty_t)(JSContext *, JSObject *, const char *, jsval *); +typedef JSBool (* JS_CallFunctionName_t)(JSContext *, JSObject *, const char *, uintN, jsval *, jsval *); +typedef JSBool (* JS_CallFunctionValue_t)(JSContext *, JSObject *, jsval, uintN, jsval *, jsval *); +typedef JSObject * (* JS_ConstructObjectWithArguments_t)(JSContext *, JSClass *, JSObject *, JSObject *, uintN, jsval *); +typedef JSRuntime * (* JS_NewRuntime_t)(uint32_t); +typedef void (* JS_DestroyRuntime_t)(JSRuntime *); +typedef JSContext * (* JS_NewContext_t)(JSRuntime *, size_t); +typedef void (* JS_DestroyContext_t)(JSContext *); +typedef void (* JS_ShutDown_t)(void); +typedef JSObject * (* JS_NewObject_t)(JSContext *, JSClass *, JSObject *, JSObject *); +typedef JSBool (* JS_InitStandardClasses_t)(JSContext *, JSObject *); +typedef JSErrorReporter (* JS_SetErrorReporter_t)(JSContext *, JSErrorReporter); +typedef JSBool (* JS_PropertyStub_t)(JSContext *, JSObject *, jsval, jsval *); +typedef JSBool (* JS_EnumerateStub_t)(JSContext *, JSObject *); +typedef JSBool (* JS_ResolveStub_t)(JSContext *, JSObject *, jsval); +typedef JSBool (* JS_ConvertStub_t)(JSContext *, JSObject *, JSType, jsval *); +typedef void (* JS_FinalizeStub_t)(JSContext *, JSObject *); +typedef const char * (* JS_GetImplementationVersion_t)(void); +typedef void * (* JS_GetPrivate_t)(JSContext *, JSObject *); +typedef JSBool (* JS_SetPrivate_t)(JSContext *, JSObject *, void *); +typedef JSFunction * (* JS_NewFunction_t)(JSContext *, JSNative, uintN, uintN flags, JSObject *, const char *); +typedef JSObject * (* JS_GetFunctionObject_t)(JSFunction *); +typedef JSObject * (* JS_DefineObject_t)(JSContext *, JSObject *, const char *, JSClass *, JSObject *, uintN); +typedef JSBool (* JS_DefineProperties_t)(JSContext *, JSObject *, JSPropertySpec *); +typedef JSObject * (* JS_GetParent_t)(JSContext *, JSObject *); +typedef JSBool (* JS_SetParent_t)(JSContext *, JSObject *, JSObject *); +typedef JSBool (* JS_DefineFunctions_t)(JSContext *, JSObject *, JSFunctionSpec *); +typedef JSString * (* JS_NewStringCopyZ_t)(JSContext *, const char *); +typedef JSType (* JS_TypeOfValue_t)(JSContext *, jsval); +typedef const char * (* JS_GetTypeName_t)(JSContext *, JSType); +typedef JSBool (* JS_InstanceOf_t)(JSContext *, JSObject *, JSClass *, jsval *); +typedef JSObject * (* JS_InitClass_t)(JSContext *, JSObject *, JSObject *, JSClass *, + JSNative, uintN, JSPropertySpec *, JSFunctionSpec *, + JSPropertySpec *, JSFunctionSpec *); +typedef JSBool (* JS_NewDoubleValue_t)(JSContext *, double, jsval *); +typedef void * (* JS_GetContextPrivate_t)(JSContext *); +typedef void (* JS_SetContextPrivate_t)(JSContext *, void *); +typedef JSBool (* JS_ValueToBoolean_t)(JSContext *, jsval, JSBool *); +typedef JSBool (* JS_ValueToNumber_t)(JSContext *, jsval, double *); +typedef JSObject * (* JS_NewArrayObject_t)(JSContext *, int32_t, jsval *); +typedef JSBool (* JS_GetArrayLength_t)(JSContext *, JSObject *, uint32_t *); +typedef JSBool (* JS_SetArrayLength_t)(JSContext *, JSObject *, uint32_t); +typedef JSBool (* JS_HasArrayLength_t)(JSContext *, JSObject *, uint32_t *); +typedef JSBool (* JS_GetElement_t)(JSContext *, JSObject *, int32_t, jsval *); +typedef JSBool (* JS_SetElement_t)(JSContext *, JSObject *, int32_t, jsval *); +typedef JSBool (* JS_AddRoot_t)(JSContext *, void *); +typedef JSBool (* JS_RemoveRoot_t)(JSContext *, void *); +typedef size_t (* JS_GetStringLength_t)(JSString *); +typedef JSBool (* JS_LookupProperty_t)(JSContext *, JSObject *, const char *, jsval *); +typedef JSBool (* JS_DefineProperty_t)(JSContext *, JSObject *, const char *, jsval, JSPropertyOp, JSPropertyOp, uintN); +typedef JSScript * (* JS_CompileFile_t)(JSContext *, JSObject *, const char *); +typedef JSBool (* JS_ValueToObject_t)(JSContext *, jsval, JSObject **); +typedef JSBool (* JS_ExecuteScript_t)(JSContext *, JSObject *, JSScript *, jsval *); +typedef JSBool (* JS_IsExceptionPending_t)(JSContext *); +typedef JSBool (* JS_GetPendingException_t)(JSContext *, jsval *); +typedef void (* JS_SetPendingException_t)(JSContext *, jsval); +typedef void (* JS_ClearPendingException_t)(JSContext *); +typedef double * (* JS_NewDouble_t)(JSContext *, double); +typedef JSBool (* JS_CallFunction_t)(JSContext *, JSObject *, JSFunction *, uintN, jsval *, jsval *); +typedef JSFunction * (* JS_ValueToFunction_t)(JSContext *, jsval); +typedef void (* JS_ReportError_t)(JSContext *, const char *, ...); +typedef JSBool (* JS_IsArrayObject_t)(JSContext *, JSObject *); +typedef JSBool (* JS_ObjectIsFunction_t)(JSContext *, JSObject *); +typedef JSBool (* JS_ValueToECMAInt32_t)(JSContext *, jsval, int32_t *); +typedef JSFunction * (* JS_DefineFunction_t)(JSContext *, JSObject *, const char *, JSNative, uintN, uintN); +typedef JSObject * (* JS_GetGlobalObject_t)(JSContext *); +typedef JSGCCallback (* JS_SetGCCallback_t)(JSContext *, JSGCCallback); +typedef void (* JS_GC_t)(JSContext *); +typedef void (* JS_MaybeGC_t)(JSContext *); +typedef JSBool (* JS_IsRunning_t)(JSContext *); +typedef JSBool (* JS_DeleteProperty_t)(JSContext *, JSObject *, const char *); +typedef JSScript * (* JS_CompileScript_t)(JSContext *, JSObject *, + const char *, size_t, + const char *, uintN); +typedef jsval (* JS_GetNaNValue_t)(JSContext *); +typedef jsval (* JS_GetNegativeInfinityValue_t)(JSContext *); +typedef jsval (* JS_GetPositiveInfinityValue_t)(JSContext *); +typedef jsval (* JS_GetEmptyStringValue_t)(JSContext *); +typedef JSBool (* JS_SetPropertyAttributes_t)(JSContext *, JSObject *, const char *, uintN, JSBool *); +typedef JSBool (* JS_GetPropertyAttributes_t)(JSContext *, JSObject *, const char *, uintN *, JSBool *); +typedef JSClass * (* JS_GetClass_t)(JSObject *); +typedef JSObject * (* JS_GetPrototype_t)(JSContext *, JSObject *); +typedef JSObject * (* JS_SetPrototype_t)(JSContext *, JSObject *, JSObject *); +typedef intN (* JS_CompareStrings_t)(JSString *, JSString *); +typedef uint32_t (* JS_GetOptions_t)(JSContext *); +typedef uint32_t (* JS_SetOptions_t)(JSContext *, uint32_t); +typedef uint32_t (* JS_ToggleOptions_t)(JSContext *, uint32_t); +typedef struct JSIdArray * (* JS_Enumerate_t)(JSContext *, JSObject *); +typedef JSBool (* JS_IdToValue_t)(JSContext *, jsid, jsval *); +typedef const char * (* JS_GetFunctionName_t)(JSFunction *); +typedef JSObject * (* JS_GetConstructor_t)(JSContext *, JSObject *); +typedef void (* JS_DestroyIdArray_t)(JSContext *, struct JSIdArray *); + + +/* Access interface. **************************************************** */ + +typedef struct { + int available; + + JS_CallFunctionName_t JS_CallFunctionName; + JS_CallFunctionValue_t JS_CallFunctionValue; + JS_ConstructObjectWithArguments_t JS_ConstructObjectWithArguments; + JS_ConvertStub_t JS_ConvertStub; + JS_DestroyContext_t JS_DestroyContext; + JS_DestroyRuntime_t JS_DestroyRuntime; + JS_EnumerateStub_t JS_EnumerateStub; + JS_EvaluateScript_t JS_EvaluateScript; + JS_FinalizeStub_t JS_FinalizeStub; + JS_GetClass_t JS_GetClass; + JS_GetImplementationVersion_t JS_GetImplementationVersion; + JS_GetProperty_t JS_GetProperty; + JS_GetStringBytes_t JS_GetStringBytes; + JS_InitStandardClasses_t JS_InitStandardClasses; + JS_NewContext_t JS_NewContext; + JS_NewObject_t JS_NewObject; + JS_NewRuntime_t JS_NewRuntime; + JS_PropertyStub_t JS_PropertyStub; + JS_ResolveStub_t JS_ResolveStub; + JS_SetErrorReporter_t JS_SetErrorReporter; + JS_SetProperty_t JS_SetProperty; + JS_ShutDown_t JS_ShutDown; + JS_ValueToString_t JS_ValueToString; + JS_DefineObject_t JS_DefineObject; + JS_DefineProperties_t JS_DefineProperties; + JS_GetPrivate_t JS_GetPrivate; + JS_SetPrivate_t JS_SetPrivate; + JS_NewFunction_t JS_NewFunction; + JS_GetFunctionObject_t JS_GetFunctionObject; + JS_GetParent_t JS_GetParent; + JS_SetParent_t JS_SetParent; + JS_DefineFunctions_t JS_DefineFunctions; + JS_NewStringCopyZ_t JS_NewStringCopyZ; + JS_TypeOfValue_t JS_TypeOfValue; + JS_GetTypeName_t JS_GetTypeName; + JS_InstanceOf_t JS_InstanceOf; + JS_InitClass_t JS_InitClass; + JS_NewDoubleValue_t JS_NewDoubleValue; + JS_GetContextPrivate_t JS_GetContextPrivate; + JS_SetContextPrivate_t JS_SetContextPrivate; + JS_ValueToBoolean_t JS_ValueToBoolean; + JS_ValueToNumber_t JS_ValueToNumber; + JS_NewArrayObject_t JS_NewArrayObject; + JS_GetArrayLength_t JS_GetArrayLength; + JS_SetArrayLength_t JS_SetArrayLength; + JS_HasArrayLength_t JS_HasArrayLength; + JS_GetElement_t JS_GetElement; + JS_SetElement_t JS_SetElement; + JS_AddRoot_t JS_AddRoot; + JS_RemoveRoot_t JS_RemoveRoot; + JS_GetStringLength_t JS_GetStringLength; + JS_LookupProperty_t JS_LookupProperty; + JS_DefineProperty_t JS_DefineProperty; + JS_CompileFile_t JS_CompileFile; + JS_ValueToObject_t JS_ValueToObject; + JS_ExecuteScript_t JS_ExecuteScript; + JS_IsExceptionPending_t JS_IsExceptionPending; + JS_GetPendingException_t JS_GetPendingException; + JS_SetPendingException_t JS_SetPendingException; + JS_ClearPendingException_t JS_ClearPendingException; + JS_NewDouble_t JS_NewDouble; + JS_CallFunction_t JS_CallFunction; + JS_ValueToFunction_t JS_ValueToFunction; + JS_ReportError_t JS_ReportError; + JS_IsArrayObject_t JS_IsArrayObject; + JS_ObjectIsFunction_t JS_ObjectIsFunction; + // Note: We use this function instead of JS_ValueToInt32() since the + // latter is buggy in versions of SpiderMonkey older than 2005-09-29, + // see Mozilla bug #284032. + JS_ValueToECMAInt32_t JS_ValueToECMAInt32; + JS_DefineFunction_t JS_DefineFunction; + JS_GetGlobalObject_t JS_GetGlobalObject; + JS_SetGCCallback_t JS_SetGCCallback; + JS_GC_t JS_GC; + JS_MaybeGC_t JS_MaybeGC; + JS_IsRunning_t JS_IsRunning; + JS_DeleteProperty_t JS_DeleteProperty; + JS_CompileScript_t JS_CompileScript; + JS_GetNaNValue_t JS_GetNaNValue; + JS_GetNegativeInfinityValue_t JS_GetNegativeInfinityValue; + JS_GetPositiveInfinityValue_t JS_GetPositiveInfinityValue; + JS_GetEmptyStringValue_t JS_GetEmptyStringValue; + JS_SetPropertyAttributes_t JS_SetPropertyAttributes; + JS_GetPropertyAttributes_t JS_GetPropertyAttributes; + JS_GetPrototype_t JS_GetPrototype; + JS_SetPrototype_t JS_SetPrototype; + JS_CompareStrings_t JS_CompareStrings; + JS_GetOptions_t JS_GetOptions; + JS_SetOptions_t JS_SetOptions; + JS_ToggleOptions_t JS_ToggleOptions; + JS_Enumerate_t JS_Enumerate; + JS_IdToValue_t JS_IdToValue; + JS_GetFunctionName_t JS_GetFunctionName; + JS_GetConstructor_t JS_GetConstructor; + JS_DestroyIdArray_t JS_DestroyIdArray; + +} SpiderMonkey_t; + +COIN_DLL_API const SpiderMonkey_t * spidermonkey(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !COIN_GLUE_SPIDERMONKEY_H */ diff --git a/src/foreignfiles/SoSTLFileKit.cpp b/src/foreignfiles/SoSTLFileKit.cpp index 1111111..2222222 100644 --- a/src/foreignfiles/SoSTLFileKit.cpp +++ b/src/foreignfiles/SoSTLFileKit.cpp @@ -594,14 +594,14 @@ SoSTLFileKit::addFacet(const SbVec3f & v1, const SbVec3f & v2, const SbVec3f & v SO_GET_ANY_PART(this, "facets", SoIndexedFaceSet); // find existing indexes if any - long v1idx = PRIVATE(this)->points->findPoint(v1), v1new = (v1idx == -1); - long v2idx = PRIVATE(this)->points->findPoint(v2), v2new = (v2idx == -1); - long v3idx = PRIVATE(this)->points->findPoint(v3), v3new = (v3idx == -1); - if (!v1new) { v1idx = (long) PRIVATE(this)->points->getUserData(v1idx); } - if (!v2new) { v2idx = (long) PRIVATE(this)->points->getUserData(v2idx); } - if (!v3new) { v3idx = (long) PRIVATE(this)->points->getUserData(v3idx); } - long nidx = PRIVATE(this)->normals->findPoint(n); - if (nidx != -1) { nidx = (long) PRIVATE(this)->normals->getUserData(nidx); } + intmax_t v1idx = PRIVATE(this)->points->findPoint(v1), v1new = (v1idx == -1); + intmax_t v2idx = PRIVATE(this)->points->findPoint(v2), v2new = (v2idx == -1); + intmax_t v3idx = PRIVATE(this)->points->findPoint(v3), v3new = (v3idx == -1); + if (!v1new) { v1idx = (intmax_t) PRIVATE(this)->points->getUserData(v1idx); } + if (!v2new) { v2idx = (intmax_t) PRIVATE(this)->points->getUserData(v2idx); } + if (!v3new) { v3idx = (intmax_t) PRIVATE(this)->points->getUserData(v3idx); } + intmax_t nidx = PRIVATE(this)->normals->findPoint(n); + if (nidx != -1) { nidx = (intmax_t) PRIVATE(this)->normals->getUserData(nidx); } // toss out invalid facets - facets where two or more points are in // the same location. what are these - are they lines and points or diff --git a/src/foreignfiles/SoSTLFileKit.cpp.orig b/src/foreignfiles/SoSTLFileKit.cpp.orig new file mode 100644 index 1111111..2222222 --- /dev/null +++ b/src/foreignfiles/SoSTLFileKit.cpp.orig @@ -0,0 +1,799 @@ +/**************************************************************************\ + * + * This file is part of the Coin 3D visualization library. + * Copyright (C) by Kongsberg Oil & Gas Technologies. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * ("GPL") version 2 as published by the Free Software Foundation. + * See the file LICENSE.GPL at the root directory of this source + * distribution for additional information about the GNU GPL. + * + * For using Coin with software that can not be combined with the GNU + * GPL, and for taking advantage of the additional benefits of our + * support services, please contact Kongsberg Oil & Gas Technologies + * about acquiring a Coin Professional Edition License. + * + * See http://www.coin3d.org/ for more information. + * + * Kongsberg Oil & Gas Technologies, Bygdoy Alle 5, 0257 Oslo, NORWAY. + * http://www.sim.no/ sales@sim.no coin-support@coin3d.org + * +\**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif // HAVE_CONFIG_H + +#ifdef HAVE_NODEKITS + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "steel.h" +#include "nodekits/SoSubKitP.h" + + +#if 0 + SoCallback "callbackList" SoBaseKit + SoSeparator "topSeparator" SoForeignFileKit + SoShapeHints "shapehints" SoSTLFileKit + SoTexture2 "texture" SoSTLFileKit + SoNormalBinding "normalbinding" SoSTLFileKit + SoNormal "normals" SoSTLFileKit + SoMaterialBinding "materialbinding" SoSTLFileKit + SoMaterial "material" SoSTLFileKit + SoCoordinate3 "coordinates" SoSTLFileKit + SoIndexedFaceSet "facets" SoSTLFileKit +#endif // 0 + +class SoSTLFileKitP { +public: + SoSTLFileKitP(SoSTLFileKit * pub) + : api(pub) { + this->data = new SbList; + this->points = new SbBSPTree; + this->normals = new SbBSPTree; + } + ~SoSTLFileKitP(void) { + delete this->data; + delete this->points; + delete this->normals; + } + +public: + SoSTLFileKit * const api; + + SbList * data; + SbBSPTree * points; + SbBSPTree * normals; + + int numfacets; + int numvertices; + int numnormals; + int numsharedvertices; + int numsharednormals; + int numredundantfacets; +}; // SoSTLFileKitP + +// ************************************************************************* + +/*! + \class SoSTLFileKit SoSTLFileKit.h ForeignFiles/SoSTLFileKit.h + \brief SoSTLFileKit is a class for using STL files with Coin. + + Class for using STL files with Coin. You can use it to read and + write STL files, and convert back and forth between Open Inventor + scene graphs and SoSTLFileKits. + + STL files are 3D models intended for 3D printers, and is a format + supported by a wide variety of computer-aided design programs. STL + models are, because of their intended purpose, always + representations of solid objects. STL is short for + Stereolithography, the process used for 3D printing. + + Ordinary STL models do not contain color information. There are, + however, two extensions to the binary file format for specifying + color. Currently neither extension is supported. This is caused by + lack of sample models using the extensions and will be added as soon + as such models are found. We have the specs on the extensions, and + it should be pretty straight-forwards to implement, but we want to + get it right at once since we have write support (we don't want to + inadvertently create a third color extension ;). + + When writing STL files, certain STL model criterias are not enforced + by SoSTLFileKit. These are: + + - STL models should represent complete solids - it is the user's + responsibility to give models of solid data to readScene(), and + not readScene()'s responsibility to check the incoming data. + + - STL models should have all triangles in counterclockwise order. + This is not enforced either. + + - STL models should reside in the positive octant of the coordinate + space. This is also the user's responsibility to ensure, although + adding functionality for translating the model should be easy, so + it might get implemented. + + Since the color extensions are not supported yet, color information + is not collected either when converting Open Inventor scene graphs to + SoSTLFileKits. + + \relates foreignfileformats + \COIN_CLASS_EXTENSION + \since Coin 3.0 +*/ + +#define PRIVATE(obj) ((obj)->pimpl) + +SO_KIT_SOURCE(SoSTLFileKit) + +/*! + Initializes class and registers file identification functions. +*/ + +void +SoSTLFileKit::initClass(void) +{ + SO_KIT_INIT_CLASS(SoSTLFileKit, SoForeignFileKit, SoForeignFileKit); + + SoType type = SoSTLFileKit::getClassTypeId(); + SoForeignFileKit::registerFileExtension(type, "stl", SoSTLFileKit::identify); +} + +/*! + Returns wether or not \a filename is identified as an STL file. +*/ + +SbBool +SoSTLFileKit::identify(const char * filename) +{ + assert(filename); + stl_reader * reader = stl_reader_create(filename); + if ( !reader ) { + return FALSE; + } + stl_reader_destroy(reader); + return TRUE; +} + +/*! + Constructor. +*/ + +SoSTLFileKit::SoSTLFileKit(void) +{ + PRIVATE(this) = new SoSTLFileKitP(this); + + SO_KIT_INTERNAL_CONSTRUCTOR(SoSTLFileKit); + + SO_KIT_ADD_FIELD(info, ("")); + SO_KIT_ADD_FIELD(binary, (FALSE)); + SO_KIT_ADD_FIELD(colorization, (SoSTLFileKit::GREY)); + + SO_KIT_DEFINE_ENUM_VALUE(Colorization, GREY); + SO_KIT_DEFINE_ENUM_VALUE(Colorization, MATERIALISE); + SO_KIT_DEFINE_ENUM_VALUE(Colorization, TNO_VISICAM); + + SO_KIT_SET_SF_ENUM_TYPE(colorization, Colorization); + + SO_KIT_ADD_CATALOG_ENTRY(facets, SoIndexedFaceSet, + FALSE, topSeparator, \x0, FALSE); + SO_KIT_ADD_CATALOG_ENTRY(coordinates, SoCoordinate3, + FALSE, topSeparator, facets, FALSE); + SO_KIT_ADD_CATALOG_ENTRY(material, SoMaterial, + FALSE, topSeparator, coordinates, FALSE); + SO_KIT_ADD_CATALOG_ENTRY(materialbinding, SoMaterialBinding, + FALSE, topSeparator, material, FALSE); + SO_KIT_ADD_CATALOG_ENTRY(normals, SoNormal, + FALSE, topSeparator, materialbinding, FALSE); + SO_KIT_ADD_CATALOG_ENTRY(normalbinding, SoNormalBinding, + FALSE, topSeparator, normals, FALSE); + SO_KIT_ADD_CATALOG_ENTRY(texture, SoTexture2, + FALSE, topSeparator, normalbinding, FALSE); + SO_KIT_ADD_CATALOG_ENTRY(shapehints, SoShapeHints, + FALSE, topSeparator, texture, FALSE); + + SO_KIT_INIT_INSTANCE(); +} + +/*! + Destructor. +*/ + +SoSTLFileKit::~SoSTLFileKit(void) +{ + delete PRIVATE(this); + PRIVATE(this) = NULL; +} + +// doc in inherited class +SbBool +SoSTLFileKit::canReadFile(const char * filename) const +{ + if ( !filename ) return TRUE; // we can read STL files, in general + return SoSTLFileKit::identify(filename); +} + +/*! + Reads in an STL file. Both ascii and binary files are supported. + For binary files, the color extensions are not implemented yet. + + Returns FALSE if \a filename could not be opened or parsed + correctly. + + \sa canReadFile, canWriteScene, writeScene +*/ + +SbBool +SoSTLFileKit::readFile(const char * filename) +{ + assert(filename); + + this->reset(); + + stl_reader * reader = stl_reader_create(filename); + if ( !reader ) { + SoDebugError::postInfo("SoSTLFileKit::readFile", + "unable to create STL reader for '%s'.", + filename); + return FALSE; + } + + SbBool binary = (stl_reader_flags(reader) & STL_BINARY) ? TRUE : FALSE; + + SoShapeHints * hints = + SO_GET_ANY_PART(this, "shapehints", SoShapeHints); + hints->vertexOrdering.setValue(SoShapeHints::UNKNOWN_ORDERING); + // what it should have been + // hints->vertexOrdering.setValue(SoShapeHints::COUNTERCLOCKWISE); + hints->shapeType.setValue(SoShapeHints::SOLID); + hints->faceType.setValue(SoShapeHints::UNKNOWN_FACE_TYPE); + + SoNormalBinding * normalbinding = + SO_GET_ANY_PART(this, "normalbinding", SoNormalBinding); + normalbinding->value = SoNormalBinding::PER_FACE_INDEXED; + + stl_facet * facet = stl_facet_create(); + SbBool loop = TRUE, success = TRUE; + while ( loop ) { + const int peekval = stl_reader_peek(reader); + if ( peekval == STL_BEGIN ) { + } else if ( peekval == STL_INIT_INFO ) { + // FIXME: set info + } else if ( peekval == STL_EXIT_INFO ) { + } else if ( peekval == STL_END ) { + loop = FALSE; + } else if ( peekval == STL_FACET ) { + stl_real x, y, z; + stl_reader_fill_facet(reader, facet); + stl_facet_get_normal(facet, &x, &y, &z); + SbVec3f normal((float) x, (float) y, (float) z); + stl_facet_get_vertex1(facet, &x, &y, &z); + SbVec3f vertex1((float) x, (float) y, (float) z); + stl_facet_get_vertex2(facet, &x, &y, &z); + SbVec3f vertex2((float) x, (float) y, (float) z); + stl_facet_get_vertex3(facet, &x, &y, &z); + SbVec3f vertex3((float) x, (float) y, (float) z); + if ( normal.length() == 0.0f ) { // auto-calculate + SbVec3f v1(vertex2-vertex1); + SbVec3f v2(vertex3-vertex1); + normal = v1.cross(v2); + float len = normal.length(); + if ( len > 0 ) normal /= len; + } + unsigned int data = stl_facet_get_padding(facet); + + SbBool added = this->addFacet(vertex1, vertex2, vertex3, normal); + +#if defined(COIN_EXTRA_DEBUG) || 1 + if ( added && binary ) { + // binary contains padding, which might be colorization + // colorization is not implemented yet, so therefore some debug + // output comes here so colorized models can be detected. + PRIVATE(this)->data->append((uint16_t) data); + if ( data != 0 ) { + fprintf(stderr, "facet %5d - data: %04x\n", PRIVATE(this)->numfacets - 1, data); + } + } +#endif // COIN_EXTRA_DEBUG + } else if ( peekval == STL_ERROR ) { + SoDebugError::post("SoSTLFileKit::readFile", + "error '%s' after %d facets, line %d.", + stl_reader_get_error(reader), + PRIVATE(this)->numfacets, + stl_reader_get_line_number(reader)); + loop = FALSE; + success = FALSE; + if (strcmp(stl_reader_get_error(reader), "premature end of file") == 0) { + // this one we will accept though - models with missing + // end-indicator have been found... + success = TRUE; + } + } + } + + // done - no need for the BSP trees to contain data any more + PRIVATE(this)->points->clear(); + PRIVATE(this)->normals->clear(); + + stl_facet_destroy(facet); + stl_reader_destroy(reader); + + if ( !success ) { + this->reset(); + } else { + this->organizeModel(); + } + return success; +} + +// doc in inherited class +SbBool +SoSTLFileKit::canReadScene(void) const +{ + return TRUE; +} + +/*! + Converts a scene graph into an SoSTLFileKit. Useful for creating + STL files. + + \sa canReadScene, canWriteFile, writeFile +*/ + +SbBool +SoSTLFileKit::readScene(SoNode * scene) +{ + this->reset(); + + scene->ref(); + SoCallbackAction cba; + cba.addTriangleCallback(SoType::fromName("SoNode"), add_facet_cb, this); + cba.apply(scene); + scene->unrefNoDelete(); + + // no need for the BSP trees to contain data any more + PRIVATE(this)->points->clear(); + PRIVATE(this)->normals->clear(); + + this->organizeModel(); + + return TRUE; +} + +// doc in inherited class +SbBool +SoSTLFileKit::canWriteScene(const char * format) const +{ + if ( !format ) return TRUE; + // FIXME: implement format checking (VRML1, VRML97) + return TRUE; +} + +/*! + Converts the STL model into a native scene graph. + + \sa canWriteScene +*/ + +SbBool +SoSTLFileKit::writeScene(SoNode *& root, const char * format) +{ + static const char default_format[] = "#VRML 1.0"; // syntax for this? + if ( !format ) format = default_format; + + SbBool success = true; + + // FIXME: implement format check to specify scene graph setup + enum Format { + UNKNOWN, + VRML1, + VRML97 + }; + + Format build = VRML1; + + if ( build == VRML1 ) { + // create VRML1 scene + SoSeparator * sceneroot = new SoSeparator; + sceneroot->ref(); + + SoInfo * info = new SoInfo; + info->string = "STL model data, created by Coin " COIN_VERSION "."; + sceneroot->addChild(info); + + SoShapeHints * shapehints_orig = + SO_GET_ANY_PART(this, "shapehints", SoShapeHints); + SoShapeHints * shapehints_copy = new SoShapeHints; + shapehints_copy->copyContents(shapehints_orig, FALSE); + sceneroot->addChild(shapehints_copy); + + SoTexture2 * texture_orig = SO_GET_ANY_PART(this, "texture", SoTexture2); + SoTexture2 * texture_copy = new SoTexture2; + texture_copy->copyContents(texture_orig, FALSE); + sceneroot->addChild(texture_copy); + + SoNormalBinding * normalbinding_orig = + SO_GET_ANY_PART(this, "normalbinding", SoNormalBinding); + SoNormalBinding * normalbinding_copy = new SoNormalBinding; + normalbinding_copy->copyContents(normalbinding_orig, FALSE); + sceneroot->addChild(normalbinding_copy); + + SoNormal * normals_orig = SO_GET_ANY_PART(this, "normals", SoNormal); + SoNormal * normals_copy = new SoNormal; + normals_copy->copyContents(normals_orig, FALSE); + sceneroot->addChild(normals_copy); + + SoMaterialBinding * materialbinding_orig = + SO_GET_ANY_PART(this, "materialbinding", SoMaterialBinding); + SoMaterialBinding * materialbinding_copy = new SoMaterialBinding; + materialbinding_copy->copyContents(materialbinding_orig, FALSE); + sceneroot->addChild(materialbinding_copy); + + SoMaterial * material_orig = SO_GET_ANY_PART(this, "material", SoMaterial); + SoMaterial * material_copy = new SoMaterial; + material_copy->copyContents(material_orig, FALSE); + sceneroot->addChild(material_copy); + + SoCoordinate3 * coordinates_orig = + SO_GET_ANY_PART(this, "coordinates", SoCoordinate3); + SoCoordinate3 * coordinates_copy = new SoCoordinate3; + coordinates_copy->copyContents(coordinates_orig, FALSE); + sceneroot->addChild(coordinates_copy); + + SoIndexedFaceSet * facets_orig = + SO_GET_ANY_PART(this, "facets", SoIndexedFaceSet); + SoIndexedFaceSet * facets_copy = new SoIndexedFaceSet; + facets_copy->copyContents(facets_orig, FALSE); + sceneroot->addChild(facets_copy); + + // optimize/reorganize mesh + SoReorganizeAction ra; + ra.apply(sceneroot); + + // FIXME: remove redundant scene graph nodes after scene reorganization + + sceneroot->unrefNoDelete(); + root = sceneroot; + } else { + SoDebugError::postWarning("SoSTLFileKit::writeScene", + "unsupported format - could not create scene."); + success = FALSE; + } + + return success; +} + +// doc in inherited class +SbBool +SoSTLFileKit::canWriteFile(const char * filename) const +{ + return inherited::canWriteFile(filename); +} + +/*! + Writes the STL model to an STL file. + + \sa binary, info, canWriteFile, canReadScene +*/ + +SbBool +SoSTLFileKit::writeFile(const char * filename) +{ + unsigned int flags = 0; + if ( this->binary.getValue() ) { + flags |= STL_BINARY; + // set up flags for colorization if wanted + } + + stl_writer * writer = stl_writer_create(filename, flags); + if ( !writer ) { + return FALSE; + } + + stl_facet * facet = stl_facet_create(); + assert(facet); + stl_writer_set_facet(writer, facet); + + SbString infostring = this->info.getValue(); + if ( infostring.getLength() > 0 ) { + if ( stl_writer_set_info(writer, infostring.getString()) != STL_OK ) { + SoDebugError::post("SoSTLFileKit::writeFile", + "error: '%s'", + stl_writer_get_error(writer)); + return FALSE; + } + } + + this->ref(); + SoCallbackAction cba; + cba.addTriangleCallback(SoNode::getClassTypeId(), put_facet_cb, writer); + cba.apply(this); + this->unrefNoDelete(); + + stl_writer_destroy(writer); + + return TRUE; +} + +// ************************************************************************* + +/*! + Resets the STL model so it contains nothing. +*/ + +void +SoSTLFileKit::reset(void) +{ + PRIVATE(this)->numvertices = 0; + PRIVATE(this)->numfacets = 0; + PRIVATE(this)->numnormals = 0; + PRIVATE(this)->numsharedvertices = 0; + PRIVATE(this)->numsharednormals = 0; + PRIVATE(this)->numredundantfacets = 0; + + PRIVATE(this)->data->truncate(0); + PRIVATE(this)->points->clear(); + PRIVATE(this)->normals->clear(); + + this->setAnyPart("shapehints", new SoShapeHints); + this->setAnyPart("texture", new SoTexture2); + this->setAnyPart("normalbinding", new SoNormalBinding); + this->setAnyPart("normals", new SoNormal); + this->setAnyPart("materialbinding", new SoMaterialBinding); + this->setAnyPart("material", new SoMaterial); + this->setAnyPart("coordinates", new SoCoordinate3); + this->setAnyPart("facets", new SoIndexedFaceSet); + + SoNormalBinding * normalbinding = + SO_GET_ANY_PART(this, "normalbinding", SoNormalBinding); + normalbinding->value = SoNormalBinding::PER_FACE_INDEXED; + + SoShapeHints * shapehints = + SO_GET_ANY_PART(this, "shapehints", SoShapeHints); + shapehints->vertexOrdering = SoShapeHints::UNKNOWN_ORDERING; + // proper model is + // shapehints->vertexOrdering = SoShapeHints::COUNTERCLOCKWISE; + // but many models are not proper + shapehints->shapeType = SoShapeHints::SOLID; +} + +/*! + Adds one triangle to the STL model. + + \sa reset, organizeModel +*/ + +SbBool +SoSTLFileKit::addFacet(const SbVec3f & v1, const SbVec3f & v2, const SbVec3f & v3, const SbVec3f & n) +{ + SoNormal * normals = + SO_GET_ANY_PART(this, "normals", SoNormal); + SoCoordinate3 * coordinates = + SO_GET_ANY_PART(this, "coordinates", SoCoordinate3); + SoIndexedFaceSet * facets = + SO_GET_ANY_PART(this, "facets", SoIndexedFaceSet); + + // find existing indexes if any + long v1idx = PRIVATE(this)->points->findPoint(v1), v1new = (v1idx == -1); + long v2idx = PRIVATE(this)->points->findPoint(v2), v2new = (v2idx == -1); + long v3idx = PRIVATE(this)->points->findPoint(v3), v3new = (v3idx == -1); + if (!v1new) { v1idx = (long) PRIVATE(this)->points->getUserData(v1idx); } + if (!v2new) { v2idx = (long) PRIVATE(this)->points->getUserData(v2idx); } + if (!v3new) { v3idx = (long) PRIVATE(this)->points->getUserData(v3idx); } + long nidx = PRIVATE(this)->normals->findPoint(n); + if (nidx != -1) { nidx = (long) PRIVATE(this)->normals->getUserData(nidx); } + + // toss out invalid facets - facets where two or more points are in + // the same location. what are these - are they lines and points or + // something? selection? borders? creases? + if ((!v1new && !v2new && (v1idx == v2idx)) || + (!v1new && !v3new && (v1idx == v3idx)) || + (!v2new && !v3new && (v2idx == v3idx)) || + (v1new && v2new && (v1 == v2)) || + (v1new && v3new && (v1 == v3)) || + (v2new && v3new && (v2 == v3))) { + // the above test is optimized for using vertex indexes if + // possible and avoid vec3f-comparisons when index-comparisons + // should have sufficed. + PRIVATE(this)->numredundantfacets += 1; + return FALSE; + } + +#if 0 // disabled (O(n^2)) + // toss out redundant facets, if any... + if (!v1new && !v2new && !v3new) { + int count = facets->coordIndex.getNum(); + const int32_t * points = facets->coordIndex.getValues(0); + int i; + for (i = 0; i < count; i++) { + if (points[i] == v1idx) { + int beg = i - (i % 4); + if ( ((points[beg] == v1idx) && (points[beg+1] == v2idx) && + (points[beg+2] == v3idx)) || + ((points[beg] == v2idx) && (points[beg+1] == v3idx) && + (points[beg+2] == v1idx)) || + ((points[beg] == v3idx) && (points[beg+1] == v1idx) && + (points[beg+2] == v2idx)) ) { + // same vertices, same vertex ordering (we drop comparing normal) + PRIVATE(this)->numredundantfacets += 1; + return FALSE; + } + } + } + } +#endif + + // add facet (triangle) to faceset + if (v1new) { + v1idx = PRIVATE(this)->numvertices; + coordinates->point.set1Value(v1idx, v1); + PRIVATE(this)->points->addPoint(v1, (void *) v1idx); + PRIVATE(this)->numvertices++; + } else { + PRIVATE(this)->numsharedvertices++; + } + facets->coordIndex.set1Value(PRIVATE(this)->numfacets*4, v1idx); + + if (v2new) { + v2idx = PRIVATE(this)->numvertices; + coordinates->point.set1Value(v2idx, v2); + PRIVATE(this)->points->addPoint(v2, (void *) v2idx); + PRIVATE(this)->numvertices++; + } else { + PRIVATE(this)->numsharedvertices++; + } + facets->coordIndex.set1Value(PRIVATE(this)->numfacets*4+1, v2idx); + + if (v3new) { + v3idx = PRIVATE(this)->numvertices; + coordinates->point.set1Value(v3idx, v3); + PRIVATE(this)->points->addPoint(v3, (void *) v3idx); + PRIVATE(this)->numvertices++; + } else { + PRIVATE(this)->numsharedvertices++; + } + facets->coordIndex.set1Value(PRIVATE(this)->numfacets*4+2, v3idx); + facets->coordIndex.set1Value(PRIVATE(this)->numfacets*4+3, -1); + + if (nidx == -1) { + nidx = PRIVATE(this)->numnormals; + normals->vector.set1Value(nidx, n); + PRIVATE(this)->normals->addPoint(n, (void *) nidx); + PRIVATE(this)->numnormals++; + } else { + PRIVATE(this)->numsharednormals++; + } + facets->normalIndex.set1Value(PRIVATE(this)->numfacets, nidx); + + PRIVATE(this)->numfacets++; + return TRUE; +} + +/*! + Should be called after the STL model is completely set up in the + SoSTLFileKit through import from a file or from a scene graph. The + model will then be optimized for fast rendering. + + \sa addFacet, reset +*/ + +void +SoSTLFileKit::organizeModel(void) +{ +#if defined(COIN_EXTRA_DEBUG) + SoDebugError::postInfo("SoSTLFileKit::organizeModel", + "model data imported successfully. " + "%d unique vertices, %d reuses. " + "%d unique normals, %d reuses. " + "%d facets, %d redundant facets.", + PRIVATE(this)->numvertices, + PRIVATE(this)->numsharedvertices, + PRIVATE(this)->numnormals, + PRIVATE(this)->numsharednormals, + PRIVATE(this)->numfacets, + PRIVATE(this)->numredundantfacets); +#endif // COIN_EXTRA_DEBUG + + SoIndexedFaceSet * facets = + SO_GET_ANY_PART(this, "facets", SoIndexedFaceSet); + + assert(facets->coordIndex.getNum() == PRIVATE(this)->numfacets*4); + assert(facets->normalIndex.getNum() == (PRIVATE(this)->numfacets)); + + if ( PRIVATE(this)->numfacets > 300 ) { + // FIXME: at some number of facets, reorganization for faster + // rendering should really be performed. + } +} + +/*! + Helper callback for readScene(), calling addFacet() for each + triangle in the provided scene graph. + + \sa readScene +*/ + +void +SoSTLFileKit::add_facet_cb(void * closure, + SoCallbackAction * action, + const SoPrimitiveVertex * v1, + const SoPrimitiveVertex * v2, + const SoPrimitiveVertex * v3) +{ + assert(closure); assert(v1); assert(v2); assert(v3); + SoSTLFileKit * filekit = (SoSTLFileKit *) closure; + + SbVec3f vertex1(v1->getPoint()); + SbVec3f vertex2(v2->getPoint()); + SbVec3f vertex3(v3->getPoint()); + + SbVec3f vec1(vertex2-vertex1); + SbVec3f vec2(vertex3-vertex1); + SbVec3f normal(vec1.cross(vec2)); + float len = normal.length(); + if ( len > 0.0f && len != 1.0f ) normal /= len; + assert(len != 0.0f); + + filekit->addFacet(vertex1, vertex2, vertex3, normal); +} + +/*! + Helper callback for writeFile(), writing each triangle in the STL + model to the STL file. + + \sa writeFile +*/ + +void +SoSTLFileKit::put_facet_cb(void * closure, + SoCallbackAction * action, + const SoPrimitiveVertex * v1, + const SoPrimitiveVertex * v2, + const SoPrimitiveVertex * v3) +{ + assert(closure); assert(v1); assert(v2); assert(v3); + stl_writer * writer = (stl_writer *) closure; + + SbVec3f vertex1(v1->getPoint()); + SbVec3f vertex2(v2->getPoint()); + SbVec3f vertex3(v3->getPoint()); + + SbVec3f vec1(vertex2-vertex1); + SbVec3f vec2(vertex3-vertex1); + SbVec3f normal(vec1.cross(vec2)); + float len = normal.length(); + if ( len > 0 ) normal /= len; + + stl_facet * facet = stl_writer_get_facet(writer); + assert(facet); + stl_facet_set_vertex1(facet, vertex1[0], vertex1[1], vertex1[2]); + stl_facet_set_vertex2(facet, vertex2[0], vertex2[1], vertex2[2]); + stl_facet_set_vertex3(facet, vertex3[0], vertex3[1], vertex3[2]); + stl_facet_set_normal(facet, normal[0], normal[1], normal[2]); + stl_facet_set_padding(facet, 0); + + stl_writer_put_facet(writer, facet); +} + +#undef PRIVATE +#endif // HAVE_NODEKITS diff --git a/src/threads/thread.cpp b/src/threads/thread.cpp index 1111111..2222222 100644 --- a/src/threads/thread.cpp +++ b/src/threads/thread.cpp @@ -120,7 +120,7 @@ cc_thread_join(cc_thread * thread, void cc_sleep(float seconds) { -#ifndef _WIN32 +#if !defined(_WIN32) || defined(__MINGW32__) /* FIXME: 20011107, thammer: create a configure macro to detect * which sleep function is available */ sleep(floor(seconds)); @@ -154,7 +154,7 @@ cc_thread_id(void) assert(0 && "unexpected failure"); } } - return (unsigned long) val; + return static_cast(reinterpret_cast(val)); } static void diff --git a/src/threads/thread.cpp.orig b/src/threads/thread.cpp.orig new file mode 100644 index 1111111..2222222 --- /dev/null +++ b/src/threads/thread.cpp.orig @@ -0,0 +1,347 @@ +/**************************************************************************\ + * + * This file is part of the Coin 3D visualization library. + * Copyright (C) by Kongsberg Oil & Gas Technologies. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * ("GPL") version 2 as published by the Free Software Foundation. + * See the file LICENSE.GPL at the root directory of this source + * distribution for additional information about the GNU GPL. + * + * For using Coin with software that can not be combined with the GNU + * GPL, and for taking advantage of the additional benefits of our + * support services, please contact Kongsberg Oil & Gas Technologies + * about acquiring a Coin Professional Edition License. + * + * See http://www.coin3d.org/ for more information. + * + * Kongsberg Oil & Gas Technologies, Bygdoy Alle 5, 0257 Oslo, NORWAY. + * http://www.sim.no/ sales@sim.no coin-support@coin3d.org + * +\**************************************************************************/ + +#include + +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#ifdef HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ + +#include + +#include "threads/threadp.h" +#include "threads/mutexp.h" +#include "threads/recmutexp.h" +#include "threads/syncp.h" +#include "tidbitsp.h" + + +/* ********************************************************************** */ + +/* + FIXME: + - copy struct malloc/free/init/clean setup scheme from cc_string + - use static table of cc_thread structures? + - use cc_storage to reference self-structure for cc_thread_get_self()? +*/ + +/* ********************************************************************** */ + +#ifdef USE_PTHREAD +#include "threads/thread_pthread.icc" +#endif /* USE_PTHREAD */ + +#ifdef USE_W32THREAD +#include "threads/thread_win32.icc" +#endif /* USE_W32THREAD */ + +/* +*/ + +cc_thread * +cc_thread_construct(cc_thread_f * func, void * closure) +{ + cc_thread * thread; + int ok; + + thread = (cc_thread*) malloc(sizeof(cc_thread)); + assert(thread != NULL); + thread->func = func; + thread->closure = closure; + + ok = internal_init(thread); + if (ok) return thread; + assert(0 && "unable to create thread"); + free(thread); + return NULL; +} + +/* ********************************************************************** */ + +/* +*/ + +void +cc_thread_destruct(cc_thread * thread) +{ + int ok; + assert(thread != NULL); + ok = internal_clean(thread); + assert(ok == CC_OK); + free(thread); +} + +/* ********************************************************************** */ + +/* +*/ + +int +cc_thread_join(cc_thread * thread, + void ** retvalptr) +{ + int ok; + assert(thread != NULL); + + ok = internal_join(thread, retvalptr); + assert(ok == CC_OK); + return ok; +} + +/* ********************************************************************** */ + +void +cc_sleep(float seconds) +{ +#ifndef _WIN32 + /* FIXME: 20011107, thammer: create a configure macro to detect + * which sleep function is available */ + sleep(floor(seconds)); +#else + Sleep((int)(seconds*1000.0)); +#endif +}; + +#ifdef USE_PTHREAD +unsigned long +cc_thread_id(void) +{ + return (unsigned long) pthread_self(); +} +#endif /* USE_PTHREAD */ + +#ifdef USE_W32THREAD + +static DWORD win32_threadid_idx; + +unsigned long +cc_thread_id(void) +{ + static unsigned long currentidx = 1; + LPVOID val = TlsGetValue(win32_threadid_idx); + if (val == 0) { /* not set yet */ + cc_mutex_global_lock(); + val = (LPVOID) currentidx++; + cc_mutex_global_unlock(); + if (!TlsSetValue(win32_threadid_idx, (LPVOID)val)) { + assert(0 && "unexpected failure"); + } + } + return (unsigned long) val; +} + +static void +win32_threadid_idx_cleanup(void) +{ + TlsFree(win32_threadid_idx); +} + +#endif /* USE_WIN32THREAD */ + + +void +cc_thread_init(void) +{ + cc_mutex_init(); + cc_sync_init(); +#ifdef USE_W32THREAD + /* needed to quickly generate a thread-id for each thread */ + win32_threadid_idx = TlsAlloc(); + assert(win32_threadid_idx != TLS_OUT_OF_INDEXES); + /* clean-up priority for the thread sub-system in Coin is set so it + is done very late at exit */ + /* FIXME: not sure if this really needs the "- 2", but I added it + to keep the same order wrt the other thread-related clean-up + functions, since before I changed hard-coded numbers for + enumerated values for coin_atexit() invocations. 20060301 mortene. */ + coin_atexit(win32_threadid_idx_cleanup, CC_ATEXIT_THREADING_SUBSYSTEM_VERYLOWPRIORITY); +#endif /* USE_WIN32THREAD */ + cc_recmutex_init(); +} + +/* ********************************************************************** */ + +/* maybe use static table of thread structures, reference counted, to be + able to implement something like this, if needed */ +/* cc_thread * cc_thread_get_self(void); */ + +/* ********************************************************************** */ + +/* + * We don't really want to expose internal id types, which would mean we + * must include threads-implementation-specific headers in the header files. + * It's therefore better to implement the missing/needed functionality for + * the cc_thread type, so id peeking won't be necessary. + */ + +/* cc_thread_get_id(cc_thread * thread); */ +/* cc_thread_get_current_id(void); */ + +/* ********************************************************************** */ + +/*! + \page multithreading_support Multithreading Support in Coin + + The support in Coin for using multiple threads in application + programs and the Coin library itself, consists of two main features: + +
    + +
  • + Coin provides platform-independent thread-handling abstraction + classes. These are classes that the application programmer can + freely use in her application code to start new threads, control + their execution, work with mutexes and do other tasks related to + handling multiple threads. + + The classes in question are SbThread, SbMutex, SbStorage, SbBarrier, + SbCondVar, SbFifo, SbThreadAutoLock, SbRWMutex, and + SbTypedStorage. See their respective documentation for the detailed + information. + + The classes fully hides the system-specific implementation, which is + either done on top of native Win32 (if on Microsoft Windows), or + over POSIX threads (on UNIX and UNIX-like systems). +
  • + +
  • + The other aspect of our multi-threading support is that Coin can be + specially configured so that rendering traversals of the scene graph + are done in a thread-safe manner. This means e.g. that it is + possible to have Coin render the scene in parallel on multiple CPUs + for multiple rendering pipes, to better take advantage of such + high-end systems (like CAVE environments, for instance). + + Thread-safe render traversals are \e off by default, because there + is a small overhead involved which would make rendering (very) + slightly slower on single-threaded invocations. + + To get a Coin library built with thread-safe rendering, one must + actively re-configure Coin and build a special, local version. For + configure-based builds (UNIX and UNIX-like systems, or with Cygwin + on Microsoft Windows) this is done with the option + "--enable-threadsafe" to Autoconf configure. For how to change the + configuration and re-build with Visual Studio, get in touch with us + at "coin-support@coin3d.org". +
  • + +
+ + There are some restrictions and other issues which it is important + to be aware of: + +
    + +
  • We do not yet provide any support for binding the + multi-threaded rendering support into the SoQt / SoWin / etc GUI + bindings, and neither do we provide bindings against any specific + library that handles multi-pipe rendering. This means the + application programmer will have to possess some expertise, and put + in some effort, to be able to utilize multi-pipe rendering with + Coin.
  • + +
  • Rendering traversals is currently the only operation which we + publicly support to be thread-safe. There are other aspects of Coin + that we know are thread-safe, like most other action traversals + beside just rendering, but we make no guarantees in this + regard.
  • + +
  • Be careful about using a separate thread for changing Coin + structures versus what is used for the application's GUI event + thread. + + We are aware of at least issues with Qt (and thereby SoQt), where + you should not modify the scene graph in any way in a thread + separate from the main Qt thread. This because it will trigger + operations where Qt is not thread-safe.
  • + +
+ + \since Coin 2.0 +*/ + +/* ********************************************************************** */ + +/*! + \class SbThread Inventor/threads/SbThread.h + \brief A class for managing threads. + \ingroup threads + + This class provides a portable framework around the tasks of + instantiating, starting, stopping and joining threads. + + It wraps the underlying native thread-handling toolkit in a + transparent manner, to make multiplatform threads programming + straightforward for the application programmer. +*/ + +/*! + \fn static SbThread * SbThread::create(void *(*func)(void *), void * closure) + + This function creates a new thread, or returns NULL on failure. +*/ + +/*! + \fn static void SbThread::destroy(SbThread * thread) + + This function destroys a thread. +*/ + +/*! + \fn static int SbThread::join(SbThread * thread, void ** retval) + + This function waits on the death of the given thread, returning the thread's + return value at the location pointed to by \c retval. +*/ + +/*! + \fn int SbThread::join(void ** retval) + + This function waits on the death of the given thread, returning the thread's + return value at the location pointed to by \c retval. +*/ + +/*! + \fn SbThread::SbThread(cc_thread * thread) + + Protected constructor handling the internal thread ADT. + + \sa SbThread::create +*/ + +/*! + \fn SbThread::~SbThread(void) + + Destructor. + + \sa SbThread::destroy +*/ + +/* ********************************************************************** */ diff --git a/src/threads/thread_win32.icc b/src/threads/thread_win32.icc index 1111111..2222222 100644 --- a/src/threads/thread_win32.icc +++ b/src/threads/thread_win32.icc @@ -29,7 +29,7 @@ static DWORD WINAPI cc_w32thread_thread_proc(LPVOID lpParameter) { cc_thread *thread = (cc_thread *)lpParameter; - return (DWORD) thread->func(thread->closure); + return static_cast(reinterpret_cast(thread->func(thread->closure))); } static int diff --git a/src/threads/thread_win32.icc.orig b/src/threads/thread_win32.icc.orig new file mode 100644 index 1111111..2222222 --- /dev/null +++ b/src/threads/thread_win32.icc.orig @@ -0,0 +1,110 @@ +/**************************************************************************\ + * + * This file is part of the Coin 3D visualization library. + * Copyright (C) by Kongsberg Oil & Gas Technologies. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * ("GPL") version 2 as published by the Free Software Foundation. + * See the file LICENSE.GPL at the root directory of this source + * distribution for additional information about the GNU GPL. + * + * For using Coin with software that can not be combined with the GNU + * GPL, and for taking advantage of the additional benefits of our + * support services, please contact Kongsberg Oil & Gas Technologies + * about acquiring a Coin Professional Edition License. + * + * See http://www.coin3d.org/ for more information. + * + * Kongsberg Oil & Gas Technologies, Bygdoy Alle 5, 0257 Oslo, NORWAY. + * http://www.sim.no/ sales@sim.no coin-support@coin3d.org + * +\**************************************************************************/ + +/* this file should only be included from thread.c */ + +#include "glue/win32api.h" + +static DWORD WINAPI +cc_w32thread_thread_proc(LPVOID lpParameter) +{ + cc_thread *thread = (cc_thread *)lpParameter; + return (DWORD) thread->func(thread->closure); +} + +static int +internal_init(cc_thread * thread) +{ + DWORD threadid_unused; + + thread->w32thread.threadhandle = CreateThread(NULL, 0, + cc_w32thread_thread_proc, (LPVOID) thread, 0, &threadid_unused); + + /* threadid_unused - see PlatformSDK doc. for CreateThread */ + + /* FIXME: thammer 20011108, check PlatformSDK doc for + * _beginthreadex, _endthreadex, and note about using these with + * LIBCMT.LIB "A thread that uses functions from the C run-time + * libraries should use the beginthread and endthread C run-time + * functions for thread management rather than CreateThread and + * ExitThread. Failure to do so results in small memory leaks when + * ExitThread is called. " */ + + if (thread->w32thread.threadhandle == NULL) { + if (COIN_DEBUG) { + cc_win32_print_error("internal_init", "CreateThread()", GetLastError()); + } + return CC_ERROR; + } + return CC_OK; +} + +static int +internal_clean(cc_thread * thread_struct) +{ + /* FIXME: Is there really nothing to do here? pederb, 2001-12-10 */ + return CC_OK; +} + +static int +internal_join(cc_thread * thread, + void ** retvalptr) +{ + DWORD status; + BOOL bstatus; + DWORD exitcode; + + status = WaitForSingleObject(thread->w32thread.threadhandle, INFINITE); + if (status == WAIT_FAILED) { + if (COIN_DEBUG) { + cc_win32_print_error("internal_join", "WaitForSingleObject()", + GetLastError()); + } + return CC_ERROR; + } + else if (status != WAIT_OBJECT_0) { + if (COIN_DEBUG) { + cc_debugerror_post("internal_join", + "WaitForSingleObject() - unknown return value: %d\n", + status); + } + return CC_ERROR; + } + bstatus = GetExitCodeThread(thread->w32thread.threadhandle, &exitcode); + if (bstatus == FALSE) { + if (COIN_DEBUG) { + cc_win32_print_error("internal_join", "GetExitCodeThread()", + GetLastError()); + } + } + else if (retvalptr) { + *retvalptr = (void *)exitcode; + } + /* termination could be forced with TerminateThread() - but this + * will result in memory leaks - or bigger problems - see Platform + * SDK doc. */ + CloseHandle(thread->w32thread.threadhandle); + thread->w32thread.threadhandle = NULL; + + return bstatus ? CC_OK : CC_ERROR; +} diff --git a/src/vrml97/JS_VRMLClasses.cpp b/src/vrml97/JS_VRMLClasses.cpp index 1111111..2222222 100644 --- a/src/vrml97/JS_VRMLClasses.cpp +++ b/src/vrml97/JS_VRMLClasses.cpp @@ -100,8 +100,11 @@ struct CoinVrmlJs { struct CoinVrmlJs_SensorInfo { SbList objects; }; +#if defined(_WIN64) +SbHash * CoinVrmlJs_sensorinfohash = NULL; +#else SbHash * CoinVrmlJs_sensorinfohash = NULL; - +#endif const char * CoinVrmlJs_SFColorAliases[] = {"r", "g", "b"}; const char * CoinVrmlJs_SFRotationAliases[] = {"x", "y", "z", "angle"}; @@ -664,7 +667,11 @@ static void SFNode_deleteCB(void * data, SoSensor * sensor) { SoNode * node = ((SoNodeSensor *) sensor)->getAttachedNode(); void * tmp; +#if defined(_WIN64) + if(!CoinVrmlJs_sensorinfohash->get((unsigned long long) node, tmp)) { +#else if(!CoinVrmlJs_sensorinfohash->get((unsigned long) node, tmp)) { +#endif assert(FALSE && "Trying to delete an unregistered SoNodeSensor. Internal error."); return; } @@ -680,7 +687,11 @@ static void SFNode_deleteCB(void * data, SoSensor * sensor) // Store the sensor-pointer so that it can be properly deleted later nodesensorstobedeleted->append((SoNodeSensor *) sensor); +#if defined(_WIN64) + CoinVrmlJs_sensorinfohash->remove((unsigned long long) node); +#else CoinVrmlJs_sensorinfohash->remove((unsigned long) node); +#endif delete si; } @@ -1418,13 +1429,21 @@ static void attachSensorToNode(SoNode * node, JSObject * obj) { // Has the hash-table been initialized? if (!CoinVrmlJs_sensorinfohash) { +#if defined(_WIN64) + CoinVrmlJs_sensorinfohash = new SbHash ; +#else CoinVrmlJs_sensorinfohash = new SbHash ; +#endif coin_atexit(deleteSensorInfoHash, CC_ATEXIT_NORMAL); } // Is a sensor already attached to this SoNode? void * tmp; +#if defined(_WIN64) + if (CoinVrmlJs_sensorinfohash->get((unsigned long long) node, tmp)) { +#else if (CoinVrmlJs_sensorinfohash->get((unsigned long) node, tmp)) { +#endif CoinVrmlJs_SensorInfo * si = (CoinVrmlJs_SensorInfo *) tmp; si->objects.append(obj); } @@ -1434,7 +1453,11 @@ static void attachSensorToNode(SoNode * node, JSObject * obj) ns->attach(node); CoinVrmlJs_SensorInfo * si = new CoinVrmlJs_SensorInfo; si->objects.append(obj); +#if defined(_WIN64) + CoinVrmlJs_sensorinfohash->put((unsigned long long) node, si); +#else CoinVrmlJs_sensorinfohash->put((unsigned long) node, si); +#endif } } diff --git a/src/vrml97/JS_VRMLClasses.cpp.orig b/src/vrml97/JS_VRMLClasses.cpp.orig new file mode 100644 index 1111111..2222222 --- /dev/null +++ b/src/vrml97/JS_VRMLClasses.cpp.orig @@ -0,0 +1,2099 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif // HAVE_CONFIG_H + +#ifdef HAVE_VRML97 + +/**************************************************************************\ + * + * This file is part of the Coin 3D visualization library. + * Copyright (C) by Kongsberg Oil & Gas Technologies. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * ("GPL") version 2 as published by the Free Software Foundation. + * See the file LICENSE.GPL at the root directory of this source + * distribution for additional information about the GNU GPL. + * + * For using Coin with software that can not be combined with the GNU + * GPL, and for taking advantage of the additional benefits of our + * support services, please contact Kongsberg Oil & Gas Technologies + * about acquiring a Coin Professional Edition License. + * + * See http://www.coin3d.org/ for more information. + * + * Kongsberg Oil & Gas Technologies, Bygdoy Alle 5, 0257 Oslo, NORWAY. + * http://www.sim.no/ sales@sim.no coin-support@coin3d.org + * +\**************************************************************************/ + +#include "JS_VRMLClasses.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "misc/SbHash.h" + +// FIXME: toString() missing for all classes + +// "namespace" for all vrml classes +struct CoinVrmlJs { + struct ClassDescriptor { + JSClass cls; + JSFunctionSpec * functions; + + }; + + static ClassDescriptor SFColor; + static ClassDescriptor SFNode; + static ClassDescriptor SFRotation; + static ClassDescriptor SFVec2f; + static ClassDescriptor SFVec3f; + static ClassDescriptor SFVec3d; + + static ClassDescriptor MFColor; + static ClassDescriptor MFFloat; + static ClassDescriptor MFInt32; + static ClassDescriptor MFNode; + static ClassDescriptor MFRotation; + static ClassDescriptor MFString; + static ClassDescriptor MFTime; + static ClassDescriptor MFVec2f; + static ClassDescriptor MFVec3f; + static ClassDescriptor MFVec3d; +}; + +// Struct and SbHash for keeping track of SoNodeSensors for recycling +// purposes. +struct CoinVrmlJs_SensorInfo { + SbList objects; +}; +SbHash * CoinVrmlJs_sensorinfohash = NULL; + + +const char * CoinVrmlJs_SFColorAliases[] = {"r", "g", "b"}; +const char * CoinVrmlJs_SFRotationAliases[] = {"x", "y", "z", "angle"}; +float CoinVrmlJs_SFdefaultValues[] = {0.0, 0.0, 0.0, 0.0}; +double CoinVrmlJs_SFdefaultValuesDouble[] = {0.0, 0.0, 0.0, 0.0}; +float CoinVrmlJs_SFRotationDefaultValues[] = {0.0, 1.0, 0.0, 0.0}; + +// Macros for instance checking +#define JSVAL_IS_SFVEC2F(cx, jsval) (JSVAL_IS_OBJECT(jsval) && spidermonkey()->JS_InstanceOf(cx, JSVAL_TO_OBJECT(jsval), &CoinVrmlJs::SFVec2f.cls, NULL)) +#define JSVAL_IS_SFVEC3F(cx, jsval) (JSVAL_IS_OBJECT(jsval) && spidermonkey()->JS_InstanceOf(cx, JSVAL_TO_OBJECT(jsval), &CoinVrmlJs::SFVec3f.cls, NULL)) +#define JSVAL_IS_SFVEC3D(cx, jsval) (JSVAL_IS_OBJECT(jsval) && spidermonkey()->JS_InstanceOf(cx, JSVAL_TO_OBJECT(jsval), &CoinVrmlJs::SFVec3d.cls, NULL)) +#define JSVAL_IS_SFCOLOR(cx, jsval) (JSVAL_IS_OBJECT(jsval) && spidermonkey()->JS_InstanceOf(cx, JSVAL_TO_OBJECT(jsval), &CoinVrmlJs::SFColor.cls, NULL)) +#define JSVAL_IS_SFROTATION(cx, jsval) (JSVAL_IS_OBJECT(jsval) && spidermonkey()->JS_InstanceOf(cx, JSVAL_TO_OBJECT(jsval), &CoinVrmlJs::SFRotation.cls, NULL)) + +// Handlers +#define SFColorHandler CoinVrmlJsSFHandler +#define SFRotationHandler CoinVrmlJsSFHandler +#define SFVec2fHandler CoinVrmlJsSFHandler +#define SFVec3fHandler CoinVrmlJsSFHandler +#define SFVec3dHandler CoinVrmlJsSFHandler + +#define MFColorHandler CoinVrmlJsMFHandler +#define MFFloatHandler CoinVrmlJsMFHandler +#define MFInt32Handler CoinVrmlJsMFHandler +#define MFNodeHandler CoinVrmlJsMFHandler +#define MFRotationHandler CoinVrmlJsMFHandler +#define MFStringHandler CoinVrmlJsMFHandler +#define MFTimeHandler CoinVrmlJsMFHandler +#define MFVec2fHandler CoinVrmlJsMFHandler +#define MFVec3fHandler CoinVrmlJsMFHandler +#define MFVec3dHandler CoinVrmlJsMFHandler + +static JSFunctionSpec MFFunctions[] = { +// {"toString", MF_toString, 0, 0, 0}, + {NULL, NULL, 0, 0, 0} +}; + +static JSBool SFRotationConstructor(JSContext * cx, JSObject * obj, + uintN argc, jsval * argv, jsval * rval); + +// Factory methods for converting to javascript objects +static JSObject * SFColorFactory(JSContext * cx, const SbColor & self); +static JSObject * SFNodeFactory(JSContext * cx, SoNode * container); +static JSObject * SFRotationFactory(JSContext * cx, const SbRotation & self); +static JSObject * SFVec2fFactory(JSContext * cx, const SbVec2f & self); +static JSObject * SFVec3fFactory(JSContext * cx, const SbVec3f & self); +static JSObject * SFVec3dFactory(JSContext * cx, const SbVec3d & self); + +static SbList * garbagecollectedobjects = NULL; +static SbList * nodesensorstobedeleted = NULL; + +// getIndex returns -1 if id is not an alias or in range 0-max +static JSBool getIndex(JSContext * cx, jsval id, const char * aliases[], int max) +{ + int index; + + if (JSVAL_IS_INT(id)) { + index = JSVAL_TO_INT(id); + if (index < 0 || index >= max) { + spidermonkey()->JS_ReportError(cx, "index must be between 0 and %d", max); + return -1; + } + return index; + } + else { + JSString * jsstr = spidermonkey()->JS_ValueToString(cx, id); + const char * str = spidermonkey()->JS_GetStringBytes(jsstr); + + for (index=0; indexJS_ValueToECMAInt32(cx, v, &tempval)) { + return false; + } + value = tempval; + return true; +} + +bool jsval2double(JSContext *cx, const jsval v, double &value) +{ + if (JSVAL_IS_NULL(v)) return false; + double tempval; + if (!spidermonkey()->JS_ValueToNumber(cx, v, &tempval)) { + return false; + } + value = tempval; + return true; +} + + +// FIXME: number of aliases must not be lower than max. This may lead to +// unsafe programming. 20050721 erikgors. +template +struct CoinVrmlJsSFHandler { + static JSBool get(JSContext * cx, JSObject * obj, jsval id, jsval * rval) + { + int index = getIndex(cx, id, aliases, max); + if (index == -1) { + return JS_TRUE; + } + + Base * data = (Base *)spidermonkey()->JS_GetPrivate(cx, obj); + assert(data != NULL); + basetype var = (*data)[index]; + SbBool ok = spidermonkey()->JS_NewDoubleValue(cx, (double)var, rval); + assert(ok && "JS_NewDoubleValue failed"); + return JS_TRUE; + } + + static JSBool set(JSContext * cx, JSObject * obj, jsval id, jsval * val) + { + int index = getIndex(cx, id, aliases, max); + if (index == -1) { + return JS_FALSE; + } + + Base * data = (Base *)spidermonkey()->JS_GetPrivate(cx, obj); + assert(data != NULL); + + // FIXME: number may be NaN, PositiveInfinity and NegativeInfinity. + // Should be checked for every time we run JS_ValueToNumber. + // ie: "blipp" will become NaN. 20050720 erikgors. + double number; + spidermonkey()->JS_ValueToNumber(cx, *val, &number); + (*data)[index] = (basetype)number; + return JS_TRUE; + } + + static JSBool constructor(JSContext * cx, JSObject * obj, + uintN argc, jsval * argv, jsval * rval) + { + basetype vals[max]; + + // convert all arguments to numbers or use defaultValues if missing + uint32_t i; + for (i=0; iJS_ValueToNumber(cx, argv[i], &val)) { + vals[i] = (basetype)val; + } + else { + spidermonkey()->JS_ReportError(cx, "WARNING: failed converting argument %d " + "to a double", i + 1); + } + } + } + + Base * data = new Base(vals); + spidermonkey()->JS_SetPrivate(cx, obj, data); + *rval = OBJECT_TO_JSVAL(obj); + return JS_TRUE; + } + static void destructor(JSContext * cx, JSObject * obj) + { + Base * data = (Base *)spidermonkey()->JS_GetPrivate(cx, obj); + // FIXME: We cannot assume this since the class object itself is an + // instance of this JSClass. kintel 20050804. + // assert(data != NULL); + delete data; + } +}; + +template +struct CoinVrmlJsMFHandler { + static JSBool constructor(JSContext * cx, JSObject * obj, uintN argc, jsval * argv, jsval * rval) + { + jsval * val = new jsval; + JSObject * array = spidermonkey()->JS_NewArrayObject(cx, 0, NULL); + *val = OBJECT_TO_JSVAL(array); + SbBool ok = spidermonkey()->JS_AddRoot(cx, val); + assert(ok && "JS_AddRoot failed"); + spidermonkey()->JS_SetPrivate(cx, obj, val); + + SFFieldClass * field = (SFFieldClass *)SFFieldClass::createInstance(); + uintN i; + + for (i=0; ijsval2field(argv[i], field)) { + SbBool ok = spidermonkey()->JS_SetElement(cx, array, i, &argv[i]); + assert(ok && "JS_SetElement failed"); + } + else { + // FIXME: should we insert a default value? 20050727 erikgors. + spidermonkey()->JS_ReportError(cx, "argv %d is of wrong type", i); + } + } + delete field; + return JS_TRUE; + } + + static void destructor(JSContext * cx, JSObject * obj) + { + jsval * val = (jsval *)spidermonkey()->JS_GetPrivate(cx, obj); + if (val != NULL) { + SbBool ok = spidermonkey()->JS_RemoveRoot(cx, val); + assert(ok && "JS_RemoveRoot failed"); + delete val; + } + } + + static JSObject * init(JSContext * cx, JSObject * obj) + { + return spidermonkey()->JS_InitClass(cx, obj, NULL, &desc->cls, + constructor, 0, + NULL, MFFunctions, NULL, NULL); + } + + static void resize(JSContext * cx, JSObject * array, uint32_t newLength) + { + uint32_t length; + SbBool ok = spidermonkey()->JS_GetArrayLength(cx, array, &length); + assert(ok && "JS_GetArrayLength failed"); + + if (length > newLength) { + spidermonkey()->JS_SetArrayLength(cx, array, newLength); + } + else { + SoType type = MFFieldClass::getClassTypeId(); + + // expand and fill with new objects + for (; lengthJS_NewStringCopyZ(cx, ""); + val = STRING_TO_JSVAL(str); + } + else if (type == SoMFNode::getClassTypeId()) { + // All elements not explicitly initialized are set to NULL + val = JSVAL_VOID; + } + else if (type == SoMFColor::getClassTypeId()) { + JSObject * newObj = + spidermonkey()->JS_NewObject(cx, &CoinVrmlJs::SFColor.cls, NULL, NULL); + assert(newObj != NULL); + SFColorHandler::constructor(cx, newObj, 0, NULL, &val); + val = OBJECT_TO_JSVAL(newObj); + } + else if (type == SoMFRotation::getClassTypeId()) { + JSObject * newObj = + spidermonkey()->JS_NewObject(cx, &CoinVrmlJs::SFRotation.cls, NULL, NULL); + assert(newObj != NULL); + SFRotationConstructor(cx, newObj, 0, NULL, &val); + val = OBJECT_TO_JSVAL(newObj); + } + else if (type == SoMFVec2f::getClassTypeId()) { + JSObject * newObj = + spidermonkey()->JS_NewObject(cx, &CoinVrmlJs::SFVec2f.cls, NULL, NULL); + assert(newObj != NULL); + SFVec2fHandler::constructor(cx, newObj, 0, NULL, &val); + val = OBJECT_TO_JSVAL(newObj); + } + else if (type == SoMFVec3f::getClassTypeId()) { + JSObject * newObj = + spidermonkey()->JS_NewObject(cx, &CoinVrmlJs::SFVec3f.cls, NULL, NULL); + assert(newObj != NULL); + SFVec3fHandler::constructor(cx, newObj, 0, NULL, &val); + val = OBJECT_TO_JSVAL(newObj); + } + else if (type == SoMFVec3d::getClassTypeId()) { + JSObject * newObj = + spidermonkey()->JS_NewObject(cx, &CoinVrmlJs::SFVec3d.cls, NULL, NULL); + assert(newObj != NULL); + SFVec3dHandler::constructor(cx, newObj, 0, NULL, &val); + val = OBJECT_TO_JSVAL(newObj); + } + else { + assert(0 && "this should not happen"); + } + SbBool ok = spidermonkey()->JS_SetElement(cx, array, length, &val); + assert(ok && "JS_SetElement failed"); + } + } + } + + static JSBool get(JSContext * cx, JSObject * obj, jsval id, jsval * rval) + { + + jsval * array = (jsval *)spidermonkey()->JS_GetPrivate(cx, obj); + + if (JSVAL_IS_INT(id)) { + assert(array != NULL); + int index = JSVAL_TO_INT(id); + return spidermonkey()->JS_GetElement(cx, JSVAL_TO_OBJECT(*array), index, rval); + } + else if (JSVAL_IS_STRING(id)) { + const char * str = spidermonkey()->JS_GetStringBytes(JSVAL_TO_STRING(id)); + if (SbName("length") == str) { + assert(array != NULL); + uint32_t length; + SbBool ok = spidermonkey()->JS_GetArrayLength(cx, JSVAL_TO_OBJECT(*array), &length); + assert(ok && "JS_GetArrayLength failed"); + *rval = INT_TO_JSVAL(length); + return JS_TRUE; + } + } + + return JS_TRUE; + } + + static JSBool set(JSContext * cx, JSObject * obj, jsval id, jsval * val) + { + jsval * array = (jsval *)spidermonkey()->JS_GetPrivate(cx, obj); + + if (JSVAL_IS_INT(id)) { + int index = JSVAL_TO_INT(id); + + // check for bounds + if (index < 0) { + return JS_FALSE; + } + + // resize if necessary + uint32_t length; + SbBool ok = spidermonkey()->JS_GetArrayLength(cx, JSVAL_TO_OBJECT(*array), &length); + assert(ok && "JS_GetArrayLength failed"); + if (index >= (int)length) { + resize(cx, JSVAL_TO_OBJECT(*array), index+1); + } + + SFFieldClass * field = (SFFieldClass *)SFFieldClass::createInstance(); + // Check if val is not of wrong type + if (SoJavaScriptEngine::getEngine(cx)->jsval2field(*val, field)) { + // assign it + SbBool ok = spidermonkey()->JS_SetElement(cx, JSVAL_TO_OBJECT(*array), index, val); + assert(ok && "JS_SetElement failed"); + return JS_TRUE; + } + delete field; + } + else if (JSVAL_IS_STRING(id)) { + const char * str = spidermonkey()->JS_GetStringBytes(JSVAL_TO_STRING(id)); + if (SbName("length") == str) { + double number; + spidermonkey()->JS_ValueToNumber(cx, *val, &number); + if (number < 0) { + spidermonkey()->JS_ReportError(cx, "RangeError: invalid array length"); + } + else { + resize(cx, JSVAL_TO_OBJECT(*array), (uint32_t)number); + } + return JS_TRUE; + } + } + + return JS_FALSE; + } + + + static SbBool jsval2field(JSContext * cx, const jsval v, SoField * f) + { + if (JSVAL_IS_OBJECT(v) && + spidermonkey()->JS_InstanceOf(cx, JSVAL_TO_OBJECT(v), &desc->cls, NULL)) { + JSObject * obj = JSVAL_TO_OBJECT(v); + jsval * array = (jsval *)spidermonkey()->JS_GetPrivate(cx, obj); + assert(array != NULL); + + jsval element; + uint32_t i; + uint32_t num; + JSBool ok = spidermonkey()->JS_GetArrayLength(cx, JSVAL_TO_OBJECT(*array), &num); + + SFFieldClass * field = (SFFieldClass *)SFFieldClass::createInstance(); + + for (i=0; iJS_GetElement(cx, obj, i, &element); + assert(ok); + + ok = SoJavaScriptEngine::getEngine(cx)->jsval2field(element, field); + assert(ok && "jsval2field failed"); + ((MFFieldClass *)f)->set1Value(i, field->getValue()); + } + delete field; + return TRUE; + } + return FALSE; + } + + static void field2jsval(JSContext * cx, const SoField * f, jsval * v) + { + JSObject * obj = spidermonkey()->JS_NewObject(cx, &desc->cls, NULL, NULL); + spidermonkey()->JS_DefineFunctions(cx, obj, desc->functions); + + int num = ((SoMField *)f)->getNum(); + jsval * vals = new jsval[num]; + + MFFieldClass & mf = *(MFFieldClass *)f; + + SFFieldClass * field = (SFFieldClass *)SFFieldClass::createInstance(); + for (int i=0; isetValue(mf[i]); + SbBool ok = SoJavaScriptEngine::getEngine(cx)->field2jsval(field, &vals[i]); + assert(ok && "field2jsval failed"); + } + + jsval rval; + constructor(cx, obj, num, vals, &rval); + *v = OBJECT_TO_JSVAL(obj); + delete field; + delete [] vals; + } +}; + +// ************************************************************************* +// constructors + +static JSBool SFRotationConstructor(JSContext * cx, JSObject * obj, + uintN argc, jsval * argv, jsval * rval) +{ + if (argc == 2) { + if (JSVAL_IS_SFVEC3F(cx, argv[0])) { + SbVec3f & vec = + *(SbVec3f *)spidermonkey()->JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0])); + + SbVec4f * data = new SbVec4f(); + spidermonkey()->JS_SetPrivate(cx, obj, data); + *rval = OBJECT_TO_JSVAL(obj); + // new SFRotation(SFVec3f fromVector, SFVec3f toVector) + if (JSVAL_IS_SFVEC3F(cx, argv[1])) { + SbVec3f & vec2 = + *(SbVec3f *)spidermonkey()->JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[1])); + + SbRotation rot(vec, vec2); + SbVec3f axis; + float rad; + rot.getValue(axis, rad); + + data->setValue(axis[0], axis[1], axis[2], rad); + return JS_TRUE; + } + // new SFRotation(SFVec3f axis, numeric angle) + else { + SbVec4f * data = new SbVec4f(); + spidermonkey()->JS_SetPrivate(cx, obj, data); + *rval = OBJECT_TO_JSVAL(obj); + + double number = 0.0; + spidermonkey()->JS_ValueToNumber(cx, argv[1], &number); + + data->setValue(vec[0], vec[1], vec[2], (float)number); + return JS_TRUE; + } + } + } + // new SFRotation(numeric x, numeric y, numeric z, numeric angle) + // Missing values default to 0.0, except y, which defaults to 1.0. + // + // SbRotation will default to 0.0, 0.0, 1.0, when angle is 0.0 + // So we use SbVec4f to hold values for SFRotation, since we need to support + // patterns like this: + // var colors = new MFColor(); + // colors.length = 10; + // colors[0].x = 1 + // colors[0].y = 0 + // colors[0].z = 0 + // colors[0].angle = 1.8 + // + // This will not work when SbRotation holds the values. 20050714 erikgors. + + return SFRotationHandler::constructor(cx, obj, argc, argv, rval); +} + +// ************************************************************************* +// functions + +static JSBool SFNode_ref(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + // Check if the JS object has already been garbage collected. This + // must be done to prevent a Java script from crashing the + // application. + if (garbagecollectedobjects->find(obj) != -1) { + if (SoJavaScriptEngine::debug()) + SoDebugError::postInfo("SFNode_ref", "WARNING! Trying to ref a deleted node."); + return JSVAL_FALSE; + } + + SoNode & node = *(SoNode *)spidermonkey()->JS_GetPrivate(cx, obj); + node.ref(); + return JSVAL_TRUE; +} + +static JSBool SFNode_unref(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + // Check if the JS object has already been garbage collected. This + // must be done to prevent a Java script from crashing the + // application. + if (garbagecollectedobjects->find(obj) != -1) { + if (SoJavaScriptEngine::debug()) + SoDebugError::postInfo("SFNode_unref", "WARNING! Trying to unref an already deleted node."); + return JSVAL_FALSE; + } + + SoNode & node = *(SoNode *)spidermonkey()->JS_GetPrivate(cx, obj); + node.unref(); + return JSVAL_TRUE; +} + +static void * +buffer_realloc(void * bufptr, size_t size) +{ + char *buffer = (char *)realloc(bufptr, size); + return buffer; +} + +static JSBool SFNode_toString(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + // Check if the JS object has already been garbage collected. This + // must be done to prevent a Java script from crashing the + // application. + if (garbagecollectedobjects->find(obj) != -1) { + if (SoJavaScriptEngine::debug()) + SoDebugError::postInfo("SFNode_toString", "WARNING! Trying to access " + "an already deleted node."); + return JSVAL_FALSE; + } + + SoNode *node = (SoNode *)spidermonkey()->JS_GetPrivate(cx, obj); + + SoOutput out; + out.setHeaderString("#VRML V2.0 utf8"); + size_t buffer_size = 1024; + void *buffer = (void *)malloc(buffer_size); + out.setBuffer(buffer, buffer_size, buffer_realloc); + + SoWriteAction wa(&out); + wa.apply(node); + + out.getBuffer(buffer, buffer_size); + + *rval = STRING_TO_JSVAL(spidermonkey()->JS_NewStringCopyZ(cx, + (char *)buffer)); + + free(buffer); + + return JSVAL_TRUE; +} + +static void SFNode_deleteCB(void * data, SoSensor * sensor) +{ + SoNode * node = ((SoNodeSensor *) sensor)->getAttachedNode(); + void * tmp; + if(!CoinVrmlJs_sensorinfohash->get((unsigned long) node, tmp)) { + assert(FALSE && "Trying to delete an unregistered SoNodeSensor. Internal error."); + return; + } + + CoinVrmlJs_SensorInfo * si = (CoinVrmlJs_SensorInfo *) tmp; + + // Delete all JSObjects which were connected to this SoNode + while (si->objects.getLength()) { + JSObject * obj = si->objects[0]; + garbagecollectedobjects->append(obj); + si->objects.removeFast(0); + } + + // Store the sensor-pointer so that it can be properly deleted later + nodesensorstobedeleted->append((SoNodeSensor *) sensor); + CoinVrmlJs_sensorinfohash->remove((unsigned long) node); + delete si; +} + +static void cleanupObsoleteNodeSensors(void) +{ + // Delete all SoNodeSensors which no longer have a node attached. + while(nodesensorstobedeleted->getLength() > 0) { + SoNodeSensor * ns = (SoNodeSensor *) (*nodesensorstobedeleted)[0]; + nodesensorstobedeleted->removeItem(ns); + delete ns; + } +} + +static JSBool SFVec2f_add(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + SbVec2f & vec1 = *(SbVec2f *)spidermonkey()->JS_GetPrivate(cx, obj); + + if (argc >= 1 && JSVAL_IS_SFVEC2F(cx, argv[0])) { + SbVec2f & vec2 = *(SbVec2f *)spidermonkey()->JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0])); + SbVec2f result = vec1 + vec2; + *rval = OBJECT_TO_JSVAL(SFVec2fFactory(cx, result)); + return JS_TRUE; + } + + return JS_FALSE; +} + +static JSBool SFVec3f_add(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + SbVec3f & vec1 = *(SbVec3f *)spidermonkey()->JS_GetPrivate(cx, obj); + + if (argc >= 1 && JSVAL_IS_SFVEC3F(cx, argv[0])) { + SbVec3f & vec2 = *(SbVec3f *)spidermonkey()->JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0])); + SbVec3f result = vec1 + vec2; + *rval = OBJECT_TO_JSVAL(SFVec3fFactory(cx, result)); + return JS_TRUE; + } + + return JS_FALSE; +} + +static JSBool SFVec3d_add(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + SbVec3d & vec1 = *(SbVec3d *)spidermonkey()->JS_GetPrivate(cx, obj); + + if (argc >= 1 && JSVAL_IS_SFVEC3D(cx, argv[0])) { + SbVec3d & vec2 = *(SbVec3d *)spidermonkey()->JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0])); + SbVec3d result = vec1 + vec2; + *rval = OBJECT_TO_JSVAL(SFVec3dFactory(cx, result)); + return JS_TRUE; + } + + return JS_FALSE; +} + +static JSBool SFVec2f_divide(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + SbVec2f & vec = *(SbVec2f *)spidermonkey()->JS_GetPrivate(cx, obj); + + double number; + if (argc >= 1 && jsval2double(cx, argv[0], number)) { + SbVec2f newVec = vec / (float)number; + *rval = OBJECT_TO_JSVAL(SFVec2fFactory(cx, newVec)); + return JS_TRUE; + } + return JS_FALSE; +} + +static JSBool SFVec3f_divide(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + SbVec3f & vec = *(SbVec3f *)spidermonkey()->JS_GetPrivate(cx, obj); + + double number; + if (argc >= 1 && jsval2double(cx, argv[0], number)) { + SbVec3f newVec = vec / (float)number; + *rval = OBJECT_TO_JSVAL(SFVec3fFactory(cx, newVec)); + return JS_TRUE; + } + return JS_FALSE; +} + +static JSBool SFVec3d_divide(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + SbVec3d & vec = *(SbVec3d *)spidermonkey()->JS_GetPrivate(cx, obj); + + double number; + if (argc >= 1 && jsval2double(cx, argv[0], number)) { + SbVec3d newVec = vec / number; + *rval = OBJECT_TO_JSVAL(SFVec3dFactory(cx, newVec)); + return JS_TRUE; + } + return JS_FALSE; +} + +static JSBool SFVec2f_dot(JSContext *cx, JSObject *obj, uintN argc, + jsval *argv, jsval *rval) +{ + SbVec2f & vec1 = *(SbVec2f *)spidermonkey()->JS_GetPrivate(cx, obj); + + if (argc >= 1 && JSVAL_IS_SFVEC2F(cx, argv[0])) { + SbVec2f & vec2 = *(SbVec2f *)spidermonkey()->JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0])); + + float dot = vec1.dot(vec2); + JSBool ok = spidermonkey()->JS_NewDoubleValue(cx, dot, rval); + return JS_TRUE; + } + return JS_FALSE; +} + +static JSBool SFVec3f_dot(JSContext *cx, JSObject *obj, uintN argc, + jsval *argv, jsval *rval) +{ + SbVec3f & vec = *(SbVec3f *)spidermonkey()->JS_GetPrivate(cx, obj); + + if (argc >= 1 && JSVAL_IS_SFVEC3F(cx, argv[0])) { + + SbVec3f & vec2 = *(SbVec3f *)spidermonkey()->JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0])); + + float dot = vec.dot(vec2); + JSBool ok = spidermonkey()->JS_NewDoubleValue(cx, dot, rval); + return JS_TRUE; + } + return JS_FALSE; +} + +static JSBool SFVec3d_dot(JSContext *cx, JSObject *obj, uintN argc, + jsval *argv, jsval *rval) +{ + SbVec3d & vec = *(SbVec3d *)spidermonkey()->JS_GetPrivate(cx, obj); + + if (argc >= 1 && JSVAL_IS_SFVEC3D(cx, argv[0])) { + + SbVec3d & vec2 = *(SbVec3d *)spidermonkey()->JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0])); + + double dot = vec.dot(vec2); + JSBool ok = spidermonkey()->JS_NewDoubleValue(cx, dot, rval); + return JS_TRUE; + } + return JS_FALSE; +} + +static JSBool SFVec2_length(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + SbVec2f * vec = (SbVec2f *)spidermonkey()->JS_GetPrivate(cx, obj); + JSBool ok = spidermonkey()->JS_NewDoubleValue(cx, vec->length(), rval); + return JS_TRUE; +} + +static JSBool SFVec3f_length(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + SbVec3f * vec = (SbVec3f *)spidermonkey()->JS_GetPrivate(cx, obj); + JSBool ok = spidermonkey()->JS_NewDoubleValue(cx, vec->length(), rval); + return JS_TRUE; +} + +static JSBool SFVec3d_length(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + SbVec3d * vec = (SbVec3d *)spidermonkey()->JS_GetPrivate(cx, obj); + JSBool ok = spidermonkey()->JS_NewDoubleValue(cx, vec->length(), rval); + return JS_TRUE; +} + +static JSBool SFVec2f_multiply(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + + SbVec2f & vec = *(SbVec2f *)spidermonkey()->JS_GetPrivate(cx, obj); + + if (argc >= 1 && JSVAL_IS_NUMBER(argv[0])) { + double number; + spidermonkey()->JS_ValueToNumber(cx, argv[0], &number); + + SbVec2f newVec = vec * (float)number; + + *rval = OBJECT_TO_JSVAL(SFVec2fFactory(cx, newVec)); + + return JS_TRUE; + } + return JS_FALSE; +} + +static JSBool SFVec3f_multiply(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + SbVec3f & vec = *(SbVec3f *)spidermonkey()->JS_GetPrivate(cx, obj); + + double number; + if (argc >= 1 && jsval2double(cx, argv[0], number)) { + SbVec3f newVec = vec * (float)number; + *rval = OBJECT_TO_JSVAL(SFVec3fFactory(cx, newVec)); + return JS_TRUE; + } + return JS_FALSE; +} + +static JSBool SFVec3d_multiply(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + SbVec3d & vec = *(SbVec3d *)spidermonkey()->JS_GetPrivate(cx, obj); + + double number; + if (argc >= 1 && jsval2double(cx, argv[0], number)) { + SbVec3d newVec = vec * number; + *rval = OBJECT_TO_JSVAL(SFVec3dFactory(cx, newVec)); + return JS_TRUE; + } + return JS_FALSE; +} + +static JSBool SFVec2f_normalize(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + SbVec2f vec = *(SbVec2f *)spidermonkey()->JS_GetPrivate(cx, obj); + vec.normalize(); + *rval = OBJECT_TO_JSVAL(SFVec2fFactory(cx, vec)); + return JS_TRUE; +} + +static JSBool SFVec3f_normalize(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + SbVec3f vec = *(SbVec3f *)spidermonkey()->JS_GetPrivate(cx, obj); + vec.normalize(); + *rval = OBJECT_TO_JSVAL(SFVec3fFactory(cx, vec)); + return JS_TRUE; +} + +static JSBool SFVec3d_normalize(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + SbVec3d vec = *(SbVec3d *)spidermonkey()->JS_GetPrivate(cx, obj); + vec.normalize(); + *rval = OBJECT_TO_JSVAL(SFVec3dFactory(cx, vec)); + return JS_TRUE; +} + +static JSBool SFVec3f_negate(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + SbVec3f vec = *(SbVec3f *)spidermonkey()->JS_GetPrivate(cx, obj); + vec.negate(); + *rval = OBJECT_TO_JSVAL(SFVec3fFactory(cx, vec)); + return JS_TRUE; +} + +static JSBool SFVec3d_negate(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + SbVec3d vec = *(SbVec3d *)spidermonkey()->JS_GetPrivate(cx, obj); + vec.negate(); + *rval = OBJECT_TO_JSVAL(SFVec3dFactory(cx, vec)); + return JS_TRUE; +} + +static JSBool SFVec2f_subtract(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + SbVec2f & vec1 = *(SbVec2f *)spidermonkey()->JS_GetPrivate(cx, obj); + + if (argc >= 1 && JSVAL_IS_SFVEC2F(cx, argv[0])) { + SbVec2f & vec2 = *(SbVec2f *)spidermonkey()->JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0])); + SbVec2f result = vec1 - vec2; + *rval = OBJECT_TO_JSVAL(SFVec2fFactory(cx, result)); + return JS_TRUE; + } + return JS_FALSE; +} + +static JSBool SFVec3f_subtract(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + SbVec3f & vec1 = *(SbVec3f *)spidermonkey()->JS_GetPrivate(cx, obj); + + if (argc >= 1 && JSVAL_IS_SFVEC3F(cx, argv[0])) { + SbVec3f & vec2 = *(SbVec3f *)spidermonkey()->JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0])); + SbVec3f result = vec1 - vec2; + *rval = OBJECT_TO_JSVAL(SFVec3fFactory(cx, result)); + return JS_TRUE; + } + + return JS_FALSE; +} + +static JSBool SFVec3d_subtract(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + SbVec3d & vec1 = *(SbVec3d *)spidermonkey()->JS_GetPrivate(cx, obj); + + if (argc >= 1 && JSVAL_IS_SFVEC3D(cx, argv[0])) { + SbVec3d & vec2 = *(SbVec3d *)spidermonkey()->JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0])); + SbVec3d result = vec1 - vec2; + *rval = OBJECT_TO_JSVAL(SFVec3dFactory(cx, result)); + return JS_TRUE; + } + + return JS_FALSE; +} + +static JSBool SFColor_setHSV(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + if (argc != 3) { + return JS_FALSE; + } + SbColor & color = *(SbColor *)spidermonkey()->JS_GetPrivate(cx, obj); + + float vals[3]; + int i; + + for (i=0; i<3; ++i) { + double number; + spidermonkey()->JS_ValueToNumber(cx, argv[i], &number); + vals[i] = (float)number; + } + + color.setHSVValue(vals); + + *rval = JSVAL_VOID; + return JS_TRUE; +} + +static JSBool SFColor_getHSV(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + SbColor & color = *(SbColor *)spidermonkey()->JS_GetPrivate(cx, obj); + + float vals[3]; + color.getHSVValue(vals); + + jsval vector[3]; + for (int i=0; i<3; ++i) { + spidermonkey()->JS_NewDoubleValue(cx, vals[i], &vector[i]); + } + + *rval = OBJECT_TO_JSVAL(spidermonkey()->JS_NewArrayObject(cx, 3, vector)); + + return JS_TRUE; +} + +static JSBool SFRotation_getAxis(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + SbVec4f & rot = *(SbVec4f *)spidermonkey()->JS_GetPrivate(cx, obj); + SbVec3f axis(rot[0], rot[1], rot[2]); + *rval = OBJECT_TO_JSVAL(SFVec3fFactory(cx, axis)); + return JS_TRUE; +} + +static JSBool SFRotation_inverse(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + SbVec4f & rot = *(SbVec4f *)spidermonkey()->JS_GetPrivate(cx, obj); + + SbVec3f axis(rot[0], rot[1], rot[2]); + SbRotation newRot(axis, rot[3]); + newRot.invert(); + + *rval = OBJECT_TO_JSVAL(SFRotationFactory(cx, newRot)); + return JS_TRUE; +} + +static JSBool SFRotation_multiply(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + SbVec4f & vec1 = *(SbVec4f *)spidermonkey()->JS_GetPrivate(cx, obj); + + if (argc >= 1 && JSVAL_IS_SFROTATION(cx, argv[0])) { + SbVec4f & vec2 = *(SbVec4f *)spidermonkey()->JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0])); + SbVec3f axis1(vec1[0], vec1[1], vec1[2]); + SbVec3f axis2(vec2[0], vec2[1], vec2[2]); + SbRotation result = SbRotation(axis1, vec1[3]) * SbRotation(axis2, vec2[3]); + + *rval = OBJECT_TO_JSVAL(SFRotationFactory(cx, result)); + return JS_TRUE; + } + return JS_FALSE; +} + +static JSBool SFRotation_multVec(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + SbVec4f & vec = *(SbVec4f *)spidermonkey()->JS_GetPrivate(cx, obj); + SbVec3f axis(vec[0], vec[1], vec[2]); + SbRotation rot(axis, vec[3]); + + if (argc >= 1 && JSVAL_IS_SFVEC3F(cx, argv[0])) { + SbVec3f & src = *(SbVec3f *)spidermonkey()->JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0])); + SbVec3f dst; + rot.multVec(src, dst); + + *rval = OBJECT_TO_JSVAL(SFVec3fFactory(cx, dst)); + return JS_TRUE; + } + return JS_FALSE; +} + +static JSBool SFRotation_setAxis(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + SbVec4f & rot = *(SbVec4f *)spidermonkey()->JS_GetPrivate(cx, obj); + + if (argc >= 1 && JSVAL_IS_SFVEC3F(cx, argv[0])) { + SbVec3f & axis = *(SbVec3f *)spidermonkey()->JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0])); + rot[0] = axis[0]; + rot[1] = axis[1]; + rot[2] = axis[2]; + + *rval = JSVAL_VOID; + return JS_TRUE; + } + return JS_FALSE; +} + +static JSBool SFRotation_slerp(JSContext * cx, JSObject * obj, uintN argc, + jsval * argv, jsval * rval) +{ + SbVec4f & vec = *(SbVec4f *)spidermonkey()->JS_GetPrivate(cx, obj); + SbVec3f axis(vec[0], vec[1], vec[2]); + SbRotation rot(axis, vec[3]); + + double number; + if (argc >= 2 && JSVAL_IS_SFROTATION(cx, argv[0]) && jsval2double(cx, argv[1], number)) { + SbVec4f & vec2 = *(SbVec4f *)spidermonkey()->JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0])); + SbVec3f axis2(vec2[0], vec2[1], vec2[2]); + SbRotation dest(axis2, vec2[3]); + + SbRotation result = SbRotation::slerp(rot, dest, (float)number); + + *rval = OBJECT_TO_JSVAL(SFRotationFactory(cx, result)); + return JS_TRUE; + } + return JS_FALSE; +} + +static JSFunctionSpec SFNodeFunctions[] = { + {"ref", SFNode_ref, 0, 0, 0}, + {"unref", SFNode_unref, 0, 0, 0}, + {"toString", SFNode_toString, 0, 0, 0}, + {NULL, NULL, 0, 0, 0} +}; + +static JSFunctionSpec SFVec2fFunctions[] = { + {"add", SFVec2f_add, 1, 0, 0}, + {"divide", SFVec2f_divide, 1, 0, 0}, + {"dot", SFVec2f_dot, 1, 0, 0}, + {"length", SFVec2_length, 0, 0, 0}, + {"multiply", SFVec2f_multiply, 1, 0, 0}, + {"normalize", SFVec2f_normalize, 0, 0, 0}, + {"subtract", SFVec2f_subtract, 1, 0, 0}, + {NULL, NULL, 0, 0, 0} +}; + +static JSFunctionSpec SFVec3fFunctions[] = { + {"add", SFVec3f_add, 1, 0, 0}, + {"divide", SFVec3f_divide, 1, 0, 0}, + {"dot", SFVec3f_dot, 1, 0, 0}, + {"length", SFVec3f_length, 0, 0, 0}, + {"multiply", SFVec3f_multiply, 1, 0, 0}, + {"normalize", SFVec3f_normalize, 0, 0, 0}, + {"negate", SFVec3f_negate, 0, 0, 0}, + {"subtract", SFVec3f_subtract, 1, 0, 0}, + {NULL, NULL, 0, 0, 0} +}; + +static JSFunctionSpec SFVec3dFunctions[] = { + {"add", SFVec3d_add, 1, 0, 0}, + {"divide", SFVec3d_divide, 1, 0, 0}, + {"dot", SFVec3d_dot, 1, 0, 0}, + {"length", SFVec3d_length, 0, 0, 0}, + {"multiply", SFVec3d_multiply, 1, 0, 0}, + {"normalize", SFVec3d_normalize, 0, 0, 0}, + {"negate", SFVec3d_negate, 0, 0, 0}, + {"subtract", SFVec3d_subtract, 1, 0, 0}, + {NULL, NULL, 0, 0, 0} +}; + +static JSFunctionSpec SFColorFunctions[] = { + {"setHSV", SFColor_setHSV, 3, 0, 0}, + {"getHSV", SFColor_getHSV, 0, 0, 0}, + {NULL, NULL, 0, 0, 0} +}; + +static JSFunctionSpec SFRotationFunctions[] = { + {"getAxis", SFRotation_getAxis, 0, 0, 0}, + {"inverse", SFRotation_inverse, 0, 0, 0}, + {"multiply", SFRotation_multiply, 1, 0, 0}, + {"multVec", SFRotation_multVec, 1, 0, 0}, + {"setAxis", SFRotation_setAxis, 1, 0, 0}, + {"slerp", SFRotation_slerp, 2, 0, 0}, + {NULL, NULL, 0, 0, 0} +}; + +// ************************************************************************* +// factory + +static JSObject * SFColorFactory(JSContext * cx, const SbColor & self) +{ + JSObject * obj = + spidermonkey()->JS_NewObject(cx, &CoinVrmlJs::SFColor.cls, NULL, NULL); + spidermonkey()->JS_DefineFunctions(cx, obj, SFColorFunctions); + + SbColor * color = new SbColor(self); + spidermonkey()->JS_SetPrivate(cx, obj, color); + + return obj; +} + +static JSObject * SFRotationFactory(JSContext * cx, const SbRotation & self) +{ + JSObject * obj = + spidermonkey()->JS_NewObject(cx, &CoinVrmlJs::SFRotation.cls, NULL, NULL); + spidermonkey()->JS_DefineFunctions(cx, obj, SFRotationFunctions); + + SbVec3f axis; + float angle; + self.getValue(axis, angle); + SbVec4f * data = new SbVec4f(axis[0], axis[1], axis[2], angle); + spidermonkey()->JS_SetPrivate(cx, obj, data); + + return obj; +} + +static JSObject * SFVec2fFactory(JSContext * cx, const SbVec2f & self) +{ + JSObject * obj = + spidermonkey()->JS_NewObject(cx, &CoinVrmlJs::SFVec2f.cls, NULL, NULL); + spidermonkey()->JS_DefineFunctions(cx, obj, SFVec2fFunctions); + + SbVec2f * data = new SbVec2f(self); + spidermonkey()->JS_SetPrivate(cx, obj, data); + return obj; +} + +static JSObject * SFVec3fFactory(JSContext * cx, const SbVec3f & self) +{ + JSObject * obj = + spidermonkey()->JS_NewObject(cx, &CoinVrmlJs::SFVec3f.cls, NULL, NULL); + spidermonkey()->JS_DefineFunctions(cx, obj, SFVec3fFunctions); + + SbVec3f * data = new SbVec3f(self); + spidermonkey()->JS_SetPrivate(cx, obj, data); + + return obj; +} + +static JSObject * SFVec3dFactory(JSContext * cx, const SbVec3d & self) +{ + JSObject * obj = + spidermonkey()->JS_NewObject(cx, &CoinVrmlJs::SFVec3d.cls, NULL, NULL); + spidermonkey()->JS_DefineFunctions(cx, obj, SFVec3dFunctions); + + SbVec3d * data = new SbVec3d(self); + spidermonkey()->JS_SetPrivate(cx, obj, data); + + return obj; +} + +static JSObject * SFVec2f_init(JSContext * cx, JSObject * obj) +{ + return spidermonkey()->JS_InitClass(cx, obj, NULL, &CoinVrmlJs::SFVec2f.cls, + SFVec2fHandler::constructor, 0, + NULL, SFVec2fFunctions, NULL, NULL); +} + +static JSObject * SFVec3f_init(JSContext * cx, JSObject * obj) +{ + return spidermonkey()->JS_InitClass(cx, obj, NULL, &CoinVrmlJs::SFVec3f.cls, + SFVec3fHandler::constructor, 0, + NULL, SFVec3fFunctions, NULL, NULL); +} + +static JSObject * SFVec3d_init(JSContext * cx, JSObject * obj) +{ + return spidermonkey()->JS_InitClass(cx, obj, NULL, &CoinVrmlJs::SFVec3d.cls, + SFVec3dHandler::constructor, 0, + NULL, SFVec3dFunctions, NULL, NULL); +} + +static JSObject * SFColor_init(JSContext * cx, JSObject * obj) +{ + return spidermonkey()->JS_InitClass(cx, obj, NULL, &CoinVrmlJs::SFColor.cls, + SFColorHandler::constructor, 0, + NULL, SFColorFunctions, NULL, NULL); +} + +static JSObject * SFRotation_init(JSContext * cx, JSObject * obj) +{ + return spidermonkey()->JS_InitClass(cx, obj, NULL, &CoinVrmlJs::SFRotation.cls, + SFRotationConstructor, 0, + NULL, SFRotationFunctions, NULL, NULL); +} + +// ************************************************************************* +// SFNode + +static JSBool SFNode_get(JSContext * cx, JSObject * obj, jsval id, jsval * rval) +{ + + if (garbagecollectedobjects->find(obj) != -1) { + spidermonkey()->JS_ReportError(cx, "Trying to access an object with refcount=0."); + return JS_FALSE; + } + + SoNode * container = (SoNode *)spidermonkey()->JS_GetPrivate(cx, obj); + + if (container == NULL) { + // this will only happen when JS_NewObject calls "constructor" + // or the node is "undefined" + + if (JSVAL_IS_STRING(id)) { + const char * str = spidermonkey()->JS_GetStringBytes(JSVAL_TO_STRING(id)); + if (SbName("constructor") == str) { + return JS_TRUE; + } + } + spidermonkey()->JS_ReportError(cx, "node is undefined"); + return JS_FALSE; + } + + if (JSVAL_IS_STRING(id)) { + SbString str(spidermonkey()->JS_GetStringBytes(JSVAL_TO_STRING(id))); + + SoField * out = container->getField(SbName(str)); + + int len = str.getLength(); + static const char post[] = "_changed"; + static const size_t postLen = sizeof(post) - 1; + + if (out == NULL && len > (int)postLen && + str.getSubString(len - postLen) == post) { + out = container->getField(SbName(str.getSubString(0, len - postLen - 1))); + } + + if (out != NULL) { + SoJavaScriptEngine::getEngine(cx)->field2jsval(out, rval); + return JS_TRUE; + } + } + + /* Note: If we're unable to find the field, we return JS_TRUE + instead of JS_FALSE, which might seem as the logical choice + for indicating a failure. If we return JS_FALSE, execution of + the script will halt. One side-effect of this is that it is not + possible to extend the SFNode JavaScript object by adding + properties, which can be very useful in some cases. This is also + more in line with the JavaScript philosophy that one can + dynamically add and remove properties for any object at any time. + + 2005-11-23 thammer. + + Update: We should look more closely into the return values + JS_TRUE / JS_FALSE for all getters and setters, and possibly for + other functions as well. It might be more robust to report the + error (using JS_ReportError) and return JS_TRUE to allow the + script to continue running than to abort the script. + + 2006-06-21 thammer. + */ + return JS_TRUE; +} + +static JSBool SFNode_set(JSContext * cx, JSObject * obj, jsval id, jsval * rval) +{ + SoNode * container = (SoNode *)spidermonkey()->JS_GetPrivate(cx, obj); + + if (container == NULL) { + spidermonkey()->JS_ReportError(cx, "node is undefined"); + return JS_FALSE; + } + + if (JSVAL_IS_STRING(id)) { + SbString str(spidermonkey()->JS_GetStringBytes(JSVAL_TO_STRING(id))); + + SoField * in = container->getField(SbName(str)); + + int len = str.getLength(); + static const char pre[] = "set_"; + static const size_t preLen = sizeof(pre) - 1; + + if (in == NULL && len > (int)preLen && + str.getSubString(0, preLen - 1) == pre) { + in = container->getField(SbName(str.getSubString(preLen))); + } + + if (in != NULL) { + SoJavaScriptEngine::getEngine(cx)->jsval2field(*rval, in); + if (SoJavaScriptEngine::debug()) { + SoDebugError::postInfo("SFNode_set", "setting field %s", str.getString()); + } + } else if (SoJavaScriptEngine::debug()) + SoDebugError::postWarning("SFNode_set", "no such field %s", str.getString()); + } + + // See note in SFNode_get() about return value. 2005-11-23 thammer. + return JS_TRUE; +} + +static void SFNodeDestructor(JSContext * cx, JSObject * obj) +{ + // Delete all SoNodeSensors which no longer has a node attached. + cleanupObsoleteNodeSensors(); + if(garbagecollectedobjects->find(obj) != -1) { // Pointer is marked as garbage-collected + garbagecollectedobjects->removeItem(obj); + } + + SoNode * container = (SoNode *)spidermonkey()->JS_GetPrivate(cx, obj); + // FIXME: We cannot assume this since the class object itself is an + // instance of this JSClass. kintel 20050804. + // assert(container != NULL); + if (SoJavaScriptEngine::getEngine(cx)->getAutoNodeUnrefState()) + if (container) container->unref(); +} + +// Called via coin_atexit() when Coin exits. +static void deleteSensorInfoHash(void) +{ + CoinVrmlJs_sensorinfohash->clear(); + delete CoinVrmlJs_sensorinfohash; +} + +/* + Attach an SoNodeSensor to node. Adds a 'delete callback' to the + sensor which includes the 'obj' parameter. +*/ +static void attachSensorToNode(SoNode * node, JSObject * obj) +{ + // Has the hash-table been initialized? + if (!CoinVrmlJs_sensorinfohash) { + CoinVrmlJs_sensorinfohash = new SbHash ; + coin_atexit(deleteSensorInfoHash, CC_ATEXIT_NORMAL); + } + + // Is a sensor already attached to this SoNode? + void * tmp; + if (CoinVrmlJs_sensorinfohash->get((unsigned long) node, tmp)) { + CoinVrmlJs_SensorInfo * si = (CoinVrmlJs_SensorInfo *) tmp; + si->objects.append(obj); + } + else { + SoNodeSensor * ns = new SoNodeSensor(); + ns->setDeleteCallback(SFNode_deleteCB, obj); + ns->attach(node); + CoinVrmlJs_SensorInfo * si = new CoinVrmlJs_SensorInfo; + si->objects.append(obj); + CoinVrmlJs_sensorinfohash->put((unsigned long) node, si); + } +} + +static JSObject * SFNodeFactory(JSContext * cx, SoNode * container) +{ + // Delete all SoNodeSensors which no longer has a node attached. + cleanupObsoleteNodeSensors(); + + JSObject * obj = spidermonkey()->JS_NewObject(cx, &CoinVrmlJs::SFNode.cls, NULL, NULL); + + if(garbagecollectedobjects->find(obj) != -1) // Pointer has been used before. Remove from list. + garbagecollectedobjects->removeItem(obj); + + spidermonkey()->JS_SetPrivate(cx, obj, container); + spidermonkey()->JS_DefineFunctions(cx, obj, SFNodeFunctions); + + // FIXME: If the node has enums, define them here. 2007-03-08 thammer. + + attachSensorToNode(container, obj); + + if (SoJavaScriptEngine::getEngine(cx)->getAutoNodeUnrefState()) + container->ref(); + + return obj; +} + +static JSBool SFNodeConstructor(JSContext * cx, JSObject * obj, + uintN argc, jsval * argv, jsval *rval) +{ + // Delete all SoNodeSensors which no longer has a node attached. + cleanupObsoleteNodeSensors(); + + // spidermonkey ignores the return value + if (argc >= 1 && JSVAL_IS_STRING(argv[0])) { + JSString * js = JSVAL_TO_STRING(argv[0]); + char * str = spidermonkey()->JS_GetStringBytes(js); + size_t len = spidermonkey()->JS_GetStringLength(js); + + // FIXME: what about UTF8? 20050701 erikgors. + + if (SoJavaScriptEngine::debug()) { + SoDebugError::postInfo("SFNodeConstructor", + "creating new node with str = '%s'", str); + } + + SoInput input; + const char * array[2]; + array[0] = str; + array[1] = NULL; + input.setStringArray(array); + + SoGroup * group; + + if (input.isFileVRML2()) + group = SoDB::readAllVRML(&input); + else + group = SoDB::readAll(&input); + + if (group == NULL) { + spidermonkey()->JS_ReportError(cx, "input is not legal VRML string"); + return JS_FALSE; + } + if (group->getNumChildren() == 0) { + spidermonkey()->JS_ReportError(cx, "no top-level node, result is undefined"); + *rval = JSVAL_VOID; + return JS_FALSE; + } + + if(garbagecollectedobjects->find(obj) != -1) { // Pointer has been used before. Remove from list. + garbagecollectedobjects->removeItem(obj); + } + + attachSensorToNode(group, obj); + + if (SoJavaScriptEngine::getEngine(cx)->getAutoNodeUnrefState()) + group->ref(); + + spidermonkey()->JS_SetPrivate(cx, obj, group); + spidermonkey()->JS_DefineFunctions(cx, obj, SFNodeFunctions); + + return JS_TRUE; + } + return JS_FALSE; +} + +static JSObject * SFNode_init(JSContext * cx, JSObject * obj) +{ + return spidermonkey()->JS_InitClass(cx, obj, NULL, &CoinVrmlJs::SFNode.cls, + SFNodeConstructor, 0, + NULL, NULL, NULL, NULL); +} + + +// ************************************************************************* +// jsval2field + +static SbBool SFBool_jsval2field(JSContext * cx, const jsval v, SoField * f) +{ + if (JSVAL_IS_BOOLEAN(v)) { + const SbBool b = JSVAL_TO_BOOLEAN(v); + ((SoSFBool *)f)->setValue(b); + return TRUE; + } + else { + JSBool b; + if (spidermonkey()->JS_ValueToBoolean(cx, v, &b)) { + ((SoSFBool *)f)->setValue(b); + return TRUE; + } + } + return FALSE; +} + +static SbBool SFColor_jsval2field(JSContext * cx, const jsval v, SoField * f) +{ + if (JSVAL_IS_SFCOLOR(cx, v)) { + SbColor * color = (SbColor *)spidermonkey()->JS_GetPrivate(cx, JSVAL_TO_OBJECT(v)); + assert(color != NULL); + ((SoSFColor *)f)->setValue(*color); + return TRUE; + } + return FALSE; +} + +static SbBool SFFloat_jsval2field(JSContext * cx, const jsval v, SoField * f) +{ + double number; + if (jsval2double(cx, v, number)) { + ((SoSFFloat *)f)->setValue((float)number); + return TRUE; + } + return FALSE; +} + +static SbBool SFInt32_jsval2field(JSContext * cx, const jsval v, SoField * f) +{ + int32_t val; + if (jsval2int(cx, v, val)) { + ((SoSFInt32 *)f)->setValue(val); + return TRUE; + } + return FALSE; +} + +static SbBool SFEnum_jsval2field(JSContext * cx, const jsval v, SoField * f) +{ + int32_t val; + if (jsval2int(cx, v, val)) { + ((SoSFInt32 *)f)->setValue(val); + return TRUE; + } + return FALSE; +} + +static SbBool SFNode_jsval2field(JSContext * cx, const jsval v, SoField * f) +{ + if (JSVAL_IS_NULL(v)) { + ((SoSFNode *)f)->setValue(NULL); + return TRUE; + } + if (JSVAL_IS_OBJECT(v) && + spidermonkey()->JS_InstanceOf(cx, JSVAL_TO_OBJECT(v), &CoinVrmlJs::SFNode.cls, NULL)) { + SoNode * node = (SoNode *)spidermonkey()->JS_GetPrivate(cx, JSVAL_TO_OBJECT(v)); + ((SoSFNode *)f)->setValue(node); + return TRUE; + } + return FALSE; +} + +static SbBool SFRotation_jsval2field(JSContext * cx, const jsval v, SoField * f) +{ + if (JSVAL_IS_SFROTATION(cx, v)) { + SbVec4f * rot = (SbVec4f *)spidermonkey()->JS_GetPrivate(cx, JSVAL_TO_OBJECT(v)); + assert(rot != NULL); + SbVec3f axis((*rot)[0], (*rot)[1], (*rot)[2]); + ((SoSFRotation *)f)->setValue(SbRotation(axis, (*rot)[3])); + return TRUE; + } + return FALSE; +} + +static SbBool SFString_jsval2field(JSContext * cx, const jsval v, SoField * f) +{ + if (JSVAL_IS_STRING(v)) { + const char * str = spidermonkey()->JS_GetStringBytes(JSVAL_TO_STRING(v)); + ((SoSFString *)f)->setValue(str); + return TRUE; + } + return FALSE; +} + +static SbBool SFTime_jsval2field(JSContext * cx, const jsval v, SoField * f) +{ + double number; + if (jsval2double(cx, v, number)) { + spidermonkey()->JS_ValueToNumber(cx, v, &number); + ((SoSFTime*)f)->setValue(SbTime(number)); + return TRUE; + } + return FALSE; +} + +static SbBool SFVec2f_jsval2field(JSContext * cx, const jsval v, SoField * f) +{ + if (JSVAL_IS_SFVEC2F(cx, v)) { + SbVec2f * vec = (SbVec2f *)spidermonkey()->JS_GetPrivate(cx, JSVAL_TO_OBJECT(v)); + assert(vec != NULL); + ((SoSFVec2f *)f)->setValue(*vec); + return TRUE; + } + return FALSE; +} + +static SbBool SFVec3f_jsval2field(JSContext * cx, const jsval v, SoField * f) +{ + if (JSVAL_IS_SFVEC3F(cx, v)) { + SbVec3f * vec = (SbVec3f *)spidermonkey()->JS_GetPrivate(cx, JSVAL_TO_OBJECT(v)); + assert(vec != NULL); + ((SoSFVec3f *)f)->setValue(*vec); + return TRUE; + } + return FALSE; +} + +static SbBool SFVec3d_jsval2field(JSContext * cx, const jsval v, SoField * f) +{ + if (JSVAL_IS_SFVEC3D(cx, v)) { + SbVec3d * vec = (SbVec3d *)spidermonkey()->JS_GetPrivate(cx, JSVAL_TO_OBJECT(v)); + assert(vec != NULL); + ((SoSFVec3d *)f)->setValue(*vec); + return TRUE; + } + return FALSE; +} + +// ************************************************************************* +// field2jsval + +static void SFBool_field2jsval(JSContext * cx, const SoField * f, jsval * v) +{ + const SbBool val = ((SoSFBool *)f)->getValue(); + *v = BOOLEAN_TO_JSVAL(val); +} + +static void SFColor_field2jsval(JSContext * cx, const SoField * f, jsval *v) +{ + const SbColor & val = ((SoSFColor *)f)->getValue(); + JSObject * obj = SFColorFactory(cx, val); + *v = OBJECT_TO_JSVAL(obj); +} + +static void SFFloat_field2jsval(JSContext * cx, const SoField * f, jsval * v) +{ + const float val = ((SoSFFloat *)f)->getValue(); + JSBool ok = spidermonkey()->JS_NewDoubleValue(cx, val, v); +} + +static void SFInt32_field2jsval(JSContext * cx, const SoField * f, jsval * v) +{ + const int32_t val = ((SoSFInt32 *)f)->getValue(); + *v = INT_TO_JSVAL(val); +} + +static void SFEnum_field2jsval(JSContext * cx, const SoField * f, jsval * v) +{ + const int32_t val = ((SoSFInt32 *)f)->getValue(); + *v = INT_TO_JSVAL(val); +} + +static void SFNode_field2jsval(JSContext * cx, const SoField * f, jsval * v) +{ + SoNode * node = ((SoSFNode *)f)->getValue(); + if (node == NULL) + *v = JSVAL_NULL; + else { + JSObject * obj = SFNodeFactory(cx, node); + *v = OBJECT_TO_JSVAL(obj); + } +} + +static void SFRotation_field2jsval(JSContext * cx, const SoField * f, jsval *v) +{ + const SbRotation & val = ((SoSFRotation *)f)->getValue(); + JSObject * obj = SFRotationFactory(cx, val); + *v = OBJECT_TO_JSVAL(obj); +} + +static void SFString_field2jsval(JSContext * cx, const SoField * f, jsval * v) +{ + const SbString & val = ((SoSFString *)f)->getValue(); + JSString * str = spidermonkey()->JS_NewStringCopyZ(cx, val.getString()); + *v = STRING_TO_JSVAL(str); +} + +static void SFTime_field2jsval(JSContext * cx, const SoField * f, jsval * v) +{ + const SbTime & time = ((SoSFTime *)f)->getValue(); + spidermonkey()->JS_NewDoubleValue(cx, time.getValue(), v); +} + +static void SFVec2f_field2jsval(JSContext * cx, const SoField * f, jsval *v) +{ + const SbVec2f & val = ((SoSFVec2f *)f)->getValue(); + JSObject * obj = SFVec2fFactory(cx, val); + *v = OBJECT_TO_JSVAL(obj); +} + +static void SFVec3f_field2jsval(JSContext * cx, const SoField * f, jsval *v) +{ + const SbVec3f & val = ((SoSFVec3f *)f)->getValue(); + JSObject * obj = SFVec3fFactory(cx, val); + *v = OBJECT_TO_JSVAL(obj); +} + +static void SFVec3d_field2jsval(JSContext * cx, const SoField * f, jsval *v) +{ + const SbVec3d & val = ((SoSFVec3d *)f)->getValue(); + JSObject * obj = SFVec3dFactory(cx, val); + *v = OBJECT_TO_JSVAL(obj); +} + +// ************************************************************************* +// classes + +CoinVrmlJs::ClassDescriptor CoinVrmlJs::SFColor = { + { + "SFColor", JSCLASS_HAS_PRIVATE, NULL, NULL, + SFColorHandler::get, SFColorHandler::set, + NULL, NULL, NULL, + SFColorHandler::destructor, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + SFColorFunctions +}; + +CoinVrmlJs::ClassDescriptor CoinVrmlJs::SFNode = { + { + "SFNode", JSCLASS_HAS_PRIVATE, NULL, NULL, + SFNode_get, SFNode_set, + NULL, NULL, NULL, + SFNodeDestructor, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + NULL +}; + + +CoinVrmlJs::ClassDescriptor CoinVrmlJs::SFRotation = { + { + "SFRotation", JSCLASS_HAS_PRIVATE, NULL, NULL, + SFRotationHandler::get, SFRotationHandler::set, + NULL, NULL, NULL, + SFRotationHandler::destructor, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + SFRotationFunctions +}; + +CoinVrmlJs::ClassDescriptor CoinVrmlJs::SFVec2f = { + { + "SFVec2f", JSCLASS_HAS_PRIVATE, NULL, NULL, + SFVec2fHandler::get, SFVec2fHandler::set, + NULL, NULL, NULL, + SFVec2fHandler::destructor, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + SFVec2fFunctions +}; + +CoinVrmlJs::ClassDescriptor CoinVrmlJs::SFVec3f = { + { + "SFVec3f", JSCLASS_HAS_PRIVATE, NULL, NULL, + SFVec3fHandler::get, SFVec3fHandler::set, + NULL, NULL, NULL, + SFVec3fHandler::destructor, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + SFVec3fFunctions +}; + +CoinVrmlJs::ClassDescriptor CoinVrmlJs::SFVec3d = { + { + "SFVec3d", JSCLASS_HAS_PRIVATE, NULL, NULL, + SFVec3dHandler::get, SFVec3dHandler::set, + NULL, NULL, NULL, + SFVec3dHandler::destructor, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + SFVec3dFunctions +}; + +CoinVrmlJs::ClassDescriptor CoinVrmlJs::MFColor = { + { + "MFColor", JSCLASS_HAS_PRIVATE, NULL, NULL, + MFColorHandler::get, MFColorHandler::set, + NULL, NULL, NULL, + MFColorHandler::destructor, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + MFFunctions, +}; + +CoinVrmlJs::ClassDescriptor CoinVrmlJs::MFFloat = { + { + "MFFloat", JSCLASS_HAS_PRIVATE, NULL, NULL, + MFFloatHandler::get, MFFloatHandler::set, + NULL, NULL, NULL, + MFFloatHandler::destructor, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + MFFunctions, +}; + +CoinVrmlJs::ClassDescriptor CoinVrmlJs::MFInt32 = { + { + "MFInt32", JSCLASS_HAS_PRIVATE, NULL, NULL, + MFInt32Handler::get, MFInt32Handler::set, + NULL, NULL, NULL, + MFInt32Handler::destructor, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + MFFunctions, +}; + +CoinVrmlJs::ClassDescriptor CoinVrmlJs::MFNode = { + { + "MFNode", JSCLASS_HAS_PRIVATE, NULL, NULL, + MFNodeHandler::get, MFNodeHandler::set, + NULL, NULL, NULL, + MFNodeHandler::destructor, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + MFFunctions, +}; + +CoinVrmlJs::ClassDescriptor CoinVrmlJs::MFRotation = { + { + "MFRotation", JSCLASS_HAS_PRIVATE, NULL, NULL, + MFRotationHandler::get, MFRotationHandler::set, + NULL, NULL, NULL, + MFRotationHandler::destructor, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + MFFunctions, +}; + +CoinVrmlJs::ClassDescriptor CoinVrmlJs::MFString = { + { + "MFString", JSCLASS_HAS_PRIVATE, NULL, NULL, + MFStringHandler::get, MFStringHandler::set, + NULL, NULL, NULL, + MFStringHandler::destructor, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + MFFunctions, +}; + +CoinVrmlJs::ClassDescriptor CoinVrmlJs::MFTime = { + { + "MFTime", JSCLASS_HAS_PRIVATE, NULL, NULL, + MFTimeHandler::get, MFTimeHandler::set, + NULL, NULL, NULL, + MFTimeHandler::destructor, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + MFFunctions, +}; + +CoinVrmlJs::ClassDescriptor CoinVrmlJs::MFVec2f = { + { + "MFVec2f", JSCLASS_HAS_PRIVATE, NULL, NULL, + MFVec2fHandler::get, MFVec2fHandler::set, + NULL, NULL, NULL, + MFVec2fHandler::destructor, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + MFFunctions, +}; + +CoinVrmlJs::ClassDescriptor CoinVrmlJs::MFVec3f = { + { + "MFVec3f", JSCLASS_HAS_PRIVATE, NULL, NULL, + MFVec3fHandler::get, MFVec3fHandler::set, + NULL, NULL, NULL, + MFVec3fHandler::destructor, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + MFFunctions, +}; + +CoinVrmlJs::ClassDescriptor CoinVrmlJs::MFVec3d = { + { + "MFVec3d", JSCLASS_HAS_PRIVATE, NULL, NULL, + MFVec3dHandler::get, MFVec3dHandler::set, + NULL, NULL, NULL, + MFVec3dHandler::destructor, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 + }, + MFFunctions, +}; + + +CoinVrmlJs::ClassDescriptor * CLASSDESCRIPTORS[] = { + &CoinVrmlJs::SFColor, &CoinVrmlJs::SFNode, &CoinVrmlJs::SFRotation, + &CoinVrmlJs::SFVec2f, &CoinVrmlJs::SFVec3f, &CoinVrmlJs::SFVec3d, + &CoinVrmlJs::MFColor, + &CoinVrmlJs::MFFloat, &CoinVrmlJs::MFInt32, &CoinVrmlJs::MFNode, + &CoinVrmlJs::MFRotation, &CoinVrmlJs::MFString, &CoinVrmlJs::MFTime, + &CoinVrmlJs::MFVec2f, &CoinVrmlJs::MFVec3f, &CoinVrmlJs::MFVec3d +}; + +// ************************************************************************* + +// cleans up static / one-off resource allocations +static void +js_vrmlclasses_cleanup(void) +{ + delete garbagecollectedobjects; + delete nodesensorstobedeleted; + + garbagecollectedobjects = NULL; + nodesensorstobedeleted = NULL; +} + +// ************************************************************************* +// helper function to add all classes to engine + +void +JS_addVRMLclasses(SoJavaScriptEngine * engine) +{ + // init static data + if (garbagecollectedobjects == NULL) { + garbagecollectedobjects = new SbList ; + nodesensorstobedeleted = new SbList ; + coin_atexit((coin_atexit_f *)js_vrmlclasses_cleanup, CC_ATEXIT_NORMAL); + + // set up default function stubs for Spidermonkey classes we + // make. must be done at run-time to avoid calling spidermonkey() + // early (i.e. not on demand). + const size_t NRELEMENTS = sizeof(CLASSDESCRIPTORS) / sizeof(CLASSDESCRIPTORS[0]); + for (size_t i=0; i < NRELEMENTS; i++) { + CoinVrmlJs::ClassDescriptor * desc = CLASSDESCRIPTORS[i]; + desc->cls.addProperty = spidermonkey()->JS_PropertyStub; + desc->cls.delProperty = spidermonkey()->JS_PropertyStub; + desc->cls.enumerate = spidermonkey()->JS_EnumerateStub; + desc->cls.resolve = spidermonkey()->JS_ResolveStub; + desc->cls.convert = spidermonkey()->JS_ConvertStub; + } + } + + // Bool + engine->addHandler( + SoSFBool::getClassTypeId(), NULL, + SFBool_field2jsval, SFBool_jsval2field); + + // Color + engine->addHandler( + SoSFColor::getClassTypeId(), SFColor_init, + SFColor_field2jsval, SFColor_jsval2field); + engine->addHandler( + SoMFColor::getClassTypeId(), + MFColorHandler::init, + MFColorHandler::field2jsval, + MFColorHandler::jsval2field); + + // Float + engine->addHandler( + SoSFFloat::getClassTypeId(), NULL, + SFFloat_field2jsval, SFFloat_jsval2field); + engine->addHandler( + SoMFFloat::getClassTypeId(), + MFFloatHandler::init, + MFFloatHandler::field2jsval, + MFFloatHandler::jsval2field); + + // Int32 + engine->addHandler( + SoSFInt32::getClassTypeId(), NULL, + SFInt32_field2jsval, SFInt32_jsval2field); + engine->addHandler( + SoMFInt32::getClassTypeId(), + MFInt32Handler::init, + MFInt32Handler::field2jsval, + MFInt32Handler::jsval2field); + + // Enum + engine->addHandler( + SoSFEnum::getClassTypeId(), NULL, + SFEnum_field2jsval, SFEnum_jsval2field); + + // Node + engine->addHandler( + SoSFNode::getClassTypeId(), SFNode_init, + SFNode_field2jsval, SFNode_jsval2field); + engine->addHandler( + SoMFNode::getClassTypeId(), + MFNodeHandler::init, + MFNodeHandler::field2jsval, + MFNodeHandler::jsval2field); + + // Rotation + engine->addHandler( + SoSFRotation::getClassTypeId(), SFRotation_init, + SFRotation_field2jsval, SFRotation_jsval2field); + engine->addHandler( + SoMFRotation::getClassTypeId(), + MFRotationHandler::init, + MFRotationHandler::field2jsval, + MFRotationHandler::jsval2field); + + // String + engine->addHandler( + SoSFString::getClassTypeId(), NULL, + SFString_field2jsval, SFString_jsval2field); + engine->addHandler( + SoMFString::getClassTypeId(), + MFStringHandler::init, + MFStringHandler::field2jsval, + MFStringHandler::jsval2field); + + // Time + engine->addHandler( + SoSFTime::getClassTypeId(), NULL, + SFTime_field2jsval, SFTime_jsval2field); + engine->addHandler( + SoMFTime::getClassTypeId(), + MFTimeHandler::init, + MFTimeHandler::field2jsval, + MFTimeHandler::jsval2field); + + // Vec2f + engine->addHandler( + SoSFVec2f::getClassTypeId(), SFVec2f_init, + SFVec2f_field2jsval, SFVec2f_jsval2field); + engine->addHandler( + SoMFVec2f::getClassTypeId(), + MFVec2fHandler::init, + MFVec2fHandler::field2jsval, + MFVec2fHandler::jsval2field); + + // Vec3f + engine->addHandler( + SoSFVec3f::getClassTypeId(), SFVec3f_init, + SFVec3f_field2jsval, SFVec3f_jsval2field); + engine->addHandler( + SoMFVec3f::getClassTypeId(), + MFVec3fHandler::init, + MFVec3fHandler::field2jsval, + MFVec3fHandler::jsval2field); + + // Vec3d + engine->addHandler( + SoSFVec3d::getClassTypeId(), SFVec3d_init, + SFVec3d_field2jsval, SFVec3d_jsval2field); + engine->addHandler( + SoMFVec3d::getClassTypeId(), + MFVec3dHandler::init, + MFVec3dHandler::field2jsval, + MFVec3dHandler::jsval2field); +} + +#endif // HAVE_VRML97 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Tony Theodore Date: Sat, 18 Nov 2017 20:45:31 +1100 Subject: [PATCH 2/2] gcc 4.7 fixes This patch was taken from Gentoo: https://gitweb.gentoo.org/repo/gentoo.git/tree/media-libs/coin/files/coin-3.1.3-gcc-4.7.patch?id=17d7c853393ff83e3422e48e9ad2810f23889bbf diff --git a/include/Inventor/SbBasic.h b/include/Inventor/SbBasic.h index 1111111..2222222 100644 --- a/include/Inventor/SbBasic.h +++ b/include/Inventor/SbBasic.h @@ -24,6 +24,7 @@ * \**************************************************************************/ +#include #include /* ********************************************************************** */