void MaterialList::mapMaterial( U32 i ) { AssertFatal( i < size(), "MaterialList::mapMaterialList - index out of bounds" ); if( mMatInstList[i] != NULL ) return; // lookup a material property entry const String &matName = getMaterialName(i); // JMQ: this code assumes that all materials have names. if( matName.isEmpty() ) { mMatInstList[i] = NULL; return; } String materialName = MATMGR->getMapEntry(matName); // IF we didn't find it, then look for a PolyStatic generated Material // [a little cheesy, but we need to allow for user override of generated Materials] //if ( materialName.isEmpty() ) // materialName = MATMGR->getMapEntry( String::ToString( "polyMat_%s", (const char*)matName ) ); if ( materialName.isNotEmpty() ) { TSMaterial * mat = MATMGR->getMaterialDefinitionByName( materialName ); mMatInstList[i] = mat->createMatInstance(); } else { mMatInstList[i] = MATMGR->createFallbackMatInstance(); } }
//------------------------------------------------------------------------------ // drawFunc() //------------------------------------------------------------------------------ void Polygon::drawFunc() { BEGIN_DLIST unsigned int nv = getNumberOfVertices(); const osg::Vec3* vertices = getVertices(); if (nv >= 2) { // Draw with texture unsigned int ntc = getNumberOfTextureCoords(); if (ntc > 0 && hasTexture()) { const osg::Vec2* texCoord = getTextureCoord(); unsigned int tc = 0; // texture count glBegin(GL_POLYGON); for (unsigned int i = 0; i < nv; i++) { if (tc < ntc) { lcTexCoord2v(texCoord[tc++].ptr()); } lcVertex3v( vertices[i].ptr() ); } glEnd(); } // Draw without texture else { // get our color gradient, because if we have one, instead of a regular color, we will // override it here and set it on a per vertex level. ColorGradient* colGradient = dynamic_cast<ColorGradient*>(getColor()); glBegin(GL_POLYGON); osg::Vec3* ptr = nullptr; for (unsigned int i = 0; i < nv; i++) { if (colGradient != nullptr) { Basic::Color* col = colGradient->getColorByIdx(i+1); if (col != nullptr) glColor4f(static_cast<GLfloat>(col->red()), static_cast<GLfloat>(col->green()), static_cast<GLfloat>(col->blue()), static_cast<GLfloat>(col->alpha())); } // if we have a material name, we will set up like we have a material if (getMaterialName() != nullptr) { //lcVertex3v( vertices[i].ptr() ); ptr = const_cast<osg::Vec3*>(reinterpret_cast<const osg::Vec3*>(vertices[i].ptr())); if (ptr != nullptr) { calcNormal(); lcNormal3(norm.x(), norm.y(), -(norm.z())); lcVertex3(ptr->x(), ptr->y(), ptr->z()); } } else { lcVertex3v(vertices[i].ptr()); } } glEnd(); } } END_DLIST }
void GearsMeshBuilder::importIndexedTriangleList( const char *_meshName, const char *_materialName, uint32 vertexFlags, uint32 vcount, const MeshVertex *vertices, uint32 tcount, const uint32 *indices ) { _materialName = getMaterialName(_materialName); getCurrentMesh(_meshName); for (uint32 i=0; i<vcount; i++) { mAABB.setVector( vertices[i].mPos ); } mCurrentMesh->importIndexedTriangleList(_materialName,vertexFlags,vcount,vertices,tcount,indices); }
void GearsMeshBuilder::importTriangle( const char *_meshName, const char *_materialName, uint32 vertexFlags, const MeshVertex &v1, const MeshVertex &v2, const MeshVertex &v3 ) { _materialName = getMaterialName(_materialName); getCurrentMesh(_meshName); mAABB.setVector(v1.mPos); mAABB.setVector(v2.mPos); mAABB.setVector(v3.mPos); mCurrentMesh->importTriangle(_materialName,vertexFlags,v1,v2,v3); }
//----------------------------------------------------------------------- void TerrainCircleDecorator::buildMaterial(void) { Str matName = getMaterialName(); /// 得到或创建材质 mOgreMaterialPtr = Ogre::MaterialManager::getSingleton().getByName(matName); if (mOgreMaterialPtr.isNull()) { mOgreMaterialPtr = Ogre::MaterialManager::getSingleton().create(matName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); mOgreMaterialPtr->setReceiveShadows( false ); /// 得到渲染通道 Ogre::Pass* pass = mOgreMaterialPtr->getTechnique(0)->getPass(0); pass->setLightingEnabled(false); pass->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA); pass->setCullingMode(Ogre::CULL_NONE); pass->setDepthCheckEnabled( false ); } }
IGameObject* gkGameObject::clone( const gkStdString& newName ) const { IGameObject* ret = NULL; if ( m_pRenderLayer ) { Vec3 pos = getPosition(); Quat rot = getOrientation(); static int name_gen = 0; TCHAR new_name[255]; _tcscpy(new_name, getName().c_str()); _stprintf( new_name, _T("%s_%d"), new_name, name_gen++ ); ret = gEnv->pGameObjSystem->CreateStaticGeoGameObject( new_name, m_pRenderLayer->getMesh()->getName(), pos, rot ); ret->setScale( m_pRenderLayer->getScale() ); ret->getRenderLayer()->setMaterialName( getMaterialName() ); } return ret; }
TextureObject::TextureObject(const int width, const int height, const std::string name): width_(width), height_(height), name_(name) { texture_ = Ogre::TextureManager::getSingleton().createManual( name, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, width, height, 0, Ogre::PF_A8R8G8B8, Ogre::TU_DEFAULT ); material_ = Ogre::MaterialManager::getSingleton().create( getMaterialName(), // name Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); material_->getTechnique(0)->getPass(0)->createTextureUnitState( texture_->getName()); material_->setReceiveShadows(false); material_->getTechnique(0)->setLightingEnabled(true); material_->getTechnique(0)->getPass(0)->setCullingMode(Ogre::CULL_NONE); material_->getTechnique(0)->getPass(0)->setLightingEnabled(false); material_->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); material_->getTechnique(0)->getPass(0)->setDepthCheckEnabled(true); material_->getTechnique(0)->getPass(0)->setVertexColourTracking(Ogre::TVC_DIFFUSE); material_->getTechnique(0)->getPass(0)->createTextureUnitState(texture_->getName()); material_->getTechnique(0)->getPass(0)->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA); material_->getTechnique(0)->getPass(0) ->setSceneBlending(Ogre::SBT_TRANSPARENT_ALPHA); // material_->getTechnique(0)->getPass(0) // ->setSceneBlending(Ogre::SBT_MODULATE); }
//------------------------------------------------------ void MaterialService::loadMaterials(const FileGroupPtr& db) { if (!db->hasFile("TXLIST")) throw Exception(Exception::ERR_ITEM_NOT_FOUND, "Mission file does not contain Texture list chunk (TXLIST)", "MaterialService::loadMaterials"); // Load the TXLIST chunk from the resource mission file. Opde::FilePtr txtList = db->getFile("TXLIST"); // TODO: Exception handling on the chunk readout! // Okay, we are ready to map the arrays if (mFamilies != NULL) delete[] mFamilies; if (mTextures != NULL) delete[] mTextures; try { // TODO: This should be implemented using dtypes // Read the header... txtList->read(&mTxlistHeader, sizeof(DarkDBChunkTXLIST)); // now read all the families // allocate the needed space mFamilies = new DarkDBTXLIST_fam[mTxlistHeader.fam_count]; // load txtList->read(&(mFamilies[0]), sizeof(DarkDBTXLIST_fam) * mTxlistHeader.fam_count); // Now read the textures. Same as before // allocate the needed space mTextures = new DarkDBTXLIST_texture[mTxlistHeader.txt_count]; // load texture names txtList->read(&(mTextures[0]), sizeof(DarkDBTXLIST_texture) * mTxlistHeader.txt_count); } catch (Ogre::Exception& e) { if (mFamilies != NULL) delete[] mFamilies; if (mTextures != NULL) delete[] mTextures; // Connect the original exception to the printout: OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, String("Could not load texture list : ") + e.getFullDescription(), "BspLevel::loadMaterials"); } // Okay, we are ready to load the materials now! // Our resource group String resourceGroup = ResourceGroupManager::getSingleton().getWorldResourceGroupName(); // ------------- Following code loads the standard materials ------------------- // Iterate through all materials, and load them (tries to load material as a script (named family/texture), and if it fails, // it constructs one with the default settings, and tries a few extensions too for the image) for (unsigned int id = 1; id < mTxlistHeader.txt_count; id++) { // Try to find the family for the texture std::string path = getMaterialName(id); // Resulting material name StringUtil::StrStreamType matName; matName << "@template" << id; if (MaterialManager::getSingleton().resourceExists(matName.str())) // if the material is already defined // remove, as we have to redefine it MaterialManager::getSingleton().remove(matName.str()); // See if the material is defined by a script. If so, clone it to be named @templateXXXX (XXXX = texture number) // We seek material named: family/texture if (MaterialManager::getSingleton().resourceExists(path)) { LOG_INFO("loadMaterials: Found material definition for %s", path.c_str()); MaterialPtr origMat = MaterialManager::getSingleton().getByName(path); MaterialPtr shadMat = origMat->clone(matName.str(), true, resourceGroup); shadMat->load(); addWorldMaterialTemplate(id, shadMat); } else { // The material script was not found createStandardMaterial(id, matName.str(), path, resourceGroup); } // This is it. Material @templateXX created } // Initialize the flow textures (do this first so water specialisation will override) loadFlowTextures(db); createSkyHackMaterial(resourceGroup); createJorgeMaterial(resourceGroup); }
void Exporter::exportMaterial(const aiMaterial& mtl) const { std::string diffTex; std::string normTex; std::string specColTex; std::string shininessTex; std::string dispTex; std::string emissiveTex; std::string metallicTex; aiString path; std::string name = getMaterialName(mtl); LOGI("Exporting material %s", name.c_str()); // Diffuse texture if(mtl.GetTextureCount(aiTextureType_DIFFUSE) > 0) { if(mtl.GetTexture(aiTextureType_DIFFUSE, 0, &path) == AI_SUCCESS) { diffTex = getFilename(path.C_Str()); } else { ERROR("Failed to retrieve texture"); } } // Normal texture if(mtl.GetTextureCount(aiTextureType_NORMALS) > 0) { if(mtl.GetTexture(aiTextureType_NORMALS, 0, &path) == AI_SUCCESS) { normTex = getFilename(path.C_Str()); } else { ERROR("Failed to retrieve texture"); } } // Specular color if(mtl.GetTextureCount(aiTextureType_SPECULAR) > 0) { if(mtl.GetTexture(aiTextureType_SPECULAR, 0, &path) == AI_SUCCESS) { specColTex = getFilename(path.C_Str()); } else { ERROR("Failed to retrieve texture"); } } // Shininess color if(mtl.GetTextureCount(aiTextureType_SHININESS) > 0) { if(mtl.GetTexture(aiTextureType_SHININESS, 0, &path) == AI_SUCCESS) { shininessTex = getFilename(path.C_Str()); } else { ERROR("Failed to retrieve texture"); } } // Height texture if(mtl.GetTextureCount(aiTextureType_DISPLACEMENT) > 0) { if(mtl.GetTexture(aiTextureType_DISPLACEMENT, 0, &path) == AI_SUCCESS) { dispTex = getFilename(path.C_Str()); } else { ERROR("Failed to retrieve texture"); } } // Emissive texture if(mtl.GetTextureCount(aiTextureType_EMISSIVE) > 0) { if(mtl.GetTexture(aiTextureType_EMISSIVE, 0, &path) == AI_SUCCESS) { emissiveTex = getFilename(path.C_Str()); } else { ERROR("Failed to retrieve texture"); } } // Metallic texture if(mtl.GetTextureCount(aiTextureType_REFLECTION) > 0) { if(mtl.GetTexture(aiTextureType_REFLECTION, 0, &path) == AI_SUCCESS) { metallicTex = getFilename(path.C_Str()); } else { ERROR("Failed to retrieve texture"); } } // Write file static const char* diffNormSpecFragTemplate = #include "templates/diffNormSpecFrag.h" ; static const char* simpleVertTemplate = #include "templates/simpleVert.h" ; static const char* tessVertTemplate = #include "templates/tessVert.h" ; static const char* readRgbFromTextureTemplate = R"( <operation> <id>%id%</id> <returnType>vec3</returnType> <function>readRgbFromTexture</function> <arguments> <argument>%map%</argument> <argument>out2</argument> </arguments> </operation>)"; static const char* readRFromTextureTemplate = R"( <operation> <id>%id%</id> <returnType>float</returnType> <function>readRFromTexture</function> <arguments> <argument>%map%</argument> <argument>out2</argument> </arguments> </operation>)"; // Compose full template // First geometry part std::string materialStr; materialStr = R"(<?xml version="1.0" encoding="UTF-8" ?>)"; materialStr += "\n<material>\n\t<programs>\n"; if(/*dispTex.empty()*/ 1) { materialStr += simpleVertTemplate; } else { materialStr += tessVertTemplate; } materialStr += "\n"; // Then fragment part materialStr += diffNormSpecFragTemplate; materialStr += "\n\t</programs>\t</material>"; // Replace strings if(!dispTex.empty()) { materialStr = replaceAllString(materialStr, "%dispMap%", m_texrpath + dispTex); } // Diffuse if(!diffTex.empty()) { materialStr = replaceAllString(materialStr, "%diffuseColorInput%", R"(<input><type>sampler2D</type><name>uDiffuseColor</name><value>)" + m_texrpath + diffTex + R"(</value></input>)"); materialStr = replaceAllString(materialStr, "%diffuseColorFunc%", readRgbFromTextureTemplate); materialStr = replaceAllString(materialStr, "%id%", "10"); materialStr = replaceAllString(materialStr, "%map%", "uDiffuseColor"); materialStr = replaceAllString(materialStr, "%diffuseColorArg%", "out10"); }
void GearsMeshBuilder::importMaterial( const char *matName,const char *metaData ) { matName = getMaterialName(matName); mMaterialMap[matName] = metaData; }
void MaterialList::mapMaterial( U32 i ) { AssertFatal( i < size(), "MaterialList::mapMaterialList - index out of bounds" ); if( mMatInstList[i] != NULL ) return; // lookup a material property entry const String &matName = getMaterialName(i); // JMQ: this code assumes that all materials have names. if( matName.isEmpty() ) { mMatInstList[i] = NULL; return; } String materialName = MATMGR->getMapEntry(matName); // IF we didn't find it, then look for a PolyStatic generated Material // [a little cheesy, but we need to allow for user override of generated Materials] if ( materialName.isEmpty() ) materialName = MATMGR->getMapEntry( String::ToString( "polyMat_%s", matName.c_str() ) ); if ( materialName.isNotEmpty() ) { Material * mat = MATMGR->getMaterialDefinitionByName( materialName ); mMatInstList[i] = mat ? mat->createMatInstance() : MATMGR->createWarningMatInstance(); } else { if ( Con::getBoolVariable( "$Materials::createMissing", true ) ) { // No Material found, create new "default" material with just a diffuseMap // First see if there is a valid diffuse texture GFXTexHandle texHandle; if (mLookupPath.isEmpty()) { texHandle.set( mMaterialNames[i], &GFXDefaultStaticDiffuseProfile, avar("%s() - handle (line %d)", __FUNCTION__, __LINE__) ); } else { // Should we strip off the extension of the path here before trying // to load the texture? String fullPath = String::ToString( "%s/%s", mLookupPath.c_str(), mMaterialNames[i].c_str() ); texHandle.set( fullPath, &GFXDefaultStaticDiffuseProfile, avar("%s() - handle (line %d)", __FUNCTION__, __LINE__) ); } if ( texHandle.isValid() ) { String newMatName = Sim::getUniqueName( "DefaultMaterial" ); Material *newMat = MATMGR->allocateAndRegister( newMatName, mMaterialNames[i] ); // Flag this as an autogenerated Material newMat->mAutoGenerated = true; // Overwrite diffuseMap in new material newMat->mDiffuseMapFilename[0] = texHandle->mTextureLookupName; // Set up some defaults for transparent textures if (texHandle->mHasTransparency) { newMat->mTranslucent = true; newMat->mTranslucentBlendOp = Material::LerpAlpha; newMat->mTranslucentZWrite = true; newMat->mAlphaRef = 20; } // create a MatInstance for the new material mMatInstList[i] = newMat->createMatInstance(); #ifndef TORQUE_SHIPPING Con::warnf( "[MaterialList::mapMaterials] Creating missing material for texture: %s", texHandle->mTextureLookupName.c_str() ); #endif } else { Con::errorf( "[MaterialList::mapMaterials] Unable to find material for texture: %s", mMaterialNames[i].c_str() ); mMatInstList[i] = MATMGR->createWarningMatInstance(); } } else { mMatInstList[i] = MATMGR->createWarningMatInstance(); } } }
MStatus CXRayObjectExport::ExportPart(CEditableObject* O, MDagPath& mdagPath, MObject& mComponent) { MStatus stat = MS::kSuccess; MSpace::Space space = MSpace::kWorld; MFnMesh fnMesh( mdagPath, &stat ); if ( MS::kSuccess != stat) { fprintf(stderr,"Failure in MFnMesh initialization.\n"); return MS::kFailure; } MString mdagPathNodeName = fnMesh.name(); MFnDagNode dagNode1(mdagPath); u32 pc = dagNode1.parentCount(); for(u32 ip=0;ip<pc;++ip) { MObject object_parent = dagNode1.parent(ip, &stat); if(object_parent.hasFn(MFn::kTransform)) { MFnTransform parent_transform(object_parent,&stat); if ( MS::kSuccess == stat) { mdagPathNodeName = parent_transform.name(); break; } } } MItMeshPolygon meshPoly( mdagPath, mComponent, &stat ); if ( MS::kSuccess != stat) { fprintf(stderr,"Failure in MItMeshPolygon initialization.\n"); return MS::kFailure; } MItMeshVertex vtxIter( mdagPath, mComponent, &stat ); if ( MS::kSuccess != stat) { fprintf(stderr,"Failure in MItMeshVertex initialization.\n"); return MS::kFailure; } // If the shape is instanced then we need to determine which // instance this path refers to. // int instanceNum = 0; if (mdagPath.isInstanced()) instanceNum = mdagPath.instanceNumber(); // Get a list of all shaders attached to this mesh MObjectArray rgShaders; MIntArray texMap; MStatus status; status = fnMesh.getConnectedShaders (instanceNum, rgShaders, texMap); if (status == MStatus::kFailure) { Log("! Unable to load shaders for mesh"); return (MStatus::kFailure); } XRShaderDataVec xr_data; { for ( int i=0; i<(int)rgShaders.length(); i++ ) { MObject shader = rgShaders[i]; xr_data.push_back(SXRShaderData()); SXRShaderData& D = xr_data.back(); status = parseShader(shader, D); if (status == MStatus::kFailure) { status.perror ("Unable to retrieve filename of texture"); continue; } } } CEditableMesh* MESH = new CEditableMesh(O); MESH->SetName(mdagPathNodeName.asChar()); O->AppendMesh(MESH); int objectIdx, length; // Find i such that objectGroupsTablePtr[i] corresponds to the // object node pointed to by mdagPath length = objectNodeNamesArray.length(); { for( int i=0; i<length; i++ ) { if( objectNodeNamesArray[i] == mdagPathNodeName ) { objectIdx = i; break; } } } // Reserve uv table { VMapVec& _vmaps = MESH->m_VMaps; _vmaps.resize (1); st_VMap*& VM = _vmaps.back(); VM = new st_VMap("Texture",vmtUV,false); } // write faces { using FaceVec = xr_vector<st_Face>; using FaceIt = FaceVec::iterator; VMapVec& _vmaps = MESH->m_VMaps; SurfFaces& _surf_faces = MESH->m_SurfFaces; VMRefsVec& _vmrefs = MESH->m_VMRefs; // temp variables FvectorVec _points; FaceVec _faces; U32Vec _sgs; int f_cnt = fnMesh.numPolygons(); _sgs.reserve (f_cnt); _faces.reserve (f_cnt); _vmrefs.reserve (f_cnt*3); // int lastSmoothingGroup = INITIALIZE_SMOOTHING; MPointArray rgpt; MIntArray rgint; PtLookupMap ptMap; CSurface* surf = 0; for ( ; !meshPoly.isDone(); meshPoly.next()){ // Write out the smoothing group that this polygon belongs to // We only write out the smoothing group if it is different // from the last polygon. // int compIdx = meshPoly.index(); int smoothingGroup = polySmoothingGroups[ compIdx ]; // for each polygon, first setup the reverse mapping // between object-relative vertex indices and face-relative // vertex indices ptMap.clear(); for (int i=0; i<(int)meshPoly.polygonVertexCount(); i++) ptMap.insert (PtLookupMap::value_type(meshPoly.vertexIndex(i), i) ); // verify polygon zero area if (meshPoly.zeroArea()){ status = MS::kFailure; Log("! polygon have zero area:",meshPoly.index()); return status; } // verify polygon zero UV area /* if (meshPoly.zeroUVArea()){ status = MS::kFailure; Log("! polygon have zero UV area:",meshPoly.index()); return status; } */ // verify polygon has UV information if (!meshPoly.hasUVs (&status)) { status = MS::kFailure; Log("! polygon is missing UV information:",meshPoly.index()); return status; } int cTri; // now iterate through each triangle on this polygon and create a triangle object in our list status = meshPoly.numTriangles (cTri); if (!status) { Log("! can't getting triangle count"); return status; } for (int i=0; i < cTri; i++) { // for each triangle, first get the triangle data rgpt.clear();//triangle vertices rgint.clear();//triangle vertex indices // triangles that come from object are retrieved in world space status = meshPoly.getTriangle (i, rgpt, rgint, MSpace::kWorld); if (!status) { Log("! can't getting triangle for mesh poly"); return status; } if ((rgpt.length() != 3) || (rgint.length() != 3)) { Msg("! 3 points not returned for triangle"); return MS::kFailure; } // Write out vertex/uv index information // R_ASSERT2(fnMesh.numUVs()>0,"Can't find uvmaps."); _faces.push_back(st_Face()); _sgs.push_back(smoothingGroup); //set_smooth set_smoth_flags( _sgs.back(), rgint ); st_Face& f_it = _faces.back(); for ( int vtx=0; vtx<3; vtx++ ) { // get face-relative vertex PtLookupMap::iterator mapIt; int vtLocal, vtUV; int vt = rgint[vtx]; mapIt = ptMap.find(vt); Fvector2 uv; if (mapIt == ptMap.end()){ Msg("! Can't find local index."); return MS::kFailure; } vtLocal = (*mapIt).second; status = meshPoly.getUVIndex (vtLocal, vtUV, uv.x, uv.y); if (!status) { Msg("! error getting UV Index for local vertex '%d' and object vertex '%d'",vtLocal,vt); return status; } // flip v-part uv.y=1.f-uv.y; f_it.pv[2-vtx].pindex = AppendVertex(_points,rgpt[vtx]); f_it.pv[2-vtx].vmref = _vmrefs.size(); _vmrefs.push_back (st_VMapPtLst()); st_VMapPtLst& vm_lst = _vmrefs.back(); vm_lst.count = 1; vm_lst.pts = xr_alloc<st_VMapPt>(vm_lst.count); vm_lst.pts[0].vmap_index= 0; vm_lst.pts[0].index = AppendUV(_vmaps.back(),uv); } // out face material int iTexture = texMap[meshPoly.index()]; if (iTexture<0) xrDebug::Fatal(DEBUG_INFO,"Can't find material for polygon: %d",meshPoly.index()); SXRShaderData& D= xr_data[iTexture]; int compIdx = meshPoly.index(); surf = MESH->Parent()->CreateSurface(getMaterialName(mdagPath, compIdx, objectIdx),D); if (!surf) return MStatus::kFailure; _surf_faces[surf].push_back(_faces.size()-1); } } { // copy from temp MESH->m_VertCount = _points.size(); MESH->m_FaceCount = _faces.size(); MESH->m_Vertices = xr_alloc<Fvector>(MESH->m_VertCount); Memory.mem_copy (MESH->m_Vertices,&*_points.begin(),MESH->m_VertCount*sizeof(Fvector)); MESH->m_Faces = xr_alloc<st_Face>(MESH->m_FaceCount); Memory.mem_copy (MESH->m_Faces,&*_faces.begin(),MESH->m_FaceCount*sizeof(st_Face)); MESH->m_SmoothGroups = xr_alloc<u32>(MESH->m_FaceCount); Memory.mem_copy (MESH->m_SmoothGroups,&*_sgs.begin(),MESH->m_FaceCount*sizeof(u32)); MESH->RecomputeBBox (); } if ((MESH->GetVertexCount()<4)||(MESH->GetFaceCount()<2)) { Log ("! Invalid mesh: '%s'. Faces<2 or Verts<4",*MESH->Name()); return MS::kFailure; } } return stat; }