/*! The SLRefGroup::shapeInit checks the validity of the referenced node. To avoid endless loops a refShape node is not allowed to refShape its ancestors. An ancestor of a refShape node is group node followed along the previous pointers with lower depth than the depth of the refShape node. */ void SLRefGroup::shapeInit(SLSceneView* sv) { // cummulate wm with referenced wm SLShape* ref = (SLShape*)_refGroup; _wm *= ref->m(); _wmI.setMatrix(_wm.inverse()); _wmN.setMatrix(_wmI.mat3()); _wmN.transpose(); // check circular references SLNode* parent = this->parent(); while (parent) { if (parent==_refGroup) SL_EXIT_MSG("Reference node produces a never ending loop."); parent = parent->parent(); } // set transparency flag _aabb.hasAlpha(((SLShape*)_refGroup)->aabb()->hasAlpha()); // delete all child references if (_first) deleteAll(); // loop through the referenced group and add a SLRefShape or SLRefGroup SLNode* current = ((SLGroup*)_refGroup)->first(); while (current) { if (typeid(*current)==typeid(SLGroup)) addNode(new SLRefGroup((SLGroup*)current, name()+"_"+current->name())); else addNode(new SLRefShape((SLShape*)current, name()+"_"+current->name())); ((SLShape*)_last)->wm(_wm); ((SLShape*)_last)->depth(depth()+1); ((SLShape*)_last)->shapeInit(sv); current = current->next(); } }
/*! SLGroup::shapeDraw loops over all child nodes and calls the their draw method. Groups are only traversed for opaque objects. Transparent objects are rendere extra afterwards. */ void SLGroup::shapeDraw(SLSceneView* sv) { SLNode* current = _first; while (current) { current->draw(sv); current = current->next(); } }
/*! SLGroup::shapeCopy loops over all child nodes and calls their copy method. A new group with all copied child node is returned. */ SLShape* SLGroup::shapeCopy() { SLGroup* copy = new SLGroup(name()); SLNode* current = _first; while (current) { copy->addNode(current->copy()); current = current->next(); } return copy; }
/*! SLRefGroup::shapeHit calls the shapeHit method of the referenced group. */ SLbool SLRefGroup::shapeHit(SLRay* ray) { // loop through child references an hit each SLNode* current = _first; SLbool wasHit = false; while (current) { if (((SLShape*)current)->hit(ray) && !wasHit) wasHit = true; current = current->next(); } return wasHit; }
/*! SLGroup::getNode finds a node by a name */ SLNode* SLGroup::getNode(SLstring name) { SLNode* current = _first; while (current) { if(current->name() == name) return current; if (typeid(*current)==typeid(SLGroup)) { SLNode* found = ((SLGroup*)current)->getNode(name); if (found) return found; } current = current->next(); } return 0; }
/*! SLGroup::buildAABB() loops over all child nodes and merges their AABB to the axis aligned bounding box of the group. */ SLAABBox& SLGroup::buildAABB() { SLNode* current = _first; // empty the groups AABB _aabb.minWS(SLVec3f( FLT_MAX, FLT_MAX, FLT_MAX)); _aabb.maxWS(SLVec3f(-FLT_MAX,-FLT_MAX,-FLT_MAX)); while (current) { _aabb.merge(current->buildAABB()); current = current->next(); } _aabb.fromWStoOS(_aabb.minWS(), _aabb.maxWS(), _wmI); return _aabb; }
/*! SLGroup::shapeInit loops over all child nodes and calls their init method with an incremented depth. While looping it must be checked that all child nodes have a depth equal the groups depth + 1. */ void SLGroup::shapeInit(SLSceneView* sv) { SLNode* current = _first; while (current) { if (current->depth() && current->depth() != depth()+1) { SL_EXIT_MSG("Scenegraph is not directed acyclic. There is a loop."); } current->init(sv, depth()+1); // Set transparent flags of the group if (!_aabb.hasAlpha() && ((SLShape*)current)->aabb()->hasAlpha()) _aabb.hasAlpha(true); current = current->next(); } }
/*! SLGroup::intersect loops over all child nodes of the group and calls their intersect method. */ SLbool SLGroup::shapeHit(SLRay* ray) { assert(ray != 0); SLNode* current = _first; SLbool wasHit = false; while (current) { // do not test origin node for shadow rays if (!(current==ray->originShape && ray->type==SHADOW)) { if (current->hit(ray) && !wasHit) wasHit = true; } if (ray->isShaded()) return true; current = current->next(); } return wasHit; }
/*! SLGroup::updateStats updates the statistic counters of a group. Be aware that when you add, insert or delete nodes in group only the numChildren counter is updated automatically. For the correct counters of the root3D group you have to call its updateStats method first. Achtung: the light node is counted in numShapes and numLights. */ void SLGroup::updateStats(SLGroup* parent) { SLNode* current = _first; numBytes = 0; numBytesAccel = 0; numGroups = 1; numShapes = 0; numRefShapes = 0; numLights = 0; numTriangles = 0; numRTTriangles= 0; numRTVertices = 0; numVoxels = 0; numVoxEmpty = 0; numVoxMaxTria = 0; while (current) { current->updateStats(this); current = current->next(); } if (parent) { ((SLGroup*)parent)->numBytes += numBytes; ((SLGroup*)parent)->numBytesAccel += numBytesAccel; ((SLGroup*)parent)->numGroups += numGroups; ((SLGroup*)parent)->numShapes += numShapes; ((SLGroup*)parent)->numRefShapes += numRefShapes; ((SLGroup*)parent)->numTriangles += numTriangles; ((SLGroup*)parent)->numRTTriangles+= numRTTriangles; ((SLGroup*)parent)->numRTVertices += numRTVertices; ((SLGroup*)parent)->numVoxels += numVoxels; ((SLGroup*)parent)->numVoxEmpty += numVoxEmpty; if (numVoxMaxTria > ((SLGroup*)parent)->numVoxMaxTria) ((SLGroup*)parent)->numVoxMaxTria = numVoxMaxTria; } }