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

📄 pqmaploader_new.cpp

📁 一个类似QUAKE的CSG关卡编辑器
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// **************************************************************************************
// Copyright (c) 2000-2005 Zalsoft Inc
// www.zalsoft.com
// sales@zalsoft.com
// You are licensed to use this file on a single computer only. 
// **************************************************************************************

#include "stdafx.h"
#include "stdio.h"
#include "baselib.h"
#include "basecont.h"
#include "PqmapLoader.h"
#include <algorithm>

//----------------------------------------------------------------------------------
const REAL	__epsilon = 1e-5;	
#define     HAS_FRONTS  0x1
#define     HAS_BACKS   0x2
#define     HAS_BOTH    0x3

//---------------------------------------------------------------------------------------
struct QLevel
{
    vvector<QEntity*>   _entities;          // quake level entities
    vvector<string>     _texnames;          // texture names

    // adds a unique tex and returns the index into this array. polygons hold to this index
    int  AddTex(const char* n){
        vvector<string>::iterator fi  = find(_texnames.begin(), _texnames.end(), n);
        if(fi != _texnames.end())
            return fi-_texnames.begin();
        _texnames<<n;
        return _texnames.size()-1;
    }
}__QLevel;


//---------------------------------------------------------------------------------------
// this may not be properly handeled. See UT calc tex coord how is done or search for 
// quaketools and take a look.
void CalcTexCoord(QPoly& qp, UV* shift)
{
    UV			        maxuv[2];
    Box                 box ;
    vvector<UV>&        uvs    = qp._uvs;

    FOREACH(vvector<V3>, qp._vxes, pvx){
        box.AddPoint(*pvx);
    }
    box.FlatIt(maxuv);

    for(int i=0; i < qp._vxes.size() ;i++)
    {
        V3& v  = qp._vxes[i];
        UV t;

        switch(box.GetMinimAx())
        {
            case 'x':   //z,y
                t.v = (v.y-maxuv[0].v) / (maxuv[1].v-maxuv[0].v);
                t.u = (v.z-maxuv[0].u) / (maxuv[1].u-maxuv[0].u);
                break;
            case 'y':   //x,z
                t.u = (v.x-maxuv[0].u) / (maxuv[1].u-maxuv[0].u);
                t.v = (v.z-maxuv[0].v) / (maxuv[1].v-maxuv[0].v);
                break;
            case 'z':   //x,y
                t.u = (v.x-maxuv[0].u) / (maxuv[1].u-maxuv[0].u);
                t.v = (v.y-maxuv[0].v) / (maxuv[1].v-maxuv[0].v);
                break;
        }
		t.v +=shift->u;
		t.u +=shift->v;
        qp._uvs << t;
    }
}

//---------------------------------------------------------------------------------------
// Splits by plane all 'p' and populates a and b
void    Split(Plane& plane, vvector<V3>& p, vvector<V3>& a, vvector<V3>& b)
{
	V3      iv;
    V3      itxB = *p.begin();
    V3      itxA = p.back();
	REAL    fB;
    REAL	fA   = plane.DistTo(itxA);
    
    FOREACH(vvector<V3>, p, vxI){
        itxB = *vxI;
        fB   = plane.DistTo(itxB);
        if(fB > __epsilon){
            if(fA < -__epsilon){
                REAL   t = -fA /(fB - fA);
				iv.interpolate(itxA,itxB,t);
                a << iv;
                b << iv;
            }
            a<<itxB;
        }
        else if(fB < -__epsilon){
            if(fA > __epsilon){
                REAL t = -fA /(fB - fA);          
				iv.interpolate(itxA,itxB,t);
                a << iv;
                b << iv;
            }
            b <<itxB;
        }
		else{
			a << itxB;
            b << itxB;
		}
        itxA = itxB;
        fA   = fB;
    }
}

//---------------------------------------------------------------------------------------
// from plane p builds a huge polygon 'qp'
void FromPlane(const Plane& p, QPoly& qp, V3* center)
{
    // get to see what wax we are using for rotation cp
	V3		ax = GetMajorAxes((V3&)p._n);  
    ax.norm();

    // to corner vectors;
	V3		uDr  = Vcp(ax,  p._n);		   
	V3		vDr  = Vcp(uDr, p._n);

    uDr		*= 32768.0;             // huge one ()
	vDr		*= 32768.0;
    REAL vdp = Vdp(p._n, ax);
    V3&  c   = *center;

    qp._vxes <<  c+(uDr-vDr);       // build corner points
	qp._vxes <<  c+(uDr+vDr);
	qp._vxes <<  c-(uDr-vDr);	
	qp._vxes <<  c-(uDr+vDr);
}

