X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FScripting%2Fnasal-props.cxx;h=1df4b0d42b93741296eb0229dafb18166b102d1a;hb=688d76613e2ece5fdb0e36b5d836719d7a68830c;hp=0b97e42add4dbf74ecb8fc561659cabb88ec10be;hpb=f3ba7a3bd4250d8ddbd7e095456f0b0360d3a7e7;p=flightgear.git diff --git a/src/Scripting/nasal-props.cxx b/src/Scripting/nasal-props.cxx index 0b97e42ad..1df4b0d42 100644 --- a/src/Scripting/nasal-props.cxx +++ b/src/Scripting/nasal-props.cxx @@ -3,13 +3,18 @@ # include "config.h" #endif +#include + #include #include +#include #include
#include "NasalSys.hxx" +using namespace std; + // Implementation of a Nasal wrapper for the SGPropertyNode class, // using the Nasal "ghost" (er... Garbage collection Handle for // OutSide Thingy) facility. @@ -40,6 +45,15 @@ naRef FGNasalSys::propNodeGhost(SGPropertyNode* handle) return propNodeGhostCreate(_context, handle); } +SGPropertyNode* ghostToPropNode(naRef ref) +{ + if (!naIsGhost(ref) || (naGhost_type(ref) != &PropNodeGhostType)) + return NULL; + + SGPropertyNode_ptr* pp = (SGPropertyNode_ptr*) naGhost_ptr(ref); + return pp->ptr(); +} + #define NASTR(s) s ? naStr_fromdata(naNewString(c),(char*)(s),strlen(s)) : naNil() // @@ -49,27 +63,34 @@ naRef FGNasalSys::propNodeGhost(SGPropertyNode* handle) // array. This allows the Nasal handlers to do things like: // Node.getChild = func { _getChild(me.ghost, arg) } // -#define NODEARG() \ +#define NODENOARG() \ if(argc < 2 || !naIsGhost(args[0]) || \ naGhost_type(args[0]) != &PropNodeGhostType) \ naRuntimeError(c, "bad argument to props function"); \ - SGPropertyNode_ptr* node = (SGPropertyNode_ptr*)naGhost_ptr(args[0]); \ + SGPropertyNode_ptr* node = (SGPropertyNode_ptr*)naGhost_ptr(args[0]); + +#define NODEARG() \ + NODENOARG(); \ naRef argv = args[1] static naRef f_getType(naContext c, naRef me, int argc, naRef* args) { - NODEARG(); + using namespace simgear; + NODENOARG(); const char* t = "unknown"; switch((*node)->getType()) { - case SGPropertyNode::NONE: t = "NONE"; break; - case SGPropertyNode::ALIAS: t = "ALIAS"; break; - case SGPropertyNode::BOOL: t = "BOOL"; break; - case SGPropertyNode::INT: t = "INT"; break; - case SGPropertyNode::LONG: t = "LONG"; break; - case SGPropertyNode::FLOAT: t = "FLOAT"; break; - case SGPropertyNode::DOUBLE: t = "DOUBLE"; break; - case SGPropertyNode::STRING: t = "STRING"; break; - case SGPropertyNode::UNSPECIFIED: t = "UNSPECIFIED"; break; + case props::NONE: t = "NONE"; break; + case props::ALIAS: t = "ALIAS"; break; + case props::BOOL: t = "BOOL"; break; + case props::INT: t = "INT"; break; + case props::LONG: t = "LONG"; break; + case props::FLOAT: t = "FLOAT"; break; + case props::DOUBLE: t = "DOUBLE"; break; + case props::STRING: t = "STRING"; break; + case props::UNSPECIFIED: t = "UNSPECIFIED"; break; + case props::VEC3D: t = "VEC3D"; break; + case props::VEC4D: t = "VEC4D"; break; + case props::EXTENDED: t = "EXTENDED"; break; // shouldn't happen } return NASTR(t); } @@ -94,6 +115,7 @@ static naRef f_getAttribute(naContext c, naRef me, int argc, naRef* args) else if(!strcmp(a, "trace-read")) attr = SGPropertyNode::TRACE_READ; else if(!strcmp(a, "trace-write")) attr = SGPropertyNode::TRACE_WRITE; else if(!strcmp(a, "userarchive")) attr = SGPropertyNode::USERARCHIVE; + else if(!strcmp(a, "preserve")) attr = SGPropertyNode::PRESERVE; else { naRuntimeError(c, "props.getAttribute() with invalid attribute"); return naNil(); @@ -119,6 +141,7 @@ static naRef f_setAttribute(naContext c, naRef me, int argc, naRef* args) else if(!strcmp(a, "trace-read")) attr = SGPropertyNode::TRACE_READ; else if(!strcmp(a, "trace-write")) attr = SGPropertyNode::TRACE_WRITE; else if(!strcmp(a, "userarchive")) attr = SGPropertyNode::USERARCHIVE; + else if(!strcmp(a, "preserve")) attr = SGPropertyNode::PRESERVE; else { naRuntimeError(c, "props.setAttribute() with invalid attribute"); return naNil(); @@ -130,43 +153,100 @@ static naRef f_setAttribute(naContext c, naRef me, int argc, naRef* args) static naRef f_getName(naContext c, naRef me, int argc, naRef* args) { - NODEARG(); + NODENOARG(); return NASTR((*node)->getName()); } static naRef f_getIndex(naContext c, naRef me, int argc, naRef* args) { - NODEARG(); + NODENOARG(); return naNum((*node)->getIndex()); } +template +naRef makeVectorFromVec(naContext c, const T& vec) +{ + const int num_components + = sizeof(vec.data()) / sizeof(typename T::value_type); + naRef vector = naNewVector(c); + naVec_setsize(c, vector, num_components); + for (int i = 0; i < num_components; ++i) + naVec_set(vector, i, naNum(vec[i])); + return vector; +} + static naRef f_getValue(naContext c, naRef me, int argc, naRef* args) { - NODEARG(); + using namespace simgear; + NODENOARG(); switch((*node)->getType()) { - case SGPropertyNode::BOOL: case SGPropertyNode::INT: - case SGPropertyNode::LONG: case SGPropertyNode::FLOAT: - case SGPropertyNode::DOUBLE: - return naNum((*node)->getDoubleValue()); - case SGPropertyNode::STRING: - case SGPropertyNode::UNSPECIFIED: + case props::BOOL: case props::INT: + case props::LONG: case props::FLOAT: + case props::DOUBLE: + { + double dv = (*node)->getDoubleValue(); + if (osg::isNaN(dv)) { + SG_LOG(SG_NASAL, SG_ALERT, "Nasal getValue: property " << (*node)->getPath() << " is NaN"); + return naNil(); + } + + return naNum(dv); + } + + case props::STRING: + case props::UNSPECIFIED: return NASTR((*node)->getStringValue()); + case props::VEC3D: + return makeVectorFromVec(c, (*node)->getValue()); + case props::VEC4D: + return makeVectorFromVec(c, (*node)->getValue()); default: return naNil(); } } +template +T makeVecFromVector(naRef vector) +{ + T vec; + const int num_components + = sizeof(vec.data()) / sizeof(typename T::value_type); + int size = naVec_size(vector); + + for (int i = 0; i < num_components && i < size; ++i) { + naRef element = naVec_get(vector, i); + naRef n = naNumValue(element); + if (!naIsNil(n)) + vec[i] = n.num; + } + return vec; +} + static naRef f_setValue(naContext c, naRef me, int argc, naRef* args) { NODEARG(); naRef val = naVec_get(argv, 0); bool result = false; - if(naIsString(val)) result = (*node)->setStringValue(naStr_data(val)); - else { + if(naIsString(val)) { + result = (*node)->setStringValue(naStr_data(val)); + } else if(naIsVector(val)) { + if(naVec_size(val) == 3) + result = (*node)->setValue(makeVecFromVector(val)); + else if(naVec_size(val) == 4) + result = (*node)->setValue(makeVecFromVector(val)); + else + naRuntimeError(c, "props.setValue() vector value has wrong size"); + } else { naRef n = naNumValue(val); if(naIsNil(n)) naRuntimeError(c, "props.setValue() with non-number"); - result = (*node)->setDoubleValue(naNumValue(val).num); + + double d = naNumValue(val).num; + if (osg::isNaN(d)) { + naRuntimeError(c, "props.setValue() passed a NaN"); + } + + result = (*node)->setDoubleValue(d); } return naNum(result); } @@ -199,14 +279,19 @@ static naRef f_setDoubleValue(naContext c, naRef me, int argc, naRef* args) { NODEARG(); naRef r = naNumValue(naVec_get(argv, 0)); - if(naIsNil(r)) + if (naIsNil(r)) naRuntimeError(c, "props.setDoubleValue() with non-number"); + + if (osg::isNaN(r.num)) { + naRuntimeError(c, "props.setDoubleValue() passed a NaN"); + } + return naNum((*node)->setDoubleValue(r.num)); } static naRef f_getParent(naContext c, naRef me, int argc, naRef* args) { - NODEARG(); + NODENOARG(); SGPropertyNode* n = (*node)->getParent(); if(!n) return naNil(); return propNodeGhostCreate(c, n); @@ -317,13 +402,13 @@ static naRef f_alias(naContext c, naRef me, int argc, naRef* args) static naRef f_unalias(naContext c, naRef me, int argc, naRef* args) { - NODEARG(); + NODENOARG(); return naNum((*node)->unalias()); } static naRef f_getAliasTarget(naContext c, naRef me, int argc, naRef* args) { - NODEARG(); + NODENOARG(); return propNodeGhostCreate(c, (*node)->getAliasTarget()); }