//-------------------------------------------------------------------------- // 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; }
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()); } }
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; }