//---------------------------------------------------------------------------------------
// from all brush planes build all brush polygons
void  FromPlanes(vvector<Plane*>& planes,
                 vvector<V3*>&    centers,
                 vvector<UV*>     shifts,  
                 vvector<int>     texIdxes,
                 BOOL             front, 
                 vvector<QPoly>&  outPolys)
{
    int jidx = 0;

    FOREACH(vvector<Plane*>, planes, pplane){

        QPoly qp;                                       // polygon we build

        FromPlane(*(*pplane), qp, centers[jidx]);
        qp._texIdx = texIdxes[jidx];                    // find tex index
        // see if the polygon plane faces as original plane
        do{
            Plane pOfPoly;
            pOfPoly.CalcNormal(qp._vxes[0], qp._vxes[1], qp._vxes[2]);
            if(IsZero(Vdp(pOfPoly._n, (*pplane)->_n)), __epsilon)
            {
                qp._vxes.reverse();
            }
        }while(0);

        // cut it with all other polygons excluding this one
        FOREACH(vvector<Plane*>, planes, pplane2){
            if(pplane2 == pplane)
                continue;
            vvector<V3> a;
            vvector<V3> b;
            Split(**pplane2, qp._vxes, a, b);  
            qp._vxes.clear();

            if(front){
                qp._vxes = a;
            }
            else{
                qp._vxes = b;
            }
        }

        if(qp._vxes.size() >= 3){                   // should have minim 3 vertexes
            CalcTexCoord(qp, shifts[jidx]);
            outPolys << qp;
        }
        ++jidx;
    }
}

//---------------------------------------------------------------------------------------
void GatherBrushes(vvector<QBrush*>& allBrushes)
{
    FOREACH(vvector<QEntity*>, __QLevel._entities, ppEntity){
        if((*ppEntity)->_classname== "\"worldspawn\""){
            FOREACH(vvector<QBrush*>, (*ppEntity)->_brushes, ppBrush){
                allBrushes << (*ppBrush);
            }
        }
    }
}

//---------------------------------------------------------------------------------------
long PqmapLoader::PostProcess(Plg_Scene** pScene)
{
    vvector<QBrush*>    allBrushes;

    GatherBrushes(allBrushes);

    // allocate space for scene and for all brushes
    *pScene = new Plg_Scene;
	::memset(*pScene, 0, sizeof(Plg_Scene));        // DO NOT FORGET TO SET ALL SCENE MEMBERS TO NULL
    (*pScene)->nBrushes  = allBrushes.size();
    (*pScene)->pBrushes  = new Plg_Brush[allBrushes.size()];
    (*pScene)->nTextures = __QLevel._texnames.size();
    (*pScene)->pTextures = new Plg_Texture[__QLevel._texnames.size()];

    // store textures 
    for(int t = 0; t < __QLevel._texnames.size(); t++){
        (*pScene)->pTextures[t].target = 0; // GL_TEXTURE2D        (see irender.h)
        ::strcpy((*pScene)->pTextures[t].filename, __QLevel._texnames[t].c_str());
    }

    // store brushes
    int indexBr = 0;
    FOREACH(vvector<QBrush*>,  allBrushes, ppBrush){
        vvector<Plane*>     planes;  
        vvector<QPoly>      polys;
        vvector<V3*>        centers;  
        vvector<UV*>        shifts;  
        vvector<int>        texIdxes;  

        Plg_Brush&          plgBrush =  (*pScene)->pBrushes[indexBr];
        QBrush*             pBrush   = *ppBrush;
        int                 indexp   = 0;
        
        // for each qface line collect planes 
        FOREACH(vvector<QBrushFace*>,  pBrush->_pbrshlines, ppBrLine){
            QBrushFace* pLine = *ppBrLine;
            planes   << &pLine->_plane;
            centers  << &pLine->_center;
            shifts   << &pLine->_shft;
            texIdxes <<  pLine->_indexTex;
        }

        // all brush faces, get out brush polygons
        FromPlanes(planes, centers, shifts, texIdxes, 0, polys);   
        // load them in the plgBrush
        if(polys.size() > 4)    // if we have more than 4 polys into the scen 
        {                       // we may have a convex region
            plgBrush.nPolys = polys.size();
            plgBrush.pPolys = new Plg_Poly[polys.size()];
            ::memset(plgBrush.pPolys, 0, sizeof(polys.size())); // DONT FORGET !!!!
            // alloc vertexes space        
            FOREACH(vvector<QPoly>, polys, ppPoly)
            {
                plgBrush.pPolys[indexp].nvXes = ppPoly->_vxes.size();
                plgBrush.pPolys[indexp].vXes  = new Vtx[ppPoly->_vxes.size()];
                ++indexp;
            }
            // store info in plg brush
            plgBrush.flags = pBrush->_pParent->_flags;

            indexp = 0;
            _FOREACH(vvector<QPoly>, polys, ppPoly){
                plgBrush.pPolys[indexp].texIdx[2]   = -1;   // NO TEXTURE SET INDEX TO -1
                plgBrush.pPolys[indexp].texIdx[1]   = -1;   // NO TEXTURE SET INDEX TO -1
                plgBrush.pPolys[indexp].texIdx[0]   = ppPoly->_texIdx; // index in texture previously saved
                
                plgBrush.pPolys[indexp].texapply[0] = 0;    // for how to apply the texture
                plgBrush.pPolys[indexp].texapply[1] = 0;    // see irender.h
                plgBrush.pPolys[indexp].texapply[2] = 0;

                plgBrush.pPolys[indexp].combine     = 0x1; // LOWER BYTE INDICATES HOW MANY TEXTURES WERE SET
                plgBrush.pPolys[indexp].flags       = 0;   // no special flags for the polygon couse I dont know them  
                                                           // SEE POLYGON FLAGS IN THE bspfilestr.h
                int idxv = 0;
                FOREACH(vvector<V3>, ppPoly->_vxes, pVx){
                    plgBrush.pPolys[indexp].vXes[idxv]._xyz   = *pVx;
                    plgBrush.pPolys[indexp].vXes[idxv]._uv[0] = ppPoly->_uvs[idxv];
                    ++idxv;
                }
                ++indexp;
            }
        }
        ++indexBr;
    }
    return 0;   // no error
}

