//--------------------------------------------------------------------------
// On add - verify data settings
//--------------------------------------------------------------------------
bool CustomMaterial::onAdd()
{
   if (Parent::onAdd() == false)
      return false;

   mShaderData = dynamic_cast<ShaderData*>(Sim::findObject( mShaderDataName ) );
   if(mShaderDataName.isNotEmpty() && mShaderData == NULL)
   {
      logError("Failed to find ShaderData %s", mShaderDataName.c_str());
      return false;
   }
   
   const char* samplerDecl = "sampler";
   S32 i = 0;
   for (SimFieldDictionaryIterator itr(getFieldDictionary()); *itr; ++itr)
   {
   	SimFieldDictionary::Entry* entry = *itr;
      if (dStrStartsWith(entry->slotName, samplerDecl))
      {
      	if (i >= MAX_TEX_PER_PASS)
         {
            logError("Too many sampler declarations, you may only have %i", MAX_TEX_PER_PASS);
            return false;
         }
         
         if (dStrlen(entry->slotName) == dStrlen(samplerDecl))
         {
         	logError("sampler declarations must have a sampler name, e.g. sampler[\"diffuseMap\"]");
            return false;
         }
         
         // Assert sampler names are defined on ShaderData
         S32 pos = -1;
         String samplerName = entry->slotName + dStrlen(samplerDecl);
         samplerName.insert(0, '$');
         mShaderData->hasSamplerDef(samplerName, pos);
         
         if(pos == -1)
         {
            const char *error = (avar("CustomMaterial(%s) bind sampler[%s] and is not present on ShaderData(%s)", 
               getName(), samplerName.c_str(), mShaderDataName.c_str() ));
            Con::errorf(error);
            GFXAssertFatal(0, error);
            continue;
         }
         mSamplerNames[pos] = samplerName;
         mTexFilename[pos] = entry->value;
         ++i;
      }
   }

   return true;
}
Example #2
0
void STDCALL glDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, 
	const GLchar *message, const void *userParam)
{
    // JTH [11/24/2016]: This is a temporary fix so that we do not get spammed for redundant fbo changes.
    // This only happens on Intel cards. This should be looked into sometime in the near future.
    if (dStrStartsWith(message, "API_ID_REDUNDANT_FBO"))
        return;
    if (severity == GL_DEBUG_SEVERITY_HIGH)
        Con::errorf("OPENGL: %s", message);
    else if (severity == GL_DEBUG_SEVERITY_MEDIUM)
        Con::warnf("OPENGL: %s", message);
    else if (severity == GL_DEBUG_SEVERITY_LOW)
        Con::printf("OPENGL: %s", message);
}
//--------------------------------------------------------------------------
// On add - verify data settings
//--------------------------------------------------------------------------
bool CustomMaterial::onAdd()
{
   if (Parent::onAdd() == false)
      return false;

   mShaderData = dynamic_cast<ShaderData*>(Sim::findObject( mShaderDataName ) );
   if(mShaderDataName.isNotEmpty() && mShaderData == NULL)
   {
      logError("Failed to find ShaderData %s", mShaderDataName.c_str());
      return false;
   }
   
   const char* samplerDecl = "sampler";
   S32 i = 0;
   for (SimFieldDictionaryIterator itr(getFieldDictionary()); *itr; ++itr)
   {
   	SimFieldDictionary::Entry* entry = *itr;
      if (dStrStartsWith(entry->slotName, samplerDecl))
      {
      	if (i >= MAX_TEX_PER_PASS)
         {
            logError("Too many sampler declarations, you may only have %i", MAX_TEX_PER_PASS);
            return false;
         }
         
         if (dStrlen(entry->slotName) == dStrlen(samplerDecl))
         {
         	logError("sampler declarations must have a sampler name, e.g. sampler[\"diffuseMap\"]");
            return false;
         }
         
      	mSamplerNames[i] = entry->slotName + dStrlen(samplerDecl);
         mSamplerNames[i].insert(0, '$');
         mTexFilename[i] = entry->value;
         ++i;
      }
   }

   return true;
}
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;
   }
}
void TSShapeLoader::generateObjects()
{
   for (S32 iSub = 0; iSub < subshapes.size(); iSub++)
   {
      Subshape* subshape = subshapes[iSub];
      shape->subShapeFirstObject.push_back(shape->objects.size());

      // Get the names and sizes of the meshes for this subshape
      Vector<String> meshNames;
      for (S32 iMesh = 0; iMesh < subshape->objMeshes.size(); iMesh++)
      {
         AppMesh* mesh = subshape->objMeshes[iMesh];
         mesh->detailSize = 2;
         String name = String::GetTrailingNumber( mesh->getName(), mesh->detailSize );
         name = getUniqueName( name, cmpMeshNameAndSize, meshNames, &(subshape->objMeshes), (void*)mesh->detailSize );
         meshNames.push_back( name );

         // Fix up any collision details that don't have a negative detail level.
         if (  dStrStartsWith(meshNames[iMesh], "Collision") ||
               dStrStartsWith(meshNames[iMesh], "LOSCol") )
         {
            if (mesh->detailSize > 0)
               mesh->detailSize = -mesh->detailSize;
         }
      }

      // An 'object' is a collection of meshes with the same base name and
      // different detail sizes. The object is attached to the node of the
      // highest detail mesh.

      // Sort the 3 arrays (objMeshes, objNodes, meshNames) by name and size
      for (S32 i = 0; i < subshape->objMeshes.size()-1; i++)
      {
         for (S32 j = i+1; j < subshape->objMeshes.size(); j++)
         {
            if ((meshNames[i].compare(meshNames[j]) < 0) ||
               ((meshNames[i].compare(meshNames[j]) == 0) &&
               (subshape->objMeshes[i]->detailSize < subshape->objMeshes[j]->detailSize)))
            {
               {
                  AppMesh* tmp = subshape->objMeshes[i];
                  subshape->objMeshes[i] = subshape->objMeshes[j];
                  subshape->objMeshes[j] = tmp;
               }
               {
                  S32 tmp = subshape->objNodes[i];
                  subshape->objNodes[i] = subshape->objNodes[j];
                  subshape->objNodes[j] = tmp;
               }
               {
                  String tmp = meshNames[i];
                  meshNames[i] = meshNames[j];
                  meshNames[j] = tmp;
               }
            }
         }
      }

      // Now create objects
      const String* lastName = 0;
      for (S32 iMesh = 0; iMesh < subshape->objMeshes.size(); iMesh++)
      {
         AppMesh* mesh = subshape->objMeshes[iMesh];

         if (!lastName || (meshNames[iMesh] != *lastName))
         {
            shape->objects.increment();
            shape->objects.last().nameIndex = shape->addName(meshNames[iMesh]);
            shape->objects.last().nodeIndex = subshape->objNodes[iMesh];
            shape->objects.last().startMeshIndex = appMeshes.size();
            shape->objects.last().numMeshes = 0;
            lastName = &meshNames[iMesh];
         }

         // Add this mesh to the object
         appMeshes.push_back(mesh);
         shape->objects.last().numMeshes++;

         // Set mesh flags
         mesh->flags = 0;
         if (mesh->isBillboard())
         {
            mesh->flags |= TSMesh::Billboard;
            if (mesh->isBillboardZAxis())
               mesh->flags |= TSMesh::BillboardZAxis;
         }

         // Set the detail name... do fixups for collision details.
         const char* detailName = "detail";
         if ( mesh->detailSize < 0 )
         {
            if (  dStrStartsWith(meshNames[iMesh], "Collision") ||
                  dStrStartsWith(meshNames[iMesh], "Col") )
               detailName = "Collision";
            else if (dStrStartsWith(meshNames[iMesh], "LOSCol"))
               detailName = "LOS";
         }

         // Attempt to add the detail (will fail if it already exists)
         S32 oldNumDetails = shape->details.size();
         shape->addDetail(detailName, mesh->detailSize, iSub);
         if (shape->details.size() > oldNumDetails)
         {
            Con::warnf("Object mesh \"%s\" has no matching detail (\"%s%d\" has"
               " been added automatically)", mesh->getName(false), detailName, mesh->detailSize);
         }
      }

      // Get object count for this subshape
      shape->subShapeNumObjects.push_back(shape->objects.size() - shape->subShapeFirstObject.last());
   }
}
Example #6
0
PhysicsCollision* CollisionComponent::buildColShapes()
{
   PROFILE_SCOPE(CollisionComponent_buildColShapes);

   PhysicsCollision *colShape = NULL;
   U32 surfaceKey = 0;

   TSShape* shape = mOwnerRenderInterface->getShape();

   if (mCollisionType == VisibleMesh)
   {
      // Here we build triangle collision meshes from the
      // visible detail levels.

      // A negative subshape on the detail means we don't have geometry.
      const TSShape::Detail &detail = shape->details[0];
      if (detail.subShapeNum < 0)
         return NULL;

      // We don't try to optimize the triangles we're given
      // and assume the art was created properly for collision.
      ConcretePolyList polyList;
      polyList.setTransform(&MatrixF::Identity, mOwner->getScale());

      // Create the collision meshes.
      S32 start = shape->subShapeFirstObject[detail.subShapeNum];
      S32 end = start + shape->subShapeNumObjects[detail.subShapeNum];
      for (S32 o = start; o < end; o++)
      {
         const TSShape::Object &object = shape->objects[o];
         if (detail.objectDetailNum >= object.numMeshes)
            continue;

         // No mesh or no verts.... nothing to do.
         TSMesh *mesh = shape->meshes[object.startMeshIndex + detail.objectDetailNum];
         if (!mesh || mesh->mNumVerts == 0)
            continue;

         // Gather the mesh triangles.
         polyList.clear();
         mesh->buildPolyList(0, &polyList, surfaceKey, NULL);

         // Create the collision shape if we haven't already.
         if (!colShape)
            colShape = PHYSICSMGR->createCollision();

         // Get the object space mesh transform.
         MatrixF localXfm;
         shape->getNodeWorldTransform(object.nodeIndex, &localXfm);

         colShape->addTriangleMesh(polyList.mVertexList.address(),
            polyList.mVertexList.size(),
            polyList.mIndexList.address(),
            polyList.mIndexList.size() / 3,
            localXfm);
      }

      // Return what we built... if anything.
      return colShape;
   }
   else if (mCollisionType == CollisionMesh)
   {

      // Scan out the collision hulls...
      //
      // TODO: We need to support LOS collision for physics.
      //
      for (U32 i = 0; i < shape->details.size(); i++)
      {
         const TSShape::Detail &detail = shape->details[i];
         const String &name = shape->names[detail.nameIndex];

         // Is this a valid collision detail.
         if (!dStrStartsWith(name, colisionMeshPrefix) || detail.subShapeNum < 0)
            continue;

         // Now go thru the meshes for this detail.
         S32 start = shape->subShapeFirstObject[detail.subShapeNum];
         S32 end = start + shape->subShapeNumObjects[detail.subShapeNum];
         if (start >= end)
            continue;

         for (S32 o = start; o < end; o++)
         {
            const TSShape::Object &object = shape->objects[o];
            const String &meshName = shape->names[object.nameIndex];

            if (object.numMeshes <= detail.objectDetailNum)
               continue;

            // No mesh, a flat bounds, or no verts.... nothing to do.
            TSMesh *mesh = shape->meshes[object.startMeshIndex + detail.objectDetailNum];
            if (!mesh || mesh->getBounds().isEmpty() || mesh->mNumVerts == 0)
               continue;

            // We need the default mesh transform.
            MatrixF localXfm;
            shape->getNodeWorldTransform(object.nodeIndex, &localXfm);

            // We have some sort of collision shape... so allocate it.
            if (!colShape)
               colShape = PHYSICSMGR->createCollision();

            // Any other mesh name we assume as a generic convex hull.
            //
            // Collect the verts using the vertex polylist which will 
            // filter out duplicates.  This is importaint as the convex
            // generators can sometimes fail with duplicate verts.
            //
            VertexPolyList polyList;
            MatrixF meshMat(localXfm);

            Point3F t = meshMat.getPosition();
            t.convolve(mOwner->getScale());
            meshMat.setPosition(t);

            polyList.setTransform(&MatrixF::Identity, mOwner->getScale());
            mesh->buildPolyList(0, &polyList, surfaceKey, NULL);
            colShape->addConvex(polyList.getVertexList().address(),
               polyList.getVertexList().size(),
               meshMat);
         } // objects
      } // details
   }

   return colShape;
}