/* * Node.cpp * * Copyright (C) 1999 Stephen F. White * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (see the file "COPYING" for details); if * not, write to the Free Software Foundation, Inc., 675 Mass Ave, * Cambridge, MA 02139, USA. */ #include #include #include #include "stdafx.h" #include "Node.h" #include "Scene.h" #include "Field.h" #include "FieldValue.h" #include "FieldCommand.h" #include "Proto.h" #include "Path.h" #include "SFNode.h" #include "MFNode.h" #include "SFString.h" #include "MFString.h" #include "EventIn.h" #include "EventOut.h" #include "ExposedField.h" #include "URL.h" #include "DuneApp.h" #include "NodeScript.h" #define HANDLE_SIZE 2.0f NodeData::NodeData(Scene *scene, Proto *proto) { static unsigned long identifier_source=0; identifier_source++; _identifier=identifier_source; _scene = scene; _graphX = _graphY = 0; _graphWidth = _graphHeight = 0; _scene->addNode((Node*)this); _refs = 0; _flags = 1<getNumFields(); _fields = new FieldValue *[_numFields]; for (i = 0; i < _numFields; i++) { _fields[i] = _proto->getField(i)->getDefault()->copy(); _fields[i]->ref(); } _numEventIns = _proto->getNumEventIns(); _inputs = new SocketList[_numEventIns]; _numEventOuts = _proto->getNumEventOuts(); _outputs = new SocketList[_numEventOuts]; _numberUse = 1; } NodeData::NodeData(const Node &node) { _identifier=node._identifier; // FIXME: unclear: should all IDs be unique?? _scene = node._scene; _refs = 0; _graphX = _graphY = 0; _graphWidth = _graphHeight = 0; _scene->addNode((Node*)this); _flags = node._flags; _proto = node._proto; _numFields = _proto->getNumFields(); _fields = new FieldValue *[_numFields]; if (_name.length() !=0) _scene->def(_name, (Node*)this); for (int i = 0; i < _numFields; i++) { _fields[i] = node._fields[i]->copy(); _fields[i]->ref(); } _numEventIns = _proto->getNumEventIns(); _inputs = new SocketList[_numEventIns]; _numEventOuts = _proto->getNumEventOuts(); _outputs = new SocketList[_numEventOuts]; _numberUse = 1; } Node::Node(Scene *scene, Proto *proto) : NodeData(scene,proto) { _commentsList = new NodeList; } Node::Node(const Node &node) : NodeData(node) { _geometricParentIter=node._geometricParentIter; _commentsList = new NodeList; } Node::Node(const Node &node, Proto *proto) : NodeData(node) { _geometricParentIter=node._geometricParentIter; _proto = proto; for (int i = 0; i < proto->getNumEventOuts(); i++) _outputs[i] = node._outputs[i]; _commentsList = new NodeList; } Node::~Node() { _scene->removeNode(this); for (int i = 0; i < _numFields; i++) { _fields[i]->unref(); } _numFields = 0; delete [] _fields; delete [] _inputs; delete [] _outputs; delete _commentsList; _scene->undef(_name); } const MyString& NodeData::getName(void) { if (needsDEF()) if (_name.length() == 0) _scene->generateUniqueNodeName((Node*)this); return _name; } bool NodeData::hasName(void) { if (_name[0]) return true; else return false; } FieldValue * NodeData::getField(int index, bool ignoreproto) const { // fixme: PROTO implemenation incomplete if (ignoreproto) if (_proto->isPROTO()) return NULL; assert (index >= 0 && index < _numFields); if (ignoreproto) if (_fields[index]->getType() == SFNODE) { Node* node = ((SFNode *) _fields[index])->getValue(); if (node) if (node->getProto()->isPROTO()) return NULL; } return _fields[index]; } void NodeData::setField(int index, FieldValue *value) { assert (index >= 0 && index < _numFields); if (_fields[index]!=NULL) assert( _fields[index]->getType() == value->getType() ); // if field is an SFNode or MFNode type, remove old values from // children's parent list if (value->getType() == SFNODE) { Node *child = ((SFNode *) _fields[index])->getValue(); if (child) child->removeParent((Node*)this, index); } else if (value->getType() == MFNODE) { NodeList *childList = ((MFNode *) _fields[index])->getValues(); if (childList) { for (int i = 0; i < childList->size(); i++) { Node *child = childList->get(i); if (child) child->removeParent((Node*)this, index); } } } value->clamp(_proto->getField(index)->getMin(), _proto->getField(index)->getMax()); _fields[index]->unref(); _fields[index] = value; _fields[index]->ref(); if (value->getType() == SFNODE) { Node *child = ((SFNode *) value)->getValue(); if (child) child->addParent((Node*)this, index); } else if (value->getType() == MFNODE) { NodeList *childList = ((MFNode *) value)->getValues(); if (childList) { for (int i = 0; i < childList->size(); i++) { Node *child = childList->get(i); if (child) child->addParent((Node*)this, index); } } } } void Node::addFieldNodeList(int index, NodeList *childList) { assert (index >= 0 && index < _numFields); if (((MFNode*)_fields[index])->getSize() == 0) setField(index, new MFNode(childList)); else { for (int i = 0; i < childList->size(); i++) { Node *child = childList->get(i); FieldValue* newField= ((MFNode*)_fields[index])->addNode(child); newField->clamp(_proto->getField(index)->getMin(), _proto->getField(index)->getMax()); _fields[index]->unref(); _fields[index] = newField; _fields[index]->ref(); if (child) { child->addParent(this, index); } } } ((MFNode*)_fields[index])->getValues(); } int NodeData::write(int f, int indent) { if (_proto) { TheApp->checkSelectionLinenumberCounting(_scene, (Node*) this); RET_ONERROR( indentf(f, indent) ) if (getFlag(NODE_FLAG_DEFED)) { RET_ONERROR( mywritestr(f ,"USE ") ) RET_ONERROR( mywritestr(f ,(const char *) _name) ) RET_ONERROR( mywritestr(f ,"\n") ) TheApp->incSelectionLinenumber(); } else { if (needsDEF()) { if (!_name[0]) _scene->generateUniqueNodeName((Node*)this); RET_ONERROR( mywritestr(f ,"DEF ") ) RET_ONERROR( mywritestr(f ,(const char *) _name) ) RET_ONERROR( mywritestr(f ," ") ) } setFlag(NODE_FLAG_DEFED); RET_ONERROR( mywritestr(f ,(const char *) _proto->getName()) ) RET_ONERROR( mywritestr(f ," ") ) if (!TheApp->GetkrFormating()) { RET_ONERROR( mywritestr(f, "\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( indentf(f, indent + TheApp->GetIndent()) ) } RET_ONERROR( mywritestr(f ,"{\n") ) TheApp->incSelectionLinenumber(); RET_ONERROR( writeFields(f, indent + TheApp->GetIndent()) ) if (!TheApp->GetkrFormating()) RET_ONERROR( indentf(f, indent + TheApp->GetIndent()) ) else RET_ONERROR( indentf(f, indent) ) RET_ONERROR( mywritestr(f ,"}\n") ) TheApp->incSelectionLinenumber(); if (indent==0) { RET_ONERROR( mywritestr(f ,"\n") ) TheApp->incSelectionLinenumber(); } RET_ONERROR( writeRoutes(f, indent) ) setFlag(NODE_FLAG_TOUCHED); } } return(0); } bool NodeData::writeEXTERNPROTO(int filedes) { // used to write a EXTERNPROTO definition of a new VRML200x node return true; } bool NodeData::needsDEF() const { if (_name.length() != 0) return true; if (getNumParents() > 1) return true; for (int i = 0; i < _numEventIns; i++) { if (_inputs[i].size() > 0) { return true; } } for (int j = 0; j < _numEventOuts; j++) { if (_outputs[j].size() > 0) { return true; } } return false; } int NodeData::writeFields(int f, int indent) { if (!_proto) return(0); const char *oldBase = _scene->getURL(); const char *newBase = _scene->getNewURL(); bool tempSave = _scene->isTempSave(); for (int i = 0; i < _numFields; i++) { Field *field = _proto->getField(i); FieldValue *value = _fields[i]; int type = field->getType(); if (value) { // see bug: testing in NodeData::writeFields in TODO file if (!value->equals(field->getDefault())) { RET_ONERROR( indentf(f, indent) ) RET_ONERROR( mywritestr(f ,(const char *) field->getName()) ) RET_ONERROR( mywritestr(f ," ") ) if ((field->getFlags() & FF_URL) && (!TheApp->GetKeepURLs())) { value = rewriteField(value, oldBase, newBase); RET_ONERROR( value->write(f, indent) ) if (!tempSave) { setField(i, value); FieldUpdate* fieldUpdate=new FieldUpdate((Node*)this, i); _scene->UpdateViews(NULL, UPDATE_FIELD, (Hint *) fieldUpdate); delete fieldUpdate; } else { delete value; } } else { RET_ONERROR( value->write(f, indent) ) } } } } return(0); } FieldValue * NodeData::rewriteField(FieldValue *value, const char *oldBase, const char *newBase) { MyString r; switch (value->getType()) { case SFSTRING: r = rewriteURL(((SFString *) value)->getValue(), oldBase, newBase); #ifdef _WIN32 // handle invalid paths like c:/something if (r != NULL) r.gsubOnce("|",":"); #endif return new SFString(r); case MFSTRING: { bool flag = false; StringArray *a = new StringArray(); int n = ((MFString *) value)->getSize(); if (n != 0) flag = notJavascript((const char*)(((MFString *) value)-> getValue(0))); for (int i = 0; i < n; i++) { const char* url = (const char*) ((MFString *) value)->getValue(i); if (notURN(url) && flag) { /* need to replace "vrmlscript:" ? */ (*a)[i] = rewriteURL(url, oldBase, newBase); #ifdef _WIN32 // handle invalid paths like c:/something if ((*a)[i] != NULL) ((*a)[i]).gsubOnce("|",":"); #endif } else (*a)[i] = url; } return new MFString(a); } default: assert( 0 ); return NULL; } } int NodeData::writeRoutes(int f, int indent) const { int i; SocketList::Iterator *j; if (!_proto) return(0); for (i = 0; i < _numEventIns; i++) { for (j = _inputs[i].first(); j != NULL; j = j->next()) { if (j->item()._node->getFlag(NODE_FLAG_TOUCHED)) { MyString routestring; Node *src = j->item()._node; routestring="ROUTE "; routestring+=src->getName(); routestring+="."; routestring+=src->getProto()-> getEventOut(j->item()._index)->getName(); routestring+=" TO "; routestring+=_name; routestring+="."; routestring+=getProto()->getEventIn(i)->getName(); _scene->addRouteString(routestring); } } } for (i = 0; i < _numEventOuts; i++) { for (j = _outputs[i].first(); j != NULL; j = j->next()) { if (j->item()._node->getFlag(NODE_FLAG_TOUCHED)) { MyString routestring; Node *dst = j->item()._node; routestring="ROUTE "; routestring+=_name; routestring+="."; routestring+=getProto()->getEventOut(i)->getName(); routestring+=" TO "; routestring+=dst->getName(); routestring+="."; routestring+=dst->getProto()->getEventIn(j->item()._index)-> getName(); _scene->addRouteString(routestring); } } } #ifndef HAVE_ROUTE_AT_END if (indent==0) RET_ONERROR( _scene->writeRouteStrings(f) ) #endif return(0); } int NodeData::lookupEventIn(const MyString &name) const { return _proto ? _proto->lookupEventIn(name) : INVALID_INDEX; } int NodeData::lookupEventOut(const MyString &name) const { return _proto ? _proto->lookupEventOut(name) : INVALID_INDEX; } MyString NodeData::newEventName(int typeEnum, bool out) { char name[1024]; MyString eventName = ""; const char *typestr = typeEnumToString(typeEnum); if (typestr[0] == 'M') eventName += "m"; for (int i = 2; i < strlen(typestr); i++) eventName += tolower(typestr[i]); int counter = 0; bool foundflag; do { foundflag = false; counter++; char *format = "%d_in"; if (out) format = "%d_out"; mysnprintf(name, 1023, (const char *)format, counter); int numberEvents = 0; if (out) numberEvents = _proto->getNumEventOuts(); else numberEvents = _proto->getNumEventIns(); for (int i = 0; i < numberEvents; i++) { char *oldName; if (out) oldName = (char*)(const char*) _proto->getEventOut(i)->getName(); else oldName = (char*)(const char*) _proto->getEventIn(i)->getName(); MyString cmpName = ""; cmpName += eventName; cmpName += name; if (strcmp(oldName, (const char*)cmpName) == 0) foundflag = true; } } while (foundflag == true); eventName += name; return eventName; } void NodeData::addInput(int eventIn, Node *src, int eventOut) { if (eventIn >= _numEventIns) if (getType() == NODE_SCRIPT) { int typeEnum = src->getProto()->getEventOut(eventOut)->getType(); ((NodeScript *)this)->addEventIn(typeEnum, newEventName(typeEnum, false)); update(); NodeUpdate *hint= new NodeUpdate((Node *)this, NULL, 0); _scene->UpdateViews(NULL, UPDATE_CHANGE_INTERFACE_NODE, (Hint*) hint); } _inputs[eventIn].append(Socket(src, eventOut)); } void NodeData::addOutput(int eventOut, Node *dst, int eventIn) { if (eventOut >= _numEventOuts) if (getType() == NODE_SCRIPT) { int typeEnum = dst->getProto()->getEventIn(eventIn)->getType(); ((NodeScript *)this)->addEventOut(typeEnum, newEventName(typeEnum, true)); update(); NodeUpdate *hint= new NodeUpdate((Node *)this, NULL, 0); _scene->UpdateViews(NULL, UPDATE_CHANGE_INTERFACE_NODE, (Hint*) hint); } _outputs[eventOut].append(Socket(dst, eventIn)); } void NodeData::removeInput(int eventIn, Node *src, int eventOut) { SocketList::Iterator *j = _inputs[eventIn].find(Socket(src, eventOut)); if (j) _inputs[eventIn].remove(j); } void NodeData::removeOutput(int eventOut, Node *dst, int eventIn) { SocketList::Iterator *j = _outputs[eventOut].find(Socket(dst, eventIn)); if (j) _outputs[eventOut].remove(j); } void NodeData::update() { // used by Script to update its fields and // used by shapes to redraw after a change of a MF-field } void NodeData::reInit() { // used to reinitialise private data of a "copy"-ed node // e.g. to reinitialise mesh data of some geometric shapes } void Node::addParent(Node *parent, int field) { _parents.append(Parent(parent, field, this)); _geometricParentIter = _parents.last(); } int NodeData::findChild(Node *child, int field) const { assert(field >= 0 && field < _numFields); FieldValue *value = _fields[field]; if (value->getType() == SFNODE) { return (((SFNode *) value)->getValue() == child) ? 0 : -1; } else if (value->getType() == MFNODE) { NodeList *list = ((MFNode *) value)->getValues(); for (int i = 0; i < list->size(); i++) { if (list->get(i) == child) return i; } return -1; } else { return -1; } } bool Node::hasAncestor(Node *node) const { if (this != _scene->getRoot()) { if (hasParent()) { Node *parent = getParent(); if (parent == node || parent->hasAncestor(node)) return true; } } return false; } int NodeData::findValidFieldType(int childType) { int match = -1; for (int field = 0; field < _numFields; field++) { if (validChildType(field, childType)) { if (match != -1) return -1; // ambiguous match = field; } } return match; } int NodeData::findValidField(Node *child) { return findValidFieldType(child->getNodeClass()); } bool NodeData::validChild(int field, Node *child) { return validChildType(field, child->getNodeClass()); } bool NodeData::validChildType(int field, int childType) { if (field < 0 || field >= _numFields) return false; Field *def = _proto->getField(field); if (def->getType() == SFNODE && ((SFNode *) _fields[field])->getValue() != NULL) return false; if (def->getType() == SFNODE || def->getType() == MFNODE) { int nodeType = def->getNodeType(); if (nodeType == ANY_NODE) { return true; } else if (childType == nodeType) { return true; } else if (isClassType(childType) && isClassType(nodeType) && (childType & nodeType)) { return true; } else return false; } else { return false; } } void NodeData::setFlagRec(int flag) { setFlag(flag); for (int i = 0; i < _numFields; i++) { if (_fields[i]->getType() == MFNODE) { ((MFNode *) _fields[i])->getValues()->setFlag(flag); } else if (_fields[i]->getType() == SFNODE) { SFNode *value = (SFNode *) _fields[i]; if (value->getValue()) value->getValue()->setFlagRec(flag); } } } void NodeData::clearFlagRec(int flag) { setFlag(flag); for (int i = 0; i < _numFields; i++) { if (_fields[i]->getType() == MFNODE) { ((MFNode *) _fields[i])->getValues()->clearFlag(flag); } else if (_fields[i]->getType() == SFNODE) { SFNode *value = (SFNode *) _fields[i]; if (value->getValue()) value->getValue()->clearFlagRec(flag); } } } Path * NodeData::getPrimaryPath() const { int len = 0; const Node *node, *root = _scene->getRoot(); for (node = (Node*)this; node != root; node = node->getParent()) { len += 2; } int *list = new int[len]; int i = len-1; for (node = (Node*)this; node != root; node = node->getParent()) { Node *parent = node->getParent(); int field = node->getParentField(); FieldValue *value = parent->getField(field); if (value->getType() == MFNODE) { list[i--] = ((MFNode *) value)->getValues()->find((Node *) node); } else if (value->getType() == SFNODE) { list[i--] = 0; } else { assert(false); } list[i--] = field; } Path *path = new Path(list, len, _scene); delete [] list; return path; } bool Node::isInScene(Scene* scene) const { if (scene != _scene) return false; if (this == _scene->getRoot()) return true; if (!this->hasParent()) return false; if (this->getParent()->isInScene(scene)) return true; return false; } void NodeData::sendEvent(int eventOut, double timestamp, FieldValue *value) { assert(eventOut >= 0 && eventOut <= _numEventOuts); value->ref(); SocketList::Iterator *i; for (i = _outputs[eventOut].first(); i != NULL; i = i->next()) { Socket s = i->item(); s._node->receiveEvent(s._index, timestamp, value); } value->unref(); } void NodeData::receiveEvent(int eventIn, double /* timestamp */, FieldValue *value) { // check to see if this eventIn is part of an exposedField or // conntected to a normal field int field = -1; ExposedField *e = _proto->getEventIn(eventIn)->getExposedField(); if (e) field = e->getField(); else field = _proto->getEventIn(eventIn)->getField(); if (field != -1) { // set the appropriate field setField(field, value); _scene->OnFieldChange((Node*)this, field); // fire off an event here? } } /// compare content bool NodeData::isEqual(Node* node) { if (_identifier==node->_identifier) return true; else return false; } bool NodeData::hasFieldFlag(int flag) { for (int field = 0; field < _numFields; field++) { Field *def = _proto->getField(field); if (def->getFlags() & FF_URL) return true; } return false; } bool hasRoute(SocketList socketlist) { if (socketlist.first() == NULL) return false; else return true; } bool Node::isAnimateable(void) { Proto *proto = getProto(); for (int i = 0; i < proto->getNumEventIns(); i++) { int type = proto->getEventIn(i)->getType(); if (typeDefaultValue(type)->isAnimateable() && typeDefaultValue(type)->hasAnimationSupport()) return true; } return false; } bool Node::isInvalidChild(void) { if (this == _scene->getRoot()) return true; if (isInvalidChildNode() && (getParent()->getProto()->getField(getParentField())->getType() == MFNODE) ) return true; return false; } void Node::removeParent(Node *parent, int field) { ParentList::Iterator *i = _parents.find(Parent(parent, field, this)); if (!i) { #ifdef DEBUG assert(false); #else return; #endif } else { _parents.remove(i); } } Vec3f Node::getMinBoundingBox(void) { Vec3f ret(0, 0, 0); return ret; } Vec3f Node::getMaxBoundingBox(void) { Vec3f ret(0, 0, 0); return ret; } void Node::appendComment(Node *node) { _commentsList->append(node); } void Node::appendTo(NodeList* nodelist) { for (int i = 0;i < _commentsList->size(); i++) nodelist->append((*_commentsList)[i]); nodelist->append(this); _commentsList->resize(0); }