//---------------------------------------------------------------------------------------
long PqmapLoader::GetVersion()
{
    return 1;
}

//---------------------------------------------------------------------------------------
// Exporter. Brushes comming in are not convex, therefore they have to be split and capped
// back in order to have them convex as qmap file wants them. This works only if
// the scene you are exporting is build with no cuts. (just by adding convex)
long PqmapLoader::ExportFile(IGeticEditor* pe, TCHAR* bsFileName, const Plg_Scene* pScene)
{
    FileWrap    fw;
    char        texname[64];

    if(!fw.Open(bsFileName, "wb"))
        return -1;
        
    // expand textures in a readable variable
    Plg_Texture* ptrTotextures = pScene->pTextures;
    
    fprintf(fw._pf, "{\r\n");
    fprintf(fw._pf, "\"message\" \"%s\"\r\n", "scene");
    fprintf(fw._pf,"\"classname\" \"worldspawn\"\r\n");
    fprintf(fw._pf,"\"_color\" \"1 1 1\"\r\n"); // poly caries the color
    for(int i=0; i< pScene->nBrushes;i++)
    {
        Plg_Brush& b = pScene->pBrushes[i];

        //// vvector<QBrCvx>  cvxbr; 
        //// MakeConvex(b, cvxbr); // later on

        FOREACH(vvector<Plg_Brush*>,  fragments, ppPlgBrush)
        {
            Plg_Brush& bf = *(*ppPlgBrush);

            fprintf(fw._pf,"// brush %d\r\n", i+1); 
            fprintf(fw._pf, "{\r\n");
        
	        for(int j=0; j< bf.nPolys;j++)
	        {
                Plg_Poly& p = bf.pPolys[j];
                // put first 3 points of the poly. 
                // scale world by 4
            
                p.vXes[0]._xyz/=4.0f;
                p.vXes[1]._xyz/=4.0f;
                p.vXes[2]._xyz/=4.0f;

                if(p.texIdx[0] < pScene->nTextures)
                {
                    ::strcpy(texname, pScene->pTextures[p.texIdx[0]].filename);
                }
                else
                {
                    ::strcpy(texname, "none");
                }
                ::fprintf(fw._pf, "( %f %f %f ) ( %f %f %f ) ( %f %f %f ) %s %f %f %f %f %f %f %f %f\r\n", //// %f %f
                          p.vXes[0]._xyz.x, p.vXes[0]._xyz.z, p.vXes[0]._xyz.y,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -