📄 qmapexp.cpp
字号:
MySceneEntry(INode *n, Object *o, int t) { node = n; obj = o; type = t ; next = NULL; }
};
class MySceneEnumProc : public ITreeEnumProc
{
public:
Interface *i;
MySceneEntry *head;
MySceneEntry *tail;
IScene *theScene;
int count;
TimeValue time;
MySceneEnumProc(IScene *scene, TimeValue t, Interface *i);
~MySceneEnumProc();
int Count() { return count; }
void Append(INode *node, Object *obj, int type);
int callback( INode *node );
Box3 Bound();
MySceneEntry *operator[](int index);
};
MySceneEnumProc::MySceneEnumProc(IScene *scene, TimeValue t, Interface *i)
{
time = t;
theScene = scene;
count = 0;
head = tail = NULL;
this->i = i;
theScene->EnumTree(this);
}
MySceneEnumProc::~MySceneEnumProc()
{
while(head)
{
MySceneEntry *next = head->next;
delete head;
head = next;
}
head = tail = NULL;
count = 0;
}
int MySceneEnumProc::callback(INode *node)
{
// get object from node
Object *obj = node->EvalWorldState(time).obj;
// check if it can be represented by a mesh
if(obj->CanConvertToType(triObjectClassID))
{
// create a MySceneEntry for the meshable object
Append(node, obj, OBTYPE_MESH);
}
else
{
// check for other valid types
switch (obj->SuperClassID())
{
case HELPER_CLASS_ID:
// check for entity helper class ID
if ( obj->ClassID()==QENTHELP_CLASS_ID)
Append(node, obj, OBTYPE_QENTITY);
break;
case LIGHT_CLASS_ID:
// check for omni light
if (obj->ClassID()==Class_ID(OMNI_LIGHT_CLASS_ID,0))
Append(node, obj, OBTYPE_OMNILIGHT);
break;
}
} ;
return TREE_CONTINUE; // Keep on enumeratin'!
}
void MySceneEnumProc::Append(INode *node, Object *obj, int type)
// add node/object/type to MySceneEntry list
{
MySceneEntry *entry = new MySceneEntry(node, obj, type);
if(tail)
tail->next = entry;
tail = entry;
if(!head)
head = entry;
count++;
}
Box3 MySceneEnumProc::Bound()
{
Box3 bound;
bound.Init();
MySceneEntry *e = head;
ViewExp *vpt = i->GetViewport(NULL);
while(e)
{
Box3 bb;
e->obj->GetWorldBoundBox(time, e->node, vpt, bb);
bound += bb;
e = e->next;
} ;
return bound;
}
MySceneEntry *MySceneEnumProc::operator[](int index)
{
MySceneEntry *e = head;
while(index)
{
e = e->next;
index--;
}
return e;
}
// ********************************************************************
// QMAP routines
void DecodeMapParams ( char* params, FILE* stream )
// decode params from entity helper.
// The entity helper object stores the free form user parameters
// as a string. The '|' character is used to separate each parameter
// and argument.
{
char * start; char* end ; char str [128] ; BOOL token ;
start = params ;
while (TRUE)
{
token = FALSE ;
// arg
end = strchr(start,'|') ;
if ( end == NULL )
return ;
memset(str,0,sizeof(str)) ;
strncpy(str,start,(end-start)) ;
if ( str[0] != (char)0 )
{
fprintf(stream,"\"%s\" ",str) ;
token = TRUE ;
} ;
start= end+1 ;
// val
end = strchr(start,'|') ;
if ( end == NULL )
return ;
memset(str,0,sizeof(str)) ;
strncpy(str,start,(end-start)) ;
if ( str[0] != (char)0 )
{
fprintf(stream,"\"%s\"",str) ;
token = TRUE ;
} ;
if (token)
fprintf(stream,"\n") ;
start= end+1 ;
} ;
} ;
void GetMtlTextureData ( Mtl* m, int& xOff, int& yOff, float& rotAngle, float& xScale, float& yScale )
// given material, return the QMAP texture data
{
if ( m->ClassID() == Class_ID(DMTL_CLASS_ID,0))
{
StdMat* std = (StdMat*)m ;
Texmap* tx ;
if ( (tx = std->GetSubTexmap(1)) != NULL )
{
// just do bitmaps
if ( tx->ClassID() == Class_ID(BMTEX_CLASS_ID,0))
{
BitmapTex* bmt = (BitmapTex*)tx ;
StdUVGen* uv = bmt->GetUVGen() ;
xOff = (int)uv->GetUOffs(0) ;
yOff = (int)uv->GetVOffs(0) ;
xScale = uv->GetUScl(0) ;
yScale = uv->GetVScl(0) ;
rotAngle = (uv->GetAng(0)/(2.0f*3.14159265359f))*360.0f ;
} ;
} ;
} ;
} ;
int errorBrushes ;
BOOL WriteMesh ( MySceneEntry* sEntry, Interface* gi, FILE* stream )
// given a MAX object, convert and write out as a Quake brush
{
int numPlanes = 0 ;
// get entry from scene
INode* n = sEntry->node ;
Object* obj = sEntry->obj ;
// convert object to a mesh (has been checked by MySceneEnumProc that this is possible)
TriObject* tri = (TriObject*) obj->ConvertToType(gi->GetTime(),triObjectClassID) ;
Mesh &mesh = tri->mesh ;
// get transformation matrix
Matrix3 tm = n->GetObjectTM(gi->GetTime()) ;
// check for valid object
if (mesh.numFaces == 0)
return FALSE ;
// got node, get material
Mtl* nodeMtl = n->GetMtl() ;
BOOL multiMtl = FALSE ;
if ( nodeMtl != NULL)
{
multiMtl = nodeMtl->IsMultiMtl() ;
} ;
// ok, got a mesh, now convert it
int verts = mesh.getNumVerts() ;
int faces = mesh.getNumFaces() ;
// start brush definition
if (fprintf(stream,"{\n"
"// %s\n"
,n->GetName()
)<0)
return TRUE ;
int i, j ; Point3 vert ; Point3 cross ; int numNormals = 0 ;
#define MAX_NORMALS 256
Face face ;
Point3 normal [MAX_NORMALS] ; // list of face normals
for ( i = 0 ; i<faces ; i++ ) // loop for all faces in the mesh
{
face = mesh.faces[i] ;
Point3 vert ;
// find face normal by cross product
float ax, ay, az, bx, by, bz, cx, cy, cz, u1, u2, u3, v1, v2, v3, length ;
Point3 cross ;
vert = mesh.verts[face.v[0]] * tm ;
ax = vert.x ; ay = vert.y ; az = vert.z ;
vert = mesh.verts[face.v[1]] * tm ;
bx = vert.x ; by = vert.y ; bz = vert.z ;
vert = mesh.verts[face.v[2]] * tm ;
cx = vert.x ; cy = vert.y ; cz = vert.z ;
u1 = ax - bx ; u2 = ay - by ; u3 = az - bz ;
v1 = cx - bx ; v2 = cy - by ; v3 = cz - bz ;
cross.x = (u2*v3) - (u3*v2) ;
cross.y = (u3*v1) - (u1*v3) ;
cross.z = (u1*v2) - (u2*v1) ;
length = sqrt( (cross.x*cross.x) + (cross.y*cross.y) + (cross.z*cross.z) ) ;
cross.x = cross.x/length ;
cross.y = cross.y/length ;
cross.z = cross.z/length ;
// handle material
char mtlName [60] ; int xOff, yOff ; float rotAngle, xScale, yScale ;
MtlID mat = face.getMatID() ;
// preset defualt material data
strcpy(mtlName,"UNKNOWN") ;
xOff = yOff = 0 ; rotAngle = 0.0f ; xScale = yScale = 1.0f ;
if ( multiMtl )
{
// if multi material get sub material
if ( nodeMtl != NULL )
{
Mtl* subMtl = nodeMtl->GetSubMtl(mat) ;
if ( subMtl != NULL )
{
strcpy(mtlName,subMtl->GetName());
GetMtlTextureData(subMtl,xOff,yOff,rotAngle,xScale,yScale) ;
} ;
} ;
}
else // not multi material
{
if ( nodeMtl != NULL )
{
strcpy(mtlName,nodeMtl->GetName()) ;
GetMtlTextureData(nodeMtl,xOff,yOff,rotAngle,xScale,yScale) ;
} ;
} ;
if ( numNormals == 0 ) // if first face, start face list
{
normal[0] = cross ;
numNormals++ ;
// write brush plane definition
if (fprintf(stream, "( %ld %ld %ld ) "
"( %ld %ld %ld ) "
"( %ld %ld %ld ) "
"%s %ld %ld %f %f %f\n",
(int)ax, (int)ay, (int)az,
(int)cx, (int)cy, (int)cz,
(int)bx, (int)by, (int)bz,
mtlName, xOff, yOff, rotAngle, xScale, yScale
)<0)
return TRUE ;
numPlanes++ ; // count planes for error check
}
else // not first face
{
// now scan through past faces looking for same normal
BOOL planeFound = FALSE ;
for ( j = 0 ; j<=numNormals ; j++ )
{
planeFound = (cross.x == normal[j].x) &&
(cross.y == normal[j].y) &&
(cross.z == normal[j].z) ;
if (planeFound)
{
// same normal (i.e. plane) found, now check at least one vertex matches
planeFound = FALSE ; // assume no equal verts
int v1 ;
for ( v1 = 0 ; v1 < 4; v1++)
{
if ((mesh.faces[j].v[0] == face.v[v1]) ||
(mesh.faces[j].v[1] == face.v[v1]) ||
(mesh.faces[j].v[2] == face.v[v1]))
{
v1 = 4 ; j = numNormals ; // exit loops
planeFound = TRUE ; // flag face is part of same plane
} ;
} ;
} ;
} ;
numNormals++ ;
// check for too many normals
if ( numNormals >= MAX_NORMALS )
{
char errStr [255] ;
sprintf(errStr,"Error: Object %s has too many normals (i.e. faces)",n->GetName()) ;
MessageBox(GetActiveWindow(),errStr,"QMAPEXP", MB_OK) ;
i = faces ; // exit loop
}
else // save normal in list
{
normal[numNormals] = cross ;
if (!planeFound) // if no existing plane found
{
if (fprintf(stream, "( %ld %ld %ld ) "
"( %ld %ld %ld ) "
"( %ld %ld %ld ) "
"%s %ld %ld %f %f %f\n",
(int)ax, (int)ay, (int)az,
(int)cx, (int)cy, (int)cz,
(int)bx, (int)by, (int)bz,
mtlName, xOff, yOff, rotAngle, xScale, yScale
)<0)
return TRUE ;
numPlanes++ ;
} ;
} ;
} ;
} ;
if ( numPlanes < 4 ) // check for min Quake brush
{
errorBrushes++ ;
if (fprintf(stream,"// ****ERROR*** BRUSH HAS TOO FEW PLANES (<4)\n")<0)
return TRUE ;
} ;
// finish brush definition
if (fprintf(stream,"}\n")<0)
return TRUE ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -