mirror of
https://github.com/UberGames/GtkRadiant.git
synced 2024-11-26 05:41:43 +00:00
593 lines
12 KiB
C
593 lines
12 KiB
C
/*
|
|
Copyright (C) 1999-2007 id Software, Inc. and contributors.
|
|
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
|
|
|
This file is part of GtkRadiant.
|
|
|
|
GtkRadiant 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.
|
|
|
|
GtkRadiant 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 GtkRadiant; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
#include "qbsp.h"
|
|
|
|
int c_nofaces;
|
|
int c_facenodes;
|
|
|
|
|
|
/*
|
|
=========================================================
|
|
|
|
ONLY SAVE OUT PLANES THAT ARE ACTUALLY USED AS NODES
|
|
|
|
=========================================================
|
|
*/
|
|
|
|
int planeused[MAX_MAP_PLANES];
|
|
|
|
/*
|
|
============
|
|
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;
|
|
int planetranslate[MAX_MAP_PLANES];
|
|
|
|
mp = mapplanes;
|
|
for ( i = 0 ; i < nummapplanes ; i++, mp++ )
|
|
{
|
|
dp = &dplanes[numplanes];
|
|
planetranslate[i] = numplanes;
|
|
VectorCopy( mp->normal, dp->normal );
|
|
dp->dist = mp->dist;
|
|
dp->type = mp->type;
|
|
numplanes++;
|
|
}
|
|
}
|
|
|
|
|
|
//========================================================
|
|
|
|
void EmitMarkFace( dleaf_t *leaf_p, face_t *f ){
|
|
int i;
|
|
int facenum;
|
|
|
|
while ( f->merged )
|
|
f = f->merged;
|
|
|
|
if ( f->split[0] ) {
|
|
EmitMarkFace( leaf_p, f->split[0] );
|
|
EmitMarkFace( leaf_p, f->split[1] );
|
|
return;
|
|
}
|
|
|
|
facenum = f->outputnumber;
|
|
if ( facenum == -1 ) {
|
|
return; // degenerate face
|
|
|
|
}
|
|
if ( facenum < 0 || facenum >= numfaces ) {
|
|
Error( "Bad leafface" );
|
|
}
|
|
for ( i = leaf_p->firstleafface ; i < numleaffaces ; i++ )
|
|
if ( dleaffaces[i] == facenum ) {
|
|
break;
|
|
} // merged out face
|
|
if ( i == numleaffaces ) {
|
|
if ( numleaffaces >= MAX_MAP_LEAFFACES ) {
|
|
Error( "MAX_MAP_LEAFFACES" );
|
|
}
|
|
|
|
dleaffaces[numleaffaces] = facenum;
|
|
numleaffaces++;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
==================
|
|
EmitLeaf
|
|
==================
|
|
*/
|
|
void EmitLeaf( node_t *node ){
|
|
dleaf_t *leaf_p;
|
|
portal_t *p;
|
|
int s;
|
|
face_t *f;
|
|
bspbrush_t *b;
|
|
int i;
|
|
int brushnum;
|
|
|
|
// emit a leaf
|
|
if ( numleafs >= MAX_MAP_LEAFS ) {
|
|
Error( "MAX_MAP_LEAFS" );
|
|
}
|
|
|
|
leaf_p = &dleafs[numleafs];
|
|
numleafs++;
|
|
|
|
leaf_p->contents = node->contents;
|
|
leaf_p->cluster = node->cluster;
|
|
leaf_p->area = node->area;
|
|
|
|
//
|
|
// write bounding box info
|
|
//
|
|
VectorCopy( (short) node->mins, leaf_p->mins );
|
|
VectorCopy( (short) 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" );
|
|
}
|
|
|
|
brushnum = b->original - mapbrushes;
|
|
for ( i = leaf_p->firstleafbrush ; i < numleafbrushes ; i++ )
|
|
if ( dleafbrushes[i] == brushnum ) {
|
|
break;
|
|
}
|
|
if ( i == numleafbrushes ) {
|
|
dleafbrushes[numleafbrushes] = brushnum;
|
|
numleafbrushes++;
|
|
}
|
|
}
|
|
leaf_p->numleafbrushes = numleafbrushes - leaf_p->firstleafbrush;
|
|
|
|
//
|
|
// write the leaffaces
|
|
//
|
|
if ( leaf_p->contents & CONTENTS_SOLID ) {
|
|
return; // no leaffaces in solids
|
|
|
|
}
|
|
leaf_p->firstleafface = numleaffaces;
|
|
|
|
for ( p = node->portals ; p ; p = p->next[s] )
|
|
{
|
|
s = ( p->nodes[1] == node );
|
|
f = p->face[s];
|
|
if ( !f ) {
|
|
continue; // not a visible portal
|
|
|
|
}
|
|
EmitMarkFace( leaf_p, f );
|
|
}
|
|
|
|
leaf_p->numleaffaces = numleaffaces - leaf_p->firstleafface;
|
|
}
|
|
|
|
|
|
/*
|
|
==================
|
|
EmitFace
|
|
==================
|
|
*/
|
|
void EmitFace( face_t *f ){
|
|
dface_t *df;
|
|
int i;
|
|
int e;
|
|
|
|
f->outputnumber = -1;
|
|
|
|
if ( f->numpoints < 3 ) {
|
|
return; // degenerated
|
|
}
|
|
if ( f->merged || f->split[0] || f->split[1] ) {
|
|
return; // not a final face
|
|
}
|
|
|
|
// save output number so leaffaces can use
|
|
f->outputnumber = numfaces;
|
|
|
|
if ( numfaces >= MAX_MAP_FACES ) {
|
|
Error( "numfaces == MAX_MAP_FACES" );
|
|
}
|
|
df = &dfaces[numfaces];
|
|
numfaces++;
|
|
|
|
// planenum is used by qlight, but not quake
|
|
df->planenum = f->planenum & ( ~1 );
|
|
df->side = f->planenum & 1;
|
|
|
|
df->firstedge = numsurfedges;
|
|
df->numedges = f->numpoints;
|
|
df->texinfo = f->texinfo;
|
|
for ( i = 0 ; i < f->numpoints ; i++ )
|
|
{
|
|
// e = GetEdge (f->pts[i], f->pts[(i+1)%f->numpoints], f);
|
|
e = GetEdge2( f->vertexnums[i], f->vertexnums[( i + 1 ) % f->numpoints], f );
|
|
if ( numsurfedges >= MAX_MAP_SURFEDGES ) {
|
|
Error( "numsurfedges == MAX_MAP_SURFEDGES" );
|
|
}
|
|
dsurfedges[numsurfedges] = e;
|
|
numsurfedges++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
============
|
|
EmitDrawingNode_r
|
|
============
|
|
*/
|
|
int EmitDrawNode_r( node_t *node ){
|
|
dnode_t *n;
|
|
face_t *f;
|
|
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( (short) node->mins, n->mins );
|
|
VectorCopy( (short) node->maxs, n->maxs );
|
|
|
|
planeused[node->planenum]++;
|
|
planeused[node->planenum ^ 1]++;
|
|
|
|
if ( node->planenum & 1 ) {
|
|
Error( "WriteDrawNodes_r: odd planenum" );
|
|
}
|
|
n->planenum = node->planenum;
|
|
n->firstface = numfaces;
|
|
|
|
if ( !node->faces ) {
|
|
c_nofaces++;
|
|
}
|
|
else{
|
|
c_facenodes++;
|
|
}
|
|
|
|
for ( f = node->faces ; f ; f = f->next )
|
|
EmitFace( f );
|
|
|
|
n->numfaces = numfaces - n->firstface;
|
|
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
//=========================================================
|
|
|
|
|
|
/*
|
|
============
|
|
WriteBSP
|
|
============
|
|
*/
|
|
void WriteBSP( node_t *headnode ){
|
|
int oldfaces;
|
|
|
|
c_nofaces = 0;
|
|
c_facenodes = 0;
|
|
|
|
Sys_FPrintf( SYS_VRB, "--- WriteBSP ---\n" );
|
|
|
|
oldfaces = numfaces;
|
|
dmodels[nummodels].headnode = EmitDrawNode_r( headnode );
|
|
EmitAreaPortals( headnode );
|
|
|
|
Sys_FPrintf( SYS_VRB, "%5i nodes with faces\n", c_facenodes );
|
|
Sys_FPrintf( SYS_VRB, "%5i nodes without faces\n", c_nofaces );
|
|
Sys_FPrintf( SYS_VRB, "%5i faces\n", numfaces - oldfaces );
|
|
}
|
|
|
|
//===========================================================
|
|
|
|
/*
|
|
============
|
|
SetModelNumbers
|
|
============
|
|
*/
|
|
void SetModelNumbers( void ){
|
|
int i;
|
|
int models;
|
|
char value[10];
|
|
|
|
models = 1;
|
|
for ( i = 1 ; i < num_entities ; i++ )
|
|
{
|
|
if ( entities[i].numbrushes ) {
|
|
sprintf( value, "*%i", models );
|
|
models++;
|
|
SetKeyValue( &entities[i], "model", value );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
============
|
|
SetLightStyles
|
|
============
|
|
*/
|
|
#define MAX_SWITCHED_LIGHTS 32
|
|
void SetLightStyles( void ){
|
|
int stylenum;
|
|
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 );
|
|
}
|
|
|
|
}
|
|
|
|
//===========================================================
|
|
|
|
/*
|
|
============
|
|
EmitBrushes
|
|
============
|
|
*/
|
|
void EmitBrushes( void ){
|
|
int i, j, bnum, s, x;
|
|
dbrush_t *db;
|
|
mapbrush_t *b;
|
|
dbrushside_t *cp;
|
|
vec3_t normal;
|
|
vec_t dist;
|
|
int planenum;
|
|
|
|
numbrushsides = 0;
|
|
numbrushes = nummapbrushes;
|
|
|
|
for ( bnum = 0 ; bnum < nummapbrushes ; bnum++ )
|
|
{
|
|
b = &mapbrushes[bnum];
|
|
db = &dbrushes[bnum];
|
|
|
|
db->contents = b->contents;
|
|
db->firstside = numbrushsides;
|
|
db->numsides = b->numsides;
|
|
for ( j = 0 ; j < b->numsides ; j++ )
|
|
{
|
|
if ( numbrushsides == MAX_MAP_BRUSHSIDES ) {
|
|
Error( "MAX_MAP_BRUSHSIDES" );
|
|
}
|
|
cp = &dbrushsides[numbrushsides];
|
|
numbrushsides++;
|
|
cp->planenum = b->original_sides[j].planenum;
|
|
cp->texinfo = b->original_sides[j].texinfo;
|
|
}
|
|
|
|
// add any axis planes not contained in the brush to bevel off corners
|
|
for ( x = 0 ; x < 3 ; x++ )
|
|
for ( s = -1 ; s <= 1 ; s += 2 )
|
|
{
|
|
// add the plane
|
|
VectorCopy( vec3_origin, normal );
|
|
normal[x] = (float) s;
|
|
if ( s == -1 ) {
|
|
dist = -b->mins[x];
|
|
}
|
|
else{
|
|
dist = b->maxs[x];
|
|
}
|
|
planenum = FindFloatPlane( normal, dist );
|
|
for ( i = 0 ; i < b->numsides ; i++ )
|
|
if ( b->original_sides[i].planenum == planenum ) {
|
|
break;
|
|
}
|
|
if ( i == b->numsides ) {
|
|
if ( numbrushsides >= MAX_MAP_BRUSHSIDES ) {
|
|
Error( "MAX_MAP_BRUSHSIDES" );
|
|
}
|
|
|
|
dbrushsides[numbrushsides].planenum = planenum;
|
|
dbrushsides[numbrushsides].texinfo =
|
|
dbrushsides[numbrushsides - 1].texinfo;
|
|
numbrushsides++;
|
|
db->numsides++;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//===========================================================
|
|
|
|
/*
|
|
==================
|
|
BeginBSPFile
|
|
==================
|
|
*/
|
|
void BeginBSPFile( void ){
|
|
// these values may actually be initialized
|
|
// if the file existed when loaded, so clear them explicitly
|
|
nummodels = 0;
|
|
numfaces = 0;
|
|
numnodes = 0;
|
|
numbrushsides = 0;
|
|
numvertexes = 0;
|
|
numleaffaces = 0;
|
|
numleafbrushes = 0;
|
|
numsurfedges = 0;
|
|
|
|
// edge 0 is not used, because 0 can't be negated
|
|
numedges = 1;
|
|
|
|
// leave vertex 0 as an error
|
|
numvertexes = 1;
|
|
|
|
// leave leaf 0 as an error
|
|
numleafs = 1;
|
|
dleafs[0].contents = CONTENTS_SOLID;
|
|
}
|
|
|
|
|
|
/*
|
|
============
|
|
EndBSPFile
|
|
============
|
|
*/
|
|
void EndBSPFile( void ){
|
|
char path[1024];
|
|
|
|
#if 0
|
|
int len;
|
|
byte *buf;
|
|
#endif
|
|
|
|
EmitBrushes();
|
|
EmitPlanes();
|
|
UnparseEntities();
|
|
|
|
// load the pop
|
|
#if 0
|
|
sprintf( path, "%s/pics/pop.lmp", gamedir );
|
|
len = LoadFile( path, &buf );
|
|
memcpy( dpop, buf, sizeof( dpop ) );
|
|
free( buf );
|
|
#endif
|
|
|
|
// write the map
|
|
sprintf( path, "%s.bsp", source );
|
|
Sys_Printf( "Writing %s\n", path );
|
|
WriteBSPFile( path );
|
|
}
|
|
|
|
|
|
/*
|
|
==================
|
|
BeginModel
|
|
==================
|
|
*/
|
|
int firstmodleaf;
|
|
extern int firstmodeledge;
|
|
extern int firstmodelface;
|
|
void BeginModel( void ){
|
|
dmodel_t *mod;
|
|
int start, end;
|
|
mapbrush_t *b;
|
|
int j;
|
|
entity_t *e;
|
|
vec3_t mins, maxs;
|
|
|
|
if ( nummodels == MAX_MAP_MODELS ) {
|
|
Error( "MAX_MAP_MODELS" );
|
|
}
|
|
mod = &dmodels[nummodels];
|
|
|
|
mod->firstface = numfaces;
|
|
|
|
firstmodleaf = numleafs;
|
|
firstmodeledge = numedges;
|
|
firstmodelface = numfaces;
|
|
|
|
//
|
|
// bound the brushes
|
|
//
|
|
e = &entities[entity_num];
|
|
|
|
start = e->firstbrush;
|
|
end = start + e->numbrushes;
|
|
ClearBounds( mins, maxs );
|
|
|
|
for ( j = start ; j < end ; j++ )
|
|
{
|
|
b = &mapbrushes[j];
|
|
if ( !b->numsides ) {
|
|
continue; // not a real brush (origin brush)
|
|
}
|
|
AddPointToBounds( b->mins, mins, maxs );
|
|
AddPointToBounds( b->maxs, mins, maxs );
|
|
}
|
|
|
|
VectorCopy( mins, mod->mins );
|
|
VectorCopy( maxs, mod->maxs );
|
|
}
|
|
|
|
|
|
/*
|
|
==================
|
|
EndModel
|
|
==================
|
|
*/
|
|
void EndModel( void ){
|
|
dmodel_t *mod;
|
|
|
|
mod = &dmodels[nummodels];
|
|
|
|
mod->numfaces = numfaces - mod->firstface;
|
|
|
|
nummodels++;
|
|
}
|