gtkradiant/tools/quake2/extra/bsp/qbsp3/qbsp3.c
2012-04-07 18:53:01 -05:00

537 lines
11 KiB
C

/*
===========================================================================
Copyright (C) 1997-2006 Id Software, Inc.
This file is part of Quake 2 Tools source code.
Quake 2 Tools source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake 2 Tools source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Quake 2 Tools source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
#include "qbsp.h"
extern float subdivide_size;
char source[1024];
char name[1024];
vec_t microvolume = 1.0;
qboolean noprune;
qboolean glview;
qboolean nodetail;
qboolean fulldetail;
qboolean onlyents;
qboolean nomerge;
qboolean nowater;
qboolean nofill;
qboolean nocsg;
qboolean noweld;
qboolean noshare;
qboolean nosubdiv;
qboolean notjunc;
qboolean noopt;
qboolean leaktest;
qboolean verboseentities;
char outbase[32];
int block_xl = -8, block_xh = 7, block_yl = -8, block_yh = 7;
int entity_num;
node_t *block_nodes[10][10];
/*
============
BlockTree
============
*/
node_t *BlockTree (int xl, int yl, int xh, int yh)
{
node_t *node;
vec3_t normal;
float dist;
int mid;
if (xl == xh && yl == yh)
{
node = block_nodes[xl+5][yl+5];
if (!node)
{ // return an empty leaf
node = AllocNode ();
node->planenum = PLANENUM_LEAF;
node->contents = 0; //CONTENTS_SOLID;
return node;
}
return node;
}
// create a seperator along the largest axis
node = AllocNode ();
if (xh - xl > yh - yl)
{ // split x axis
mid = xl + (xh-xl)/2 + 1;
normal[0] = 1;
normal[1] = 0;
normal[2] = 0;
dist = mid*1024;
node->planenum = FindFloatPlane (normal, dist);
node->children[0] = BlockTree ( mid, yl, xh, yh);
node->children[1] = BlockTree ( xl, yl, mid-1, yh);
}
else
{
mid = yl + (yh-yl)/2 + 1;
normal[0] = 0;
normal[1] = 1;
normal[2] = 0;
dist = mid*1024;
node->planenum = FindFloatPlane (normal, dist);
node->children[0] = BlockTree ( xl, mid, xh, yh);
node->children[1] = BlockTree ( xl, yl, xh, mid-1);
}
return node;
}
/*
============
ProcessBlock_Thread
============
*/
int brush_start, brush_end;
void ProcessBlock_Thread (int blocknum)
{
int xblock, yblock;
vec3_t mins, maxs;
bspbrush_t *brushes;
tree_t *tree;
node_t *node;
yblock = block_yl + blocknum / (block_xh-block_xl+1);
xblock = block_xl + blocknum % (block_xh-block_xl+1);
qprintf ("############### block %2i,%2i ###############\n", xblock, yblock);
mins[0] = xblock*1024;
mins[1] = yblock*1024;
mins[2] = -4096;
maxs[0] = (xblock+1)*1024;
maxs[1] = (yblock+1)*1024;
maxs[2] = 4096;
// the makelist and chopbrushes could be cached between the passes...
brushes = MakeBspBrushList (brush_start, brush_end, mins, maxs);
if (!brushes)
{
node = AllocNode ();
node->planenum = PLANENUM_LEAF;
node->contents = CONTENTS_SOLID;
block_nodes[xblock+5][yblock+5] = node;
return;
}
if (!nocsg)
brushes = ChopBrushes (brushes);
tree = BrushBSP (brushes, mins, maxs);
block_nodes[xblock+5][yblock+5] = tree->headnode;
}
/*
============
ProcessWorldModel
============
*/
void ProcessWorldModel (void)
{
entity_t *e;
tree_t *tree;
qboolean leaked;
qboolean optimize;
e = &entities[entity_num];
brush_start = e->firstbrush;
brush_end = brush_start + e->numbrushes;
leaked = false;
//
// perform per-block operations
//
if (block_xh * 1024 > map_maxs[0])
block_xh = floor(map_maxs[0]/1024.0);
if ( (block_xl+1) * 1024 < map_mins[0])
block_xl = floor(map_mins[0]/1024.0);
if (block_yh * 1024 > map_maxs[1])
block_yh = floor(map_maxs[1]/1024.0);
if ( (block_yl+1) * 1024 < map_mins[1])
block_yl = floor(map_mins[1]/1024.0);
if (block_xl <-4)
block_xl = -4;
if (block_yl <-4)
block_yl = -4;
if (block_xh > 3)
block_xh = 3;
if (block_yh > 3)
block_yh = 3;
for (optimize = false ; optimize <= true ; optimize++)
{
qprintf ("--------------------------------------------\n");
RunThreadsOnIndividual ((block_xh-block_xl+1)*(block_yh-block_yl+1),
!verbose, ProcessBlock_Thread);
//
// build the division tree
// oversizing the blocks guarantees that all the boundaries
// will also get nodes.
//
qprintf ("--------------------------------------------\n");
tree = AllocTree ();
tree->headnode = BlockTree (block_xl-1, block_yl-1, block_xh+1, block_yh+1);
tree->mins[0] = (block_xl)*1024;
tree->mins[1] = (block_yl)*1024;
tree->mins[2] = map_mins[2] - 8;
tree->maxs[0] = (block_xh+1)*1024;
tree->maxs[1] = (block_yh+1)*1024;
tree->maxs[2] = map_maxs[2] + 8;
//
// perform the global operations
//
MakeTreePortals (tree);
if (FloodEntities (tree))
FillOutside (tree->headnode);
else
{
printf ("**** leaked ****\n");
leaked = true;
LeakFile (tree);
if (leaktest)
{
printf ("--- MAP LEAKED ---\n");
exit (0);
}
}
MarkVisibleSides (tree, brush_start, brush_end);
if (noopt || leaked)
break;
if (!optimize)
{
FreeTree (tree);
}
}
FloodAreas (tree);
if (glview)
WriteGLView (tree, source);
MakeFaces (tree->headnode);
FixTjuncs (tree->headnode);
if (!noprune)
PruneNodes (tree->headnode);
WriteBSP (tree->headnode);
if (!leaked)
WritePortalFile (tree);
FreeTree (tree);
}
/*
============
ProcessSubModel
============
*/
void ProcessSubModel (void)
{
entity_t *e;
int start, end;
tree_t *tree;
bspbrush_t *list;
vec3_t mins, maxs;
e = &entities[entity_num];
start = e->firstbrush;
end = start + e->numbrushes;
mins[0] = mins[1] = mins[2] = -4096;
maxs[0] = maxs[1] = maxs[2] = 4096;
list = MakeBspBrushList (start, end, mins, maxs);
if (!nocsg)
list = ChopBrushes (list);
tree = BrushBSP (list, mins, maxs);
MakeTreePortals (tree);
MarkVisibleSides (tree, start, end);
MakeFaces (tree->headnode);
FixTjuncs (tree->headnode);
WriteBSP (tree->headnode);
FreeTree (tree);
}
/*
============
ProcessModels
============
*/
void ProcessModels (void)
{
BeginBSPFile ();
for (entity_num=0 ; entity_num< num_entities ; entity_num++)
{
if (!entities[entity_num].numbrushes)
continue;
qprintf ("############### model %i ###############\n", nummodels);
BeginModel ();
if (entity_num == 0)
ProcessWorldModel ();
else
ProcessSubModel ();
EndModel ();
if (!verboseentities)
verbose = false; // don't bother printing submodels
}
EndBSPFile ();
}
/*
============
main
============
*/
int main (int argc, char **argv)
{
int i;
double start, end;
char path[1024];
printf ("---- qbsp3 ----\n");
for (i=1 ; i<argc ; i++)
{
if (!strcmp(argv[i],"-threads"))
{
numthreads = atoi (argv[i+1]);
i++;
}
else if (!strcmp(argv[i],"-glview"))
{
glview = true;
}
else if (!strcmp(argv[i], "-v"))
{
printf ("verbose = true\n");
verbose = true;
}
else if (!strcmp(argv[i], "-draw"))
{
printf ("drawflag = true\n");
drawflag = true;
}
else if (!strcmp(argv[i], "-noweld"))
{
printf ("noweld = true\n");
noweld = true;
}
else if (!strcmp(argv[i], "-nocsg"))
{
printf ("nocsg = true\n");
nocsg = true;
}
else if (!strcmp(argv[i], "-noshare"))
{
printf ("noshare = true\n");
noshare = true;
}
else if (!strcmp(argv[i], "-notjunc"))
{
printf ("notjunc = true\n");
notjunc = true;
}
else if (!strcmp(argv[i], "-nowater"))
{
printf ("nowater = true\n");
nowater = true;
}
else if (!strcmp(argv[i], "-noopt"))
{
printf ("noopt = true\n");
noopt = true;
}
else if (!strcmp(argv[i], "-noprune"))
{
printf ("noprune = true\n");
noprune = true;
}
else if (!strcmp(argv[i], "-nofill"))
{
printf ("nofill = true\n");
nofill = true;
}
else if (!strcmp(argv[i], "-nomerge"))
{
printf ("nomerge = true\n");
nomerge = true;
}
else if (!strcmp(argv[i], "-nosubdiv"))
{
printf ("nosubdiv = true\n");
nosubdiv = true;
}
else if (!strcmp(argv[i], "-nodetail"))
{
printf ("nodetail = true\n");
nodetail = true;
}
else if (!strcmp(argv[i], "-fulldetail"))
{
printf ("fulldetail = true\n");
fulldetail = true;
}
else if (!strcmp(argv[i], "-onlyents"))
{
printf ("onlyents = true\n");
onlyents = true;
}
else if (!strcmp(argv[i], "-micro"))
{
microvolume = atof(argv[i+1]);
printf ("microvolume = %f\n", microvolume);
i++;
}
else if (!strcmp(argv[i], "-leaktest"))
{
printf ("leaktest = true\n");
leaktest = true;
}
else if (!strcmp(argv[i], "-verboseentities"))
{
printf ("verboseentities = true\n");
verboseentities = true;
}
else if (!strcmp(argv[i], "-chop"))
{
subdivide_size = atof(argv[i+1]);
printf ("subdivide_size = %f\n", subdivide_size);
i++;
}
else if (!strcmp(argv[i], "-block"))
{
block_xl = block_xh = atoi(argv[i+1]);
block_yl = block_yh = atoi(argv[i+2]);
printf ("block: %i,%i\n", block_xl, block_yl);
i+=2;
}
else if (!strcmp(argv[i], "-blocks"))
{
block_xl = atoi(argv[i+1]);
block_yl = atoi(argv[i+2]);
block_xh = atoi(argv[i+3]);
block_yh = atoi(argv[i+4]);
printf ("blocks: %i,%i to %i,%i\n",
block_xl, block_yl, block_xh, block_yh);
i+=4;
}
else if (!strcmp (argv[i],"-tmpout"))
{
strcpy (outbase, "/tmp");
}
else if (argv[i][0] == '-')
Error ("Unknown option \"%s\"", argv[i]);
else
break;
}
if (i != argc - 1)
Error ("usage: qbsp3 [options] mapfile");
start = I_FloatTime ();
ThreadSetDefault ();
numthreads = 1; // multiple threads aren't helping...
SetQdirFromPath (argv[i]);
strcpy (source, ExpandArg (argv[i]));
StripExtension (source);
// delete portal and line files
sprintf (path, "%s.prt", source);
remove (path);
sprintf (path, "%s.lin", source);
remove (path);
strcpy (name, ExpandArg (argv[i]));
DefaultExtension (name, ".map"); // might be .reg
//
// if onlyents, just grab the entites and resave
//
if (onlyents)
{
char out[1024];
sprintf (out, "%s.bsp", source);
LoadBSPFile (out);
num_entities = 0;
LoadMapFile (name);
SetModelNumbers ();
SetLightStyles ();
UnparseEntities ();
WriteBSPFile (out);
}
else
{
//
// start from scratch
//
LoadMapFile (name);
SetModelNumbers ();
SetLightStyles ();
ProcessModels ();
}
end = I_FloatTime ();
printf ("%5.0f seconds elapsed\n", end-start);
return 0;
}