⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qmapexp.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 3 页
字号:
		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 + -