Mesh* SGP_MaxInterface::GetMesh( INode* pNode ) { if( !IsMesh( pNode ) ) return NULL; TimeValue time = 0; // get max mesh instance ObjectState os; os = pNode->EvalWorldState(time); Object* obj = os.obj; if( !os.obj ) { assert( false ); return NULL; } TriObject* triObj = (TriObject *)obj->ConvertToType( time, triObjectClassID ); if( !triObj ) { assert( false ); return NULL; } Mesh* pMesh = &triObj->GetMesh(); return pMesh; }
bool CollisionImport::ImportTriStripsShape(INode *rbody, bhkRigidBodyRef body, bhkNiTriStripsShapeRef shape, INode *parent, Matrix3& tm) { if (shape->GetNumStripsData() != 1) return NULL; if ( ImpNode *node = ni.i->CreateNode() ) { TriObject *triObject = CreateNewTriObject(); node->Reference(triObject); INode *inode = node->GetINode(); // Texture Mesh& mesh = triObject->GetMesh(); NiTriStripsDataRef triShapeData = shape->GetStripsData(0); if (triShapeData == NULL) return false; // Temporary shape NiTriStripsRef triShape = new NiTriStrips(); vector<Triangle> tris = triShapeData->GetTriangles(); ni.ImportMesh(node, triObject, triShape, triShapeData, tris); CreatebhkCollisionModifier(inode, bv_type_shapes, shape->GetMaterial(), OL_UNIDENTIFIED, 0); ImportBase(body, shape, parent, inode, tm); AddShape(rbody, inode); return true; } return false; }
void MatMod::ModifyObject(TimeValue t, ModContext &mc, ObjectState *os, INode *node) { Interval valid = FOREVER; int id; pblock->GetValue(PB_MATID,t,id,valid); id--; if (id<0) id = 0; if (id>0xffff) id = 0xffff; // For version 4 and later, we process patch meshes as they are and pass them on. Earlier // versions converted to TriMeshes (done below). For adding other new types of objects, add // them here! #ifndef NO_PATCHES if(version >= MATMOD_VER4 && os->obj->IsSubClassOf(patchObjectClassID)) { PatchObject *patchOb = (PatchObject *)os->obj; PatchMesh &pmesh = patchOb->GetPatchMesh(t); BOOL useSel = pmesh.selLevel >= PO_PATCH; for (int i=0; i<pmesh.getNumPatches(); i++) { if (!useSel || pmesh.patchSel[i]) { pmesh.setPatchMtlIndex(i,(MtlID)id); } } pmesh.InvalidateGeomCache(); // Do this because there isn't a topo cache in PatchMesh patchOb->UpdateValidity(TOPO_CHAN_NUM,valid); } else #endif // NO_PATCHES // Process PolyObjects if(os->obj->IsSubClassOf(polyObjectClassID)) { PolyObject *polyOb = (PolyObject *)os->obj; MNMesh &mesh = polyOb->GetMesh(); BOOL useSel = mesh.selLevel == MNM_SL_FACE; for (int i=0; i<mesh.numf; i++) { if (!useSel || mesh.f[i].GetFlag(MN_SEL)) { mesh.f[i].material = (MtlID)id; } } polyOb->UpdateValidity(TOPO_CHAN_NUM,valid); } else // If it's a TriObject, process it if(os->obj->IsSubClassOf(triObjectClassID)) { TriObject *triOb = (TriObject *)os->obj; DoMaterialSet(triOb, id); triOb->UpdateValidity(TOPO_CHAN_NUM,valid); } else // Fallback position: If it can convert to a TriObject, do it! if(os->obj->CanConvertToType(triObjectClassID)) { TriObject *triOb = (TriObject *)os->obj->ConvertToType(t, triObjectClassID); // Now stuff this into the pipeline! os->obj = triOb; DoMaterialSet(triOb, id); triOb->UpdateValidity(TOPO_CHAN_NUM,valid); } else return; // Do nothing if it can't convert to triObject }
void CVDModifier::ModifyObject(TimeValue t, ModContext &mc, ObjectState *os, INode *node) { if (!os->obj->IsSubClassOf(triObjectClassID)) return; // Get a mesh from input object TriObject *tobj = (TriObject*)os->obj; Mesh* mesh = &tobj->GetMesh(); int numVert = mesh->getNumVerts(); // Get parameters from pblock float sparam = 0.0f; Interval valid = FOREVER; pblock->GetValue(cvd_codev, t, sparam, valid); // Take over the channel, realloc with size == number of verts mesh->setVDataSupport(MY_CHANNEL,TRUE); // Get a pointer back to the floating point array float *vdata = mesh->vertexFloat(MY_CHANNEL); if(vdata) { // loop through all verticies // Ask the random number generator for a value bound to the // paramblock value // and encode it into the vertex. for(int i=0;i<numVert;i++) { vdata[i] = randomGen.getf(sparam); } } }
void bhkProxyObject::BuildColCapsule() { proxyMesh.FreeAll(); MeshDelta md(proxyMesh); for (int i = 0;i < pblock2->Count(PB_MESHLIST); i++) { INode *tnode = NULL; pblock2->GetValue(PB_MESHLIST,0,tnode,FOREVER,i); if (tnode) { ObjectState os = tnode->EvalWorldState(0); Matrix3 wm = tnode->GetNodeTM(0); TriObject *tri = (TriObject *)os.obj->ConvertToType(0, Class_ID(TRIOBJ_CLASS_ID, 0)); if (tri) { Mesh& mesh = tri->GetMesh(); MeshDelta tmd (mesh); md.AttachMesh(proxyMesh, mesh, wm, 0); md.Apply(proxyMesh); } } } Point3 pt1 = Point3::Origin; Point3 pt2 = Point3::Origin; float r1 = 0.0; float r2 = 0.0; if (proxyMesh.getNumVerts() > 3) // Doesn't guarantee that the mesh is not a plane. { CalcCapsule(proxyMesh, pt1, pt2, r1, r2); BuildCapsule(proxyMesh, pt1, pt2, r1, r2); } proxyPos = Point3::Origin; forceRedraw = true; }
void bhkProxyObject::BuildColBox() { Box3 box; box.Init(); for (int i = 0;i < pblock2->Count(PB_MESHLIST); i++) { INode *tnode = NULL; pblock2->GetValue(PB_MESHLIST,0,tnode,FOREVER,i); if (tnode) { ObjectState os = tnode->EvalWorldState(0); Matrix3 wm = tnode->GetNodeTM(0); TriObject *tri = (TriObject *)os.obj->ConvertToType(0, Class_ID(TRIOBJ_CLASS_ID, 0)); if (tri) { Box3 box2; box2.Init(); Mesh& mesh = tri->GetMesh(); CalcAxisAlignedBox(mesh, box2, &wm); box += box2; } } } BuildBox(proxyMesh, box.Max().y-box.Min().y, box.Max().x-box.Min().x, box.Max().z-box.Min().z); MNMesh mn(proxyMesh); Matrix3 tm(true); tm.SetTranslate(box.Center()); mn.Transform(tm); mn.OutToTri(proxyMesh); //proxyPos = box.Center(); proxyPos = Point3::Origin; forceRedraw = true; }
void bhkProxyObject::BuildColConvex() { proxyMesh.FreeAll(); MeshDelta md(proxyMesh); for (int i = 0;i < pblock2->Count(PB_MESHLIST); i++) { INode *tnode = NULL; pblock2->GetValue(PB_MESHLIST,0,tnode,FOREVER,i); if (tnode) { ObjectState os = tnode->EvalWorldState(0); Matrix3 wm = tnode->GetNodeTM(0); TriObject *tri = (TriObject *)os.obj->ConvertToType(0, Class_ID(TRIOBJ_CLASS_ID, 0)); if (tri) { Mesh& mesh = tri->GetMesh(); MeshDelta tmd (mesh); md.AttachMesh(proxyMesh, mesh, wm, 0); md.Apply(proxyMesh); } } } compute_convex_hull(proxyMesh, proxyMesh); BuildOptimize(proxyMesh); proxyPos = Point3::Origin; forceRedraw = true; }
BOOL plDistributor::IReadyRepNodes(plMeshCacheTab& cache) const { int i; for( i = 0; i < fRepNodes.Count(); i++ ) { Mesh* mesh = nil; TriObject* obj = nil; if( IGetMesh(fRepNodes[i], obj, mesh) ) { plMaxNode* repNode = (plMaxNode*)fRepNodes[i]; int iCache = cache.Count(); cache.SetCount(iCache + 1); cache[iCache].fMesh = new Mesh(*mesh); cache[iCache].fFlex = repNode->GetFlexibility(); if( obj ) obj->DeleteThis(); BOOL hasXImp = nil != repNode->GetXImposterComp(); ISetupNormals(repNode, cache[iCache].fMesh, hasXImp); ISetupSkinWeights(repNode, cache[iCache].fMesh, cache[iCache].fFlex); } else { fRepNodes.Delete(i, 1); i--; } } return fRepNodes.Count() > 0; }
int XTCSample::Display(TimeValue t, INode* inode, ViewExp *vpt, int flags, Object *pObj) { if ( ! vpt || ! vpt->IsAlive() ) { // why are we here DbgAssert(!_T("Doing Display() on invalid viewport!")); return FALSE; } if(pObj->ClassID() == XGSPHERE_CLASS_ID || pObj->IsSubClassOf(triObjectClassID)) { return DisplayMesh(t, inode, vpt, flags, GetMesh(pObj)); } #ifndef NO_PATCHES else if( pObj->IsSubClassOf(patchObjectClassID) ) { return DisplayPatch(t, inode, vpt, flags, (PatchObject *) pObj); } #endif else if(pObj->CanConvertToType(triObjectClassID)) { TriObject *pTri = (TriObject *) pObj->ConvertToType(t,triObjectClassID); DisplayMesh(t, inode, vpt, flags, &pTri->mesh); if(pTri != pObj) pTri->DeleteThis(); } return 0; }
float plMaxNodeBase::RegionPriority() { TimeValue currTime = 0;//hsConverterUtils::Instance().GetTime(GetInterface()); Object *obj = EvalWorldState(currTime).obj; if( !obj ) return 0; Matrix3 l2w = GetObjectTM(currTime); if( obj->ClassID() == Class_ID(DUMMY_CLASS_ID,0) ) { DummyObject* dummy = (DummyObject*)obj; Box3 bnd = dummy->GetBox(); return BoxVolume(bnd, l2w); } if( obj->CanConvertToType(triObjectClassID) ) { TriObject *meshObj = (TriObject *)obj->ConvertToType(currTime, triObjectClassID); if( !meshObj ) return 0; Mesh& mesh = meshObj->mesh; Box3 bnd = mesh.getBoundingBox(); if( meshObj != obj ) meshObj->DeleteThis(); return BoxVolume(bnd, l2w); } // Don't know how to interpret other, it's not contained. return 0; }
hsBool plMaxNodeBase::Contains(const Point3& worldPt) { TimeValue currTime = 0;//hsConverterUtils::Instance().GetTime(GetInterface()); Object *obj = EvalWorldState(currTime).obj; if( !obj ) return false; Matrix3 l2w = GetObjectTM(currTime); Matrix3 w2l = Inverse(l2w); Point3 pt = w2l * worldPt; if( obj->ClassID() == Class_ID(DUMMY_CLASS_ID,0) ) { DummyObject* dummy = (DummyObject*)obj; Box3 bnd = dummy->GetBox(); return bnd.Contains(pt); } if( obj->CanConvertToType(triObjectClassID) ) { TriObject *meshObj = (TriObject *)obj->ConvertToType(currTime, triObjectClassID); if( !meshObj ) return false; Mesh& mesh = meshObj->mesh; Box3 bnd = mesh.getBoundingBox(); if( !bnd.Contains(pt) ) { if( meshObj != obj ) meshObj->DeleteThis(); return false; } hsBool retVal = true; int i; for( i = 0; i < mesh.getNumFaces(); i++ ) { Face& face = mesh.faces[i]; Point3 p0 = mesh.verts[face.v[0]]; Point3 p1 = mesh.verts[face.v[1]]; Point3 p2 = mesh.verts[face.v[2]]; Point3 n = CrossProd(p1 - p0, p2 - p0); if( DotProd(pt, n) > DotProd(p0, n) ) { retVal = false; break; } } if( meshObj != obj ) meshObj->DeleteThis(); return retVal; } // If we can't figure out what it is, the point isn't inside it. return false; }
bool BakeRadiosity::CreateNewMesh (INode *orgNode, Mesh *orgMesh, Matrix3 orgMtx) { if((orgNode == NULL)||(orgMesh == NULL)){ DebugPrint(_T("Mesh error\n")); return false; } // Creates an instance of a registered class. Object *newObj = (Object*)(ip->CreateInstance( GEOMOBJECT_CLASS_ID, Class_ID(TRIOBJ_CLASS_ID, 0))); if(newObj == NULL){ DebugPrint(_T("CreateInstance error\n")); return false; } // Creates a new node in the scene with the given object. INode *newNode = ip->CreateObjectNode(newObj); if(newNode == NULL){ DebugPrint(_T("CreateObjectNode error\n")); return false; } // Sets the name of the node. if(keepOrgFlag != true){ newNode->SetName(orgNode->GetName()); } else { TSTR newName; newName.printf(_T("%s_BAKED"), orgNode->GetName()); newNode->SetName(newName); } // Sets the renderer material used by the node. newNode->SetMtl(orgNode->GetMtl()); // Returns a reference to the mesh data member of new TriObject. TriObject *newTriObj = (TriObject *)newObj; Mesh &newMesh = newTriObj->GetMesh(); // Returns the number of vertices from original mesh. int nbVert = orgMesh->getNumVerts(); // Sets the number of geometric vertices in the new mesh. newMesh.setNumVerts(nbVert); // The loop will continue until handling all vertices... for(int i=0; i<nbVert; i++) { newMesh.verts[i] = orgMtx * orgMesh->verts[i];//Set new vertices } // Returns the number of faces in the original mesh. int nbFace = orgMesh->getNumFaces(); // Sets the number of faces in the new mesh // and previous faces are discarded. newMesh.setNumFaces(nbFace, FALSE); // The loop will continue until handling all faces... for(int i=0; i<nbFace; i++){ // Set new faces and Material id newMesh.faces[i] = orgMesh->faces[i]; newMesh.faces[i].setMatID(orgMesh->faces[i].getMatID()); } // Makes a complete copy of the specified channels // of the original Mesh object into new Mesh. newMesh.DeepCopy(orgMesh, CNVERT_CHANNELS); return true; }
void UnwrapMod::GetFaceSelectionFromMesh(ObjectState *os, ModContext &mc, TimeValue t) { TriObject *tobj = (TriObject*)os->obj; MeshTopoData *d = (MeshTopoData*)mc.localData; if (d) { d->SetFaceSel(tobj->GetMesh().faceSel, this, t); UpdateFaceSelection(d->faceSel); } }
void AFRMod::ModifyObject (TimeValue t, ModContext &mc, ObjectState *os, INode *node) { Interval iv = FOREVER; float f, p, b; int backface; Point3 pt1, pt2; pblock->GetValue(PB_FALLOFF,t,f,iv); pblock->GetValue(PB_PINCH,t,p,iv); pblock->GetValue(PB_BUBBLE,t,b,iv); pblock->GetValue(PB_BACKFACE,t,backface,iv); p1->GetValue(t,&pt1,iv,CTRL_ABSOLUTE); p2->GetValue(t,&pt2,iv,CTRL_ABSOLUTE); if (f==0.0) { os->obj->UpdateValidity(GEOM_CHAN_NUM,iv); return; } Tab<Point3> normals; if (backface) { // Need to get vertex normals. if (os->obj->IsSubClassOf(triObjectClassID)) { TriObject *tobj = (TriObject*)os->obj; AverageVertexNormals (tobj->GetMesh(), normals); } else if (os->obj->IsSubClassOf (polyObjectClassID)) { PolyObject *pobj = (PolyObject *) os->obj; MNMesh &mesh = pobj->GetMesh(); normals.SetCount (mesh.numv); Point3 *vn = normals.Addr(0); for (int i=0; i<mesh.numv; i++) { if (mesh.v[i].GetFlag (MN_DEAD)) vn[i]=Point3(0,0,0); else vn[i] = mesh.GetVertexNormal (i); } #ifndef NO_PATCHES } else if (os->obj->IsSubClassOf (patchObjectClassID)) { PatchObject *pobj = (PatchObject *) os->obj; normals.SetCount (pobj->NumPoints ()); Point3 *vn = normals.Addr(0); for (int i=0; i<pobj->NumPoints(); i++) vn[i] = pobj->VertexNormal (i); #endif } } if (normals.Count()) { AFRDeformer deformer(mc,f,p,b,pt1,pt2,&normals); os->obj->Deform(&deformer, TRUE); } else { AFRDeformer deformer(mc,f,p,b,pt1,pt2); os->obj->Deform(&deformer, TRUE); } os->obj->UpdateValidity(GEOM_CHAN_NUM,iv); }
INode *CollisionImport::ImportCollisionMesh( const vector<Vector3>& verts, const vector<Triangle>& tris, const vector<Vector3>& norms, Matrix3& tm, INode *parent ) { INode *returnNode = NULL; if ( ImpNode *node = ni.i->CreateNode() ) { TriObject *triObject = CreateNewTriObject(); node->Reference(triObject); Mesh& mesh = triObject->GetMesh(); INode *tnode = node->GetINode(); // Vertex info { int nVertices = verts.size(); mesh.setNumVerts(nVertices); for (int i=0; i < nVertices; ++i){ Vector3 v = verts[i] * ni.bhkScaleFactor; mesh.verts[i].Set(v.x, v.y, v.z); } } // Triangles and texture vertices ni.SetTriangles(mesh, tris); //ni.SetNormals(mesh, tris, norms); MNMesh mn(mesh); mn.Transform(tm); mn.OutToTri(mesh); mesh.checkNormals(TRUE); ni.i->AddNodeToScene(node); returnNode = node->GetINode(); returnNode->EvalWorldState(0); if (parent != NULL) parent->AttachChild(tnode, 1); } return returnNode; }
Object *TriObject::MakeShallowCopy(ChannelMask channels) { TriObject* newob = CreateNewTriObject(); #ifdef TRIPIPE_DEBUG DebugPrint ("TriObject(%08x)::MakeShallowCopy (%08x): %08x\n", this, channels, newob); #endif newob->ShallowCopy(this,channels); /* Redundant code NS:03-15-00 newob->mesh.ShallowCopy(&mesh,channels); newob->CopyValidity(this,channels); newob->mDispApprox = mDispApprox; newob->mSubDivideDisplacement = mSubDivideDisplacement; newob->mSplitMesh = mSplitMesh; newob->mDisableDisplacement = mDisableDisplacement; */ return newob; }
void bhkProxyObject::BuildColOBB() { proxyMesh.FreeAll(); MeshDelta md(proxyMesh); for (int i = 0;i < pblock2->Count(PB_MESHLIST); i++) { INode *tnode = NULL; pblock2->GetValue(PB_MESHLIST,0,tnode,FOREVER,i); if (tnode) { ObjectState os = tnode->EvalWorldState(0); Matrix3 wm = tnode->GetNodeTM(0); TriObject *tri = (TriObject *)os.obj->ConvertToType(0, Class_ID(TRIOBJ_CLASS_ID, 0)); if (tri) { Mesh& mesh = tri->GetMesh(); MeshDelta tmd (mesh); md.AttachMesh(proxyMesh, mesh, wm, 0); md.Apply(proxyMesh); } } } Matrix3 rtm(true); Point3 center = Point3::Origin;; float udim = 0.0f, vdim = 0.0f, ndim = 0.0f; if (proxyMesh.getNumVerts() > 3) // Doesn't guarantee that the mesh is not a plane. { // First build a convex mesh to put the box around; // the method acts oddly if extra vertices are present. BuildColConvex(); CalcOrientedBox(proxyMesh, udim, vdim, ndim, center, rtm); BuildBox(proxyMesh, vdim, udim, ndim); } MNMesh mn(proxyMesh); mn.Transform(rtm); mn.OutToTri(proxyMesh); proxyPos = Point3::Origin; forceRedraw = true; }
Object* bhkProxyObject::ConvertToType(TimeValue t, Class_ID obtype) { if (obtype == triObjectClassID) { int bvType = 0; pblock2->GetValue(PB_BOUND_TYPE, 0, bvType, FOREVER, 0); if (bvType != 0) { TriObject *ob = CreateNewTriObject(); #if VERSION_3DSMAX >= ((5000<<16)+(15<<8)+0) // Version 5+ ob->GetMesh().CopyBasics(proxyMesh); #else ob->GetMesh() = proxyMesh; #endif ob->SetChannelValidity(TOPO_CHAN_NUM,ObjectValidity(t)); ob->SetChannelValidity(GEOM_CHAN_NUM,ObjectValidity(t)); return ob; } } return 0; }
int OBJImport::DoImport(const TCHAR *filename,ImpInterface *i,Interface *gi, BOOL suppressPrompts) { TriObject *object = CreateNewTriObject(); if(!object) return 0; if(objFileRead(filename, &object->GetMesh())) { ImpNode *node = i->CreateNode(); if(!node) { delete object; return 0; } Matrix3 tm; tm.IdentityMatrix(); node->Reference(object); node->SetTransform(0,tm); i->AddNodeToScene(node); node->SetName(GetString(IDS_TH_WAVE_OBJ_NAME)); i->RedrawViews(); return 1; } return 0; }
BOOL FaceDataExport::nodeEnum(INode* node,Interface *ip) { if(!exportSelected || node->Selected()) { ObjectState os = node->EvalWorldState(ip->GetTime()); IFaceDataMgr *pFDMgr = NULL; if (os.obj->IsSubClassOf(triObjectClassID)) { TriObject *tobj = (TriObject *)os.obj; Mesh* mesh = &tobj->GetMesh(); pFDMgr = static_cast<IFaceDataMgr*>(mesh->GetInterface( FACEDATAMGR_INTERFACE )); } else if (os.obj->IsSubClassOf (polyObjectClassID)) { PolyObject *pobj = (PolyObject *)os.obj; MNMesh *mesh = &pobj->GetMesh(); pFDMgr = static_cast<IFaceDataMgr*>(mesh->GetInterface( FACEDATAMGR_INTERFACE )); } if (pFDMgr == NULL) return FALSE; SampleFaceData* SampleDataChan = NULL; IFaceDataChannel* fdc = pFDMgr->GetFaceDataChan( FACE_MAXSAMPLEUSE_CLSID ); if ( fdc != NULL ) SampleDataChan = dynamic_cast<SampleFaceData*>(fdc); if ( SampleDataChan == NULL) { fileStream.Printf(_T("Node %s does not have our Face Data\n"),node->GetName()); return false; } //OK so We have Face data lets dump it out.. fileStream.Printf(_T("\nNode %s has %d faces with FaceFloats\n"),node->GetName(), SampleDataChan->Count()); for(ULONG i=0;i<SampleDataChan->Count();i++) { float data = SampleDataChan->data[i]; fileStream.Printf(_T("Face %d, float %f\n"),i,data); } } // Recurse through this node's children, if any for (int c = 0; c < node->NumberOfChildren(); c++) { if (!nodeEnum(node->GetChildNode(c), ip)) return FALSE; } return TRUE; }
Object* SimpleObject::ConvertToType(TimeValue t, Class_ID obtype) { if (obtype==defObjectClassID||obtype==triObjectClassID||obtype==mapObjectClassID) { TriObject *triob; UpdateMesh(t); triob = CreateNewTriObject(); triob->GetMesh() = mesh; triob->SetChannelValidity(TOPO_CHAN_NUM,ObjectValidity(t)); triob->SetChannelValidity(GEOM_CHAN_NUM,ObjectValidity(t)); return triob; } else if (obtype == patchObjectClassID) { UpdateMesh(t); PatchObject *patchob = new PatchObject(); patchob->patch = mesh; // Handy Mesh->PatchMesh conversion patchob->SetChannelValidity(TOPO_CHAN_NUM,ObjectValidity(t)); patchob->SetChannelValidity(GEOM_CHAN_NUM,ObjectValidity(t)); return patchob; } return Object::ConvertToType(t,obtype); }
void EditFaceDataMod::ModifyObject (TimeValue t, ModContext &mc, ObjectState *os, INode *node) { if (mDisabled) return; EditFaceDataModData *d = (EditFaceDataModData*)mc.localData; if (!d) mc.localData = d = new EditFaceDataModData(); if (os->obj->IsSubClassOf(triObjectClassID)) { // Access the Mesh: TriObject *tobj = (TriObject*)os->obj; Mesh & mesh = tobj->GetMesh(); // Apply our modifier's changes: d->ApplyChanges (mesh); // Update the cache used for display and hit testing: if (!d->GetCacheMesh()) d->SetCacheMesh(mesh); // Set display flags according to SO level: mesh.dispFlags = 0; mesh.SetDispFlag (levelDispFlags[selLevel]); } else if (os->obj->IsSubClassOf(polyObjectClassID)) { // Access the Mesh: PolyObject *pobj = (PolyObject*)os->obj; MNMesh & mesh = pobj->GetMesh(); // Apply our modifier's changes: d->ApplyChanges (mesh); // Update the cache used for display and hit testing: if (!d->GetCacheMNMesh()) d->SetCacheMNMesh(mesh); // Set display flags according to SO level: mesh.dispFlags = 0; mesh.SetDispFlag (mnlevelDispFlags[selLevel]); } }
bool NifImporter::ImportMesh(NiTriStripsRef triStrips) { bool ok = true; ImpNode *node = i->CreateNode(); if(!node) return false; INode *inode = node->GetINode(); TriObject *triObject = CreateNewTriObject(); node->Reference(triObject); wstring name = wide(triStrips->GetName()); node->SetName(name.c_str()); // Texture Mesh& mesh = triObject->GetMesh(); NiTriStripsDataRef triStripsData = DynamicCast<NiTriStripsData>(triStrips->GetData()); if (triStripsData == NULL) return false; vector<Triangle> tris = triStripsData->GetTriangles(); ok |= ImportMesh(node, triObject, triStrips, triStripsData, tris); return ok; }
Object* SimpleObject::ConvertToType(TimeValue t, Class_ID obtype) { if (obtype==defObjectClassID||obtype==triObjectClassID||obtype==mapObjectClassID) { TriObject *triob; UpdateMesh(t); triob = CreateNewTriObject(); triob->GetMesh() = mesh; triob->SetChannelValidity(TOPO_CHAN_NUM,ObjectValidity(t)); triob->SetChannelValidity(GEOM_CHAN_NUM,ObjectValidity(t)); return triob; } #ifndef NO_PATCHES if (obtype == patchObjectClassID) { UpdateMesh(t); PatchObject *patchob = new PatchObject(); patchob->patch = mesh; // Handy Mesh->PatchMesh conversion patchob->SetChannelValidity(TOPO_CHAN_NUM,ObjectValidity(t)); patchob->SetChannelValidity(GEOM_CHAN_NUM,ObjectValidity(t)); return patchob; } #endif if (Object::CanConvertToType (obtype)) { UpdateMesh (t); return Object::ConvertToType(t,obtype); } if (CanConvertTriObject(obtype)) { UpdateMesh (t); TriObject *triob = CreateNewTriObject (); triob->GetMesh() = mesh; triob->SetChannelValidity(TOPO_CHAN_NUM,ObjectValidity(t)); triob->SetChannelValidity(GEOM_CHAN_NUM,ObjectValidity(t)); Object *ob = triob->ConvertToType (t, obtype); if (ob != triob) triob->DeleteThis (); // (ob should never = tob.) return ob; } return NULL; }
Exporter::Result Exporter::exportMesh(NiNodeRef &ninode, INode *node, TimeValue t) { ObjectState os = node->EvalWorldState(t); bool local = !mFlattenHierarchy; TriObject *tri = (TriObject *)os.obj->ConvertToType(t, Class_ID(TRIOBJ_CLASS_ID, 0)); if (!tri) return Skip; Mesh *copymesh = NULL; Mesh *mesh = &tri->GetMesh(); Matrix3 mtx(true), rtx(true); if (Exporter::mCollapseTransforms) { mtx = GetNodeLocalTM(node, t); mtx.NoTrans(); Quat q(mtx); q.MakeMatrix(rtx); mesh = copymesh = new Mesh(*mesh); { int n = mesh->getNumVerts(); for ( unsigned int i = 0; i < n; ++i ) { Point3& vert = mesh->getVert(i); vert = mtx * vert; } mesh->checkNormals(TRUE); #if VERSION_3DSMAX > ((5000<<16)+(15<<8)+0) // Version 6+ MeshNormalSpec *specNorms = mesh->GetSpecifiedNormals (); if (NULL != specNorms) { specNorms->CheckNormals(); for ( unsigned int i = 0; i < specNorms->GetNumNormals(); ++i ) { Point3& norm = specNorms->Normal(i); norm = (rtx * norm).Normalize(); } } #endif } } // Note that calling setVCDisplayData will clear things like normals so we set this up first vector<Color4> vertColors; if (mVertexColors) { bool hasvc = false; if (mesh->mapSupport(MAP_ALPHA)) { mesh->setVCDisplayData(MAP_ALPHA); int n = mesh->getNumVertCol(); if (n > vertColors.size()) vertColors.assign(n, Color4(1.0f, 1.0f, 1.0f, 1.0f)); VertColor *vertCol = mesh->vertColArray; if (vertCol) { for (int i=0; i<n; ++i) { VertColor c = vertCol[ i ]; float a = (c.x + c.y + c.z) / 3.0f; vertColors[i].a = a; hasvc |= (a != 1.0f); } } } if (mesh->mapSupport(0)) { mesh->setVCDisplayData(0); VertColor *vertCol = mesh->vertColArray; int n = mesh->getNumVertCol(); if (n > vertColors.size()) vertColors.assign(n, Color4(1.0f, 1.0f, 1.0f, 1.0f)); if (vertCol) { for (int i=0; i<n; ++i) { VertColor col = vertCol[ i ]; vertColors[i] = Color4(col.x, col.y, col.z, vertColors[i].a); hasvc |= (col.x != 1.0f || col.y != 1.0f || col.z != 1.0f); } } } if (!hasvc) vertColors.clear(); } #if VERSION_3DSMAX <= ((5000<<16)+(15<<8)+0) // Version 5 mesh->checkNormals(TRUE); #else MeshNormalSpec *specNorms = mesh->GetSpecifiedNormals (); if (NULL != specNorms) { specNorms->CheckNormals(); if (specNorms->GetNumNormals() == 0) mesh->checkNormals(TRUE); } else { mesh->checkNormals(TRUE); } #endif Result result = Ok; Modifier* geomMorpherMod = GetMorpherModifier(node); bool noSplit = FALSE; // bool noSplit = (NULL != geomMorpherMod); while (1) { FaceGroups grps; if (!splitMesh(node, *mesh, grps, t, vertColors, noSplit)) { result = Error; break; } bool exportStrips = mTriStrips && (Exporter::mNifVersionInt > VER_4_2_2_0); Matrix44 tm = Matrix44::IDENTITY; if ( mExportExtraNodes || (mExportType != NIF_WO_ANIM && isNodeKeyed(node) ) ) { tm = TOMATRIX4(getObjectTransform(node, t, false) * Inverse(getNodeTransform(node, t, false))); } else { Matrix33 rot; Vector3 trans; objectTransform(rot, trans, node, t, local); tm = Matrix44(trans, rot, 1.0f); } tm = TOMATRIX4(Inverse(mtx)) * tm; TSTR basename = node->NodeName(); TSTR format = (!basename.isNull() && grps.size() > 1) ? "%s:%d" : "%s"; int i=1; FaceGroups::iterator grp; for (grp=grps.begin(); grp!=grps.end(); ++grp, ++i) { string name = FormatString(format, basename.data(), i); NiTriBasedGeomRef shape = makeMesh(ninode, getMaterial(node, grp->first), grp->second, exportStrips); if (shape == NULL) { result = Error; break; } if (node->IsHidden()) shape->SetVisibility(false); shape->SetName(name); shape->SetLocalTransform(tm); if (Exporter::mZeroTransforms) { shape->ApplyTransforms(); } makeSkin(shape, node, grp->second, t); if (geomMorpherMod) { vector<Vector3> verts = shape->GetData()->GetVertices(); exportGeomMorpherControl(geomMorpherMod, verts, shape->GetData()->GetVertexIndices(), shape); shape->GetData()->SetConsistencyFlags(CT_VOLATILE); } } break; } if (tri != os.obj) tri->DeleteMe(); if (copymesh) delete copymesh; return result; }
void NormalMod::ModifyObject(TimeValue t, ModContext &mc, ObjectState *os, INode *node) { Interval valid = FOREVER; int flip, unify; pblock->GetValue(PB_FLIP,t,flip,valid); pblock->GetValue(PB_UNIFY,t,unify,valid); // For version 4 and later, we process patch meshes as they are and pass them on. Earlier // versions converted to TriMeshes (done below). For adding other new types of objects, add // them here! #ifndef NO_PATCHES if(version >= MATMOD_VER4 && os->obj->IsSubClassOf(patchObjectClassID)) { PatchObject *patchOb = (PatchObject *)os->obj; PatchMesh &pmesh = patchOb->GetPatchMesh(t); BOOL useSel = pmesh.selLevel >= PO_PATCH; if (unify) pmesh.UnifyNormals(useSel); if (flip) pmesh.FlipPatchNormal(useSel ? -1 : -2); patchOb->UpdateValidity(TOPO_CHAN_NUM,valid); } else // If it's a TriObject, process it #endif // NO_PATCHES if(os->obj->IsSubClassOf(triObjectClassID)) { TriObject *triOb = (TriObject *)os->obj; DoNormalSet(triOb, unify, flip); triOb->UpdateValidity(TOPO_CHAN_NUM,valid); } // Process PolyObjects // note: Since PolyObjects must always have the normals alligned they do not // need to support unify and they do not allow normal flips on selected faces else if(os->obj->IsSubClassOf(polyObjectClassID)) { PolyObject *pPolyOb = (PolyObject *)os->obj; MNMesh& mesh = pPolyOb->GetMesh(); if (flip) { // flip selected faces only if entire elements are selected if (mesh.selLevel == MNM_SL_FACE) { // sca 12/8/2000: Use MNMesh flipping code instead of the code that was here. mesh.FlipElementNormals (MN_SEL); } else { // Flip the entire object if selected elements were not flipped for (int i=0; i<mesh.FNum(); i++) { mesh.f[i].SetFlag (MN_WHATEVER, !mesh.f[i].GetFlag(MN_DEAD)); } mesh.FlipElementNormals (MN_WHATEVER); } // Luna task 747: // We cannot support specified normals here at this time. // NOTE this assumes that both the topo and geo channels are to be freed // this means that the modifier needs to also set the channels changed to // geo and topo otherwise we will be deleting a channel we dont own. mesh.ClearSpecifiedNormals (); } pPolyOb->UpdateValidity(GEOM_CHAN_NUM,valid); pPolyOb->UpdateValidity(TOPO_CHAN_NUM,valid); } else // Fallback position: If it can convert to a TriObject, do it! if(os->obj->CanConvertToType(triObjectClassID)) { TriObject *triOb = (TriObject *)os->obj->ConvertToType(t, triObjectClassID); // Now stuff this into the pipeline! os->obj = triOb; DoNormalSet(triOb, unify, flip); triOb->UpdateValidity(TOPO_CHAN_NUM,valid); } else return; // Do nothing if it can't convert to triObject }
void SmoothMod::ModifyObject(TimeValue t, ModContext &mc, ObjectState *os, INode *node) { Interval valid = FOREVER; int autoSmooth, bits = 0, prevent = 0; float thresh = 0.0f; pblock->GetValue(sm_autosmooth, t, autoSmooth, valid); if (autoSmooth) { pblock->GetValue(sm_threshold, t, thresh, valid); pblock->GetValue(sm_prevent_indirect, t, prevent, valid); } else { pblock->GetValue(sm_smoothbits, t, bits, valid); } // For version 4 and later, we process patch meshes as they are and pass them on. Earlier // versions converted to TriMeshes (done below). For adding other new types of objects, add // them here! bool done = false; #ifndef NO_PATCHES if(version >= MATMOD_VER4 && os->obj->IsSubClassOf(patchObjectClassID)) { PatchObject *patchOb = (PatchObject *)os->obj; PatchMesh &pmesh = patchOb->GetPatchMesh(t); BOOL useSel = pmesh.selLevel >= PO_PATCH; if (autoSmooth) pmesh.AutoSmooth (thresh, useSel, prevent); else { for (int i=0; i<pmesh.getNumPatches(); i++) { if (!useSel || pmesh.patchSel[i]) pmesh.patches[i].smGroup = (DWORD)bits; } } pmesh.InvalidateGeomCache(); // Do this because there isn't a topo cache in PatchMesh patchOb->UpdateValidity(TOPO_CHAN_NUM,valid); done = true; } #endif // NO_PATCHES if (!done && os->obj->IsSubClassOf (polyObjectClassID)) { PolyObject *pPolyOb = (PolyObject *)os->obj; MNMesh &mesh = pPolyOb->GetMesh(); BOOL useSel = (mesh.selLevel == MNM_SL_FACE); if (autoSmooth) mesh.AutoSmooth (thresh, useSel, prevent); else { for (int faceIndex=0; faceIndex<mesh.FNum(); faceIndex++) { if (!useSel || mesh.F(faceIndex)->GetFlag(MN_SEL)) { mesh.F(faceIndex)->smGroup = (DWORD)bits; } } } // Luna task 747 // We need to rebuild the smoothing-group-based normals in the normalspec, if any: if (mesh.GetSpecifiedNormals()) { mesh.GetSpecifiedNormals()->SetParent (&mesh); mesh.GetSpecifiedNormals()->BuildNormals (); mesh.GetSpecifiedNormals()->ComputeNormals (); } pPolyOb->UpdateValidity(TOPO_CHAN_NUM,valid); done = true; } TriObject *triOb = NULL; if (!done) { if (os->obj->IsSubClassOf(triObjectClassID)) triOb = (TriObject *)os->obj; else { // Convert to triobject if we can. if(os->obj->CanConvertToType(triObjectClassID)) { TriObject *triOb = (TriObject *)os->obj->ConvertToType(t, triObjectClassID); // We'll need to stuff this back into the pipeline: os->obj = triOb; // Convert validities: Interval objValid = os->obj->ChannelValidity (t, TOPO_CHAN_NUM); triOb->SetChannelValidity (TOPO_CHAN_NUM, objValid); triOb->SetChannelValidity (GEOM_CHAN_NUM, objValid & os->obj->ChannelValidity (t, GEOM_CHAN_NUM)); triOb->SetChannelValidity (TEXMAP_CHAN_NUM, objValid & os->obj->ChannelValidity (t, TEXMAP_CHAN_NUM)); triOb->SetChannelValidity (VERT_COLOR_CHAN_NUM, objValid & os->obj->ChannelValidity (t, VERT_COLOR_CHAN_NUM)); triOb->SetChannelValidity (DISP_ATTRIB_CHAN_NUM, objValid & os->obj->ChannelValidity (t, DISP_ATTRIB_CHAN_NUM)); } } } if (triOb) { // one way or another, there's a triobject to smooth. Mesh & mesh = triOb->GetMesh(); BOOL useSel = mesh.selLevel == MESH_FACE; if (autoSmooth) mesh.AutoSmooth (thresh, useSel, prevent); else { for (int i=0; i<mesh.getNumFaces(); i++) { if (!useSel || mesh.faceSel[i]) mesh.faces[i].smGroup = (DWORD)bits; } } triOb->GetMesh().InvalidateTopologyCache(); triOb->UpdateValidity(TOPO_CHAN_NUM,valid); } }
void FExtrudeMod::ModifyObject( TimeValue t, ModContext &mc, ObjectState *os, INode *node) { if (os->obj->IsSubClassOf(triObjectClassID)) { TriObject *tobj = (TriObject*)os->obj; Mesh &mesh = tobj->GetMesh(); Interval iv = FOREVER; float a, s; Point3 pt, center; int c; pblock->GetValue(PB_AMOUNT,t,a,iv); pblock->GetValue(PB_SCALE,t,s,iv); pblock->GetValue(PB_CENTER,t,c,iv); base->GetValue(t,&pt,iv,CTRL_ABSOLUTE); // Extrude the faces -- this just creates the new faces mesh.ExtrudeFaces(); // Build normals of selected faces only Tab<Point3> normals; if (!c) { normals.SetCount(mesh.getNumVerts()); for (int i=0; i<mesh.getNumVerts(); i++) { normals[i] = Point3(0,0,0); } for (int i=0; i<mesh.getNumFaces(); i++) { if (mesh.faceSel[i]) { Point3 norm = (mesh.verts[mesh.faces[i].v[1]]-mesh.verts[mesh.faces[i].v[0]]) ^ (mesh.verts[mesh.faces[i].v[2]]-mesh.verts[mesh.faces[i].v[1]]); for (int j=0; j<3; j++) { normals[mesh.faces[i].v[j]] += norm; } } } for (int i=0; i<mesh.getNumVerts(); i++) { normals[i] = Normalize(normals[i]); } } else { // Compute the center point base->GetValue(t,¢er,iv,CTRL_ABSOLUTE); } // Mark vertices used by selected faces BitArray sel; sel.SetSize(mesh.getNumVerts()); for (int i=0; i<mesh.getNumFaces(); i++) { if (mesh.faceSel[i]) { for (int j=0; j<3; j++) sel.Set(mesh.faces[i].v[j],TRUE); } } // Move selected verts for (int i=0; i<mesh.getNumVerts(); i++) { if (sel[i]) { if (!c) { mesh.verts[i] += normals[i]*a; } else { Point3 vect = Normalize((mesh.verts[i] * (*mc.tm)) - center); mesh.verts[i] += vect*a; } } } // Scale verts if (s!=100.0f) { s /= 100.0f; AdjEdgeList ae(mesh); AdjFaceList af(mesh,ae); FaceClusterList clust(mesh.faceSel,af); // Make sure each vertex is only scaled once. BitArray done; done.SetSize(mesh.getNumVerts()); // scale each cluster independently for (int i=0; (DWORD)i<clust.count; i++) { // First determine cluster center Point3 cent(0,0,0); int ct=0; for (int j=0; j<mesh.getNumFaces(); j++) { if (clust[j]==(DWORD)i) { for (int k=0; k<3; k++) { cent += mesh.verts[mesh.faces[j].v[k]]; ct++; } } } if (ct) cent /= float(ct); // Now scale the cluster about its center for (int j=0; j<mesh.getNumFaces(); j++) { if (clust[j]==(DWORD)i) { for (int k=0; k<3; k++) { int index = mesh.faces[j].v[k]; if (done[index]) continue; done.Set(index); mesh.verts[index] = (mesh.verts[index]-cent)*s + cent; } } } } } mesh.InvalidateTopologyCache (); os->obj->UpdateValidity(GEOM_CHAN_NUM,iv); } }
ObjectHandle TriPatchObject::CreateTriObjRep(TimeValue t) { TriObject *tri = CreateNewTriObject(); PrepareMesh(t); // Turn it into a mesh tri->GetMesh() = patch.GetMesh(); // Place it into the TriObject return(ObjectHandle(tri)); }
BOOL Building_collision_exp::ExportOneMesh(INode* node, CExportDataBuf* pDataBuf) { if(node && pDataBuf) { pDataBuf->strName = node->GetName(); ObjectState os = node->EvalWorldState(0); if (!os.obj) { return FALSE; } // Targets are actually geomobjects, but we will export them // from the camera and light objects, so we skip them here. if (os.obj->ClassID() == Class_ID(TARGET_CLASS_ID, 0)) { return FALSE; } int i; // 以后需要用到的循环变量. Matrix3 tm = node->GetObjTMAfterWSM(0); // 三角形面的索引值. int vx1 = 0, vx2 = 1, vx3 = 2; BOOL needDel; TriObject* tri = GetTriObjectFromNode(node, 0, needDel); if (!tri) { return FALSE; } Mesh* mesh = &tri->GetMesh(); pDataBuf->m_iFaceCount = mesh->getNumFaces(); pDataBuf->m_posVectorCount = mesh->getNumVerts(); Point3 v; POS pos; for (i=0; i<mesh->getNumVerts(); i++) { v = tm * mesh->verts[i]; pos.x = v.x; pos.y = v.z; pos.z = -v.y; pDataBuf->m_posVector.push_back(pos); } FACE face; for (i=0; i<mesh->getNumFaces(); i++) { face.iF1 = (WORD)mesh->faces[i].v[vx1]; face.iF2 = (WORD)mesh->faces[i].v[vx2]; face.iF3 = (WORD)mesh->faces[i].v[vx3]; pDataBuf->m_posFaceVector.push_back(face); } if (needDel) { delete tri; } } m_bIsExport = TRUE; return TRUE; }