pqmaploader_new.cpp

来自「一个类似QUAKE的CSG关卡编辑器」· C++ 代码 · 共 702 行 · 第 1/2 页

CPP
702
字号
                          p.vXes[2]._xyz.x, p.vXes[2]._xyz.z, p.vXes[2]._xyz.y,
                          p.vXes[1]._xyz.x, p.vXes[1]._xyz.z, p.vXes[1]._xyz.y,
                          texname,
                          p.texax[0].x, p.texax[0].y, p.texax[0].z, p.texShift.u,
                          p.texax[1].x, p.texax[1].y, p.texax[1].z, p.texShift.v);                 //texScale._u, texScale._v)

	        }
            ::fprintf(fw._pf, "}\r\n");
            delete  (*ppPlgBrush);
        }
        fragments.clear();
    }
    ::fprintf(fw._pf, "}\r\n");
    return 0;
}

//---------------------------------------------------------------------------------------
void PqmapLoader::MakeConvex(Plg_Brush& bf, vvector<Plg_Brush*> outs)
{
    QBrCvx           inbrush;
    // use this for storage convenience. 
    // move them and pass the mem managemebt to stl.
    for(int j=0; j < bf.nPolys;j++){
        Plg_Poly& p  = bf.pPolys[j];
        QPoly     qp;  
        qp._texIdx = bf.pPolys[j].texIdx[0];
        qp._flags  = bf.flags;

        for(int v=0; v < p.nvXes;v++){
            qp._vxes << p.vXes[v]._xyz;
            qp._uvs  << p.vXes[v]._uv[0];
        }
        cvxbr._flags = bf.flags;
        cvxbr._polys << qp;
    }
    MakeConvex(inbrush, cvxbr);
}

//---------------------------------------------------------------------------------------
int PqmapLoader::IsConvex(QBrCvx& inbrush, QBrCvx& a, QBrCvx& b, QPoly* splPoly)
{
    FOREACH(vvector<QPoly>, inbrush._polys, pp)
    {
        Plane pl(pp->_vxes[0], pp->_vxes[1], pp->_vxes[2]);

        FOREACH(vvector<QPoly>, inbrush._polys, pp2)
        {
            if(pp2 == pp) continue;

            QPoly  pa;
            QPoly  pb;

            pa._texIdx = pp2->._texIdx;

            Split(pl, pp2->_vxes, pa._vxes, pb._vxes);

            if(pa._vxes.size()>=3)
                a._polys << pa;

            if(pb._vxes.size()>=3)
                b._polys << pb;
        }

        if(b._polys.size() && a._polys.size())
        {
            pp->_flags |= POLY_IS_SPLITTER;
            splPoly = pp;
            return HAS_BOTH;
        }
    }
    return b._polys.size() ? HAS_BACKS : HAS_FRONTS;
}

//---------------------------------------------------------------------------------------
void PqmapLoader::MakeConvex(QBrCvx inbrush, vvector<QBrCvx>& cvx)
{
    QBrCvx a;
    QBrCvx b;
    QPoly* pSlitter;

    DWORD dwRez = IsConvex(inbrush, a, b, pSlitter);
    switch(dwRez)
    {
        case HAS_BOTH:
            MakeConvex(a, cvx);
            MakeConvex(b, cvx);
            break;
        case HAS_BACKS:
            cvx << b;
            break;
        case HAS_FRONTS:
            //discard these
            break;
    }
}

//---------------------------------------------------------------------------------------
// pseudo code how to split the brush
/*
        allocate out convex brushes
        for each face plane
        classify all brush vertexes.
        if only front vertexex 
            is concave error
        if only back vertexes 
            is convex store in out convex brushes and return
        if back and front vertexes
        split brush by this face plane 
        seal both fragment brush { build a bogus poly on this splitter 
                                   cut it with all faces that have been split or touched
                                   add remainig polygon to both fragments. reverse one 
                                   face acordingly}
        repeat for front and back fragments
        save the out convex brushes
*/


//---------------------------------------------------------------------------------------
long PqmapLoader::GetMenuStringAndType(TCHAR* bsFileName, DWORD* type)
{
    _tcscpy(bsFileName,"Quake map files,map");
    *type = PLUG_IMPORTER|PLUG_EXPORTER;
    return 0;
}

//---------------------------------------------------------------------------------------
long PqmapLoader::ImportFile(IGeticEditor* pe, TCHAR* bsFileName, Plg_Scene** pScene)
{
    FileWrap fw;

    if(!fw.Open(bsFileName, "rb"))
        return -1;
    Parser  parser(&fw);
    while(parser.Step()>=0);
    fw.Close();
    return PostProcess(pScene);
}

//---------------------------------------------------------------------------------------
long PqmapLoader::ReleaseScene(Plg_Scene* pScene)
{
    RELEASE_SCENE(pScene);
    return NO_ERROR;
}

//---------------------------------------------------------------------------------------
int Parser::Parse(vvector<string>& tokens)
{
    map<string, PfHandler>::iterator fi = _classes.find(tokens[0]);
    if(fi != _classes.end()){
        return (this->*_classes[tokens[0]])(tokens);
    }
    return 1;
}

//---------------------------------------------------------------------------------------
int Parser::BaseParse(const char* pline)
{
    vvector<string> tokens;
    Explode(pline, tokens,' ');
    if(tokens.size()){
        TRACEX(pline);
        TRACEX("\r\n");
        return Parse(tokens);
    }
    return -1;
}

