ColladaAppNode::ColladaAppNode(const domNode* node, ColladaAppNode* parent) : p_domNode(node), appParent(parent), nodeExt(new ColladaExtension_node(node)), lastTransformTime(TSShapeLoader::DefaultTime-1), defaultTransformValid(false), invertMeshes(false) { mName = dStrdup(_GetNameOrId(node)); mParentName = dStrdup(parent ? parent->getName() : "ROOT"); // Extract user properties from the <node> extension as whitespace separated // "name=value" pairs char* properties = dStrdup(nodeExt->user_properties); char* pos = properties; char* end = properties + dStrlen( properties ); while ( pos < end ) { // Find the '=' character to separate the name and value pair char* split = dStrchr( pos, '=' ); if ( !split ) break; // Get the name (whitespace trimmed string up to the '=') // and value (whitespace trimmed string after the '=') *split = '\0'; char* name = TrimFirstWord( pos ); char* value = TrimFirstWord( split + 1 ); mProps.insert(StringTable->insert(name), dAtof(value)); pos = value + dStrlen( value ) + 1; } dFree( properties ); // Create vector of transform elements for (S32 iChild = 0; iChild < node->getContents().getCount(); iChild++) { switch (node->getContents()[iChild]->getElementType()) { case COLLADA_TYPE::TRANSLATE: case COLLADA_TYPE::ROTATE: case COLLADA_TYPE::SCALE: case COLLADA_TYPE::SKEW: case COLLADA_TYPE::MATRIX: case COLLADA_TYPE::LOOKAT: nodeTransforms.increment(); nodeTransforms.last().element = node->getContents()[iChild]; break; } } }
void ColladaShapeLoader::enumerateScene() { // Get animation clips Vector<const domAnimation_clip*> animationClips; for (S32 iClipLib = 0; iClipLib < root->getLibrary_animation_clips_array().getCount(); iClipLib++) { const domLibrary_animation_clips* libraryClips = root->getLibrary_animation_clips_array()[iClipLib]; for (S32 iClip = 0; iClip < libraryClips->getAnimation_clip_array().getCount(); iClip++) appSequences.push_back(new ColladaAppSequence(libraryClips->getAnimation_clip_array()[iClip])); } // Process all animations => this attaches animation channels to the targeted // Collada elements, and determines the length of the sequence if it is not // already specified in the Collada <animation_clip> element for (S32 iSeq = 0; iSeq < appSequences.size(); iSeq++) { ColladaAppSequence* appSeq = dynamic_cast<ColladaAppSequence*>(appSequences[iSeq]); F32 maxEndTime = 0; F32 minFrameTime = 1000.0f; for (S32 iAnim = 0; iAnim < appSeq->getClip()->getInstance_animation_array().getCount(); iAnim++) { domAnimation* anim = daeSafeCast<domAnimation>(appSeq->getClip()->getInstance_animation_array()[iAnim]->getUrl().getElement()); if (anim) processAnimation(anim, maxEndTime, minFrameTime); } if (appSeq->getEnd() == 0) appSeq->setEnd(maxEndTime); // Collada animations can be stored as sampled frames or true keyframes. For // sampled frames, use the same frame rate as the DAE file. For true keyframes, // resample at a fixed frame rate. appSeq->fps = mClamp(1.0f / minFrameTime + 0.5f, TSShapeLoader::MinFrameRate, TSShapeLoader::MaxFrameRate); } // First grab all of the top-level nodes Vector<domNode*> sceneNodes; for (S32 iSceneLib = 0; iSceneLib < root->getLibrary_visual_scenes_array().getCount(); iSceneLib++) { const domLibrary_visual_scenes* libScenes = root->getLibrary_visual_scenes_array()[iSceneLib]; for (S32 iScene = 0; iScene < libScenes->getVisual_scene_array().getCount(); iScene++) { const domVisual_scene* visualScene = libScenes->getVisual_scene_array()[iScene]; for (S32 iNode = 0; iNode < visualScene->getNode_array().getCount(); iNode++) sceneNodes.push_back(visualScene->getNode_array()[iNode]); } } // Set LOD option bool singleDetail = true; switch (ColladaUtils::getOptions().lodType) { case ColladaUtils::ImportOptions::DetectDTS: // Check for a baseXX->startXX hierarchy at the top-level, if we find // one, use trailing numbers for LOD, otherwise use a single size for (S32 iNode = 0; singleDetail && (iNode < sceneNodes.size()); iNode++) { domNode* node = sceneNodes[iNode]; if (dStrStartsWith(_GetNameOrId(node), "base")) { for (S32 iChild = 0; iChild < node->getNode_array().getCount(); iChild++) { domNode* child = node->getNode_array()[iChild]; if (dStrStartsWith(_GetNameOrId(child), "start")) { singleDetail = false; break; } } } } break; case ColladaUtils::ImportOptions::SingleSize: singleDetail = true; break; case ColladaUtils::ImportOptions::TrailingNumber: singleDetail = false; break; default: break; } ColladaAppMesh::fixDetailSize( singleDetail, ColladaUtils::getOptions().singleDetailSize ); // Process the top level nodes for (S32 iNode = 0; iNode < sceneNodes.size(); iNode++) { ColladaAppNode* node = new ColladaAppNode(sceneNodes[iNode], 0); if (!processNode(node)) delete node; } // Make sure that the scene has a bounds node (for getting the root scene transform) if (!boundsNode) { domVisual_scene* visualScene = root->getLibrary_visual_scenes_array()[0]->getVisual_scene_array()[0]; domNode* dombounds = daeSafeCast<domNode>( visualScene->createAndPlace( "node" ) ); dombounds->setName( "bounds" ); ColladaAppNode *appBounds = new ColladaAppNode(dombounds, 0); if (!processNode(appBounds)) delete appBounds; } }
//----------------------------------------------------------------------------- // Recurse through the collada scene to add <light>s to the Torque scene static void processNodeLights(AppNode* appNode, const MatrixF& offset, SimGroup* group) { const domNode* node = dynamic_cast<ColladaAppNode*>(appNode)->getDomNode(); for (S32 iLight = 0; iLight < node->getInstance_light_array().getCount(); iLight++) { domInstance_light* instLight = node->getInstance_light_array()[iLight]; domLight* p_domLight = daeSafeCast<domLight>(instLight->getUrl().getElement()); if (!p_domLight) { Log::warnf("Failed to find light for URL \"%s\"", instLight->getUrl().getOriginalURI()); continue; } String lightName = Sim::getUniqueName(_GetNameOrId(node)); const char* lightType = ""; domLight::domTechnique_common* technique = p_domLight->getTechnique_common(); if (!technique) { Log::warnf("No <technique_common> for light \"%s\"", lightName.c_str()); continue; } LightBase* pLight = 0; ColorF color(ColorF::WHITE); Point3F attenuation(0, 1, 1); if (technique->getAmbient()) { domLight::domTechnique_common::domAmbient* ambient = technique->getAmbient(); // No explicit support for ambient lights, so use a PointLight instead lightType = "ambient"; pLight = new PointLight; resolveLightColor(ambient, color); } else if (technique->getDirectional()) { domLight::domTechnique_common::domDirectional* directional = technique->getDirectional(); // No explicit support for directional lights, so use a SpotLight instead lightType = "directional"; pLight = new SpotLight; resolveLightColor(directional, color); } else if (technique->getPoint()) { domLight::domTechnique_common::domPoint* point = technique->getPoint(); lightType = "point"; pLight = new PointLight; resolveLightColor(point, color); resolveLightAttenuation(point, attenuation); } else if (technique->getSpot()) { domLight::domTechnique_common::domSpot* spot = technique->getSpot(); lightType = "spot"; pLight = new SpotLight; resolveLightColor(spot, color); resolveLightAttenuation(spot, attenuation); } else continue; Log::printf("Adding <%s> light \"%s\" as a %s", lightType, lightName.c_str(), pLight->getClassName()); MatrixF mat(offset); mat.mul(appNode->getNodeTransform(TSShapeLoader::DefaultTime)); pLight->setDataField("color", 0, avar("%f %f %f %f", color.red, color.green, color.blue, color.alpha)); pLight->setDataField("attenuationRatio", 0, avar("%f %f %f", attenuation.x, attenuation.y, attenuation.z)); pLight->setTransform(mat); if (!pLight->registerObject(lightName)) { Log::errorf(LogEntry::General, "Failed to register light for \"%s\"", lightName.c_str()); delete pLight; } if (group) group->addObject(pLight); } // Recurse child nodes for (S32 iChild = 0; iChild < appNode->getNumChildNodes(); iChild++) processNodeLights(appNode->getChildNode(iChild), offset, group); }
// Recurse through the <visual_scene> adding nodes and geometry to the GuiTreeView control static void processNode(GuiTreeViewCtrl* tree, domNode* node, S32 parentID, SceneStats& stats) { stats.numNodes++; S32 nodeID = tree->insertItem(parentID, _GetNameOrId(node), "node", "", 0, 0); // Update mesh and poly counts for (int i = 0; i < node->getContents().getCount(); i++) { domGeometry* geom = 0; const char* elemName = ""; daeElement* child = node->getContents()[i]; switch (child->getElementType()) { case COLLADA_TYPE::INSTANCE_GEOMETRY: { domInstance_geometry* instgeom = daeSafeCast<domInstance_geometry>(child); if (instgeom) { geom = daeSafeCast<domGeometry>(instgeom->getUrl().getElement()); elemName = _GetNameOrId(geom); } break; } case COLLADA_TYPE::INSTANCE_CONTROLLER: { domInstance_controller* instctrl = daeSafeCast<domInstance_controller>(child); if (instctrl) { domController* ctrl = daeSafeCast<domController>(instctrl->getUrl().getElement()); elemName = _GetNameOrId(ctrl); if (ctrl && ctrl->getSkin()) geom = daeSafeCast<domGeometry>(ctrl->getSkin()->getSource().getElement()); else if (ctrl && ctrl->getMorph()) geom = daeSafeCast<domGeometry>(ctrl->getMorph()->getSource().getElement()); } break; } case COLLADA_TYPE::INSTANCE_LIGHT: stats.numLights++; tree->insertItem(nodeID, _GetNameOrId(node), "light", "", 0, 0); break; } if (geom && geom->getMesh()) { const char* name = _GetNameOrId(node); if ( dStrEqual( name, "null" ) || dStrEndsWith( name, "PIVOT" ) ) name = _GetNameOrId( daeSafeCast<domNode>(node->getParent()) ); stats.numMeshes++; tree->insertItem(nodeID, name, "mesh", "", 0, 0); for (S32 j = 0; j < geom->getMesh()->getTriangles_array().getCount(); j++) stats.numPolygons += geom->getMesh()->getTriangles_array()[j]->getCount(); for (S32 j = 0; j < geom->getMesh()->getTristrips_array().getCount(); j++) stats.numPolygons += geom->getMesh()->getTristrips_array()[j]->getCount(); for (S32 j = 0; j < geom->getMesh()->getTrifans_array().getCount(); j++) stats.numPolygons += geom->getMesh()->getTrifans_array()[j]->getCount(); for (S32 j = 0; j < geom->getMesh()->getPolygons_array().getCount(); j++) stats.numPolygons += geom->getMesh()->getPolygons_array()[j]->getCount(); for (S32 j = 0; j < geom->getMesh()->getPolylist_array().getCount(); j++) stats.numPolygons += geom->getMesh()->getPolylist_array()[j]->getCount(); } } // Recurse into child nodes for (S32 i = 0; i < node->getNode_array().getCount(); i++) processNode(tree, node->getNode_array()[i], nodeID, stats); for (S32 i = 0; i < node->getInstance_node_array().getCount(); i++) { domInstance_node* instnode = node->getInstance_node_array()[i]; domNode* node = daeSafeCast<domNode>(instnode->getUrl().getElement()); if (node) processNode(tree, node, nodeID, stats); } }