551 lines
14 KiB
C++
551 lines
14 KiB
C++
#include "max.h"
|
|
#include "asciiexp.h"
|
|
|
|
#define EDITMESH_CLASS_ID 0x00050
|
|
|
|
typedef Tab<Point3> Point3Tab;
|
|
//typedef Tab<AnimPoint3> AnimPoint3Tab;
|
|
typedef Tab<Face> 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<TopoOp*> TopoOpTab;
|
|
|
|
class FaceMap {
|
|
public:
|
|
DWORD v[3];
|
|
};
|
|
typedef Tab<FaceMap> 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<Face> nfaces; // New faces
|
|
Tab<TVFace> 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; i<nv; i++) {
|
|
float tw = 0.f;
|
|
for (dw = 0; dw<Width; dw++) {
|
|
for (dd = 0; dd<Depth; dd++) {
|
|
for (dh = 0; dh<Height; dh++) {
|
|
float w;
|
|
Point3 pp = tm*obj->GetPoint(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; dw<Width; dw++) {
|
|
for (dd = 0; dd<Depth; dd++) {
|
|
for (dh = 0; dh<Height; dh++) {
|
|
for (i=0; i<nv; i++) {
|
|
float w;
|
|
Point3 pp = tm*obj->GetPoint(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; i<nbCtrlPnts; i++) {
|
|
for (t=start; t<=end; t+=delta) {
|
|
|
|
Matrix3 ntm = node->GetObjTMBeforeWSM(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; i<nbCtrlPnts; i++) {
|
|
TimeList tl;
|
|
IKeyControl *ikeys;
|
|
ITCBPoint3Key tcbPosKey;
|
|
ITCBRotKey tcbRotKey;
|
|
ITCBScaleKey tcbSclKey;
|
|
IBezPoint3Key bezPosKey;
|
|
IBezQuatKey bezRotKey;
|
|
IBezScaleKey bezSclKey;
|
|
ILinPoint3Key linPosKey;
|
|
ILinRotKey linRotKey;
|
|
ILinScaleKey linSclKey;
|
|
int num;
|
|
TimeValue time;
|
|
tl.Clear();
|
|
|
|
c = FfdMod->GetPtCont(i);
|
|
if (c) {
|
|
ikeys = GetKeyControlInterface(c);
|
|
int blah = c->IsKeyable();
|
|
if (ikeys) {
|
|
num = ikeys->GetNumKeys();
|
|
if (num >0)
|
|
{
|
|
for (int j = 0; j<num; j++) {
|
|
if (c->ClassID() == 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; j<num; j++) {
|
|
time = tl.Get(j);
|
|
|
|
Matrix3 ntm = node->GetObjTMBeforeWSM(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<IDerivedObject*>(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<IDerivedObject*>(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;
|
|
}
|
|
|