Пример #1
0
void ColladaShapeLoader::processAnimation(const domAnimation* anim, F32& maxEndTime, F32& minFrameTime)
{
   const char* sRGBANames[] =   { ".R", ".G", ".B", ".A", "" };
   const char* sXYZNames[] =    { ".X", ".Y", ".Z", "" };
   const char* sXYZANames[] =   { ".X", ".Y", ".Z", ".ANGLE" };
   const char* sLOOKATNames[] = { ".POSITIONX", ".POSITIONY", ".POSITIONZ", ".TARGETX", ".TARGETY", ".TARGETZ", ".UPX", ".UPY", ".UPZ", "" };
   const char* sSKEWNames[] =   { ".ROTATEX", ".ROTATEY", ".ROTATEZ", ".AROUNDX", ".AROUNDY", ".AROUNDZ", ".ANGLE", "" };
   const char* sNullNames[] =   { "" };

   for (S32 iChannel = 0; iChannel < anim->getChannel_array().getCount(); iChannel++) {

      // Get the animation elements: <channel>, <sampler>
      domChannel* channel = anim->getChannel_array()[iChannel];
      domSampler* sampler = daeSafeCast<domSampler>(channel->getSource().getElement());
      if (!sampler)
         continue;

      // Find the animation channel target
      daeSIDResolver resolver(channel, channel->getTarget());
      daeElement* target = resolver.getElement();
      if (!target) {
         daeErrorHandler::get()->handleWarning(avar("Failed to resolve animation "
            "target: %s", channel->getTarget()));
         continue;
      }
/*
      // If the target is a <source>, point it at the array instead
      // @todo:Only support targeting float arrays for now...
      if (target->getElementType() == COLLADA_TYPE::SOURCE)
      {
         domSource* source = daeSafeCast<domSource>(target);
         if (source->getFloat_array())
            target = source->getFloat_array();
      }
*/
      // Get the target's animation channels (create them if not already)
      if (!AnimData::getAnimChannels(target)) {
         animations.push_back(new AnimChannels(target));
      }
      AnimChannels* targetChannels = AnimData::getAnimChannels(target);

      // Add a new animation channel to the target
      targetChannels->push_back(new AnimData());
      channel->setUserData(targetChannels->last());
      AnimData& data = *targetChannels->last();

      for (S32 iInput = 0; iInput < sampler->getInput_array().getCount(); iInput++) {

         const domInputLocal* input = sampler->getInput_array()[iInput];
         const domSource* source = daeSafeCast<domSource>(input->getSource().getElement());
         if (!source)
            continue;

         // @todo:don't care about the input param names for now. Could
         // validate against the target type....
         if (dStrEqual(input->getSemantic(), "INPUT")) {
            data.input.initFromSource(source);
            // Adjust the maximum sequence end time
            maxEndTime = getMax(maxEndTime, data.input.getFloatValue((S32)data.input.size()-1));

            // Detect the frame rate (minimum time between keyframes)
            for (S32 iFrame = 1; iFrame < data.input.size(); iFrame++)
            {
               F32 delta = data.input.getFloatValue( iFrame ) - data.input.getFloatValue( iFrame-1 );
               if ( delta < 0 )
               {
                  daeErrorHandler::get()->handleError(avar("<animation> INPUT '%s' "
                     "has non-monotonic keys. Animation is unlikely to be imported correctly.", source->getID()));
                  break;
               }
               minFrameTime = getMin( minFrameTime, delta );
            }
         }
         else if (dStrEqual(input->getSemantic(), "OUTPUT"))
            data.output.initFromSource(source);
         else if (dStrEqual(input->getSemantic(), "IN_TANGENT"))
            data.inTangent.initFromSource(source);
         else if (dStrEqual(input->getSemantic(), "OUT_TANGENT"))
            data.outTangent.initFromSource(source);
         else if (dStrEqual(input->getSemantic(), "INTERPOLATION"))
            data.interpolation.initFromSource(source);
      }

      // Set initial value for visibility targets that were added automatically (in colladaUtils.cpp
      if (dStrEqual(target->getElementName(), "visibility"))
      {
         domAny* visTarget = daeSafeCast<domAny>(target);
         if (visTarget && dStrEqual(visTarget->getValue(), ""))
            visTarget->setValue(avar("%g", data.output.getFloatValue(0)));
      }

      // Ignore empty animations
      if (data.input.size() == 0) {
         channel->setUserData(0);
         delete targetChannels->last();
         targetChannels->pop_back();
         continue;
      }

      // Determine the number and offset the elements of the target value
      // targeted by this animation
      switch (target->getElementType()) {
         case COLLADA_TYPE::COLOR:        data.parseTargetString(channel->getTarget(), 4, sRGBANames);   break;
         case COLLADA_TYPE::TRANSLATE:    data.parseTargetString(channel->getTarget(), 3, sXYZNames);    break;
         case COLLADA_TYPE::ROTATE:       data.parseTargetString(channel->getTarget(), 4, sXYZANames);   break;
         case COLLADA_TYPE::SCALE:        data.parseTargetString(channel->getTarget(), 3, sXYZNames);    break;
         case COLLADA_TYPE::LOOKAT:       data.parseTargetString(channel->getTarget(), 3, sLOOKATNames); break;
         case COLLADA_TYPE::SKEW:         data.parseTargetString(channel->getTarget(), 3, sSKEWNames);   break;
         case COLLADA_TYPE::MATRIX:       data.parseTargetString(channel->getTarget(), 16, sNullNames);  break;
         case COLLADA_TYPE::FLOAT_ARRAY:  data.parseTargetString(channel->getTarget(), daeSafeCast<domFloat_array>(target)->getCount(), sNullNames); break;
         default:                         data.parseTargetString(channel->getTarget(), 1, sNullNames);   break;
      }
   }

   // Process child animations
   for (S32 iAnim = 0; iAnim < anim->getAnimation_array().getCount(); iAnim++)
      processAnimation(anim->getAnimation_array()[iAnim], maxEndTime, minFrameTime);
}
Пример #2
0
S32 TorqueMain( S32 argc, const char **argv )
{
   S32 failed = 0;

   // Initialize the subsystems.
   StandardMainLoop::init();
   Con::setVariable( "Con::Prompt", "" );
   WindowsConsole->enable( true );

   // install all drives for now until we have everything using the volume stuff
   Platform::FS::InstallFileSystems();
   Platform::FS::MountDefaults();

   bool compatMode = false;
   bool diffuseNames = false;
   bool verbose = false;
   bool saveDTS = true;
   bool saveDSQ = false;
   bool genMaterials = false;
   Torque::Path cfgPath, srcPath, destPath;

   // Parse arguments
   S32 i;
   for ( i = 1; i < argc-1; i++ )
   {
      if ( dStrEqual( argv[i], "--config" ) )
         cfgPath = makeFullPath( argv[++i] );
      else if ( dStrEqual( argv[i], "--output" ) )
         destPath = makeFullPath( argv[++i] );
      else if ( dStrEqual( argv[i], "--dsq" ) )
         saveDSQ = true;
      else if ( dStrEqual( argv[i], "--dsq-only" ) )
      {
         saveDTS = false;
         saveDSQ = true;
      }
      else if ( dStrEqual( argv[i], "--compat" ) )
         compatMode = true;
      else if ( dStrEqual( argv[i], "--diffuse" ) )
         diffuseNames = true;
      else if ( dStrEqual( argv[i], "--materials" ) )
         genMaterials = true;
      else if ( dStrEqual( argv[i], "--verbose" ) )
         verbose = true;
   }

   if ( ( i >= argc ) || ( !dStrEndsWith(argv[i], ".dae") && !dStrEndsWith(argv[i], ".kmz" ) ) )
   {
      Con::errorf( "Error: no DAE file specified.\n" );
      printUsage();
      return -1;
   }

   srcPath = makeFullPath( argv[i] );
   if ( destPath.isEmpty() )
   {
      destPath = srcPath;
      destPath.setExtension( "dts" );
   }

   if ( !cfgPath.isEmpty() )
      Con::printf( "Configuration files not yet supported.\n" );

   // Define script callbacks
   if ( verbose )
      Con::evaluate( "function UpdateTSShapeLoadProgress(%progress, %msg) { echo(%msg); }" );
   else
      Con::evaluate( "function UpdateTSShapeLoadProgress(%progress, %msg) { }" );

   if ( verbose )
      Con::printf( "Parsing configuration file...\n" );

   // Set import options
   ColladaUtils::getOptions().reset();
   ColladaUtils::getOptions().forceUpdateMaterials = genMaterials;
   ColladaUtils::getOptions().useDiffuseNames = diffuseNames;

   if ( verbose )
      Con::printf( "Reading dae file...\n" );

   // Attempt to load the DAE file
   Resource<TSShape> shape = ResourceManager::get().load( srcPath );
   if ( !shape )
   {
      Con::errorf( "Failed to convert DAE file: %s\n", srcPath.getFullPath() );
      failed = 1;
   }
   else
   {
      if ( compatMode && !shape->canWriteOldFormat() )
      {
         Con::errorf( "Warning: Attempting to save to DTS v24 but the shape "
                      "contains v26 features. Resulting DTS file may not be valid." );
      }

      FileStream outStream;

      if ( saveDSQ )
      {
         Torque::Path dsqPath( destPath );
         dsqPath.setExtension( "dsq" );

         for ( S32 i = 0; i < shape->sequences.size(); i++ )
         {
            const String& seqName = shape->getName( shape->sequences[i].nameIndex );
            if ( verbose )
               Con::printf( "Writing DSQ file for sequence '%s'...\n", seqName.c_str() );

            dsqPath.setFileName( destPath.getFileName() + "_" + seqName );

            if ( outStream.open( dsqPath, Torque::FS::File::Write ) )
            {
               shape->exportSequence( &outStream, shape->sequences[i], compatMode );
               outStream.close();
            }
            else
            {
               Con::errorf( "Failed to save sequence to %s\n", dsqPath.getFullPath().c_str() );
               failed = 1;
            }
         }
      }
      if ( saveDTS )
      {
         if ( verbose )
            Con::printf( "Writing DTS file...\n" );

         if ( outStream.open( destPath, Torque::FS::File::Write ) )
         {
            if ( saveDSQ )
               shape->sequences.setSize(0);

            shape->write( &outStream, compatMode );
            outStream.close();
         }
         else
         {
            Con::errorf( "Failed to save shape to %s\n", destPath.getFullPath().c_str() );
            failed = 1;
         }
      }
   }

   // Clean everything up.
   StandardMainLoop::shutdown();

   // Do we need to restart?
   if( StandardMainLoop::requiresRestart() )
      Platform::restartInstance();

   return failed;
}
Пример #3
0
void TSShapeLoader::recurseSubshape(AppNode* appNode, S32 parentIndex, bool recurseChildren)
{
   // Ignore local bounds nodes
   if (appNode->isBounds())
      return;

   S32 subShapeNum = shape->subShapeFirstNode.size()-1;
   Subshape* subshape = subshapes[subShapeNum];

   // Check if we should collapse this node
   S32 myIndex;
   if (ignoreNode(appNode->getName()))
   {
      myIndex = parentIndex;
   }
   else
   {
      // Check that adding this node will not exceed the maximum node count
      if (shape->nodes.size() >= MAX_TS_SET_SIZE)
         return;

      myIndex = shape->nodes.size();
      String nodeName = getUniqueName(appNode->getName(), cmpShapeName, shape->names);

      // Create the 3space node
      shape->nodes.increment();
      shape->nodes.last().nameIndex = shape->addName(nodeName);
      shape->nodes.last().parentIndex = parentIndex;
      shape->nodes.last().firstObject = -1;
      shape->nodes.last().firstChild = -1;
      shape->nodes.last().nextSibling = -1;

      // Add the AppNode to a matching list (so AppNodes can be accessed using 3space
      // node indices)
      appNodes.push_back(appNode);
      appNodes.last()->mParentIndex = parentIndex;

      // Check for NULL detail or AutoBillboard nodes (no children or geometry)
      if ((appNode->getNumChildNodes() == 0) &&
          (appNode->getNumMesh() == 0))
      {
         S32 size = 0x7FFFFFFF;
         String dname(String::GetTrailingNumber(appNode->getName(), size));

         if (dStrEqual(dname, "nulldetail") && (size != 0x7FFFFFFF))
         {
            shape->addDetail("detail", size, subShapeNum);
         }
         else if (appNode->isBillboard() && (size != 0x7FFFFFFF))
         {
            // AutoBillboard detail
            S32 numEquatorSteps = 4;
            S32 numPolarSteps = 0;
            F32 polarAngle = 0.0f;
            S32 dl = 0;
            S32 dim = 64;
            bool includePoles = true;

            appNode->getInt("BB::EQUATOR_STEPS", numEquatorSteps);
            appNode->getInt("BB::POLAR_STEPS", numPolarSteps);
            appNode->getFloat("BB::POLAR_ANGLE", polarAngle);
            appNode->getInt("BB::DL", dl);
            appNode->getInt("BB::DIM", dim);
            appNode->getBool("BB::INCLUDE_POLES", includePoles);

            S32 detIndex = shape->addDetail( "bbDetail", size, -1 );
            shape->details[detIndex].bbEquatorSteps = numEquatorSteps;
            shape->details[detIndex].bbPolarSteps = numPolarSteps;
            shape->details[detIndex].bbDetailLevel = dl;
            shape->details[detIndex].bbDimension = dim;
            shape->details[detIndex].bbIncludePoles = includePoles;
            shape->details[detIndex].bbPolarAngle = polarAngle;
         }
      }
   }

   // Collect geometry
   for (U32 iMesh = 0; iMesh < appNode->getNumMesh(); iMesh++)
   {
      AppMesh* mesh = appNode->getMesh(iMesh);
      if (!ignoreMesh(mesh->getName()))
      {
         subshape->objMeshes.push_back(mesh);
         subshape->objNodes.push_back(mesh->isSkin() ? -1 : myIndex);
      }
   }

   // Create children
   if (recurseChildren)
   {
      for (int iChild = 0; iChild < appNode->getNumChildNodes(); iChild++)
         recurseSubshape(appNode->getChildNode(iChild), myIndex, true);
   }
}
Пример #4
0
// 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);
   }
}