419 lines
8.4 KiB
C
419 lines
8.4 KiB
C
|
/*
|
||
|
===========================================================================
|
||
|
Copyright (C) 1999-2005 Id Software, Inc.
|
||
|
|
||
|
This file is part of Quake III Arena source code.
|
||
|
|
||
|
Quake III Arena 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 III Arena 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 Foobar; if not, write to the Free Software
|
||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
===========================================================================
|
||
|
*/
|
||
|
#include "qbsp.h"
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
EmitShader
|
||
|
============
|
||
|
*/
|
||
|
int EmitShader( const char *shader ) {
|
||
|
int i;
|
||
|
shaderInfo_t *si;
|
||
|
|
||
|
if ( !shader ) {
|
||
|
shader = "noshader";
|
||
|
}
|
||
|
|
||
|
for ( i = 0 ; i < numShaders ; i++ ) {
|
||
|
if ( !Q_stricmp( shader, dshaders[i].shader ) ) {
|
||
|
return i;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( i == MAX_MAP_SHADERS ) {
|
||
|
Error( "MAX_MAP_SHADERS" );
|
||
|
}
|
||
|
numShaders++;
|
||
|
strcpy( dshaders[i].shader, shader );
|
||
|
|
||
|
si = ShaderInfoForShader( shader );
|
||
|
dshaders[i].surfaceFlags = si->surfaceFlags;
|
||
|
dshaders[i].contentFlags = si->contents;
|
||
|
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
EmitPlanes
|
||
|
|
||
|
There is no oportunity to discard planes, because all of the original
|
||
|
brushes will be saved in the map.
|
||
|
============
|
||
|
*/
|
||
|
void EmitPlanes (void)
|
||
|
{
|
||
|
int i;
|
||
|
dplane_t *dp;
|
||
|
plane_t *mp;
|
||
|
|
||
|
mp = mapplanes;
|
||
|
for (i=0 ; i<nummapplanes ; i++, mp++)
|
||
|
{
|
||
|
dp = &dplanes[numplanes];
|
||
|
VectorCopy ( mp->normal, dp->normal);
|
||
|
dp->dist = mp->dist;
|
||
|
numplanes++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
==================
|
||
|
EmitLeaf
|
||
|
==================
|
||
|
*/
|
||
|
void EmitLeaf (node_t *node)
|
||
|
{
|
||
|
dleaf_t *leaf_p;
|
||
|
bspbrush_t *b;
|
||
|
drawSurfRef_t *dsr;
|
||
|
|
||
|
// emit a leaf
|
||
|
if (numleafs >= MAX_MAP_LEAFS)
|
||
|
Error ("MAX_MAP_LEAFS");
|
||
|
|
||
|
leaf_p = &dleafs[numleafs];
|
||
|
numleafs++;
|
||
|
|
||
|
leaf_p->cluster = node->cluster;
|
||
|
leaf_p->area = node->area;
|
||
|
|
||
|
//
|
||
|
// write bounding box info
|
||
|
//
|
||
|
VectorCopy (node->mins, leaf_p->mins);
|
||
|
VectorCopy (node->maxs, leaf_p->maxs);
|
||
|
|
||
|
//
|
||
|
// write the leafbrushes
|
||
|
//
|
||
|
leaf_p->firstLeafBrush = numleafbrushes;
|
||
|
for ( b = node->brushlist ; b ; b = b->next ) {
|
||
|
if ( numleafbrushes >= MAX_MAP_LEAFBRUSHES ) {
|
||
|
Error( "MAX_MAP_LEAFBRUSHES" );
|
||
|
}
|
||
|
dleafbrushes[numleafbrushes] = b->original->outputNumber;
|
||
|
numleafbrushes++;
|
||
|
}
|
||
|
leaf_p->numLeafBrushes = numleafbrushes - leaf_p->firstLeafBrush;
|
||
|
|
||
|
//
|
||
|
// write the surfaces visible in this leaf
|
||
|
//
|
||
|
if ( node->opaque ) {
|
||
|
return; // no leaffaces in solids
|
||
|
}
|
||
|
|
||
|
// add the drawSurfRef_t drawsurfs
|
||
|
leaf_p->firstLeafSurface = numleafsurfaces;
|
||
|
for ( dsr = node->drawSurfReferences ; dsr ; dsr = dsr->nextRef ) {
|
||
|
if ( numleafsurfaces >= MAX_MAP_LEAFFACES)
|
||
|
Error ("MAX_MAP_LEAFFACES");
|
||
|
dleafsurfaces[numleafsurfaces] = dsr->outputNumber;
|
||
|
numleafsurfaces++;
|
||
|
}
|
||
|
|
||
|
|
||
|
leaf_p->numLeafSurfaces = numleafsurfaces - leaf_p->firstLeafSurface;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
EmitDrawNode_r
|
||
|
============
|
||
|
*/
|
||
|
int EmitDrawNode_r (node_t *node)
|
||
|
{
|
||
|
dnode_t *n;
|
||
|
int i;
|
||
|
|
||
|
if (node->planenum == PLANENUM_LEAF)
|
||
|
{
|
||
|
EmitLeaf (node);
|
||
|
return -numleafs;
|
||
|
}
|
||
|
|
||
|
// emit a node
|
||
|
if (numnodes == MAX_MAP_NODES)
|
||
|
Error ("MAX_MAP_NODES");
|
||
|
n = &dnodes[numnodes];
|
||
|
numnodes++;
|
||
|
|
||
|
VectorCopy (node->mins, n->mins);
|
||
|
VectorCopy (node->maxs, n->maxs);
|
||
|
|
||
|
if (node->planenum & 1)
|
||
|
Error ("WriteDrawNodes_r: odd planenum");
|
||
|
n->planeNum = node->planenum;
|
||
|
|
||
|
//
|
||
|
// recursively output the other nodes
|
||
|
//
|
||
|
for (i=0 ; i<2 ; i++)
|
||
|
{
|
||
|
if (node->children[i]->planenum == PLANENUM_LEAF)
|
||
|
{
|
||
|
n->children[i] = -(numleafs + 1);
|
||
|
EmitLeaf (node->children[i]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
n->children[i] = numnodes;
|
||
|
EmitDrawNode_r (node->children[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return n - dnodes;
|
||
|
}
|
||
|
|
||
|
//=========================================================
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
SetModelNumbers
|
||
|
============
|
||
|
*/
|
||
|
void SetModelNumbers (void)
|
||
|
{
|
||
|
int i;
|
||
|
int models;
|
||
|
char value[10];
|
||
|
|
||
|
models = 1;
|
||
|
for ( i=1 ; i<num_entities ; i++ ) {
|
||
|
if ( entities[i].brushes || entities[i].patches ) {
|
||
|
sprintf ( value, "*%i", models );
|
||
|
models++;
|
||
|
SetKeyValue (&entities[i], "model", value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
SetLightStyles
|
||
|
============
|
||
|
*/
|
||
|
#define MAX_SWITCHED_LIGHTS 32
|
||
|
void SetLightStyles (void)
|
||
|
{
|
||
|
int stylenum;
|
||
|
const char *t;
|
||
|
entity_t *e;
|
||
|
int i, j;
|
||
|
char value[10];
|
||
|
char lighttargets[MAX_SWITCHED_LIGHTS][64];
|
||
|
|
||
|
|
||
|
// any light that is controlled (has a targetname)
|
||
|
// must have a unique style number generated for it
|
||
|
|
||
|
stylenum = 0;
|
||
|
for (i=1 ; i<num_entities ; i++)
|
||
|
{
|
||
|
e = &entities[i];
|
||
|
|
||
|
t = ValueForKey (e, "classname");
|
||
|
if (Q_strncasecmp (t, "light", 5))
|
||
|
continue;
|
||
|
t = ValueForKey (e, "targetname");
|
||
|
if (!t[0])
|
||
|
continue;
|
||
|
|
||
|
// find this targetname
|
||
|
for (j=0 ; j<stylenum ; j++)
|
||
|
if (!strcmp (lighttargets[j], t))
|
||
|
break;
|
||
|
if (j == stylenum)
|
||
|
{
|
||
|
if (stylenum == MAX_SWITCHED_LIGHTS)
|
||
|
Error ("stylenum == MAX_SWITCHED_LIGHTS");
|
||
|
strcpy (lighttargets[j], t);
|
||
|
stylenum++;
|
||
|
}
|
||
|
sprintf (value, "%i", 32 + j);
|
||
|
SetKeyValue (e, "style", value);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
//===========================================================
|
||
|
|
||
|
/*
|
||
|
==================
|
||
|
BeginBSPFile
|
||
|
==================
|
||
|
*/
|
||
|
void BeginBSPFile( void ) {
|
||
|
// these values may actually be initialized
|
||
|
// if the file existed when loaded, so clear them explicitly
|
||
|
nummodels = 0;
|
||
|
numnodes = 0;
|
||
|
numbrushsides = 0;
|
||
|
numleafsurfaces = 0;
|
||
|
numleafbrushes = 0;
|
||
|
|
||
|
// leave leaf 0 as an error, because leafs are referenced as
|
||
|
// negative number nodes
|
||
|
numleafs = 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
EndBSPFile
|
||
|
============
|
||
|
*/
|
||
|
void EndBSPFile( void ) {
|
||
|
char path[1024];
|
||
|
|
||
|
EmitPlanes ();
|
||
|
UnparseEntities ();
|
||
|
|
||
|
// write the map
|
||
|
sprintf (path, "%s.bsp", source);
|
||
|
_printf ("Writing %s\n", path);
|
||
|
WriteBSPFile (path);
|
||
|
}
|
||
|
|
||
|
|
||
|
//===========================================================
|
||
|
|
||
|
/*
|
||
|
============
|
||
|
EmitBrushes
|
||
|
============
|
||
|
*/
|
||
|
void EmitBrushes ( bspbrush_t *brushes ) {
|
||
|
int j;
|
||
|
dbrush_t *db;
|
||
|
bspbrush_t *b;
|
||
|
dbrushside_t *cp;
|
||
|
|
||
|
for ( b = brushes ; b ; b = b->next ) {
|
||
|
if ( numbrushes == MAX_MAP_BRUSHES ) {
|
||
|
Error( "MAX_MAP_BRUSHES" );
|
||
|
}
|
||
|
b->outputNumber = numbrushes;
|
||
|
db = &dbrushes[numbrushes];
|
||
|
numbrushes++;
|
||
|
|
||
|
db->shaderNum = EmitShader( b->contentShader->shader );
|
||
|
db->firstSide = numbrushsides;
|
||
|
|
||
|
// don't emit any generated backSide sides
|
||
|
db->numSides = 0;
|
||
|
for ( j=0 ; j<b->numsides ; j++ ) {
|
||
|
if ( b->sides[j].backSide ) {
|
||
|
continue;
|
||
|
}
|
||
|
if ( numbrushsides == MAX_MAP_BRUSHSIDES ) {
|
||
|
Error( "MAX_MAP_BRUSHSIDES ");
|
||
|
}
|
||
|
cp = &dbrushsides[numbrushsides];
|
||
|
db->numSides++;
|
||
|
numbrushsides++;
|
||
|
cp->planeNum = b->sides[j].planenum;
|
||
|
cp->shaderNum = EmitShader( b->sides[j].shaderInfo->shader );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
==================
|
||
|
BeginModel
|
||
|
==================
|
||
|
*/
|
||
|
void BeginModel( void ) {
|
||
|
dmodel_t *mod;
|
||
|
bspbrush_t *b;
|
||
|
entity_t *e;
|
||
|
vec3_t mins, maxs;
|
||
|
parseMesh_t *p;
|
||
|
int i;
|
||
|
|
||
|
if ( nummodels == MAX_MAP_MODELS ) {
|
||
|
Error( "MAX_MAP_MODELS" );
|
||
|
}
|
||
|
mod = &dmodels[nummodels];
|
||
|
|
||
|
//
|
||
|
// bound the brushes
|
||
|
//
|
||
|
e = &entities[entity_num];
|
||
|
|
||
|
ClearBounds (mins, maxs);
|
||
|
for ( b = e->brushes ; b ; b = b->next ) {
|
||
|
if ( !b->numsides ) {
|
||
|
continue; // not a real brush (origin brush, etc)
|
||
|
}
|
||
|
AddPointToBounds (b->mins, mins, maxs);
|
||
|
AddPointToBounds (b->maxs, mins, maxs);
|
||
|
}
|
||
|
|
||
|
for ( p = e->patches ; p ; p = p->next ) {
|
||
|
for ( i = 0 ; i < p->mesh.width * p->mesh.height ; i++ ) {
|
||
|
AddPointToBounds( p->mesh.verts[i].xyz, mins, maxs );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VectorCopy (mins, mod->mins);
|
||
|
VectorCopy (maxs, mod->maxs);
|
||
|
|
||
|
mod->firstSurface = numDrawSurfaces;
|
||
|
mod->firstBrush = numbrushes;
|
||
|
|
||
|
EmitBrushes( e->brushes );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
==================
|
||
|
EndModel
|
||
|
==================
|
||
|
*/
|
||
|
void EndModel( node_t *headnode ) {
|
||
|
dmodel_t *mod;
|
||
|
|
||
|
qprintf ("--- EndModel ---\n");
|
||
|
|
||
|
mod = &dmodels[nummodels];
|
||
|
EmitDrawNode_r (headnode);
|
||
|
mod->numSurfaces = numDrawSurfaces - mod->firstSurface;
|
||
|
mod->numBrushes = numbrushes - mod->firstBrush;
|
||
|
|
||
|
nummodels++;
|
||
|
}
|
||
|
|