📄 export.cpp
字号:
{
deleteIt = FALSE;
Object *obj = node->EvalWorldState(t).obj;
if (obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0))) {
TriObject *tri = (TriObject *) obj->ConvertToType(t,
Class_ID(TRIOBJ_CLASS_ID, 0));
if (obj != tri) deleteIt = TRUE;
return tri;
}
else {
return NULL;
}
}
// Return a pointer to a PatchObject given an INode or return NULL
// if the node cannot be converted to a PatchObject
PatchObject* Max2Nmo::GetPatchObjectFromNode(INode *node,TimeValue t,int &deleteIt)
{
deleteIt = FALSE;
Object *obj = node->EvalWorldState(t).obj;
if (obj->SuperClassID()==GEOMOBJECT_CLASS_ID)
if (obj->ClassID()==Class_ID(PATCHOBJ_CLASS_ID, 0))
if (obj->CanConvertToType(Class_ID(PATCHOBJ_CLASS_ID, 0)))
{
PatchObject *patch = (PatchObject *) obj->ConvertToType( t
, Class_ID(PATCHOBJ_CLASS_ID, 0) );
if (obj != patch) deleteIt = TRUE;
return patch;
}
else return NULL;
return NULL;
}
// Try to find if a skin modifier is in the modifier stack of a node
Modifier* Max2Nmo::FindSkinModifier (INode* node)
{
#ifndef MAX42
if (g_CharacterStudio312) {
return FindSkinModifierCS312(node);
} else
#endif
{
return FindSkinModifierCS300(node);
}
}
// Try to find if a physique modifier is in the modifier stack of a node
Modifier* Max2Nmo::FindPhysiqueModifier (INode* node)
{
#ifndef MAX42
if (g_CharacterStudio312) {
return FindPhysiqueModifierCS312(node);
} else
#endif
{
return FindPhysiqueModifierCS300(node);
}
}
SplineShape* Max2Nmo::GetSplineShapeFromNode(INode *node,TimeValue t,int &deleteIt)
{
deleteIt = FALSE;
Object *obj = node->EvalWorldState(t).obj;
if (obj->SuperClassID()==SHAPE_CLASS_ID) {
SplineShape *pSplineShape= (SplineShape *) obj->ConvertToType(0,splineShapeClassID );
if (obj != pSplineShape) deleteIt = TRUE;
return pSplineShape;
}
return NULL;
}
// From the Max SDK
// How to calculate UV's for face mapped materials.
static Point3 basic_tva[3] = {
Point3(0.0,0.0,0.0),Point3(1.0,1.0,0.0),Point3(1.0,0.0,0.0)
};
static Point3 basic_tvb[3] = {
Point3(0.0,1.0,0.0),Point3(1.0,1.0,0.0),Point3(0.0,0.0,0.0)
};
static int nextpt[3] = {1,2,0};
static int prevpt[3] = {2,0,1};
static int nhidCase[8] = {-1,-1,-1,-1,0,1,-1,2};
static int forceInvertTab[8] = {0,0,0,0,0,0,0,0};
static int shiftifA[8] = {2,0,2,0,2,1,2,0};
static int shiftifB[8] = {0,0,0,1,0,2,0,1};
// To check that all case have been tested
static int check[8] = {0,0,0,0,0,0,0,0};
void Max2Nmo::make_face_uv(Face *f, VxUV *tv)
{
int na,nhid,i;
Point3 *basetv;
/* make the invisible edge be 2->0 */
nhid = 1;
if (!(f->flags&EDGE_A)) nhid=0;
else if (!(f->flags&EDGE_B)) nhid = 1;
else if (!(f->flags&EDGE_C)) nhid = 2;
int fFlags = f->flags & 0x7;
if (nhidCase[fFlags] >=0) {
nhid = nhidCase[fFlags];
}
na = 2-nhid;
basetv = (f->v[prevpt[nhid]]<f->v[nhid]) ? basic_tva : basic_tvb;
if (forceInvertTab[fFlags]) {
basetv = (basetv == basic_tvb) ? basic_tva : basic_tvb;
}
if ( (basetv == basic_tva) && shiftifA[fFlags] ) {
na = nextpt[na];
if (shiftifA[fFlags] > 1)
na = nextpt[na];
}
if ( (basetv == basic_tvb) && shiftifB[fFlags] ) {
na = nextpt[na];
if (shiftifB[fFlags] > 1)
na = nextpt[na];
}
if (basetv == basic_tvb)
check[fFlags] |= 2;
if (basetv == basic_tva)
check[fFlags] |= 1;
for (i=0; i<3; i++) {
tv[i].u = basetv[na].x;
tv[i].v = basetv[na].y;
na = nextpt[na];
}
}
/*************************************************************
Since Virtools and Max referential have switched Y and Z axis
we need to swap the 2 axis in the matrix
***************************************************************/
void Max2Nmo::ConvertMaxMatrix2Virtools(Matrix3 &m, VxMatrix &WM)
{
MRow* pMRow=m.GetAddr();
// Row & Colummn 1 & 2 must be swapped
WM[0][0]=(*pMRow)[0]; WM[0][1]=(*pMRow)[2]; WM[0][2]=(*pMRow)[1]; WM[0][3]=0.0f;
WM[1][0]=(*(pMRow+2))[0]; WM[1][1]=(*(pMRow+2))[2]; WM[1][2]=(*(pMRow+2))[1]; WM[1][3]=0.0f;
WM[2][0]=(*(pMRow+1))[0]; WM[2][1]=(*(pMRow+1))[2]; WM[2][2]=(*(pMRow+1))[1]; WM[2][3]=0.0f;
WM[3][0]=(*(pMRow+3))[0]; WM[3][1]=(*(pMRow+3))[2]; WM[3][2]=(*(pMRow+3))[1]; WM[3][3]=1.0f;
}
/*************************************************************
Max Camera and Light matrix don't act like object matrix, we
need a specific conversion method
***************************************************************/
void Max2Nmo::ConvertMaxLightMatrix2Virtools(Matrix3 &m, VxMatrix &WM)
{
MRow* pMRow=m.GetAddr();
WM[0][0]=(*pMRow)[0]; WM[0][1]=(*pMRow)[2]; WM[0][2]=(*pMRow)[1]; WM[0][3]=0.0f;
WM[1][0]=(*(pMRow+1))[0]; WM[1][1]=(*(pMRow+1))[2]; WM[1][2]=(*(pMRow+1))[1]; WM[1][3]=0.0f;
WM[2][0]=(*(pMRow+2))[0]; WM[2][1]=(*(pMRow+2))[2]; WM[2][2]=(*(pMRow+2))[1]; WM[2][3]=0.0f;
WM[3][0]=(*(pMRow+3))[0]; WM[3][1]=(*(pMRow+3))[2]; WM[3][2]=(*(pMRow+3))[1]; WM[3][3]=1.0f;
WM[2][0] = -WM[2][0]; WM[2][1] = -WM[2][1]; WM[2][2] = -WM[2][2];
//--- Camera and Light Matrices should not have any scale...
WM[0].Normalize();
WM[1].Normalize();
WM[2].Normalize();
}
/********************************************************
// Max Vertices are given in the ObjectTM referential and we need them in NodeTM referential
// use this method to get the OffsetTM
*********************************************************/
Matrix3 Max2Nmo::GetNodeOffsetTM(INode* node)
{
Matrix3 tOffsetTM(1);
Point3 pos = node->GetObjOffsetPos();
tOffsetTM.PreTranslate(pos);
Quat quat = node->GetObjOffsetRot();
PreRotateMatrix(tOffsetTM, quat);
ScaleValue scaleValue = node->GetObjOffsetScale();
ApplyScaling(tOffsetTM, scaleValue);
return tOffsetTM;
}
/*****************************************************************************************/
// GetMaterialByIndex
//
// This function is used to retrieve the 3dsmax material applied to a face of an object.
// of a face.
// - pMtl: root material of the object
// - MatId: Id given to the face in order to know wich sub-material
// is to be used from the root.
// - MapChannel: channel in which to look for the material (note: 0 means no channels)
// - returnedKey: key to retrieve the matching CKMaterial later
// (note: ~ little trick for lightmap material)
/*****************************************************************************************/
Mtl* Max2Nmo::GetMaterialByIndex(Mtl *pMtl,DWORD MatId,int MapChannel, void*& returnedKey )
{
returnedKey = NULL;
if (!pMtl) return NULL;
Mtl *pSubMtl=NULL;
if(pMtl->ClassID()==Class_ID(DMTL_CLASS_ID, 0)) {
#ifdef MAX51
//--- Araya: If for this channel there's a lightmap texture enabled
///// then returnedKey is not the pMtl, but some trick to retrieve it from pMtl
if( LM::ShaderEnabled(pMtl) ){
if( MapChannel ){
if( LM::LightmapTextureEnabled(pMtl) &&
LM::LightmapTextureMapping(pMtl)==MapChannel ){
returnedKey = (void*)~(DWORD)pMtl;
return pMtl;
}
} else {
if( LM::BaseTextureEnabled(pMtl) ){
const char* baseTextureFilename = LM::BaseTextureFilename(pMtl);
if( baseTextureFilename ){
Mtl** matchingBaseMaterialPtr = m_lightmapBaseMaterials.FindPtr( baseTextureFilename );
if( matchingBaseMaterialPtr ){
returnedKey = *matchingBaseMaterialPtr;
return *matchingBaseMaterialPtr;
}
}
}
}
return NULL;
}
#endif
if (MapChannel) {
Texmap* pTexmap=pMtl->GetSubTexmap(ID_DI);
if (pTexmap && pTexmap->GetUVWSource()==UVWSRC_EXPLICIT
&& pTexmap->GetMapChannel()==MapChannel) {
returnedKey = pMtl;
return pMtl;
}
else return NULL;
} else {
returnedKey = pMtl;
return pMtl;
}
}
else
#ifdef MAX51
if(pMtl->ClassID()==Class_ID(BAKE_SHELL_CLASS_ID, 0)) {
//--- Baked Shell Material
int selectedViewPortMaterialIndex = 1;
enum { bakeShell_params };
enum { bakeShell_vp_n_mtl };
IParamBlock2* pblock = pMtl->GetParamBlockByID( bakeShell_params );
if( pblock ){
pblock->GetValue( bakeShell_vp_n_mtl, 0,
selectedViewPortMaterialIndex, FOREVER );
}
pSubMtl=pMtl->GetSubMtl( selectedViewPortMaterialIndex );
return GetMaterialByIndex(pSubMtl,MatId,MapChannel, returnedKey);
}
else
#endif
if(pMtl->ClassID()==Class_ID(MULTI_CLASS_ID, 0)) {
//Multi Material
pSubMtl=pMtl->GetSubMtl(MatId % pMtl->NumSubMtls());
return GetMaterialByIndex(pSubMtl,MatId,MapChannel, returnedKey);
}
else
if(pMtl->ClassID()==Class_ID(MIXMAT_CLASS_ID, 0))
{
// In case we are looking for a material assigned to a specific channel
if (MapChannel) {
for (int i=0;i<pMtl->NumSubMtls();i++)
if (pSubMtl=pMtl->GetSubMtl(i))
if(pSubMtl->ClassID()==Class_ID(DMTL_CLASS_ID, 0)) {
Texmap* pTexmap=pSubMtl->GetSubTexmap(ID_DI);
if (pTexmap->GetUVWSource()==UVWSRC_EXPLICIT)
if (pTexmap->GetMapChannel()==MapChannel) break;
}
if (i>=pMtl->NumSubMtls()) pSubMtl=NULL;
} else pSubMtl=pMtl->GetSubMtl(0);
return GetMaterialByIndex(pSubMtl,MatId,MapChannel, returnedKey);
}
return NULL; // ????
}
// from bmTex.cpp
#define PB_CLIPU 0
#define PB_CLIPV 1
#define PB_CLIPW 2
#define PB_CLIPH 3
#define PB_APPLYCROP 6
BOOL Max2Nmo::GetTextureUvGen(Mtl* pMtl,TextureUVGen& uvgen)
{
if (!pMtl) return FALSE;
if (pMtl->ClassID()!=Class_ID(DMTL_CLASS_ID, 0)) return FALSE;
StdMat* stdmat = (StdMat*)pMtl;
if( !stdmat->MapEnabled(ID_DI) ) return FALSE;
Texmap *ptexmap = stdmat->GetSubTexmap(ID_DI);
if( !ptexmap ) return FALSE;
if( ptexmap->ClassID()!=Class_ID(BMTEX_CLASS_ID,0) ) return FALSE;
BitmapTex *pbitmaptex = (BitmapTex*)ptexmap;
//--- Tiling & mirroring
StdUVGen* uvs = pbitmaptex->GetUVGen();
int adrMode = uvs->GetTextureTiling();
uvgen.UOffset = uvs->GetUOffs(0);
uvgen.UScale = uvs->GetUScl(0);
uvgen.VOffset = uvs->GetVOffs(0);
uvgen.VScale = uvs->GetVScl(0);
uvgen.TileU = adrMode&U_WRAP;
uvgen.MirrorU = adrMode&U_MIRROR;
uvgen.TileV = adrMode&V_WRAP;
uvgen.MirrorV = adrMode&V_MIRROR;
uvgen.AngleMap = uvs->GetAng(0);
uvgen.Cropping = FALSE;
uvgen.UCropOffset = 0;
uvgen.VCropOffset = 0;
uvgen.UCropScale = 1.0f;
uvgen.VCropScale = 1.0f;
// There is no api to access cropping values :
// use param blocks
IParamBlock2* block=(IParamBlock2*)pbitmaptex->GetReference(1);
if (block) {
uvgen.Cropping = block->GetInt( PB_APPLYCROP, 0);
uvgen.UCropOffset = block->GetFloat( PB_CLIPU, 0);
uvgen.VCropOffset = block->GetFloat( PB_CLIPV, 0);
uvgen.UCropScale = block->GetFloat( PB_CLIPW, 0);
uvgen.VCropScale = block->GetFloat( PB_CLIPH, 0);
}
return TRUE;
}
void Max2Nmo::ApplyUvGen(VxUV& uv,TextureUVGen& uvgen,BOOL useUVGen)
{
//--- Virtools and Max texture coordinates are upside down
uv.v = 1.0f - uv.v;
if( !useUVGen ) return;
float u = uv.u;
float v = uv.v;
//-- Apply cropping and test because uCropOfs sometimes is -NAND
if(uvgen.Cropping) {
if (!(_isnan(uvgen.UCropOffset) || _isnan(uvgen.UCropScale)))
u = uvgen.UCropOffset + ( u * uvgen.UCropScale);
if (!(_isnan(uvgen.VCropOffset) || _isnan(uvgen.VCropScale)))
v = uvgen.VCropOffset + ( v * uvgen.VCropScale);
}
//-- Apply tiling
u=-uvgen.UOffset + 0.5f + ((u-0.5f)*uvgen.UScale);
v=uvgen.VOffset + 0.5f + ((v-0.5f)*uvgen.VScale);
uv.u = u;
uv.v = v;
}
CKMesh* Max2Nmo::IsMeshInstance(void* mesh,Mtl* mtl)
{
for (int i=0;i<MeshTable.Size();++i) {
if ((MeshTable[i].mesh==mesh) && (MeshTable[i].mtl==mtl))
return MeshTable[i].CKMesh;
}
return NULL;
}
void Max2Nmo::InsertNewMeshInstance(void* mesh,Mtl* mtl,CKMesh* ckmesh)
{
NodeMeshMtl tmp;
tmp.mesh = mesh;
tmp.CKMesh = ckmesh;
tmp.mtl = mtl;
MeshTable.PushBack(tmp);
}
void Max2Nmo::Report(int InfoLevel,char *format, ...)
{
if (InfoLevel>nReportLevel) return;
va_list marker;
va_start(marker, format);
// Always ensure at least 16384 characters are to be written
ReportBuffer.Resize(ReportBufferPos + 16384);
DWORD nbC = vsprintf((char*)&ReportBuffer[ReportBufferPos],format,marker);
ReportBufferPos+=nbC;
}
/*--------------------------------------------------*/
/* macro */
#pragma warning (disable:4035)
_inline unsigned long GetMSB(unsigned long data)
{
_asm
{
mov eax,data
bsr eax,eax
}
}
#pragma warning (default:4035)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -