#include "max.h" #include "asciiexp.h" #define EDITMESH_CLASS_ID 0x00050 typedef Tab Point3Tab; //typedef Tab AnimPoint3Tab; typedef Tab FaceTab; class XFormProc { public: virtual Point3 proc(Point3& p, Matrix3 &mat, Matrix3 &imat)=0; virtual void SetMat( Matrix3& mat ) {} }; class MoveXForm : public XFormProc { private: Point3 delta, tdelta; public: Point3 proc(Point3& p, Matrix3 &mat, Matrix3 &imat) { return p + tdelta; } void SetMat( Matrix3& mat ) { tdelta = VectorTransform(Inverse(mat),delta); } MoveXForm(Point3 d) { delta = d; } }; class RotateXForm : public XFormProc { private: Matrix3 rot, trot; public: Point3 proc(Point3& p, Matrix3 &mat, Matrix3 &imat) { return (trot*p)*imat; } void SetMat( Matrix3& mat ) { trot = mat * rot; } RotateXForm(Quat q) { q.MakeMatrix(rot); } }; class ScaleXForm : public XFormProc { private: Matrix3 scale, tscale; public: Point3 proc(Point3& p, Matrix3 &mat, Matrix3 &imat) { return (p*tscale)*imat; } void SetMat( Matrix3& mat ) { tscale = mat*scale; } ScaleXForm(Point3 s) { scale = ScaleMatrix(s); } }; class VertexDelta { public: Point3Tab deltas; //DS-- I needed this public BitArray hide; void SetSize(int size, BOOL clear=TRUE); Point3 operator[](int i); void Set(TimeValue t,int i, Point3& p); void Move(TimeValue t,int i, const Point3& p); void Apply(TimeValue t,Mesh& mesh); void Scale(float f); VertexDelta& operator=(VertexDelta& from); ~VertexDelta(); VertexDelta(); }; class TopoOp { public: virtual void Apply(Mesh& mesh)=0; virtual TopoOp *Clone()=0; virtual ~TopoOp() {} }; typedef Tab TopoOpTab; class FaceMap { public: DWORD v[3]; }; typedef Tab FaceMapTab; // Bits for attribs: // First 3 bits are edge visibility // 4th bit is face visibility // 29,30 and 31 indicate which if any should be applied #define ATTRIB_APPLY_EDGE (1<<31) #define ATTRIB_APPLY_FACE (1<<30) #define ATTRIB_APPLY_MATID (1<<29) #define ATTRIB_APPLY_SMGROUP (1<<28) // Mat ID takes bit 5-21 #define ATTRIB_MATID_SHIFT 5 #define ATTRIB_MATID_MASK 0xffff class TopoDelta { public: DWORDTab cverts; // Clone verts DWORDTab dverts; // Delete verts Point3Tab nverts; // Add verts Point3Tab nTverts; // Add texture verts DWORDTab dfaces; // Delete faces Tab nfaces; // New faces Tab nTVfaces; // New texture vert faces FaceMapTab map; // Remap faces FaceMapTab tmap; // TVFace remap DWORDTab attribs; // Changes attributes of a face. DWORDTab smgroups; // Changes smooth groups for a face. DWORD inputFaces; // Number of faces on input mesh DWORD inputVerts; // Number of vertices input mesh has }; class EditMeshData : public LocalModData { public: DWORD flags; // These record the changes to the incomming object. VertexDelta vdelta; TopoDelta tdelta; // The selection sets. BitArray vsel; BitArray fsel; BitArray esel; // Lists of named selection sets NamedSelSetList vselSet; NamedSelSetList fselSet; NamedSelSetList eselSet; // While an object is being edited, this exists. // EMTempData *tempData; }; inline float BPoly4(int i, float u) { float s = 1.0f-u; switch (i) { case 0: return s*s*s; case 1: return 3.0f*u*s*s; case 2: return 3.0f*u*u*s; case 3: return u*u*u; default: return 0.0f; } } inline float BPoly3(int i, float u) { float s = 1.0f-u; switch (i) { case 0: return s*s; case 1: return 2.0f*u*s; case 2: return u*u; default: return 0.0f; } } inline float BPoly2(int i, float u) { switch (i) { case 0: return 1.0f-u; case 1: return u; default: return 0.0f; } } #define EPSILON 0.001f Point3 FfdLatticeSize(Box3 box) { Point3 size = box.Max()-box.Min(); if (size.x==0.0f) size.x = 0.001f; if (size.y==0.0f) size.y = 0.001f; if (size.z==0.0f) size.z = 0.001f; return size; } Matrix3 FFDMod::CompTM(TimeValue t,INode *inode,ModContext *mc) { // Compute a the transformation out of lattice space into world space Matrix3 ntm = inode->GetObjTMBeforeWSM(t); Matrix3 ctm(1); if (mc && mc->tm) { ntm = Inverse(*(mc->tm)) * ntm; } tmControl->GetValue(t,&ctm,FOREVER,CTRL_RELATIVE); return ctm * ntm; } Box3 ComputeBBox(TimeValue t, INode *node) { Box3 box; // The computed box Matrix3 mat; // The Object TM Matrix3 sclMat(1); // This will be used to apply the scaling // Get the result of the pipeline at the current time Object *obj = node->EvalWorldState(t).obj; // Determine if the object is in world space or object space // so we can get the correct TM. We can check this by getting if (node->GetObjTMAfterWSM(t).IsIdentity()) { mat = Inverse(node->GetObjTMBeforeWSM(t)); } else { // It's in object space, get the Object TM. mat = node->GetObjectTM(t); } // Extract just the scaling part from the TM AffineParts parts; decomp_affine(mat, &parts); //ApplyScaling(sclMat, ScaleValue(parts.k*parts.f, parts.u)); // Get the bound box, and affect it by just // the scaling portion obj->GetDeformBBox(t, box, &sclMat); return box; } void AsciiExp::ExportFFD( INode* node , FFDMod *FfdMod, ModContext *mc, Mesh *mesh) { TimeValue start = ip->GetAnimRange().Start(); TimeValue end = ip->GetAnimRange().End(); int delta = GetTicksPerFrame(); int nbCtrlPnts; TimeValue t; int i; int Depth; int Width; int Height; if (node->IsNodeHidden()) return; if (FfdMod) { ObjectState os; Object * obj; os = node->EvalWorldState( 0 ); obj = node->GetObjectRef(); while (obj && obj->SuperClassID() == GEN_DERIVOB_CLASS_ID) { obj = ((IDerivedObject*)obj)->GetObjRef(); } if (!obj) return; if (FfdMod->ClassID() == FFD44_CLASS_ID) { Depth = Width = Height = 4; } else if (FfdMod->ClassID() == FFD33_CLASS_ID) { Depth = Width = Height = 3; } else if (FfdMod->ClassID() == FFD22_CLASS_ID) { Depth = Width = Height = 2; } // Evaluate the TM controller Matrix3 ctm(1); FfdMod->tmControl->GetValue(start,&ctm,FOREVER,CTRL_RELATIVE); // Get the ModContext TM (if there is one) Matrix3 tm = mc->tm ? *mc->tm : Matrix3(1); // Apply our TM to the MC TM tm *= Inverse(ctm); // The origin of the TM is the lower left corner of the // box, not the center. tm.SetTrans(tm.GetTrans()-mc->box->Min()); // Compute scale factors to normalize lattice space // to the extents of the box. Point3 s = FfdLatticeSize(*mc->box); for (i=0; i<3; i++) { if (s[i]==0.0f) s[i] = 1.0f; else s[i] = 1.0f/s[i]; } tm.Scale(s,TRUE); Matrix3 itm = Inverse(tm); AffineParts ap; decomp_affine(tm, &ap); nbCtrlPnts = FfdMod->NumCtrlPts(); WriteChunkHdr( (char*)FFD_ID, 0); fwrite( &nCurObj, sizeof( Uint32 ), 1, expStream ); fwrite( &FfdNum, sizeof(Uint32), 1, expStream); fwrite( &Width, sizeof( Uint32 ), 1, expStream ); fwrite( &Height, sizeof( Uint32 ), 1, expStream ); fwrite( &Depth, sizeof( Uint32 ), 1, expStream ); MRow *mr = tm.GetAddr(); fwrite( &mr[0][0], sizeof(MRow),1,expStream); fwrite( &mr[1][0], sizeof(MRow),1,expStream); fwrite( &mr[2][0], sizeof(MRow),1,expStream); fwrite( &mr[3][0], sizeof(MRow),1,expStream); int dd,dw,dh; int nv = obj->NumPoints(); /* for (i=0; iGetPoint(i); if (pp.x>=-0.001f && pp.x<=1.001f && pp.y>=-0.001f && pp.y<=1.001f && pp.z>=-0.001f && pp.z<=1.001f) { if (FfdMod->ClassID() == FFD44_CLASS_ID) { w = BPoly4(dw,pp.x) * BPoly4(dd,pp.y) * BPoly4(dh,pp.z); } else if (FfdMod->ClassID() == FFD33_CLASS_ID) { w = BPoly3(dw,pp.x) * BPoly3(dd,pp.y) * BPoly3(dh,pp.z); } else if (FfdMod->ClassID() == FFD22_CLASS_ID) { w = BPoly2(dw,pp.x) * BPoly2(dd,pp.y) * BPoly2(dh,pp.z); } } else { w = 0; } tw+=w; } } } }*/ fprintf( tempStream, "node = %s\n\n", node->GetName() ); fprintf( tempStream, "selected = "); BitArray Selection = mesh->VertexTempSel(); for (dw = 0; dwGetPoint(i); //if (pp.x>=-0.0001f && pp.x<=1.0001f && pp.y>=-0.0001f && pp.y<=1.0001f && pp.z>=-0.0001f && pp.z<=1.0001f) { if (Selection[i]) { if (FfdMod->ClassID() == FFD44_CLASS_ID) { w = BPoly4(dw,pp.x) * BPoly4(dd,pp.y) * BPoly4(dh,pp.z); } else if (FfdMod->ClassID() == FFD33_CLASS_ID) { w = BPoly3(dw,pp.x) * BPoly3(dd,pp.y) * BPoly3(dh,pp.z); } else if (FfdMod->ClassID() == FFD22_CLASS_ID) { w = BPoly2(dw,pp.x) * BPoly2(dd,pp.y) * BPoly2(dh,pp.z); } fprintf( tempStream, "%d %f, ", i, w); } else { w = 0; } fwrite(&w, sizeof(float), 1, expStream); } fprintf( tempStream, "\nendselected\n"); } } } WriteChunkHdr( (char*)ANIM_ID, 0); fwrite( &CHANNEL_TYPE_FFD, sizeof( Uint32 ), 1, expStream ); fwrite( &nCurObj, sizeof( Uint32 ), 1, expStream ); fwrite( &totFrames, sizeof( Uint32 ), 1, expStream ); fwrite( &FfdNum, sizeof(Uint32), 1, expStream); fwrite( &Width, sizeof( Uint32 ), 1, expStream ); fwrite( &Height, sizeof( Uint32 ), 1, expStream ); fwrite( &Depth, sizeof( Uint32 ), 1, expStream ); for (i=0; iGetObjTMBeforeWSM(t); Matrix3 ctm(1); if (mc && mc->tm) { ntm = Inverse(*(mc->tm)) * ntm; } FfdMod->tmControl->GetValue(t,&ctm,FOREVER,CTRL_RELATIVE); Matrix3 mm = ctm * ntm; Box3 lbox = *mc->box; Matrix3 stm = ScaleMatrix(FfdLatticeSize(lbox)); stm.SetTrans(lbox.Min()); Point3 np = FfdMod->GetControlPoint(t,i); Point3 p = stm*FfdMod->GetControlPoint(t, i); Point3 p2 = mm * p; fwrite(&p2.x, sizeof(float), 1, expStream); fwrite(&p2.z, sizeof(float), 1, expStream); fwrite(&p2.y, sizeof(float), 1, expStream); } } TimeValue start = ip->GetAnimRange().Start(); TimeValue end = ip->GetAnimRange().End(); int delta = GetTicksPerFrame(); Control *c; WriteChunkHdr( (char*)KEY_ID, 0); fwrite( &CHANNEL_TYPE_FFD, sizeof( Uint32 ), 1, expStream ); fwrite( &CHANNEL_INFO_ALL, sizeof( Uint32) , 1, expStream); fwrite( &nCurObj, sizeof( Uint32), 1, expStream ); fwrite( &FfdNum, sizeof(Uint32), 1, expStream); fwrite( &nbCtrlPnts, sizeof( Uint32), 1, expStream ); for (i=0; iGetPtCont(i); if (c) { ikeys = GetKeyControlInterface(c); int blah = c->IsKeyable(); if (ikeys) { num = ikeys->GetNumKeys(); if (num >0) { for (int j = 0; jClassID() == Class_ID(TCBINTERP_POINT3_CLASS_ID, 0)) { ikeys->GetKey(j, &tcbPosKey); time = tcbPosKey.time; } else if (c->ClassID() == Class_ID(HYBRIDINTERP_POINT3_CLASS_ID, 0)) { ikeys->GetKey(j, &bezPosKey); time = bezPosKey.time; } tl.Add(time); } } } } if (!tl.Count()) { tl.Add(ip->GetAnimRange().Start()); } num = tl.Count(); fwrite(&num, sizeof(int), 1, expStream); for ( int j = 0; jGetObjTMBeforeWSM(time); Matrix3 ctm(1); if (mc && mc->tm) { ntm = Inverse(*(mc->tm)) * ntm; } FfdMod->tmControl->GetValue(time,&ctm,FOREVER,CTRL_RELATIVE); Matrix3 mm = ctm * ntm; Box3 lbox = *mc->box; Matrix3 stm = ScaleMatrix(FfdLatticeSize(lbox)); stm.SetTrans(lbox.Min()); Point3 np = FfdMod->GetControlPoint(time,i); Point3 p = stm*FfdMod->GetControlPoint(time, i); Point3 p2 = mm * p; time = (time - start)/delta; fwrite(&time, sizeof(int), 1, expStream); fwrite(&p2.x, sizeof(float), 1, expStream); fwrite(&p2.z, sizeof(float), 1, expStream); fwrite(&p2.y, sizeof(float), 1, expStream); } } } } bool AsciiExp::FindFFDModifier (INode* node) { // Get object from node. Abort if no object. Object* ObjectPtr = node->GetObjectRef(); FfdNum = 0; bool Found= false; if (!ObjectPtr) return false; // Is derived object ? int needDel; while (ObjectPtr->SuperClassID() == GEN_DERIVOB_CLASS_ID) { IDerivedObject* DerivedObjectPtr = static_cast(ObjectPtr); ObjectPtr = DerivedObjectPtr->GetObjRef(); } TriObject * tri = GetTriObjectFromObject(ObjectPtr, ip->GetAnimRange().Start(), needDel); if (!tri) return false; Mesh* mesh = &tri->mesh; BitArray SaveVtx = mesh->vertSel; BitArray SaveFce = mesh->faceSel; BitArray SaveEdg = mesh->edgeSel; ObjectPtr = node->GetObjectRef(); while (ObjectPtr->SuperClassID() == GEN_DERIVOB_CLASS_ID) { // Yes -> Cast. IDerivedObject* DerivedObjectPtr = static_cast(ObjectPtr); // Iterate over all entries of the modifier stack. int ModStackIndex = DerivedObjectPtr->NumModifiers() - 1; while (ModStackIndex >= 0 ) { // Get current modifier. Modifier* ModifierPtr = DerivedObjectPtr->GetModifier(ModStackIndex); ModContext *modContext = DerivedObjectPtr->GetModContext(ModStackIndex); // Is this FFD ? if (ModifierPtr->ClassID() == FFD44_CLASS_ID || ModifierPtr->ClassID() == FFD33_CLASS_ID || ModifierPtr->ClassID() == FFD22_CLASS_ID) { // Yes -> Exit. ExportFFD(node, (FFDMod*)ModifierPtr, modContext, mesh); FfdNum++; Found = true; } else if (ModifierPtr->ClassID() == Class_ID(EDITMESH_CLASS_ID,0)) { EditMeshData *meshData = (EditMeshData*)modContext->localData; mesh->vertSel = meshData->vsel; mesh->faceSel = meshData->fsel; mesh->edgeSel = meshData->esel; } // Next modifier stack entry. ModStackIndex--; } ObjectPtr = DerivedObjectPtr->GetObjRef(); } mesh->vertSel = SaveVtx; mesh->faceSel = SaveFce; mesh->edgeSel = SaveEdg; if (needDel) delete tri; return Found; }