📄 pqmaploader_new.cpp
字号:
// **************************************************************************************
// 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 + -