//---------------------------------------------------------------------------------------
void Parser::Explode(const char* pline, vvector<string>& tokens, char token)
{
    char localline[256]= {0};

    ::strcpy(localline, pline);
    char*   pLocal = localline; 
    char    pTok[2]= {token,'\0'};
    char*   pSubStr;
    while(pSubStr = strtok(pLocal, pTok)){
        pLocal = 0;
        tokens << pSubStr; 
    }
}

//---------------------------------------------------------------------------------------
int Parser::Handle_Open(vvector<string>& tokens)
{
    _pEntity = new QEntity(_pfw);
    TRACEX("New Entity\r\n");
    while(_pEntity->Step()>0);
    return 1;
}

//---------------------------------------------------------------------------------------
int Parser::Step()
{
    char line[255]={0};
    char* pline = line;
    char* pend;  //= pline+strlen(line);

    _pfw->ReadLine(line, 255);
    if(feof(_pfw->_pf))
        return -1;
    // remove triling crlf
    pend = pline+strlen(line)-1;
    while(*pend=='\n'||*pend=='\r')
        --pend;
    *(pend+1)='\0';
    // remove start spaces
    while(*pline==' '||*pline=='\t')
        ++pline;
    return BaseParse(pline);
}

//---------------------------------------------------------------------------------------
int    QEntity::Handle_Open(vvector<string>& tokens)
{
    if(_classname== "\"worldspawn\"")
    {
        TRACEX("New Brush\r\n");
        QBrush* pBrush = new QBrush(_pfw, this);
        while(pBrush->Step() > 0);
    }
    return 1;
}

//---------------------------------------------------------------------------------------
int QEntity::Handle_KeyVal(vvector<string>& tokens)
{
    if(tokens.size() == 0)
        return 1;
    string values;

    for(int i=1; i<tokens.size(); ++i){
        values += tokens[i];
        values += " ";
    }
    if(values.length())
        _keyvals[tokens[0]] = values;
    return 1;
}

//---------------------------------------------------------------------------------------
int    QEntity::Handle_Comment(vvector<string>& tokens)
{
    string values;

    for(int i=1; i<tokens.size(); ++i){
        values += tokens[i];
        values += " ";
    }
    if(values.length())
        _keyvals[tokens[0]] = values;
    return 1;
}

//---------------------------------------------------------------------------------------
int    QEntity::Handle_Close(vvector<string>& tokens)
{
    if(_classname== "\"worldspawn\""){
        TRACEX("Store entity brush in scene\r\n");
        this->_flags = BRSH_SOLID;
        __QLevel._entities << this;
    }else{
        TRACEX("Store entity in scene\r\n");
        __QLevel._entities << this;
    }
    return 0;
}

//---------------------------------------------------------------------------------------
int QBrush::Handle_Line(vvector<string>& tokens)
{
    QBrushFace* pLine = new QBrushFace(_pfw, this);
    pLine->Handle_Line(tokens);
    if(pLine->_OK)
        _pbrshlines << pLine;
    return 1;
}

//---------------------------------------------------------------------------------------
int QBrush::Handle_Close(vvector<string>& tokens)
{
    if(this->_pbrshlines.size() &&_pParent->_classname=="\"worldspawn\""){
        TRACEX("store Qbrush in entity");
        _pParent->_brushes << this;
    }
    return 0;    // end brush
}


//---------------------------------------------------------------------------------------
int QBrushFace::Handle_Line(vvector<string>& tokens)
{
    float   a,b,c,d,e,f,g,h,i;
    float   u0=0,u1=0,u2=0,u3=0,v0=0,v1=0,v2=0,v3=0;
    char    name[32];
    char    originalLine[255]={0};

    if(_pParent->_pParent->_classname != "\"worldspawn\"")
        return 1;
    
    FOREACH(vvector<string>, tokens, pstring){
        ::strcat(originalLine, pstring->c_str());
        ::strcat(originalLine, " ");
    }

    int spacecount = tokens.size();
    if(spacecount > 22){ // new file
        ::sscanf(originalLine, "( %f %f %f ) ( %f %f %f ) ( %f %f %f ) %s %f %f %f %f %f %f %f %f" , &a,&b,&c,&d,&e,&f,&g,&h,&i, name, &u0, &u1, &u2, &u3, &v0, &v1, &v2, &v3);
    }
    else{               // never tested (old file)
        ::sscanf(originalLine, "( %f %f %f ) ( %f %f %f ) ( %f %f %f ) %s %f %f %f" , &a,&b,&c,&d,&e,&f,&g,&h,&i, name, &u0, &u1, &u2);
    }
    // scale the world by 4
    V3  v11(a,c,b);
    V3  v22(d,f,e);
    V3  v33(g,i,h);
    v11*=4.0f; v22*=4.0f; v33*=4.0f;

    _center = V3(0,0,0);
    _center += v11;
    _center += v22;
    _center += v33;
    _center /= 3.0f;    // from wich we spawn the polygon

    _plane.CalcNormal (v11,v22,v33);

    // reject same planes in this brush
    FOREACH(vvector<QBrushFace*>,  _pParent->_pbrshlines, ppBrLine)
    {
        QBrushFace* pLine = *ppBrLine;
        if(_plane == pLine->_plane){
            return 1;
        }
    }
    _OK = TRUE;

    // save texture information
    _indexTex = __QLevel.AddTex(name);
    _ax[0]  = V3(u0, u1, u2);
    _shft.u = u3;
    _ax[1]  = V3(v0, v1, v2);
    _shft.v = v3;
    
    return 1;
}




⌨️ 快捷键说明

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