The Return to Castle Wolfenstein Multiplayer sources as originally released under the GPL license on August 12, 2010.

This commit is contained in:
Travis Bradshaw
2012-01-31 14:59:39 -06:00
commit 937b209a3c
520 changed files with 424914 additions and 0 deletions

90
src/bspc/_files.c Normal file
View File

@@ -0,0 +1,90 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: _files.c
// Function:
// Programmer: Mr Elusive
// Last update: 1999-12-02
// Tab Size: 4
//===========================================================================
/*
aas_areamerging.c //AAS area merging
aas_cfg.c //AAS configuration for different games
aas_create.c //AAS creating
aas_edgemelting.c //AAS edge melting
aas_facemerging.c //AAS face merging
aas_file.c //AAS file writing
aas_gsubdiv.c //AAS gravitational and ladder subdivision
aas_map.c //AAS map brush creation
aas_prunenodes.c //AAS node pruning
aas_store.c //AAS file storing
map.c //map file loading and writing
map_hl.c //Half-Life map loading
map_q1.c //Quake1 map loading
map_q2.c //Quake2 map loading
map_q3.c //Quake3 map loading
map_sin.c //Sin map loading
tree.c //BSP tree management + node pruning (*)
brushbsp.c //brush bsp creation (*)
portals.c //BSP portal creation and leaf filling (*)
csg.c //Constructive Solid Geometry brush chopping (*)
leakfile.c //leak file writing (*)
textures.c //Quake2 BSP textures (*)
l_bsp_ent.c //BSP entity parsing
l_bsp_q1.c //Quake1 BSP loading and writing
l_bsp_q2.c //Quake2 BSP loading and writing
l_bsp_q3.c //Quake2 BSP loading and writing
l_bsp_sin.c //Sin BSP loading and writing
l_cmd.c //cmd library
l_log.c //log file library
l_math.c //math library
l_mem.c //memory management library
l_poly.c //polygon (winding) library
l_script.c //script file parsing library
l_threads.c //multi-threading library
l_utils.c //utility library
l_qfiles.c //loading of quake files
gldraw.c //GL drawing (*)
glfile.c //GL file writing (*)
nodraw.c //no draw module (*)
bspc.c //BSPC Win32 console version
winbspc.c //WinBSPC Win32 GUI version
win32_terminal.c //Win32 terminal output
win32_qfiles.c //Win32 game file management (also .pak .sin)
win32_font.c //Win32 fonts
win32_folder.c //Win32 folder dialogs
*/

424
src/bspc/aas_areamerging.c Normal file
View File

@@ -0,0 +1,424 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: aas_areamerging.c
// Function: Merging of Areas
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1997-12-04
// Tab Size: 3
//===========================================================================
#include "qbsp.h"
#include "../botlib/aasfile.h"
#include "aas_create.h"
#include "aas_store.h"
#define CONVEX_EPSILON 0.3
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
tmp_node_t *AAS_RefreshMergedTree_r( tmp_node_t *tmpnode ) {
tmp_area_t *tmparea;
//if this is a solid leaf
if ( !tmpnode ) {
return NULL;
}
//if this is an area leaf
if ( tmpnode->tmparea ) {
tmparea = tmpnode->tmparea;
while ( tmparea->mergedarea ) tmparea = tmparea->mergedarea;
tmpnode->tmparea = tmparea;
return tmpnode;
} //end if
//do the children recursively
tmpnode->children[0] = AAS_RefreshMergedTree_r( tmpnode->children[0] );
tmpnode->children[1] = AAS_RefreshMergedTree_r( tmpnode->children[1] );
return tmpnode;
} //end of the function AAS_RefreshMergedTree_r
//===========================================================================
// returns true if the two given faces would create a non-convex area at
// the given sides, otherwise false is returned
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int NonConvex( tmp_face_t *face1, tmp_face_t *face2, int side1, int side2 ) {
int i;
winding_t *w1, *w2;
plane_t *plane1, *plane2;
w1 = face1->winding;
w2 = face2->winding;
plane1 = &mapplanes[face1->planenum ^ side1];
plane2 = &mapplanes[face2->planenum ^ side2];
//check if one of the points of face1 is at the back of the plane of face2
for ( i = 0; i < w1->numpoints; i++ )
{
if ( DotProduct( plane2->normal, w1->p[i] ) - plane2->dist < -CONVEX_EPSILON ) {
return true;
}
} //end for
//check if one of the points of face2 is at the back of the plane of face1
for ( i = 0; i < w2->numpoints; i++ )
{
if ( DotProduct( plane1->normal, w2->p[i] ) - plane1->dist < -CONVEX_EPSILON ) {
return true;
}
} //end for
return false;
} //end of the function NonConvex
//===========================================================================
// try to merge the areas at both sides of the given face
//
// Parameter: seperatingface : face that seperates two areas
// Returns: -
// Changes Globals: -
//===========================================================================
int AAS_TryMergeFaceAreas( tmp_face_t *seperatingface ) {
int side1, side2, area1faceflags, area2faceflags;
tmp_area_t *tmparea1, *tmparea2, *newarea;
tmp_face_t *face1, *face2, *nextface1, *nextface2;
tmparea1 = seperatingface->frontarea;
tmparea2 = seperatingface->backarea;
//areas must have the same presence type
if ( tmparea1->presencetype != tmparea2->presencetype ) {
return false;
}
//areas must have the same area contents
if ( tmparea1->contents != tmparea2->contents ) {
return false;
}
//areas must have the same bsp model inside (or both none)
if ( tmparea1->modelnum != tmparea2->modelnum ) {
return false;
}
area1faceflags = 0;
area2faceflags = 0;
for ( face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side1] )
{
side1 = ( face1->frontarea != tmparea1 );
//debug: check if the area belongs to the area
if ( face1->frontarea != tmparea1 &&
face1->backarea != tmparea1 ) {
Error( "face does not belong to area1" );
}
//just continue if the face is seperating the two areas
//NOTE: a result of this is that ground and gap areas can
// be merged if the seperating face is the gap
if ( ( face1->frontarea == tmparea1 &&
face1->backarea == tmparea2 ) ||
( face1->frontarea == tmparea2 &&
face1->backarea == tmparea1 ) ) {
continue;
}
//get area1 face flags
area1faceflags |= face1->faceflags;
if ( AAS_GapFace( face1, side1 ) ) {
area1faceflags |= FACE_GAP;
}
//
for ( face2 = tmparea2->tmpfaces; face2; face2 = face2->next[side2] )
{
side2 = ( face2->frontarea != tmparea2 );
//debug: check if the area belongs to the area
if ( face2->frontarea != tmparea2 &&
face2->backarea != tmparea2 ) {
Error( "face does not belong to area2" );
}
//just continue if the face is seperating the two areas
//NOTE: a result of this is that ground and gap areas can
// be merged if the seperating face is the gap
if ( ( face2->frontarea == tmparea1 &&
face2->backarea == tmparea2 ) ||
( face2->frontarea == tmparea2 &&
face2->backarea == tmparea1 ) ) {
continue;
}
//get area2 face flags
area2faceflags |= face2->faceflags;
if ( AAS_GapFace( face2, side2 ) ) {
area2faceflags |= FACE_GAP;
}
//if the two faces would create a non-convex area
if ( NonConvex( face1, face2, side1, side2 ) ) {
return false;
}
} //end for
} //end for
//if one area has gap faces (that aren't seperating the two areas)
//and the other has ground faces (that aren't seperating the two areas),
//the areas can't be merged
if ( ( ( area1faceflags & FACE_GROUND ) && ( area2faceflags & FACE_GAP ) ) ||
( ( area2faceflags & FACE_GROUND ) && ( area1faceflags & FACE_GAP ) ) ) {
// Log_Print(" can't merge: ground/gap\n");
return false;
} //end if
// Log_Print("merged area %d & %d to %d with %d faces\n", tmparea1->areanum, tmparea2->areanum, newarea->areanum, numfaces);
// return false;
//
//AAS_CheckArea(tmparea1);
//AAS_CheckArea(tmparea2);
//create the new area
newarea = AAS_AllocTmpArea();
newarea->presencetype = tmparea1->presencetype;
newarea->contents = tmparea1->contents;
newarea->modelnum = tmparea1->modelnum;
newarea->tmpfaces = NULL;
//add all the faces (except the seperating ones) from the first area
//to the new area
for ( face1 = tmparea1->tmpfaces; face1; face1 = nextface1 )
{
side1 = ( face1->frontarea != tmparea1 );
nextface1 = face1->next[side1];
//don't add seperating faces
if ( ( face1->frontarea == tmparea1 &&
face1->backarea == tmparea2 ) ||
( face1->frontarea == tmparea2 &&
face1->backarea == tmparea1 ) ) {
continue;
} //end if
//
AAS_RemoveFaceFromArea( face1, tmparea1 );
AAS_AddFaceSideToArea( face1, side1, newarea );
} //end for
//add all the faces (except the seperating ones) from the second area
//to the new area
for ( face2 = tmparea2->tmpfaces; face2; face2 = nextface2 )
{
side2 = ( face2->frontarea != tmparea2 );
nextface2 = face2->next[side2];
//don't add seperating faces
if ( ( face2->frontarea == tmparea1 &&
face2->backarea == tmparea2 ) ||
( face2->frontarea == tmparea2 &&
face2->backarea == tmparea1 ) ) {
continue;
} //end if
//
AAS_RemoveFaceFromArea( face2, tmparea2 );
AAS_AddFaceSideToArea( face2, side2, newarea );
} //end for
//free all shared faces
for ( face1 = tmparea1->tmpfaces; face1; face1 = nextface1 )
{
side1 = ( face1->frontarea != tmparea1 );
nextface1 = face1->next[side1];
//
AAS_RemoveFaceFromArea( face1, face1->frontarea );
AAS_RemoveFaceFromArea( face1, face1->backarea );
AAS_FreeTmpFace( face1 );
} //end for
//
tmparea1->mergedarea = newarea;
tmparea1->invalid = true;
tmparea2->mergedarea = newarea;
tmparea2->invalid = true;
//
AAS_CheckArea( newarea );
AAS_FlipAreaFaces( newarea );
// Log_Print("merged area %d & %d to %d with %d faces\n", tmparea1->areanum, tmparea2->areanum, newarea->areanum);
return true;
} //end of the function AAS_TryMergeFaceAreas
//===========================================================================
// try to merge areas
// merged areas are added to the end of the convex area list so merging
// will be tried for those areas as well
//
// Parameter: -
// Returns: -
// Changes Globals: tmpaasworld
//===========================================================================
/*
void AAS_MergeAreas(void)
{
int side, nummerges;
tmp_area_t *tmparea, *othertmparea;
tmp_face_t *face;
nummerges = 0;
Log_Write("AAS_MergeAreas\r\n");
qprintf("%6d areas merged", 1);
//first merge grounded areas only
//NOTE: this is useless because the area settings aren't available yet
for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next)
{
// Log_Print("checking area %d\n", i);
//if the area is invalid
if (tmparea->invalid)
{
// Log_Print(" area invalid\n");
continue;
} //end if
//
// if (!(tmparea->settings->areaflags & AREA_GROUNDED)) continue;
//
for (face = tmparea->tmpfaces; face; face = face->next[side])
{
side = (face->frontarea != tmparea);
//if the face has both a front and back area
if (face->frontarea && face->backarea)
{
//
if (face->frontarea == tmparea) othertmparea = face->backarea;
else othertmparea = face->frontarea;
// if (!(othertmparea->settings->areaflags & AREA_GROUNDED)) continue;
// Log_Print(" checking area %d with %d\n", face->frontarea, face->backarea);
if (AAS_TryMergeFaceAreas(face))
{
qprintf("\r%6d", ++nummerges);
break;
} //end if
} //end if
} //end for
} //end for
//merge all areas
for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next)
{
// Log_Print("checking area %d\n", i);
//if the area is invalid
if (tmparea->invalid)
{
// Log_Print(" area invalid\n");
continue;
} //end if
//
for (face = tmparea->tmpfaces; face; face = face->next[side])
{
side = (face->frontarea != tmparea);
//if the face has both a front and back area
if (face->frontarea && face->backarea)
{
// Log_Print(" checking area %d with %d\n", face->frontarea, face->backarea);
if (AAS_TryMergeFaceAreas(face))
{
qprintf("\r%6d", ++nummerges);
break;
} //end if
} //end if
} //end for
} //end for
Log_Print("\r%6d areas merged\n", nummerges);
//refresh the merged tree
AAS_RefreshMergedTree_r(tmpaasworld.nodes);
} //end of the function AAS_MergeAreas*/
int AAS_GroundArea( tmp_area_t *tmparea ) {
tmp_face_t *face;
int side;
for ( face = tmparea->tmpfaces; face; face = face->next[side] )
{
side = ( face->frontarea != tmparea );
if ( face->faceflags & FACE_GROUND ) {
return true;
}
} //end for
return false;
} //end of the function AAS_GroundArea
void AAS_MergeAreas( void ) {
int side, nummerges, merges, groundfirst;
tmp_area_t *tmparea, *othertmparea;
tmp_face_t *face;
nummerges = 0;
Log_Write( "AAS_MergeAreas\r\n" );
qprintf( "%6d areas merged", 1 );
//
groundfirst = true;
//for (i = 0; i < 4 || merges; i++)
while ( 1 )
{
//if (i < 2) groundfirst = true;
//else groundfirst = false;
//
merges = 0;
//first merge grounded areas only
for ( tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next )
{
//if the area is invalid
if ( tmparea->invalid ) {
continue;
} //end if
//
if ( groundfirst ) {
if ( !AAS_GroundArea( tmparea ) ) {
continue;
}
} //end if
//
for ( face = tmparea->tmpfaces; face; face = face->next[side] )
{
side = ( face->frontarea != tmparea );
//if the face has both a front and back area
if ( face->frontarea && face->backarea ) {
//
if ( face->frontarea == tmparea ) {
othertmparea = face->backarea;
} else { othertmparea = face->frontarea;}
//
if ( groundfirst ) {
if ( !AAS_GroundArea( othertmparea ) ) {
continue;
}
} //end if
if ( AAS_TryMergeFaceAreas( face ) ) {
qprintf( "\r%6d", ++nummerges );
merges++;
break;
} //end if
} //end if
} //end for
} //end for
if ( !merges ) {
if ( groundfirst ) {
groundfirst = false;
} else { break;}
} //end if
} //end for
qprintf( "\n" );
Log_Write( "%6d areas merged\r\n", nummerges );
//refresh the merged tree
AAS_RefreshMergedTree_r( tmpaasworld.nodes );
} //end of the function AAS_MergeAreas

View File

@@ -0,0 +1,40 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: aas_areamerging.h
// Function: Merging of Areas
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1997-12-04
// Tab Size: 3
//===========================================================================
void AAS_MergeAreas( void );

312
src/bspc/aas_cfg.c Normal file
View File

@@ -0,0 +1,312 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: cfg.c
// Function:
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1997-12-04
// Tab Size: 3
//===========================================================================
#include "qbsp.h"
#include "float.h"
#include "..\botlib\aasfile.h"
#include "aas_store.h"
#include "aas_cfg.h"
#include "../botlib/l_precomp.h"
#include "../botlib/l_struct.h"
#include "../botlib/l_libvar.h"
///////////////////////////////////
extern void LibVarSet( char *var_name, char *value );
///////////////////////////////////
//structure field offsets
#define BBOX_OFS( x ) (int)&( ( (aas_bbox_t *)0 )->x )
#define CFG_OFS( x ) (int)&( ( (cfg_t *)0 )->x )
//bounding box definition
fielddef_t bbox_fields[] =
{
{"presencetype", BBOX_OFS( presencetype ), FT_INT},
{"flags", BBOX_OFS( flags ), FT_INT},
{"mins", BBOX_OFS( mins ), FT_FLOAT | FT_ARRAY, 3},
{"maxs", BBOX_OFS( maxs ), FT_FLOAT | FT_ARRAY, 3},
{NULL, 0, 0, 0}
};
fielddef_t cfg_fields[] =
{
{"phys_gravitydirection", CFG_OFS( phys_gravitydirection ), FT_FLOAT | FT_ARRAY, 3},
{"phys_friction", CFG_OFS( phys_friction ), FT_FLOAT},
{"phys_stopspeed", CFG_OFS( phys_stopspeed ), FT_FLOAT},
{"phys_gravity", CFG_OFS( phys_gravity ), FT_FLOAT},
{"phys_waterfriction", CFG_OFS( phys_waterfriction ), FT_FLOAT},
{"phys_watergravity", CFG_OFS( phys_watergravity ), FT_FLOAT},
{"phys_maxvelocity", CFG_OFS( phys_maxvelocity ), FT_FLOAT},
{"phys_maxwalkvelocity", CFG_OFS( phys_maxwalkvelocity ), FT_FLOAT},
{"phys_maxcrouchvelocity", CFG_OFS( phys_maxcrouchvelocity ), FT_FLOAT},
{"phys_maxswimvelocity", CFG_OFS( phys_maxswimvelocity ), FT_FLOAT},
{"phys_walkaccelerate", CFG_OFS( phys_walkaccelerate ), FT_FLOAT},
{"phys_airaccelerate", CFG_OFS( phys_airaccelerate ), FT_FLOAT},
{"phys_swimaccelerate", CFG_OFS( phys_swimaccelerate ), FT_FLOAT},
{"phys_maxstep", CFG_OFS( phys_maxstep ), FT_FLOAT},
{"phys_maxsteepness", CFG_OFS( phys_maxsteepness ), FT_FLOAT},
{"phys_maxwaterjump", CFG_OFS( phys_maxwaterjump ), FT_FLOAT},
// Ridah, calculated from velocity and gravity
// {"sv_maxbarrier", CFG_OFS(sv_maxbarrier), FT_FLOAT},
// {"sv_jumpvel", CFG_OFS(sv_jumpvel), FT_FLOAT},
{"phys_maxbarrier", CFG_OFS( phys_maxbarrier ), FT_FLOAT},
{"phys_jumpvel", CFG_OFS( phys_jumpvel ), FT_FLOAT},
{"phys_falldelta5", CFG_OFS( phys_falldelta5 ), FT_FLOAT},
{"phys_falldelta10", CFG_OFS( phys_falldelta10 ), FT_FLOAT},
{"rs_waterjump", CFG_OFS( rs_waterjump ), FT_FLOAT},
{"rs_teleport", CFG_OFS( rs_teleport ), FT_FLOAT},
{"rs_barrierjump", CFG_OFS( rs_barrierjump ), FT_FLOAT},
{"rs_startcrouch", CFG_OFS( rs_startcrouch ), FT_FLOAT},
{"rs_startgrapple", CFG_OFS( rs_startgrapple ), FT_FLOAT},
{"rs_startwalkoffledge", CFG_OFS( rs_startwalkoffledge ), FT_FLOAT},
{"rs_startjump", CFG_OFS( rs_startjump ), FT_FLOAT},
{"rs_rocketjump", CFG_OFS( rs_rocketjump ), FT_FLOAT},
{"rs_bfgjump", CFG_OFS( rs_bfgjump ), FT_FLOAT},
{"rs_jumppad", CFG_OFS( rs_jumppad ), FT_FLOAT},
{"rs_aircontrolledjumppad", CFG_OFS( rs_aircontrolledjumppad ), FT_FLOAT},
{"rs_funcbob", CFG_OFS( rs_funcbob ), FT_FLOAT},
{"rs_startelevator", CFG_OFS( rs_startelevator ), FT_FLOAT},
{"rs_falldamage5", CFG_OFS( rs_falldamage5 ), FT_FLOAT},
{"rs_falldamage10", CFG_OFS( rs_falldamage10 ), FT_FLOAT},
{"rs_maxjumpfallheight", CFG_OFS( rs_maxjumpfallheight ), FT_FLOAT},
{NULL, 0, 0, 0}
};
structdef_t bbox_struct =
{
sizeof( aas_bbox_t ), bbox_fields
};
structdef_t cfg_struct =
{
sizeof( cfg_t ), cfg_fields
};
//global cfg
cfg_t cfg;
#if 0
//===========================================================================
// the default Q3A configuration
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void DefaultCfg( void ) {
int i;
// default all float values to infinite
for ( i = 0; cfg_fields[i].name; i++ )
{
if ( ( cfg_fields[i].type & FT_TYPE ) == FT_FLOAT ) {
*( float * )( ( (char*)&cfg ) + cfg_fields[i].offset ) = FLT_MAX;
}
} //end for
//
cfg.numbboxes = 2;
//bbox 0
cfg.bboxes[0].presencetype = PRESENCE_NORMAL;
cfg.bboxes[0].flags = 0;
cfg.bboxes[0].mins[0] = -18;
cfg.bboxes[0].mins[1] = -18;
cfg.bboxes[0].mins[2] = -24;
cfg.bboxes[0].maxs[0] = 18;
cfg.bboxes[0].maxs[1] = 18;
cfg.bboxes[0].maxs[2] = 48;
//bbox 1
cfg.bboxes[1].presencetype = PRESENCE_CROUCH;
cfg.bboxes[1].flags = 1;
cfg.bboxes[1].mins[0] = -18;
cfg.bboxes[1].mins[1] = -18;
cfg.bboxes[1].mins[2] = -24;
cfg.bboxes[1].maxs[0] = 18;
cfg.bboxes[1].maxs[1] = 18;
cfg.bboxes[1].maxs[2] = 24;
//
cfg.allpresencetypes = PRESENCE_NORMAL | PRESENCE_CROUCH;
cfg.phys_gravitydirection[0] = 0;
cfg.phys_gravitydirection[1] = 0;
cfg.phys_gravitydirection[2] = -1;
cfg.phys_maxsteepness = 0.7;
// cfg.phys_maxbarrier = -999;//32; // RIDAH: this is calculated at run-time now, from the gravity and jump velocity settings
} //end of the function DefaultCfg
#else
//===========================================================================
// the default Q3A configuration
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void DefaultCfg( void ) {
int i;
// default all float values to infinite
for ( i = 0; cfg_fields[i].name; i++ )
{
if ( ( cfg_fields[i].type & FT_TYPE ) == FT_FLOAT ) {
*( float * )( ( (char*)&cfg ) + cfg_fields[i].offset ) = FLT_MAX;
}
} //end for
//
cfg.numbboxes = 2;
//bbox 0
cfg.bboxes[0].presencetype = PRESENCE_NORMAL;
cfg.bboxes[0].flags = 0;
cfg.bboxes[0].mins[0] = -15;
cfg.bboxes[0].mins[1] = -15;
cfg.bboxes[0].mins[2] = -24;
cfg.bboxes[0].maxs[0] = 15;
cfg.bboxes[0].maxs[1] = 15;
cfg.bboxes[0].maxs[2] = 32;
//bbox 1
cfg.bboxes[1].presencetype = PRESENCE_CROUCH;
cfg.bboxes[1].flags = 1;
cfg.bboxes[1].mins[0] = -15;
cfg.bboxes[1].mins[1] = -15;
cfg.bboxes[1].mins[2] = -24;
cfg.bboxes[1].maxs[0] = 15;
cfg.bboxes[1].maxs[1] = 15;
cfg.bboxes[1].maxs[2] = 16;
//
cfg.allpresencetypes = PRESENCE_NORMAL | PRESENCE_CROUCH;
cfg.phys_gravitydirection[0] = 0;
cfg.phys_gravitydirection[1] = 0;
cfg.phys_gravitydirection[2] = -1;
cfg.phys_maxsteepness = 0.7;
// cfg.phys_maxbarrier = -999;//32; // RIDAH: this is calculated at run-time now, from the gravity and jump velocity settings
} //end of the function DefaultCfg
#endif
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
char * QDECL va( char *format, ... ) {
va_list argptr;
static char string[2][32000]; // in case va is called by nested functions
static int index = 0;
char *buf;
buf = string[index & 1];
index++;
va_start( argptr, format );
vsprintf( buf, format,argptr );
va_end( argptr );
return buf;
} //end of the function va
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void SetCfgLibVars( void ) {
int i;
float value;
for ( i = 0; cfg_fields[i].name; i++ )
{
if ( ( cfg_fields[i].type & FT_TYPE ) == FT_FLOAT ) {
value = *( float * )( ( (char*)&cfg ) + cfg_fields[i].offset );
if ( value != FLT_MAX ) {
LibVarSet( cfg_fields[i].name, va( "%f", value ) );
} //end if
} //end if
} //end for
} //end of the function SetCfgLibVars
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int LoadCfgFile( char *filename ) {
source_t *source;
token_t token;
int settingsdefined;
source = LoadSourceFile( filename );
if ( !source ) {
Log_Print( "couldn't open cfg file %s\n", filename );
return false;
} //end if
settingsdefined = false;
memset( &cfg, 0, sizeof( cfg_t ) );
while ( PC_ReadToken( source, &token ) )
{
if ( !stricmp( token.string, "bbox" ) ) {
if ( cfg.numbboxes >= AAS_MAX_BBOXES ) {
SourceError( source, "too many bounding box volumes defined" );
} //end if
if ( !ReadStructure( source, &bbox_struct, (char *) &cfg.bboxes[cfg.numbboxes] ) ) {
FreeSource( source );
return false;
} //end if
cfg.allpresencetypes |= cfg.bboxes[cfg.numbboxes].presencetype;
cfg.numbboxes++;
} //end if
else if ( !stricmp( token.string, "settings" ) ) {
if ( settingsdefined ) {
SourceWarning( source, "settings already defined\n" );
} //end if
settingsdefined = true;
if ( !ReadStructure( source, &cfg_struct, (char *) &cfg ) ) {
FreeSource( source );
return false;
} //end if
} //end else if
} //end while
if ( VectorLength( cfg.phys_gravitydirection ) < 0.9 || VectorLength( cfg.phys_gravitydirection ) > 1.1 ) {
SourceError( source, "invalid gravity direction specified" );
} //end if
if ( cfg.numbboxes <= 0 ) {
SourceError( source, "no bounding volumes specified" );
} //end if
FreeSource( source );
SetCfgLibVars();
Log_Print( "using cfg file %s\n", filename );
return true;
} //end of the function LoadCfgFile

88
src/bspc/aas_cfg.h Normal file
View File

@@ -0,0 +1,88 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: cfg.h
// Function:
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1997-12-04
// Tab Size: 3
//===========================================================================
#define BBOXFL_GROUNDED 1 //bounding box only valid when on ground
#define BBOXFL_NOTGROUNDED 2 //bounding box only valid when NOT on ground
typedef struct cfg_s
{
int numbboxes; //number of bounding boxes
aas_bbox_t bboxes[AAS_MAX_BBOXES]; //all the bounding boxes
int allpresencetypes; //or of all presence types
// aas settings
vec3_t phys_gravitydirection;
float phys_friction;
float phys_stopspeed;
float phys_gravity;
float phys_waterfriction;
float phys_watergravity;
float phys_maxvelocity;
float phys_maxwalkvelocity;
float phys_maxcrouchvelocity;
float phys_maxswimvelocity;
float phys_walkaccelerate;
float phys_airaccelerate;
float phys_swimaccelerate;
float phys_maxstep;
float phys_maxsteepness;
float phys_maxwaterjump;
float phys_maxbarrier;
float phys_jumpvel;
float phys_falldelta5;
float phys_falldelta10;
float rs_waterjump;
float rs_teleport;
float rs_barrierjump;
float rs_startcrouch;
float rs_startgrapple;
float rs_startwalkoffledge;
float rs_startjump;
float rs_rocketjump;
float rs_bfgjump;
float rs_jumppad;
float rs_aircontrolledjumppad;
float rs_funcbob;
float rs_startelevator;
float rs_falldamage5;
float rs_falldamage10;
float rs_maxjumpfallheight;
} cfg_t;
extern cfg_t cfg;
void DefaultCfg( void );
int LoadCfgFile( char *filename );

1182
src/bspc/aas_create.c Normal file

File diff suppressed because it is too large Load Diff

153
src/bspc/aas_create.h Normal file
View File

@@ -0,0 +1,153 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: aas_create.h
// Function:
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1997-12-04
// Tab Size: 3
//===========================================================================
#define AREA_PORTAL 1
//temporary AAS face
typedef struct tmp_face_s
{
int num; //face number
int planenum; //number of the plane the face is in
winding_t *winding; //winding of the face
struct tmp_area_s *frontarea; //area at the front of the face
struct tmp_area_s *backarea; //area at the back of the face
int faceflags; //flags of this face
int aasfacenum; //the number of the aas face used for this face
//double link list pointers for front and back area
struct tmp_face_s *prev[2], *next[2];
//links in the list with faces
struct tmp_face_s *l_prev, *l_next;
} tmp_face_t;
//temporary AAS area settings
typedef struct tmp_areasettings_s
{
//could also add all kind of statistic fields
int contents; //contents of the area
int modelnum; //bsp model inside this area
int areaflags; //area flags
int presencetype; //how a bot can be present in this area
int numreachableareas; //number of reachable areas from this one
int firstreachablearea; //first reachable area in the reachable area index
// Ridah, steepness
float groundsteepness;
} tmp_areasettings_t;
//temporary AAS area
typedef struct tmp_area_s
{
int areanum; //number of the area
struct tmp_face_s *tmpfaces; //the faces of the area
int presencetype; //presence type of the area
int contents; //area contents
int modelnum; //bsp model inside this area
int invalid; //true if the area is invalid
tmp_areasettings_t *settings; //area settings
struct tmp_area_s *mergedarea; //points to the new area after merging
//when mergedarea != 0 the area has only the
//seperating face of the merged areas
int aasareanum; //number of the aas area created for this tmp area
//links in the list with areas
struct tmp_area_s *l_prev, *l_next;
} tmp_area_t;
//temporary AAS node
typedef struct tmp_node_s
{
int planenum; //node plane number
struct tmp_area_s *tmparea; //points to an area if this node is an area
struct tmp_node_s *children[2]; //child nodes of this node
} tmp_node_t;
#define NODEBUF_SIZE 128
//node buffer
typedef struct tmp_nodebuf_s
{
int numnodes;
struct tmp_nodebuf_s *next;
tmp_node_t nodes[NODEBUF_SIZE];
} tmp_nodebuf_t;
//the whole temorary AAS
typedef struct tmp_aas_s
{
//faces
int numfaces;
int facenum;
tmp_face_t *faces;
//areas
int numareas;
int areanum;
tmp_area_t *areas;
//area settings
int numareasettings;
tmp_areasettings_t *areasettings;
//nodes
int numnodes;
tmp_node_t *nodes;
//node buffer
tmp_nodebuf_t *nodebuffer;
} tmp_aas_t;
extern tmp_aas_t tmpaasworld;
//creates a .AAS file with the given name from an already loaded map
void AAS_Create( char *aasfile );
//adds a face side to an area
void AAS_AddFaceSideToArea( tmp_face_t *tmpface, int side, tmp_area_t *tmparea );
//remvoes a face from an area
void AAS_RemoveFaceFromArea( tmp_face_t *tmpface, tmp_area_t *tmparea );
//allocate a tmp face
tmp_face_t *AAS_AllocTmpFace( void );
//free the tmp face
void AAS_FreeTmpFace( tmp_face_t *tmpface );
//allocate a tmp area
tmp_area_t *AAS_AllocTmpArea( void );
//free a tmp area
void AAS_FreeTmpArea( tmp_area_t *tmparea );
//allocate a tmp node
tmp_node_t *AAS_AllocTmpNode( void );
//free a tmp node
void AAS_FreeTmpNode( tmp_node_t *node );
//checks if an area is ok
void AAS_CheckArea( tmp_area_t *tmparea );
//flips the area faces where needed
void AAS_FlipAreaFaces( tmp_area_t *tmparea );
//returns true if the face is a gap seen from the given side
int AAS_GapFace( tmp_face_t *tmpface, int side );
//returns true if the face is a ground face
int AAS_GroundFace( tmp_face_t *tmpface );

125
src/bspc/aas_edgemelting.c Normal file
View File

@@ -0,0 +1,125 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: aas_edgemelting.c
// Function: Melting of Edges
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1997-12-04
// Tab Size: 3
//===========================================================================
#include "qbsp.h"
#include "..\botlib\aasfile.h"
#include "aas_create.h"
//===========================================================================
// try to melt the windings of the two faces
// FIXME: this is buggy
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int AAS_MeltFaceWinding( tmp_face_t *face1, tmp_face_t *face2 ) {
int i, n;
int splits = 0;
winding_t *w2, *neww;
plane_t *plane1;
#ifdef DEBUG
if ( !face1->winding ) {
Error( "face1 %d without winding", face1->num );
}
if ( !face2->winding ) {
Error( "face2 %d without winding", face2->num );
}
#endif //DEBUG
w2 = face2->winding;
plane1 = &mapplanes[face1->planenum];
for ( i = 0; i < w2->numpoints; i++ )
{
if ( PointOnWinding( face1->winding, plane1->normal, plane1->dist, w2->p[i], &n ) ) {
neww = AddWindingPoint( face1->winding, w2->p[i], n );
FreeWinding( face1->winding );
face1->winding = neww;
splits++;
} //end if
} //end for
return splits;
} //end of the function AAS_MeltFaceWinding
//===========================================================================
// melt the windings of the area faces
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int AAS_MeltFaceWindingsOfArea( tmp_area_t *tmparea ) {
int side1, side2, num_windingsplits = 0;
tmp_face_t *face1, *face2;
for ( face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1] )
{
side1 = face1->frontarea != tmparea;
for ( face2 = tmparea->tmpfaces; face2; face2 = face2->next[side2] )
{
side2 = face2->frontarea != tmparea;
if ( face1 == face2 ) {
continue;
}
num_windingsplits += AAS_MeltFaceWinding( face1, face2 );
} //end for
} //end for
return num_windingsplits;
} //end of the function AAS_MeltFaceWindingsOfArea
//===========================================================================
// melt the windings of the faces of all areas
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_MeltAreaFaceWindings( void ) {
tmp_area_t *tmparea;
int num_windingsplits = 0;
Log_Write( "AAS_MeltAreaFaceWindings\r\n" );
qprintf( "%6d edges melted", num_windingsplits );
//NOTE: first convex area (zero) is a dummy
for ( tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next )
{
num_windingsplits += AAS_MeltFaceWindingsOfArea( tmparea );
qprintf( "\r%6d", num_windingsplits );
} //end for
qprintf( "\n" );
Log_Write( "%6d edges melted\r\n", num_windingsplits );
} //end of the function AAS_MeltAreaFaceWindings

View File

@@ -0,0 +1,40 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: aas_edgemelting.h
// Function: Melting of Edges
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1997-12-04
// Tab Size: 3
//===========================================================================
void AAS_MeltAreaFaceWindings( void );

312
src/bspc/aas_facemerging.c Normal file
View File

@@ -0,0 +1,312 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: aas_facemerging.c
// Function: Merging of Faces
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1997-12-04
// Tab Size: 3
//===========================================================================
#include "qbsp.h"
#include "..\botlib\aasfile.h"
#include "aas_create.h"
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int AAS_TryMergeFaces( tmp_face_t *face1, tmp_face_t *face2 ) {
winding_t *neww;
#ifdef DEBUG
if ( !face1->winding ) {
Error( "face1 %d without winding", face1->num );
}
if ( !face2->winding ) {
Error( "face2 %d without winding", face2->num );
}
#endif //DEBUG
//
if ( face1->faceflags != face2->faceflags ) {
return false;
}
//NOTE: if the front or back area is zero this doesn't mean there's
//a real area. It means there's solid at that side of the face
//if both faces have the same front area
if ( face1->frontarea == face2->frontarea ) {
//if both faces have the same back area
if ( face1->backarea == face2->backarea ) {
//if the faces are in the same plane
if ( face1->planenum == face2->planenum ) {
//if they have both a front and a back area (no solid on either side)
if ( face1->frontarea && face1->backarea ) {
neww = MergeWindings( face1->winding, face2->winding,
mapplanes[face1->planenum].normal );
} //end if
else
{
//this function is to be found in l_poly.c
neww = TryMergeWinding( face1->winding, face2->winding,
mapplanes[face1->planenum].normal );
} //end else
if ( neww ) {
FreeWinding( face1->winding );
face1->winding = neww;
if ( face2->frontarea ) {
AAS_RemoveFaceFromArea( face2, face2->frontarea );
}
if ( face2->backarea ) {
AAS_RemoveFaceFromArea( face2, face2->backarea );
}
AAS_FreeTmpFace( face2 );
return true;
} //end if
} //end if
else if ( ( face1->planenum & ~1 ) == ( face2->planenum & ~1 ) ) {
Log_Write( "face %d and %d, same front and back area but flipped planes\r\n",
face1->num, face2->num );
} //end if
} //end if
} //end if
return false;
} //end of the function AAS_TryMergeFaces
/*
int AAS_TryMergeFaces(tmp_face_t *face1, tmp_face_t *face2)
{
winding_t *neww;
#ifdef DEBUG
if (!face1->winding) Error("face1 %d without winding", face1->num);
if (!face2->winding) Error("face2 %d without winding", face2->num);
#endif //DEBUG
//if the faces are in the same plane
if ((face1->planenum & ~1) != (face2->planenum & ~1)) return false;
// if (face1->planenum != face2->planenum) return false;
//NOTE: if the front or back area is zero this doesn't mean there's
//a real area. It means there's solid at that side of the face
//if both faces have the same front area
if (face1->frontarea != face2->frontarea ||
face1->backarea != face2->backarea)
{
if (!face1->frontarea || !face1->backarea ||
!face2->frontarea || !face2->backarea) return false;
else if (face1->frontarea != face2->backarea ||
face1->backarea != face2->frontarea) return false;
// return false;
} //end if
//this function is to be found in l_poly.c
neww = TryMergeWinding(face1->winding, face2->winding,
mapplanes[face1->planenum].normal);
if (!neww) return false;
//
FreeWinding(face1->winding);
face1->winding = neww;
//remove face2
if (face2->frontarea)
AAS_RemoveFaceFromArea(face2, &tmpaasworld.areas[face2->frontarea]);
if (face2->backarea)
AAS_RemoveFaceFromArea(face2, &tmpaasworld.areas[face2->backarea]);
return true;
} //end of the function AAS_TryMergeFaces*/
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_MergeAreaFaces( void ) {
int num_facemerges = 0;
int side1, side2, restart;
tmp_area_t *tmparea, *lasttmparea;
tmp_face_t *face1, *face2;
Log_Write( "AAS_MergeAreaFaces\r\n" );
qprintf( "%6d face merges", num_facemerges );
//NOTE: first convex area is a dummy
lasttmparea = tmpaasworld.areas;
for ( tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next )
{
restart = false;
//
if ( tmparea->invalid ) {
continue;
}
//
for ( face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1] )
{
side1 = face1->frontarea != tmparea;
for ( face2 = face1->next[side1]; face2; face2 = face2->next[side2] )
{
side2 = face2->frontarea != tmparea;
//if succesfully merged
if ( AAS_TryMergeFaces( face1, face2 ) ) {
//start over again after merging two faces
restart = true;
num_facemerges++;
qprintf( "\r%6d", num_facemerges );
AAS_CheckArea( tmparea );
break;
} //end if
} //end for
if ( restart ) {
tmparea = lasttmparea;
break;
} //end if
} //end for
lasttmparea = tmparea;
} //end for
qprintf( "\n" );
Log_Write( "%6d face merges\r\n", num_facemerges );
} //end of the function AAS_MergeAreaFaces
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_MergePlaneFaces( tmp_area_t *tmparea, int planenum ) {
tmp_face_t *face1, *face2, *nextface2;
winding_t *neww;
int side1, side2;
for ( face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1] )
{
side1 = face1->frontarea != tmparea;
if ( face1->planenum != planenum ) {
continue;
}
//
for ( face2 = face1->next[side1]; face2; face2 = nextface2 )
{
side2 = face2->frontarea != tmparea;
nextface2 = face2->next[side2];
//
if ( ( face2->planenum & ~1 ) != ( planenum & ~1 ) ) {
continue;
}
//
neww = MergeWindings( face1->winding, face2->winding,
mapplanes[face1->planenum].normal );
FreeWinding( face1->winding );
face1->winding = neww;
if ( face2->frontarea ) {
AAS_RemoveFaceFromArea( face2, face2->frontarea );
}
if ( face2->backarea ) {
AAS_RemoveFaceFromArea( face2, face2->backarea );
}
AAS_FreeTmpFace( face2 );
//
nextface2 = face1->next[side1];
} //end for
} //end for
} //end of the function AAS_MergePlaneFaces
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int AAS_CanMergePlaneFaces( tmp_area_t *tmparea, int planenum ) {
tmp_area_t *frontarea, *backarea;
tmp_face_t *face1;
int side1, merge, faceflags;
frontarea = backarea = NULL;
merge = false;
for ( face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1] )
{
side1 = face1->frontarea != tmparea;
if ( ( face1->planenum & ~1 ) != ( planenum & ~1 ) ) {
continue;
}
if ( !frontarea && !backarea ) {
frontarea = face1->frontarea;
backarea = face1->backarea;
faceflags = face1->faceflags;
} //end if
else
{
if ( frontarea != face1->frontarea ) {
return false;
}
if ( backarea != face1->backarea ) {
return false;
}
if ( faceflags != face1->faceflags ) {
return false;
}
merge = true;
} //end else
} //end for
return merge;
} //end of the function AAS_CanMergePlaneFaces
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_MergeAreaPlaneFaces( void ) {
int num_facemerges = 0;
int side1;
tmp_area_t *tmparea, *nexttmparea;
tmp_face_t *face1;
Log_Write( "AAS_MergePlaneFaces\r\n" );
qprintf( "%6d plane face merges", num_facemerges );
//NOTE: first convex area is a dummy
for ( tmparea = tmpaasworld.areas; tmparea; tmparea = nexttmparea )
{
nexttmparea = tmparea->l_next;
//
if ( tmparea->invalid ) {
continue;
}
//
for ( face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1] )
{
side1 = face1->frontarea != tmparea;
//
if ( AAS_CanMergePlaneFaces( tmparea, face1->planenum ) ) {
AAS_MergePlaneFaces( tmparea, face1->planenum );
nexttmparea = tmparea;
num_facemerges++;
qprintf( "\r%6d", num_facemerges );
break;
} //end if
} //end for
} //end for
qprintf( "\n" );
Log_Write( "%6d plane face merges\r\n", num_facemerges );
} //end of the function AAS_MergeAreaPlaneFaces

View File

@@ -0,0 +1,39 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: aas_facemerging.h
// Function: Merging of Faces
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1997-12-04
// Tab Size: 3
//===========================================================================
void AAS_MergeAreaFaces( void );
void AAS_MergeAreaPlaneFaces( void );

603
src/bspc/aas_file.c Normal file
View File

@@ -0,0 +1,603 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: aas_file.c
// Function: AAS file loading and writing
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1997-12-04
// Tab Size: 3
//===========================================================================
#include "qbsp.h"
#include "..\botlib\aasfile.h"
#include "aas_file.h"
#include "aas_store.h"
#include "aas_create.h"
#define AAS_Error Error
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_SwapAASData( void ) {
int i, j;
//bounding boxes
for ( i = 0; i < ( *aasworld ).numbboxes; i++ )
{
( *aasworld ).bboxes[i].presencetype = LittleLong( ( *aasworld ).bboxes[i].presencetype );
( *aasworld ).bboxes[i].flags = LittleLong( ( *aasworld ).bboxes[i].flags );
for ( j = 0; j < 3; j++ )
{
( *aasworld ).bboxes[i].mins[j] = LittleLong( ( *aasworld ).bboxes[i].mins[j] );
( *aasworld ).bboxes[i].maxs[j] = LittleLong( ( *aasworld ).bboxes[i].maxs[j] );
} //end for
} //end for
//vertexes
for ( i = 0; i < ( *aasworld ).numvertexes; i++ )
{
for ( j = 0; j < 3; j++ )
( *aasworld ).vertexes[i][j] = LittleFloat( ( *aasworld ).vertexes[i][j] );
} //end for
//planes
for ( i = 0; i < ( *aasworld ).numplanes; i++ )
{
for ( j = 0; j < 3; j++ )
( *aasworld ).planes[i].normal[j] = LittleFloat( ( *aasworld ).planes[i].normal[j] );
( *aasworld ).planes[i].dist = LittleFloat( ( *aasworld ).planes[i].dist );
( *aasworld ).planes[i].type = LittleLong( ( *aasworld ).planes[i].type );
} //end for
//edges
for ( i = 0; i < ( *aasworld ).numedges; i++ )
{
( *aasworld ).edges[i].v[0] = LittleLong( ( *aasworld ).edges[i].v[0] );
( *aasworld ).edges[i].v[1] = LittleLong( ( *aasworld ).edges[i].v[1] );
} //end for
//edgeindex
for ( i = 0; i < ( *aasworld ).edgeindexsize; i++ )
{
( *aasworld ).edgeindex[i] = LittleLong( ( *aasworld ).edgeindex[i] );
} //end for
//faces
for ( i = 0; i < ( *aasworld ).numfaces; i++ )
{
( *aasworld ).faces[i].planenum = LittleLong( ( *aasworld ).faces[i].planenum );
( *aasworld ).faces[i].faceflags = LittleLong( ( *aasworld ).faces[i].faceflags );
( *aasworld ).faces[i].numedges = LittleLong( ( *aasworld ).faces[i].numedges );
( *aasworld ).faces[i].firstedge = LittleLong( ( *aasworld ).faces[i].firstedge );
( *aasworld ).faces[i].frontarea = LittleLong( ( *aasworld ).faces[i].frontarea );
( *aasworld ).faces[i].backarea = LittleLong( ( *aasworld ).faces[i].backarea );
} //end for
//face index
for ( i = 0; i < ( *aasworld ).faceindexsize; i++ )
{
( *aasworld ).faceindex[i] = LittleLong( ( *aasworld ).faceindex[i] );
} //end for
//convex areas
for ( i = 0; i < ( *aasworld ).numareas; i++ )
{
( *aasworld ).areas[i].areanum = LittleLong( ( *aasworld ).areas[i].areanum );
( *aasworld ).areas[i].numfaces = LittleLong( ( *aasworld ).areas[i].numfaces );
( *aasworld ).areas[i].firstface = LittleLong( ( *aasworld ).areas[i].firstface );
for ( j = 0; j < 3; j++ )
{
( *aasworld ).areas[i].mins[j] = LittleFloat( ( *aasworld ).areas[i].mins[j] );
( *aasworld ).areas[i].maxs[j] = LittleFloat( ( *aasworld ).areas[i].maxs[j] );
( *aasworld ).areas[i].center[j] = LittleFloat( ( *aasworld ).areas[i].center[j] );
} //end for
} //end for
//area settings
for ( i = 0; i < ( *aasworld ).numareasettings; i++ )
{
( *aasworld ).areasettings[i].contents = LittleLong( ( *aasworld ).areasettings[i].contents );
( *aasworld ).areasettings[i].areaflags = LittleLong( ( *aasworld ).areasettings[i].areaflags );
( *aasworld ).areasettings[i].presencetype = LittleLong( ( *aasworld ).areasettings[i].presencetype );
( *aasworld ).areasettings[i].cluster = LittleLong( ( *aasworld ).areasettings[i].cluster );
( *aasworld ).areasettings[i].clusterareanum = LittleLong( ( *aasworld ).areasettings[i].clusterareanum );
( *aasworld ).areasettings[i].numreachableareas = LittleLong( ( *aasworld ).areasettings[i].numreachableareas );
( *aasworld ).areasettings[i].firstreachablearea = LittleLong( ( *aasworld ).areasettings[i].firstreachablearea );
// Ridah
( *aasworld ).areasettings[i].groundsteepness = LittleFloat( ( *aasworld ).areasettings[i].groundsteepness );
} //end for
//area reachability
for ( i = 0; i < ( *aasworld ).reachabilitysize; i++ )
{
( *aasworld ).reachability[i].areanum = LittleLong( ( *aasworld ).reachability[i].areanum );
( *aasworld ).reachability[i].facenum = LittleLong( ( *aasworld ).reachability[i].facenum );
( *aasworld ).reachability[i].edgenum = LittleLong( ( *aasworld ).reachability[i].edgenum );
for ( j = 0; j < 3; j++ )
{
( *aasworld ).reachability[i].start[j] = LittleFloat( ( *aasworld ).reachability[i].start[j] );
( *aasworld ).reachability[i].end[j] = LittleFloat( ( *aasworld ).reachability[i].end[j] );
} //end for
( *aasworld ).reachability[i].traveltype = LittleLong( ( *aasworld ).reachability[i].traveltype );
( *aasworld ).reachability[i].traveltime = LittleShort( ( *aasworld ).reachability[i].traveltime );
} //end for
//nodes
for ( i = 0; i < ( *aasworld ).numnodes; i++ )
{
( *aasworld ).nodes[i].planenum = LittleLong( ( *aasworld ).nodes[i].planenum );
( *aasworld ).nodes[i].children[0] = LittleLong( ( *aasworld ).nodes[i].children[0] );
( *aasworld ).nodes[i].children[1] = LittleLong( ( *aasworld ).nodes[i].children[1] );
} //end for
//cluster portals
for ( i = 0; i < ( *aasworld ).numportals; i++ )
{
( *aasworld ).portals[i].areanum = LittleLong( ( *aasworld ).portals[i].areanum );
( *aasworld ).portals[i].frontcluster = LittleLong( ( *aasworld ).portals[i].frontcluster );
( *aasworld ).portals[i].backcluster = LittleLong( ( *aasworld ).portals[i].backcluster );
( *aasworld ).portals[i].clusterareanum[0] = LittleLong( ( *aasworld ).portals[i].clusterareanum[0] );
( *aasworld ).portals[i].clusterareanum[1] = LittleLong( ( *aasworld ).portals[i].clusterareanum[1] );
} //end for
//cluster portal index
for ( i = 0; i < ( *aasworld ).portalindexsize; i++ )
{
( *aasworld ).portalindex[i] = LittleLong( ( *aasworld ).portalindex[i] );
} //end for
//cluster
for ( i = 0; i < ( *aasworld ).numclusters; i++ )
{
( *aasworld ).clusters[i].numareas = LittleLong( ( *aasworld ).clusters[i].numareas );
( *aasworld ).clusters[i].numportals = LittleLong( ( *aasworld ).clusters[i].numportals );
( *aasworld ).clusters[i].firstportal = LittleLong( ( *aasworld ).clusters[i].firstportal );
} //end for
} //end of the function AAS_SwapAASData
//===========================================================================
// dump the current loaded aas file
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_DumpAASData( void ) {
/*
if ((*aasworld).vertexes) FreeMemory((*aasworld).vertexes);
(*aasworld).vertexes = NULL;
if ((*aasworld).planes) FreeMemory((*aasworld).planes);
(*aasworld).planes = NULL;
if ((*aasworld).edges) FreeMemory((*aasworld).edges);
(*aasworld).edges = NULL;
if ((*aasworld).edgeindex) FreeMemory((*aasworld).edgeindex);
(*aasworld).edgeindex = NULL;
if ((*aasworld).faces) FreeMemory((*aasworld).faces);
(*aasworld).faces = NULL;
if ((*aasworld).faceindex) FreeMemory((*aasworld).faceindex);
(*aasworld).faceindex = NULL;
if ((*aasworld).areas) FreeMemory((*aasworld).areas);
(*aasworld).areas = NULL;
if ((*aasworld).areasettings) FreeMemory((*aasworld).areasettings);
(*aasworld).areasettings = NULL;
if ((*aasworld).reachability) FreeMemory((*aasworld).reachability);
(*aasworld).reachability = NULL;
*/
( *aasworld ).loaded = false;
} //end of the function AAS_DumpAASData
//===========================================================================
// allocate memory and read a lump of a AAS file
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
char *AAS_LoadAASLump( FILE *fp, int offset, int length, void *buf ) {
if ( !length ) {
printf( "lump size 0\n" );
return buf;
} //end if
//seek to the data
if ( fseek( fp, offset, SEEK_SET ) ) {
AAS_Error( "can't seek to lump\n" );
AAS_DumpAASData();
fclose( fp );
return 0;
} //end if
//allocate memory
if ( !buf ) {
buf = (void *) GetClearedMemory( length );
}
//read the data
if ( fread( (char *) buf, 1, length, fp ) != length ) {
AAS_Error( "can't read lump\n" );
FreeMemory( buf );
AAS_DumpAASData();
fclose( fp );
return NULL;
} //end if
return buf;
} //end of the function AAS_LoadAASLump
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_DData( unsigned char *data, int size ) {
int i;
for ( i = 0; i < size; i++ )
{
data[i] ^= (unsigned char) i * 119;
} //end for
} //end of the function AAS_DData
//===========================================================================
// load an aas file
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
qboolean AAS_LoadAASFile( char *filename, int fpoffset, int fplength ) {
FILE *fp;
aas_header_t header;
int offset, length;
//dump current loaded aas file
AAS_DumpAASData();
//open the file
fp = fopen( filename, "rb" );
if ( !fp ) {
AAS_Error( "can't open %s\n", filename );
return false;
} //end if
//seek to the correct position (in the pak file)
if ( fseek( fp, fpoffset, SEEK_SET ) ) {
AAS_Error( "can't seek to file %s\n" );
fclose( fp );
return false;
} //end if
//read the header
if ( fread( &header, sizeof( aas_header_t ), 1, fp ) != 1 ) {
AAS_Error( "can't read header of file %s\n", filename );
fclose( fp );
return false;
} //end if
//check header identification
header.ident = LittleLong( header.ident );
if ( header.ident != AASID ) {
AAS_Error( "%s is not an AAS file\n", filename );
fclose( fp );
return false;
} //end if
//check the version
header.version = LittleLong( header.version );
if ( header.version != AASVERSION ) {
AAS_Error( "%s is version %i, not %i\n", filename, header.version, AASVERSION );
fclose( fp );
return false;
} //end if
//
if ( header.version == AASVERSION ) {
AAS_DData( (unsigned char *) &header + 8, sizeof( aas_header_t ) - 8 );
} //end if
( *aasworld ).bspchecksum = LittleLong( header.bspchecksum );
//load the lumps:
//bounding boxes
offset = fpoffset + LittleLong( header.lumps[AASLUMP_BBOXES].fileofs );
length = LittleLong( header.lumps[AASLUMP_BBOXES].filelen );
( *aasworld ).bboxes = (aas_bbox_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).bboxes );
if ( !( *aasworld ).bboxes ) {
return false;
}
( *aasworld ).numbboxes = length / sizeof( aas_bbox_t );
//vertexes
offset = fpoffset + LittleLong( header.lumps[AASLUMP_VERTEXES].fileofs );
length = LittleLong( header.lumps[AASLUMP_VERTEXES].filelen );
( *aasworld ).vertexes = (aas_vertex_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).vertexes );
if ( !( *aasworld ).vertexes ) {
return false;
}
( *aasworld ).numvertexes = length / sizeof( aas_vertex_t );
//planes
offset = fpoffset + LittleLong( header.lumps[AASLUMP_PLANES].fileofs );
length = LittleLong( header.lumps[AASLUMP_PLANES].filelen );
( *aasworld ).planes = (aas_plane_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).planes );
if ( !( *aasworld ).planes ) {
return false;
}
( *aasworld ).numplanes = length / sizeof( aas_plane_t );
//edges
offset = fpoffset + LittleLong( header.lumps[AASLUMP_EDGES].fileofs );
length = LittleLong( header.lumps[AASLUMP_EDGES].filelen );
( *aasworld ).edges = (aas_edge_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).edges );
if ( !( *aasworld ).edges ) {
return false;
}
( *aasworld ).numedges = length / sizeof( aas_edge_t );
//edgeindex
offset = fpoffset + LittleLong( header.lumps[AASLUMP_EDGEINDEX].fileofs );
length = LittleLong( header.lumps[AASLUMP_EDGEINDEX].filelen );
( *aasworld ).edgeindex = (aas_edgeindex_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).edgeindex );
if ( !( *aasworld ).edgeindex ) {
return false;
}
( *aasworld ).edgeindexsize = length / sizeof( aas_edgeindex_t );
//faces
offset = fpoffset + LittleLong( header.lumps[AASLUMP_FACES].fileofs );
length = LittleLong( header.lumps[AASLUMP_FACES].filelen );
( *aasworld ).faces = (aas_face_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).faces );
if ( !( *aasworld ).faces ) {
return false;
}
( *aasworld ).numfaces = length / sizeof( aas_face_t );
//faceindex
offset = fpoffset + LittleLong( header.lumps[AASLUMP_FACEINDEX].fileofs );
length = LittleLong( header.lumps[AASLUMP_FACEINDEX].filelen );
( *aasworld ).faceindex = (aas_faceindex_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).faceindex );
if ( !( *aasworld ).faceindex ) {
return false;
}
( *aasworld ).faceindexsize = length / sizeof( int );
//convex areas
offset = fpoffset + LittleLong( header.lumps[AASLUMP_AREAS].fileofs );
length = LittleLong( header.lumps[AASLUMP_AREAS].filelen );
( *aasworld ).areas = (aas_area_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).areas );
if ( !( *aasworld ).areas ) {
return false;
}
( *aasworld ).numareas = length / sizeof( aas_area_t );
//area settings
offset = fpoffset + LittleLong( header.lumps[AASLUMP_AREASETTINGS].fileofs );
length = LittleLong( header.lumps[AASLUMP_AREASETTINGS].filelen );
( *aasworld ).areasettings = (aas_areasettings_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).areasettings );
if ( !( *aasworld ).areasettings ) {
return false;
}
( *aasworld ).numareasettings = length / sizeof( aas_areasettings_t );
//reachability list
offset = fpoffset + LittleLong( header.lumps[AASLUMP_REACHABILITY].fileofs );
length = LittleLong( header.lumps[AASLUMP_REACHABILITY].filelen );
( *aasworld ).reachability = (aas_reachability_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).reachability );
if ( length && !( *aasworld ).reachability ) {
return false;
}
( *aasworld ).reachabilitysize = length / sizeof( aas_reachability_t );
//nodes
offset = fpoffset + LittleLong( header.lumps[AASLUMP_NODES].fileofs );
length = LittleLong( header.lumps[AASLUMP_NODES].filelen );
( *aasworld ).nodes = (aas_node_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).nodes );
if ( !( *aasworld ).nodes ) {
return false;
}
( *aasworld ).numnodes = length / sizeof( aas_node_t );
//cluster portals
offset = fpoffset + LittleLong( header.lumps[AASLUMP_PORTALS].fileofs );
length = LittleLong( header.lumps[AASLUMP_PORTALS].filelen );
( *aasworld ).portals = (aas_portal_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).portals );
if ( length && !( *aasworld ).portals ) {
return false;
}
( *aasworld ).numportals = length / sizeof( aas_portal_t );
//cluster portal index
offset = fpoffset + LittleLong( header.lumps[AASLUMP_PORTALINDEX].fileofs );
length = LittleLong( header.lumps[AASLUMP_PORTALINDEX].filelen );
( *aasworld ).portalindex = (aas_portalindex_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).portalindex );
if ( length && !( *aasworld ).portalindex ) {
return false;
}
( *aasworld ).portalindexsize = length / sizeof( aas_portalindex_t );
//clusters
offset = fpoffset + LittleLong( header.lumps[AASLUMP_CLUSTERS].fileofs );
length = LittleLong( header.lumps[AASLUMP_CLUSTERS].filelen );
( *aasworld ).clusters = (aas_cluster_t *) AAS_LoadAASLump( fp, offset, length, ( *aasworld ).clusters );
if ( length && !( *aasworld ).clusters ) {
return false;
}
( *aasworld ).numclusters = length / sizeof( aas_cluster_t );
//swap everything
AAS_SwapAASData();
//aas file is loaded
( *aasworld ).loaded = true;
//close the file
fclose( fp );
return true;
} //end of the function AAS_LoadAASFile
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int AAS_WriteAASLump( FILE *fp, aas_header_t *h, int lumpnum, void *data, int length ) {
aas_lump_t *lump;
lump = &h->lumps[lumpnum];
lump->fileofs = LittleLong( ftell( fp ) );
lump->filelen = LittleLong( length );
if ( length > 0 ) {
if ( fwrite( data, length, 1, fp ) < 1 ) {
Log_Print( "error writing lump %s\n", lumpnum );
fclose( fp );
return false;
} //end if
} //end if
return true;
} //end of the function AAS_WriteAASLump
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_ShowNumReachabilities( int tt, char *name ) {
int i, num;
num = 0;
for ( i = 0; i < ( *aasworld ).reachabilitysize; i++ )
{
if ( ( ( *aasworld ).reachability[i].traveltype & TRAVELTYPE_MASK ) == tt ) {
num++;
}
} //end for
Log_Print( "%6d %s\n", num, name );
} //end of the function AAS_ShowNumReachabilities
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_ShowTotals( void ) {
Log_Print( "numvertexes = %d\r\n", ( *aasworld ).numvertexes );
Log_Print( "numplanes = %d\r\n", ( *aasworld ).numplanes );
Log_Print( "numedges = %d\r\n", ( *aasworld ).numedges );
Log_Print( "edgeindexsize = %d\r\n", ( *aasworld ).edgeindexsize );
Log_Print( "numfaces = %d\r\n", ( *aasworld ).numfaces );
Log_Print( "faceindexsize = %d\r\n", ( *aasworld ).faceindexsize );
Log_Print( "numareas = %d\r\n", ( *aasworld ).numareas );
Log_Print( "numareasettings = %d\r\n", ( *aasworld ).numareasettings );
Log_Print( "reachabilitysize = %d\r\n", ( *aasworld ).reachabilitysize );
Log_Print( "numnodes = %d\r\n", ( *aasworld ).numnodes );
Log_Print( "numportals = %d\r\n", ( *aasworld ).numportals );
Log_Print( "portalindexsize = %d\r\n", ( *aasworld ).portalindexsize );
Log_Print( "numclusters = %d\r\n", ( *aasworld ).numclusters );
AAS_ShowNumReachabilities( TRAVEL_WALK, "walk" );
AAS_ShowNumReachabilities( TRAVEL_CROUCH, "crouch" );
AAS_ShowNumReachabilities( TRAVEL_BARRIERJUMP, "barrier jump" );
AAS_ShowNumReachabilities( TRAVEL_JUMP, "jump" );
AAS_ShowNumReachabilities( TRAVEL_LADDER, "ladder" );
AAS_ShowNumReachabilities( TRAVEL_WALKOFFLEDGE, "walk off ledge" );
AAS_ShowNumReachabilities( TRAVEL_SWIM, "swim" );
AAS_ShowNumReachabilities( TRAVEL_WATERJUMP, "water jump" );
AAS_ShowNumReachabilities( TRAVEL_TELEPORT, "teleport" );
AAS_ShowNumReachabilities( TRAVEL_ELEVATOR, "elevator" );
AAS_ShowNumReachabilities( TRAVEL_ROCKETJUMP, "rocket jump" );
AAS_ShowNumReachabilities( TRAVEL_BFGJUMP, "bfg jump" );
AAS_ShowNumReachabilities( TRAVEL_GRAPPLEHOOK, "grapple hook" );
AAS_ShowNumReachabilities( TRAVEL_DOUBLEJUMP, "double jump" );
AAS_ShowNumReachabilities( TRAVEL_RAMPJUMP, "ramp jump" );
AAS_ShowNumReachabilities( TRAVEL_STRAFEJUMP, "strafe jump" );
AAS_ShowNumReachabilities( TRAVEL_JUMPPAD, "jump pad" );
AAS_ShowNumReachabilities( TRAVEL_FUNCBOB, "func bob" );
} //end of the function AAS_ShowTotals
//===========================================================================
// aas data is useless after writing to file because it is byte swapped
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
qboolean AAS_WriteAASFile( char *filename ) {
aas_header_t header;
FILE *fp;
Log_Print( "writing %s\n", filename );
AAS_ShowTotals();
//swap the aas data
AAS_SwapAASData();
//initialize the file header
memset( &header, 0, sizeof( aas_header_t ) );
header.ident = LittleLong( AASID );
header.version = LittleLong( AASVERSION );
header.bspchecksum = LittleLong( ( *aasworld ).bspchecksum );
//open a new file
fp = fopen( filename, "wb" );
if ( !fp ) {
Log_Print( "error opening %s\n", filename );
return false;
} //end if
//write the header
if ( fwrite( &header, sizeof( aas_header_t ), 1, fp ) < 1 ) {
fclose( fp );
return false;
} //end if
//add the data lumps to the file
if ( !AAS_WriteAASLump( fp, &header, AASLUMP_BBOXES, ( *aasworld ).bboxes,
( *aasworld ).numbboxes * sizeof( aas_bbox_t ) ) ) {
return false;
}
if ( !AAS_WriteAASLump( fp, &header, AASLUMP_VERTEXES, ( *aasworld ).vertexes,
( *aasworld ).numvertexes * sizeof( aas_vertex_t ) ) ) {
return false;
}
if ( !AAS_WriteAASLump( fp, &header, AASLUMP_PLANES, ( *aasworld ).planes,
( *aasworld ).numplanes * sizeof( aas_plane_t ) ) ) {
return false;
}
if ( !AAS_WriteAASLump( fp, &header, AASLUMP_EDGES, ( *aasworld ).edges,
( *aasworld ).numedges * sizeof( aas_edge_t ) ) ) {
return false;
}
if ( !AAS_WriteAASLump( fp, &header, AASLUMP_EDGEINDEX, ( *aasworld ).edgeindex,
( *aasworld ).edgeindexsize * sizeof( aas_edgeindex_t ) ) ) {
return false;
}
if ( !AAS_WriteAASLump( fp, &header, AASLUMP_FACES, ( *aasworld ).faces,
( *aasworld ).numfaces * sizeof( aas_face_t ) ) ) {
return false;
}
if ( !AAS_WriteAASLump( fp, &header, AASLUMP_FACEINDEX, ( *aasworld ).faceindex,
( *aasworld ).faceindexsize * sizeof( aas_faceindex_t ) ) ) {
return false;
}
if ( !AAS_WriteAASLump( fp, &header, AASLUMP_AREAS, ( *aasworld ).areas,
( *aasworld ).numareas * sizeof( aas_area_t ) ) ) {
return false;
}
if ( !AAS_WriteAASLump( fp, &header, AASLUMP_AREASETTINGS, ( *aasworld ).areasettings,
( *aasworld ).numareasettings * sizeof( aas_areasettings_t ) ) ) {
return false;
}
if ( !AAS_WriteAASLump( fp, &header, AASLUMP_REACHABILITY, ( *aasworld ).reachability,
( *aasworld ).reachabilitysize * sizeof( aas_reachability_t ) ) ) {
return false;
}
if ( !AAS_WriteAASLump( fp, &header, AASLUMP_NODES, ( *aasworld ).nodes,
( *aasworld ).numnodes * sizeof( aas_node_t ) ) ) {
return false;
}
if ( !AAS_WriteAASLump( fp, &header, AASLUMP_PORTALS, ( *aasworld ).portals,
( *aasworld ).numportals * sizeof( aas_portal_t ) ) ) {
return false;
}
if ( !AAS_WriteAASLump( fp, &header, AASLUMP_PORTALINDEX, ( *aasworld ).portalindex,
( *aasworld ).portalindexsize * sizeof( aas_portalindex_t ) ) ) {
return false;
}
if ( !AAS_WriteAASLump( fp, &header, AASLUMP_CLUSTERS, ( *aasworld ).clusters,
( *aasworld ).numclusters * sizeof( aas_cluster_t ) ) ) {
return false;
}
//rewrite the header with the added lumps
fseek( fp, 0, SEEK_SET );
AAS_DData( (unsigned char *) &header + 8, sizeof( aas_header_t ) - 8 );
if ( fwrite( &header, sizeof( aas_header_t ), 1, fp ) < 1 ) {
fclose( fp );
return false;
} //end if
//close the file
fclose( fp );
return true;
} //end of the function AAS_WriteAASFile

40
src/bspc/aas_file.h Normal file
View File

@@ -0,0 +1,40 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: aas_write.h
// Function:
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1997-12-04
// Tab Size: 3
//===========================================================================
qboolean AAS_WriteAASFile( char *filename );
qboolean AAS_LoadAASFile( char *filename, int fpoffset, int fplength );

688
src/bspc/aas_gsubdiv.c Normal file
View File

@@ -0,0 +1,688 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: aas_gsubdiv.c
// Function: Gravitational Subdivision
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1997-12-04
// Tab Size: 3
//===========================================================================
#include "qbsp.h"
#include "..\botlib\aasfile.h"
#include "aas_create.h"
#include "aas_store.h"
#include "aas_cfg.h"
#define FACECLIP_EPSILON 0.2
#define FACE_EPSILON 1.0
int numgravitationalsubdivisions = 0;
int numladdersubdivisions = 0;
//NOTE: only do gravitational subdivision BEFORE area merging!!!!!!!
// because the bsp tree isn't refreshes like with ladder subdivision
//===========================================================================
// NOTE: the original face is invalid after splitting
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_SplitFace( tmp_face_t *face, vec3_t normal, float dist,
tmp_face_t **frontface, tmp_face_t **backface ) {
winding_t *frontw, *backw;
//
*frontface = *backface = NULL;
ClipWindingEpsilon( face->winding, normal, dist, FACECLIP_EPSILON, &frontw, &backw );
#ifdef DEBUG
//
if ( frontw ) {
if ( WindingIsTiny( frontw ) ) {
Log_Write( "AAS_SplitFace: tiny back face\r\n" );
FreeWinding( frontw );
frontw = NULL;
} //end if
} //end if
if ( backw ) {
if ( WindingIsTiny( backw ) ) {
Log_Write( "AAS_SplitFace: tiny back face\r\n" );
FreeWinding( backw );
backw = NULL;
} //end if
} //end if
#endif //DEBUG
//if the winding was split
if ( frontw ) {
//check bounds
( *frontface ) = AAS_AllocTmpFace();
( *frontface )->planenum = face->planenum;
( *frontface )->winding = frontw;
( *frontface )->faceflags = face->faceflags;
} //end if
if ( backw ) {
//check bounds
( *backface ) = AAS_AllocTmpFace();
( *backface )->planenum = face->planenum;
( *backface )->winding = backw;
( *backface )->faceflags = face->faceflags;
} //end if
} //end of the function AAS_SplitFace
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
winding_t *AAS_SplitWinding( tmp_area_t *tmparea, int planenum ) {
tmp_face_t *face;
plane_t *plane;
int side;
winding_t *splitwinding;
//
plane = &mapplanes[planenum];
//create a split winding, first base winding for plane
splitwinding = BaseWindingForPlane( plane->normal, plane->dist );
//chop with all the faces of the area
for ( face = tmparea->tmpfaces; face && splitwinding; face = face->next[side] )
{
//side of the face the original area was on
side = face->frontarea != tmparea;
plane = &mapplanes[face->planenum ^ side];
ChopWindingInPlace( &splitwinding, plane->normal, plane->dist, 0 ); // PLANESIDE_EPSILON);
} //end for
return splitwinding;
} //end of the function AAS_SplitWinding
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int AAS_TestSplitPlane( tmp_area_t *tmparea, vec3_t normal, float dist,
int *facesplits, int *groundsplits, int *epsilonfaces ) {
int j, side, front, back, planenum;
float d, d_front, d_back;
tmp_face_t *face;
winding_t *w;
*facesplits = *groundsplits = *epsilonfaces = 0;
planenum = FindFloatPlane( normal, dist );
w = AAS_SplitWinding( tmparea, planenum );
if ( !w ) {
return false;
}
FreeWinding( w );
//
for ( face = tmparea->tmpfaces; face; face = face->next[side] )
{
//side of the face the area is on
side = face->frontarea != tmparea;
if ( ( face->planenum & ~1 ) == ( planenum & ~1 ) ) {
Log_Print( "AAS_TestSplitPlane: tried face plane as splitter\n" );
return false;
} //end if
w = face->winding;
//reset distance at front and back side of plane
d_front = d_back = 0;
//reset front and back flags
front = back = 0;
for ( j = 0; j < w->numpoints; j++ )
{
d = DotProduct( w->p[j], normal ) - dist;
if ( d > d_front ) {
d_front = d;
}
if ( d < d_back ) {
d_back = d;
}
if ( d > 0.4 ) { // PLANESIDE_EPSILON)
front = 1;
}
if ( d < -0.4 ) { // PLANESIDE_EPSILON)
back = 1;
}
} //end for
//check for an epsilon face
if ( ( d_front > FACECLIP_EPSILON && d_front < FACE_EPSILON )
|| ( d_back < -FACECLIP_EPSILON && d_back > -FACE_EPSILON ) ) {
( *epsilonfaces )++;
} //end if
//if the face has points at both sides of the plane
if ( front && back ) {
( *facesplits )++;
if ( face->faceflags & FACE_GROUND ) {
( *groundsplits )++;
} //end if
} //end if
} //end for
return true;
} //end of the function AAS_TestSplitPlane
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_SplitArea( tmp_area_t *tmparea, int planenum, tmp_area_t **frontarea, tmp_area_t **backarea ) {
int side;
tmp_area_t *facefrontarea, *facebackarea, *faceotherarea;
tmp_face_t *face, *frontface, *backface, *splitface, *nextface;
winding_t *splitwinding;
plane_t *splitplane;
/*
#ifdef AW_DEBUG
int facesplits, groundsplits, epsilonface;
Log_Print("\n----------------------\n");
Log_Print("splitting area %d\n", areanum);
Log_Print("with normal = \'%f %f %f\', dist = %f\n", normal[0], normal[1], normal[2], dist);
AAS_TestSplitPlane(areanum, normal, dist,
&facesplits, &groundsplits, &epsilonface);
Log_Print("face splits = %d\nground splits = %d\n", facesplits, groundsplits);
if (epsilonface) Log_Print("aaahh epsilon face\n");
#endif //AW_DEBUG*/
//the original area
AAS_FlipAreaFaces( tmparea );
AAS_CheckArea( tmparea );
//
splitplane = &mapplanes[planenum];
/* //create a split winding, first base winding for plane
splitwinding = BaseWindingForPlane(splitplane->normal, splitplane->dist);
//chop with all the faces of the area
for (face = tmparea->tmpfaces; face && splitwinding; face = face->next[side])
{
//side of the face the original area was on
side = face->frontarea != tmparea->areanum;
plane = &mapplanes[face->planenum ^ side];
ChopWindingInPlace(&splitwinding, plane->normal, plane->dist, 0); // PLANESIDE_EPSILON);
} //end for*/
splitwinding = AAS_SplitWinding( tmparea, planenum );
if ( !splitwinding ) {
/*
#ifdef DEBUG
AAS_TestSplitPlane(areanum, normal, dist,
&facesplits, &groundsplits, &epsilonface);
Log_Print("\nface splits = %d\nground splits = %d\n", facesplits, groundsplits);
if (epsilonface) Log_Print("aaahh epsilon face\n");
#endif //DEBUG*/
Error( "AAS_SplitArea: no split winding when splitting area %d\n", tmparea->areanum );
} //end if
//create a split face
splitface = AAS_AllocTmpFace();
//get the map plane
splitface->planenum = planenum;
//store the split winding
splitface->winding = splitwinding;
//the new front area
( *frontarea ) = AAS_AllocTmpArea();
( *frontarea )->presencetype = tmparea->presencetype;
( *frontarea )->contents = tmparea->contents;
( *frontarea )->modelnum = tmparea->modelnum;
( *frontarea )->tmpfaces = NULL;
//the new back area
( *backarea ) = AAS_AllocTmpArea();
( *backarea )->presencetype = tmparea->presencetype;
( *backarea )->contents = tmparea->contents;
( *backarea )->modelnum = tmparea->modelnum;
( *backarea )->tmpfaces = NULL;
//add the split face to the new areas
AAS_AddFaceSideToArea( splitface, 0, ( *frontarea ) );
AAS_AddFaceSideToArea( splitface, 1, ( *backarea ) );
//split all the faces of the original area
for ( face = tmparea->tmpfaces; face; face = nextface )
{
//side of the face the original area was on
side = face->frontarea != tmparea;
//next face of the original area
nextface = face->next[side];
//front area of the face
facefrontarea = face->frontarea;
//back area of the face
facebackarea = face->backarea;
//remove the face from both the front and back areas
if ( facefrontarea ) {
AAS_RemoveFaceFromArea( face, facefrontarea );
}
if ( facebackarea ) {
AAS_RemoveFaceFromArea( face, facebackarea );
}
//split the face
AAS_SplitFace( face, splitplane->normal, splitplane->dist, &frontface, &backface );
//free the original face
AAS_FreeTmpFace( face );
//get the number of the area at the other side of the face
if ( side ) {
faceotherarea = facefrontarea;
} else { faceotherarea = facebackarea;}
//if there is an area at the other side of the original face
if ( faceotherarea ) {
if ( frontface ) {
AAS_AddFaceSideToArea( frontface, !side, faceotherarea );
}
if ( backface ) {
AAS_AddFaceSideToArea( backface, !side, faceotherarea );
}
} //end if
//add the front and back part left after splitting the original face to the new areas
if ( frontface ) {
AAS_AddFaceSideToArea( frontface, side, ( *frontarea ) );
}
if ( backface ) {
AAS_AddFaceSideToArea( backface, side, ( *backarea ) );
}
} //end for
if ( !( *frontarea )->tmpfaces ) {
Log_Print( "AAS_SplitArea: front area without faces\n" );
}
if ( !( *backarea )->tmpfaces ) {
Log_Print( "AAS_SplitArea: back area without faces\n" );
}
tmparea->invalid = true;
/*
#ifdef AW_DEBUG
for (i = 0, face = frontarea->tmpfaces; face; face = face->next[side])
{
side = face->frontarea != frontarea->areanum;
i++;
} //end for
Log_Print("created front area %d with %d faces\n", frontarea->areanum, i);
for (i = 0, face = backarea->tmpfaces; face; face = face->next[side])
{
side = face->frontarea != backarea->areanum;
i++;
} //end for
Log_Print("created back area %d with %d faces\n", backarea->areanum, i);
#endif //AW_DEBUG*/
AAS_FlipAreaFaces( ( *frontarea ) );
AAS_FlipAreaFaces( ( *backarea ) );
//
AAS_CheckArea( ( *frontarea ) );
AAS_CheckArea( ( *backarea ) );
} //end of the function AAS_SplitArea
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int AAS_FindBestAreaSplitPlane( tmp_area_t *tmparea, vec3_t normal, float *dist ) {
int side1, side2;
int foundsplitter, facesplits, groundsplits, epsilonfaces, bestepsilonfaces;
float bestvalue, value;
tmp_face_t *face1, *face2;
vec3_t tmpnormal, invgravity;
float tmpdist;
//get inverse of gravity direction
VectorCopy( cfg.phys_gravitydirection, invgravity );
VectorInverse( invgravity );
foundsplitter = false;
bestvalue = -999999;
bestepsilonfaces = 0;
//
#ifdef AW_DEBUG
Log_Print( "finding split plane for area %d\n", tmparea->areanum );
#endif //AW_DEBUG
for ( face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1] )
{
//side of the face the area is on
side1 = face1->frontarea != tmparea;
//
if ( WindingIsTiny( face1->winding ) ) {
Log_Write( "gsubdiv: area %d has a tiny winding\r\n", tmparea->areanum );
continue;
} //end if
//if the face isn't a gap or ground there's no split edge
if ( !( face1->faceflags & FACE_GROUND ) && !AAS_GapFace( face1, side1 ) ) {
continue;
}
//
for ( face2 = face1->next[side1]; face2; face2 = face2->next[side2] )
{
//side of the face the area is on
side2 = face2->frontarea != tmparea;
//
if ( WindingIsTiny( face1->winding ) ) {
Log_Write( "gsubdiv: area %d has a tiny winding\r\n", tmparea->areanum );
continue;
} //end if
//if the face isn't a gap or ground there's no split edge
if ( !( face2->faceflags & FACE_GROUND ) && !AAS_GapFace( face2, side2 ) ) {
continue;
}
//only split between gaps and ground
if ( !( ( ( face1->faceflags & FACE_GROUND ) && AAS_GapFace( face2, side2 ) ) ||
( ( face2->faceflags & FACE_GROUND ) && AAS_GapFace( face1, side1 ) ) ) ) {
continue;
}
//find a plane seperating the windings of the faces
if ( !FindPlaneSeperatingWindings( face1->winding, face2->winding, invgravity,
tmpnormal, &tmpdist ) ) {
continue;
}
#ifdef AW_DEBUG
Log_Print( "normal = \'%f %f %f\', dist = %f\n",
tmpnormal[0], tmpnormal[1], tmpnormal[2], tmpdist );
#endif //AW_DEBUG
//get metrics for this vertical plane
if ( !AAS_TestSplitPlane( tmparea, tmpnormal, tmpdist,
&facesplits, &groundsplits, &epsilonfaces ) ) {
continue;
} //end if
#ifdef AW_DEBUG
Log_Print( "face splits = %d\nground splits = %d\n",
facesplits, groundsplits );
#endif //AW_DEBUG
value = 100 - facesplits - 2 * groundsplits;
//avoid epsilon faces
value += epsilonfaces * -1000;
if ( value > bestvalue ) {
VectorCopy( tmpnormal, normal );
*dist = tmpdist;
bestvalue = value;
bestepsilonfaces = epsilonfaces;
foundsplitter = true;
} //end if
} //end for
} //end for
if ( bestepsilonfaces ) {
Log_Write( "found %d epsilon faces trying to split area %d\r\n",
epsilonfaces, tmparea->areanum );
} //end else
return foundsplitter;
} //end of the function AAS_FindBestAreaSplitPlane
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
tmp_node_t *AAS_SubdivideArea_r( tmp_node_t *tmpnode ) {
int planenum;
tmp_area_t *frontarea, *backarea;
tmp_node_t *tmpnode1, *tmpnode2;
vec3_t normal;
float dist;
if ( AAS_FindBestAreaSplitPlane( tmpnode->tmparea, normal, &dist ) ) {
qprintf( "\r%6d", ++numgravitationalsubdivisions );
//
planenum = FindFloatPlane( normal, dist );
//split the area
AAS_SplitArea( tmpnode->tmparea, planenum, &frontarea, &backarea );
//
tmpnode->tmparea = NULL;
tmpnode->planenum = FindFloatPlane( normal, dist );
//
tmpnode1 = AAS_AllocTmpNode();
tmpnode1->planenum = 0;
tmpnode1->tmparea = frontarea;
//
tmpnode2 = AAS_AllocTmpNode();
tmpnode2->planenum = 0;
tmpnode2->tmparea = backarea;
//subdivide the areas created by splitting recursively
tmpnode->children[0] = AAS_SubdivideArea_r( tmpnode1 );
tmpnode->children[1] = AAS_SubdivideArea_r( tmpnode2 );
} //end if
return tmpnode;
} //end of the function AAS_SubdivideArea_r
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
tmp_node_t *AAS_GravitationalSubdivision_r( tmp_node_t *tmpnode ) {
//if this is a solid leaf
if ( !tmpnode ) {
return NULL;
}
//negative so it's an area
if ( tmpnode->tmparea ) {
return AAS_SubdivideArea_r( tmpnode );
}
//do the children recursively
tmpnode->children[0] = AAS_GravitationalSubdivision_r( tmpnode->children[0] );
tmpnode->children[1] = AAS_GravitationalSubdivision_r( tmpnode->children[1] );
return tmpnode;
} //end of the function AAS_GravitationalSubdivision_r
//===========================================================================
// NOTE: merge faces and melt edges first
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_GravitationalSubdivision( void ) {
Log_Write( "AAS_GravitationalSubdivision\r\n" );
numgravitationalsubdivisions = 0;
qprintf( "%6i gravitational subdivisions", numgravitationalsubdivisions );
//start with the head node
AAS_GravitationalSubdivision_r( tmpaasworld.nodes );
qprintf( "\n" );
Log_Write( "%6i gravitational subdivisions\r\n", numgravitationalsubdivisions );
} //end of the function AAS_GravitationalSubdivision
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
tmp_node_t *AAS_RefreshLadderSubdividedTree_r( tmp_node_t *tmpnode, tmp_area_t *tmparea,
tmp_node_t *tmpnode1, tmp_node_t *tmpnode2, int planenum ) {
//if this is a solid leaf
if ( !tmpnode ) {
return NULL;
}
//negative so it's an area
if ( tmpnode->tmparea ) {
if ( tmpnode->tmparea == tmparea ) {
tmpnode->tmparea = NULL;
tmpnode->planenum = planenum;
tmpnode->children[0] = tmpnode1;
tmpnode->children[1] = tmpnode2;
} //end if
return tmpnode;
} //end if
//do the children recursively
tmpnode->children[0] = AAS_RefreshLadderSubdividedTree_r( tmpnode->children[0],
tmparea, tmpnode1, tmpnode2, planenum );
tmpnode->children[1] = AAS_RefreshLadderSubdividedTree_r( tmpnode->children[1],
tmparea, tmpnode1, tmpnode2, planenum );
return tmpnode;
} //end of the function AAS_RefreshLadderSubdividedTree_r
//===========================================================================
// find an area with ladder faces and ground faces that are not connected
// split the area with a horizontal plane at the lowest vertex of all
// ladder faces in the area
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
tmp_node_t *AAS_LadderSubdivideArea_r( tmp_node_t *tmpnode ) {
int side1, i, planenum;
int foundladderface, foundgroundface;
float dist;
tmp_area_t *tmparea, *frontarea, *backarea;
tmp_face_t *face1;
tmp_node_t *tmpnode1, *tmpnode2;
vec3_t lowestpoint, normal = {0, 0, 1};
plane_t *plane;
winding_t *w;
tmparea = tmpnode->tmparea;
//skip areas with a liquid
if ( tmparea->contents & ( AREACONTENTS_WATER
| AREACONTENTS_LAVA
| AREACONTENTS_SLIME ) ) {
return tmpnode;
}
//must be possible to stand in the area
if ( !( tmparea->presencetype & PRESENCE_NORMAL ) ) {
return tmpnode;
}
//
foundladderface = false;
foundgroundface = false;
lowestpoint[2] = 99999;
//
for ( face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1] )
{
//side of the face the area is on
side1 = face1->frontarea != tmparea;
//if the face is a ladder face
if ( face1->faceflags & FACE_LADDER ) {
plane = &mapplanes[face1->planenum];
//the ladder face plane should be pretty much vertical
if ( DotProduct( plane->normal, normal ) > -0.1 ) {
foundladderface = true;
//find lowest point
for ( i = 0; i < face1->winding->numpoints; i++ )
{
if ( face1->winding->p[i][2] < lowestpoint[2] ) {
VectorCopy( face1->winding->p[i], lowestpoint );
} //end if
} //end for
} //end if
} //end if
else if ( face1->faceflags & FACE_GROUND ) {
foundgroundface = true;
} //end else if
} //end for
//
if ( ( !foundladderface ) || ( !foundgroundface ) ) {
return tmpnode;
}
//
for ( face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1] )
{
//side of the face the area is on
side1 = face1->frontarea != tmparea;
//if the face isn't a ground face
if ( !( face1->faceflags & FACE_GROUND ) ) {
continue;
}
//the ground plane
plane = &mapplanes[face1->planenum];
//get the difference between the ground plane and the lowest point
dist = DotProduct( plane->normal, lowestpoint ) - plane->dist;
//if the lowest point is very near one of the ground planes
if ( dist > -1 && dist < 1 ) {
return tmpnode;
} //end if
} //end for
//
dist = DotProduct( normal, lowestpoint );
planenum = FindFloatPlane( normal, dist );
//
w = AAS_SplitWinding( tmparea, planenum );
if ( !w ) {
return tmpnode;
}
FreeWinding( w );
//split the area with a horizontal plane through the lowest point
qprintf( "\r%6d", ++numladdersubdivisions );
//
AAS_SplitArea( tmparea, planenum, &frontarea, &backarea );
//
tmpnode->tmparea = NULL;
tmpnode->planenum = planenum;
//
tmpnode1 = AAS_AllocTmpNode();
tmpnode1->planenum = 0;
tmpnode1->tmparea = frontarea;
//
tmpnode2 = AAS_AllocTmpNode();
tmpnode2->planenum = 0;
tmpnode2->tmparea = backarea;
//subdivide the areas created by splitting recursively
tmpnode->children[0] = AAS_LadderSubdivideArea_r( tmpnode1 );
tmpnode->children[1] = AAS_LadderSubdivideArea_r( tmpnode2 );
//refresh the tree
AAS_RefreshLadderSubdividedTree_r( tmpaasworld.nodes, tmparea, tmpnode1, tmpnode2, planenum );
//
return tmpnode;
} //end of the function AAS_LadderSubdivideArea_r
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
tmp_node_t *AAS_LadderSubdivision_r( tmp_node_t *tmpnode ) {
//if this is a solid leaf
if ( !tmpnode ) {
return 0;
}
//negative so it's an area
if ( tmpnode->tmparea ) {
return AAS_LadderSubdivideArea_r( tmpnode );
}
//do the children recursively
tmpnode->children[0] = AAS_LadderSubdivision_r( tmpnode->children[0] );
tmpnode->children[1] = AAS_LadderSubdivision_r( tmpnode->children[1] );
return tmpnode;
} //end of the function AAS_LadderSubdivision_r
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_LadderSubdivision( void ) {
Log_Write( "AAS_LadderSubdivision\r\n" );
numladdersubdivisions = 0;
qprintf( "%6i ladder subdivisions", numladdersubdivisions );
//start with the head node
AAS_LadderSubdivision_r( tmpaasworld.nodes );
//
qprintf( "\n" );
Log_Write( "%6i ladder subdivisions\r\n", numladdersubdivisions );
} //end of the function AAS_LadderSubdivision

40
src/bspc/aas_gsubdiv.h Normal file
View File

@@ -0,0 +1,40 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: aas_gsubdiv.h
// Function: Gravitational subdivision
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1997-12-04
// Tab Size: 3
//===========================================================================
//works with the global tmpaasworld
void AAS_GravitationalSubdivision( void );
void AAS_LadderSubdivision( void );

838
src/bspc/aas_map.c Normal file
View File

@@ -0,0 +1,838 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: aas_map.c
// Function:
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1997-12-03
// Tab Size: 3
//===========================================================================
#include "qbsp.h"
#include "l_mem.h"
#include "..\botlib\aasfile.h" //aas_bbox_t
#include "aas_store.h" //AAS_MAX_BBOXES
#include "aas_cfg.h"
#include "..\game\surfaceflags.h"
#define SPAWNFLAG_NOT_EASY 0x00000100
#define SPAWNFLAG_NOT_MEDIUM 0x00000200
#define SPAWNFLAG_NOT_HARD 0x00000400
#define SPAWNFLAG_NOT_DEATHMATCH 0x00000800
#define SPAWNFLAG_NOT_COOP 0x00001000
#define STATE_TOP 0
#define STATE_BOTTOM 1
#define STATE_UP 2
#define STATE_DOWN 3
#define DOOR_START_OPEN 1
#define DOOR_REVERSE 2
#define DOOR_CRUSHER 4
#define DOOR_NOMONSTER 8
#define DOOR_TOGGLE 32
#define DOOR_X_AXIS 64
#define DOOR_Y_AXIS 128
#define BBOX_NORMAL_EPSILON 0.0001
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
vec_t BoxOriginDistanceFromPlane( vec3_t normal, vec3_t mins, vec3_t maxs, int side ) {
vec3_t v1, v2;
int i;
if ( side ) {
for ( i = 0; i < 3; i++ )
{
if ( normal[i] > BBOX_NORMAL_EPSILON ) {
v1[i] = maxs[i];
} else if ( normal[i] < -BBOX_NORMAL_EPSILON ) {
v1[i] = mins[i];
} else { v1[i] = 0;}
} //end for
} //end if
else
{
for ( i = 0; i < 3; i++ )
{
if ( normal[i] > BBOX_NORMAL_EPSILON ) {
v1[i] = mins[i];
} else if ( normal[i] < -BBOX_NORMAL_EPSILON ) {
v1[i] = maxs[i];
} else { v1[i] = 0;}
} //end for
} //end else
VectorCopy( normal, v2 );
VectorInverse( v2 );
return DotProduct( v1, v2 );
} //end of the function BoxOriginDistanceFromPlane
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
vec_t CapsuleOriginDistanceFromPlane( vec3_t normal, vec3_t mins, vec3_t maxs ) {
float offset_up, offset_down, width, radius;
width = maxs[0] - mins[0];
// if the box is less high then it is wide
if ( maxs[2] - mins[2] < width ) {
width = maxs[2] - mins[2];
}
radius = width * 0.5;
// offset to upper and lower sphere
offset_up = maxs[2] - radius;
offset_down = -mins[2] - radius;
// if normal points upward
if ( normal[2] > 0 ) {
// touches lower sphere first
return normal[2] * offset_down + radius;
} else {
// touched upper sphere first
return -normal[2] * offset_up + radius;
}
}
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_ExpandMapBrush( mapbrush_t *brush, vec3_t mins, vec3_t maxs ) {
int sn;
float dist;
side_t *s;
plane_t *plane;
for ( sn = 0; sn < brush->numsides; sn++ )
{
s = brush->original_sides + sn;
plane = &mapplanes[s->planenum];
dist = plane->dist;
if ( capsule_collision ) {
dist += CapsuleOriginDistanceFromPlane( plane->normal, mins, maxs );
} else {
dist += BoxOriginDistanceFromPlane( plane->normal, mins, maxs, 0 );
}
s->planenum = FindFloatPlane( plane->normal, dist );
//the side isn't a bevel after expanding
s->flags &= ~SFL_BEVEL;
//don't skip the surface
s->surf &= ~SURF_SKIP;
//make sure the texinfo is not TEXINFO_NODE
//when player clip contents brushes are read from the bsp tree
//they have the texinfo field set to TEXINFO_NODE
//s->texinfo = 0;
} //end for
} //end of the function AAS_ExpandMapBrush
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_SetTexinfo( mapbrush_t *brush ) {
int n;
side_t *side;
if ( brush->contents & ( CONTENTS_LADDER
| CONTENTS_AREAPORTAL
| CONTENTS_CLUSTERPORTAL
| CONTENTS_TELEPORTER
| CONTENTS_JUMPPAD
| CONTENTS_DONOTENTER
| CONTENTS_DONOTENTER_LARGE
| CONTENTS_WATER
| CONTENTS_LAVA
| CONTENTS_SLIME
| CONTENTS_WINDOW
| CONTENTS_PLAYERCLIP ) ) {
//we just set texinfo to 0 because these brush sides MUST be used as
//bsp splitters textured or not textured
for ( n = 0; n < brush->numsides; n++ )
{
side = brush->original_sides + n;
//side->flags |= SFL_TEXTURED|SFL_VISIBLE;
side->texinfo = 0;
} //end for
} //end if
else
{
//only use brush sides as splitters if they are textured
//texinfo of non-textured sides will be set to TEXINFO_NODE
for ( n = 0; n < brush->numsides; n++ )
{
side = brush->original_sides + n;
//don't use side as splitter (set texinfo to TEXINFO_NODE) if not textured
if ( side->flags & ( SFL_TEXTURED | SFL_BEVEL ) ) {
side->texinfo = 0;
} else { side->texinfo = TEXINFO_NODE;}
} //end for
} //end else
} //end of the function AAS_SetTexinfo
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void FreeBrushWindings( mapbrush_t *brush ) {
int n;
side_t *side;
//
for ( n = 0; n < brush->numsides; n++ )
{
side = brush->original_sides + n;
//
if ( side->winding ) {
FreeWinding( side->winding );
}
} //end for
} //end of the function FreeBrushWindings
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_AddMapBrushSide( mapbrush_t *brush, int planenum ) {
side_t *side;
//
if ( nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES ) {
Error( "MAX_MAPFILE_BRUSHSIDES" );
}
//
side = brush->original_sides + brush->numsides;
side->original = NULL;
side->winding = NULL;
side->contents = brush->contents;
side->flags &= ~( SFL_BEVEL | SFL_VISIBLE );
side->surf = 0;
side->planenum = planenum;
side->texinfo = 0;
//
nummapbrushsides++;
brush->numsides++;
} //end of the function AAS_AddMapBrushSide
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_FixMapBrush( mapbrush_t *brush ) {
int i, j, planenum;
float dist;
winding_t *w;
plane_t *plane, *plane1, *plane2;
side_t *side;
vec3_t normal;
//calculate the brush bounds
ClearBounds( brush->mins, brush->maxs );
for ( i = 0; i < brush->numsides; i++ )
{
plane = &mapplanes[brush->original_sides[i].planenum];
w = BaseWindingForPlane( plane->normal, plane->dist );
for ( j = 0; j < brush->numsides && w; j++ )
{
if ( i == j ) {
continue;
}
//there are no brush bevels marked but who cares :)
if ( brush->original_sides[j].flags & SFL_BEVEL ) {
continue;
}
plane = &mapplanes[brush->original_sides[j].planenum ^ 1];
ChopWindingInPlace( &w, plane->normal, plane->dist, 0 ); //CLIP_EPSILON);
} //end for
side = &brush->original_sides[i];
side->winding = w;
if ( w ) {
for ( j = 0; j < w->numpoints; j++ )
{
AddPointToBounds( w->p[j], brush->mins, brush->maxs );
} //end for
} //end if
} //end for
//
for ( i = 0; i < brush->numsides; i++ )
{
for ( j = 0; j < brush->numsides; j++ )
{
if ( i == j ) {
continue;
}
plane1 = &mapplanes[brush->original_sides[i].planenum];
plane2 = &mapplanes[brush->original_sides[j].planenum];
if ( WindingsNonConvex( brush->original_sides[i].winding,
brush->original_sides[j].winding,
plane1->normal, plane2->normal,
plane1->dist, plane2->dist ) ) {
Log_Print( "non convex brush" );
} //end if
} //end for
} //end for
//NOW close the fucking brush!!
for ( i = 0; i < 3; i++ )
{
if ( brush->mins[i] < -MAX_MAP_BOUNDS ) {
VectorClear( normal );
normal[i] = -1;
dist = MAX_MAP_BOUNDS - 10;
planenum = FindFloatPlane( normal, dist );
//
Log_Print( "mins out of range: added extra brush side\n" );
AAS_AddMapBrushSide( brush, planenum );
} //end if
if ( brush->maxs[i] > MAX_MAP_BOUNDS ) {
VectorClear( normal );
normal[i] = 1;
dist = MAX_MAP_BOUNDS - 10;
planenum = FindFloatPlane( normal, dist );
//
Log_Print( "maxs out of range: added extra brush side\n" );
AAS_AddMapBrushSide( brush, planenum );
} //end if
if ( brush->mins[i] > MAX_MAP_BOUNDS || brush->maxs[i] < -MAX_MAP_BOUNDS ) {
Log_Print( "entity %i, brush %i: no visible sides on brush\n", brush->entitynum, brush->brushnum );
} //end if
} //end for
//free all the windings
FreeBrushWindings( brush );
} //end of the function AAS_FixMapBrush
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
qboolean AAS_MakeBrushWindings( mapbrush_t *ob ) {
int i, j;
winding_t *w;
side_t *side;
plane_t *plane, *plane1, *plane2;
ClearBounds( ob->mins, ob->maxs );
for ( i = 0; i < ob->numsides; i++ )
{
plane = &mapplanes[ob->original_sides[i].planenum];
w = BaseWindingForPlane( plane->normal, plane->dist );
for ( j = 0; j < ob->numsides && w; j++ )
{
if ( i == j ) {
continue;
}
if ( ob->original_sides[j].flags & SFL_BEVEL ) {
continue;
}
plane = &mapplanes[ob->original_sides[j].planenum ^ 1];
ChopWindingInPlace( &w, plane->normal, plane->dist, 0 ); //CLIP_EPSILON);
}
side = &ob->original_sides[i];
side->winding = w;
if ( w ) {
side->flags |= SFL_VISIBLE;
for ( j = 0; j < w->numpoints; j++ )
AddPointToBounds( w->p[j], ob->mins, ob->maxs );
}
}
//check if the brush is convex
for ( i = 0; i < ob->numsides; i++ )
{
for ( j = 0; j < ob->numsides; j++ )
{
if ( i == j ) {
continue;
}
plane1 = &mapplanes[ob->original_sides[i].planenum];
plane2 = &mapplanes[ob->original_sides[j].planenum];
if ( WindingsNonConvex( ob->original_sides[i].winding,
ob->original_sides[j].winding,
plane1->normal, plane2->normal,
plane1->dist, plane2->dist ) ) {
Log_Print( "non convex brush" );
} //end if
} //end for
} //end for
//check for out of bound brushes
for ( i = 0; i < 3; i++ )
{
//IDBUG: all the indexes into the mins and maxs were zero (not using i)
if ( ob->mins[i] < -MAX_MAP_BOUNDS || ob->maxs[i] > MAX_MAP_BOUNDS ) {
Log_Print( "entity %i, brush %i: bounds out of range\n", ob->entitynum, ob->brushnum );
Log_Print( "ob->mins[%d] = %f, ob->maxs[%d] = %f\n", i, ob->mins[i], i, ob->maxs[i] );
ob->numsides = 0; //remove the brush
break;
} //end if
if ( ob->mins[i] > MAX_MAP_BOUNDS || ob->maxs[i] < -MAX_MAP_BOUNDS ) {
Log_Print( "entity %i, brush %i: no visible sides on brush\n", ob->entitynum, ob->brushnum );
Log_Print( "ob->mins[%d] = %f, ob->maxs[%d] = %f\n", i, ob->mins[i], i, ob->maxs[i] );
ob->numsides = 0; //remove the brush
break;
} //end if
} //end for
return true;
} //end of the function AAS_MakeBrushWindings
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
mapbrush_t *AAS_CopyMapBrush( mapbrush_t *brush, entity_t *mapent ) {
int n;
mapbrush_t *newbrush;
side_t *side, *newside;
if ( nummapbrushes >= MAX_MAPFILE_BRUSHES ) {
Error( "MAX_MAPFILE_BRUSHES" );
}
newbrush = &mapbrushes[nummapbrushes];
newbrush->original_sides = &brushsides[nummapbrushsides];
newbrush->entitynum = brush->entitynum;
newbrush->brushnum = nummapbrushes - mapent->firstbrush;
newbrush->numsides = brush->numsides;
newbrush->contents = brush->contents;
//copy the sides
for ( n = 0; n < brush->numsides; n++ )
{
if ( nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES ) {
Error( "MAX_MAPFILE_BRUSHSIDES" );
}
side = brush->original_sides + n;
newside = newbrush->original_sides + n;
newside->original = NULL;
newside->winding = NULL;
newside->contents = side->contents;
newside->flags = side->flags;
newside->surf = side->surf;
newside->planenum = side->planenum;
newside->texinfo = side->texinfo;
nummapbrushsides++;
} //end for
//
nummapbrushes++;
mapent->numbrushes++;
return newbrush;
} //end of the function AAS_CopyMapBrush
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int AAS_AlwaysTriggered( char *targetname ) {
int i;
if ( !strlen( targetname ) ) {
return false;
}
//
for ( i = 0; i < num_entities; i++ )
{
//if the entity will activate the given targetname
if ( !strcmp( targetname, ValueForKey( &entities[i], "target" ) ) ) {
//if this activator is present in deathmatch
if ( !( atoi( ValueForKey( &entities[i], "spawnflags" ) ) & SPAWNFLAG_NOT_DEATHMATCH ) ) {
//if it is a trigger_always entity
if ( !strcmp( "trigger_always", ValueForKey( &entities[i], "classname" ) ) ) {
return true;
} //end if
//check for possible trigger_always entities activating this entity
if ( AAS_AlwaysTriggered( ValueForKey( &entities[i], "targetname" ) ) ) {
return true;
} //end if
} //end if
} //end if
} //end for
return false;
} //end of the function AAS_AlwaysTriggered
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int AAS_ValidEntity( entity_t *mapent ) {
int i;
char target[1024];
//all world brushes are used for AAS
if ( mapent == &entities[0] ) {
return true;
} //end if
//some of the func_wall brushes are also used for AAS
else if ( !strcmp( "func_wall", ValueForKey( mapent, "classname" ) ) ) {
//Log_Print("found func_wall entity %d\n", mapent - entities);
//if the func wall is used in deathmatch
//if (!(atoi(ValueForKey(mapent, "spawnflags")) & SPAWNFLAG_NOT_DEATHMATCH))
{
//Log_Print("func_wall USED in deathmatch mode %d\n", atoi(ValueForKey(mapent, "spawnflags")));
return true;
} //end if
} //end else if
else if ( !strcmp( "func_door_rotating", ValueForKey( mapent, "classname" ) ) ||
!strcmp( "func_door", ValueForKey( mapent, "classname" ) ) ||
!strcmp( "func_invisible_user", ValueForKey( mapent, "classname" ) ) ) {
//if the func_door_rotating is present in deathmatch
//if (!(atoi(ValueForKey(mapent, "spawnflags")) & SPAWNFLAG_NOT_DEATHMATCH))
{
//if the func_door_rotating is always activated in deathmatch
if ( AAS_AlwaysTriggered( ValueForKey( mapent, "targetname" ) ) ) {
//Log_Print("found func_door_rotating in deathmatch\ntargetname %s\n", ValueForKey(mapent, "targetname"));
return true;
} //end if
} //end if
} //end else if
else if ( !strcmp( "trigger_hurt", ValueForKey( mapent, "classname" ) ) ) {
// RF, spawnflag & 1 is for delayed spawn, so ignore it
if ( atoi( ValueForKey( mapent, "spawnflags" ) ) & 1 ) {
return false;
}
//"dmg" is the damage, for instance: "dmg" "666"
return true;
} //end else if
else if ( !strcmp( "trigger_push", ValueForKey( mapent, "classname" ) ) ) {
return true;
} //end else if
else if ( !strcmp( "trigger_multiple", ValueForKey( mapent, "classname" ) ) ) {
//find out if the trigger_multiple is pointing to a target_teleporter
strcpy( target, ValueForKey( mapent, "target" ) );
for ( i = 0; i < num_entities; i++ )
{
//if the entity will activate the given targetname
if ( !strcmp( target, ValueForKey( &entities[i], "targetname" ) ) ) {
if ( !strcmp( "target_teleporter", ValueForKey( &entities[i], "classname" ) ) ) {
return true;
} //end if
} //end if
} //end for
} //end else if
else if ( !strcmp( "trigger_teleport", ValueForKey( mapent, "classname" ) ) ) {
return true;
} //end else if
else if ( !strcmp( "func_tramcar", ValueForKey( mapent, "classname" ) ) ) {
return true;
} //end else if
else if ( !strcmp( "func_invisible_user", ValueForKey( mapent, "classname" ) ) ) {
return true;
}
/*
else if (!strcmp("func_static", ValueForKey(mapent, "classname")))
{
//FIXME: easy/medium/hard/deathmatch specific?
return true;
} //end else if
*/
return false;
} //end of the function AAS_ValidEntity
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int AAS_TransformPlane( int planenum, vec3_t origin, vec3_t angles ) {
float newdist, matrix[3][3];
vec3_t normal;
//rotate the node plane
VectorCopy( mapplanes[planenum].normal, normal );
CreateRotationMatrix( angles, matrix );
RotatePoint( normal, matrix );
newdist = mapplanes[planenum].dist + DotProduct( normal, origin );
return FindFloatPlane( normal, newdist );
} //end of the function AAS_TransformPlane
//===========================================================================
// this function sets the func_rotating_door in it's final position
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_PositionFuncRotatingBrush( entity_t *mapent, mapbrush_t *brush ) {
int spawnflags, i;
float distance;
vec3_t movedir, angles, pos1, pos2;
side_t *s;
spawnflags = FloatForKey( mapent, "spawnflags" );
VectorClear( movedir );
if ( spawnflags & DOOR_X_AXIS ) {
movedir[2] = 1.0; //roll
} else if ( spawnflags & DOOR_Y_AXIS ) {
movedir[0] = 1.0; //pitch
} else { // Z_AXIS
movedir[1] = 1.0; //yaw
}
// check for reverse rotation
if ( spawnflags & DOOR_REVERSE ) {
VectorInverse( movedir );
}
distance = FloatForKey( mapent, "distance" );
if ( !distance ) {
distance = 90;
}
GetVectorForKey( mapent, "angles", angles );
VectorCopy( angles, pos1 );
VectorMA( angles, -distance, movedir, pos2 );
// if it starts open, switch the positions
if ( spawnflags & DOOR_START_OPEN ) {
VectorCopy( pos2, angles );
VectorCopy( pos1, pos2 );
VectorCopy( angles, pos1 );
VectorInverse( movedir );
} //end if
//
for ( i = 0; i < brush->numsides; i++ )
{
s = &brush->original_sides[i];
s->planenum = AAS_TransformPlane( s->planenum, mapent->origin, pos2 );
} //end for
//
FreeBrushWindings( brush );
AAS_MakeBrushWindings( brush );
AddBrushBevels( brush );
FreeBrushWindings( brush );
} //end of the function AAS_PositionFuncRotatingBrush
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_PositionBrush( entity_t *mapent, mapbrush_t *brush ) {
side_t *s;
float newdist;
int i;
char *model;
if ( !strcmp( ValueForKey( mapent, "classname" ), "func_door_rotating" ) ) {
AAS_PositionFuncRotatingBrush( mapent, brush );
} //end if
else
{
if ( mapent->origin[0] || mapent->origin[1] || mapent->origin[2] ) {
for ( i = 0; i < brush->numsides; i++ )
{
s = &brush->original_sides[i];
newdist = mapplanes[s->planenum].dist +
DotProduct( mapplanes[s->planenum].normal, mapent->origin );
s->planenum = FindFloatPlane( mapplanes[s->planenum].normal, newdist );
} //end for
} //end if
//if it's a trigger hurt
if ( !strcmp( "trigger_hurt", ValueForKey( mapent, "classname" ) ) ) {
//set the lava contents
brush->contents |= CONTENTS_LAVA;
//Log_Print("found trigger_hurt brush\n");
} //end if
//
else if ( !strcmp( "trigger_push", ValueForKey( mapent, "classname" ) ) ) {
//set the jumppad contents
brush->contents = CONTENTS_JUMPPAD;
//Log_Print("found trigger_push brush\n");
} //end if
//
else if ( !strcmp( "trigger_multiple", ValueForKey( mapent, "classname" ) ) ) {
//set teleporter contents
brush->contents = CONTENTS_TELEPORTER;
//Log_Print("found trigger_multiple teleporter brush\n");
} //end if
//
else if ( !strcmp( "trigger_teleport", ValueForKey( mapent, "classname" ) ) ) {
//set teleporter contents
brush->contents = CONTENTS_TELEPORTER;
//Log_Print("found trigger_teleport teleporter brush\n");
} //end if
else if ( !strcmp( "func_door", ValueForKey( mapent, "classname" ) ) ) {
//set mover contents
brush->contents = CONTENTS_MOVER;
//get the model number
model = ValueForKey( mapent, "model" );
brush->modelnum = atoi( model + 1 );
} //end if
else if ( !strcmp( "func_invisible_user", ValueForKey( mapent, "classname" ) ) ) {
//set mover contents
brush->contents = CONTENTS_TRIGGER;
} //end if
} //end else
} //end of the function AAS_PositionBrush
//===========================================================================
// uses the global cfg_t cfg
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_CreateMapBrushes( mapbrush_t *brush, entity_t *mapent, int addbevels ) {
int i;
//side_t *s;
mapbrush_t *bboxbrushes[16];
//if the brushes are not from an entity used for AAS
if ( !AAS_ValidEntity( mapent ) ) {
nummapbrushsides -= brush->numsides;
brush->numsides = 0;
return;
} //end if
//
AAS_PositionBrush( mapent, brush );
//from all normal solid brushes only the textured brush sides will
//be used as bsp splitters, so set the right texinfo reference here
AAS_SetTexinfo( brush );
//remove contents detail flag, otherwise player clip contents won't be
//bsped correctly for AAS!
brush->contents &= ~CONTENTS_DETAIL;
//if the brush has contents area portal it should be the only contents
if ( brush->contents & ( CONTENTS_AREAPORTAL | CONTENTS_CLUSTERPORTAL ) ) {
brush->contents = CONTENTS_CLUSTERPORTAL;
brush->leafnum = -1;
} //end if
//window and playerclip are used for player clipping, make them solid
if ( brush->contents & ( CONTENTS_WINDOW | CONTENTS_PLAYERCLIP ) ) {
//
brush->contents &= ~( CONTENTS_WINDOW | CONTENTS_PLAYERCLIP );
brush->contents |= CONTENTS_SOLID;
brush->leafnum = -1;
} //end if
//
// Rafael TBD: no flag to support CONTENTS_BOTCLIP
/*
if (brush->contents & CONTENTS_BOTCLIP)
{
brush->contents = CONTENTS_SOLID;
brush->leafnum = -1;
} // end if
*/
//
//Log_Write("brush %d contents = ", brush->brushnum);
//PrintContents(brush->contents);
//Log_Write("\r\n");
//if not one of the following brushes then the brush is NOT used for AAS
if ( !( brush->contents & ( CONTENTS_SOLID
| CONTENTS_LADDER
| CONTENTS_CLUSTERPORTAL
| CONTENTS_DONOTENTER
| CONTENTS_DONOTENTER_LARGE
| CONTENTS_TELEPORTER
| CONTENTS_JUMPPAD
| CONTENTS_WATER
| CONTENTS_LAVA
| CONTENTS_SLIME
| CONTENTS_MOVER
) ) ) {
nummapbrushsides -= brush->numsides;
brush->numsides = 0;
return;
} //end if
//fix the map brush
//AAS_FixMapBrush(brush);
//if brush bevels should be added (for real map brushes, not bsp map brushes)
if ( addbevels ) {
//NOTE: we first have to get the mins and maxs of the brush before
// creating the brush bevels... the mins and maxs are used to
// create them. so we call MakeBrushWindings to get the mins
// and maxs and then after creating the bevels we free the
// windings because they are created for all sides (including
// bevels) a little later
AAS_MakeBrushWindings( brush );
AddBrushBevels( brush );
FreeBrushWindings( brush );
} //end if
//NOTE: add the brush to the WORLD entity!!!
mapent = &entities[0];
//there's at least one new brush for now
nummapbrushes++;
mapent->numbrushes++;
//liquid brushes are expanded for the maximum possible bounding box
if ( brush->contents & ( CONTENTS_WATER
| CONTENTS_LAVA
| CONTENTS_SLIME
| CONTENTS_TELEPORTER
| CONTENTS_JUMPPAD
| CONTENTS_DONOTENTER
| CONTENTS_DONOTENTER_LARGE
| CONTENTS_MOVER
) ) {
brush->expansionbbox = 0;
//NOTE: the first bounding box is the max
//FIXME: use max bounding box created from all bboxes
AAS_ExpandMapBrush( brush, cfg.bboxes[0].mins, cfg.bboxes[0].maxs );
AAS_MakeBrushWindings( brush );
} //end if
//area portal brushes are NOT expanded
else if ( brush->contents & CONTENTS_CLUSTERPORTAL ) {
brush->expansionbbox = 0;
//NOTE: the first bounding box is the max
//FIXME: use max bounding box created from all bboxes
AAS_ExpandMapBrush( brush, cfg.bboxes[0].mins, cfg.bboxes[0].maxs );
AAS_MakeBrushWindings( brush );
} //end if
//all solid brushes are expanded for all bounding boxes
else if ( brush->contents & ( CONTENTS_SOLID
| CONTENTS_LADDER
) ) {
//brush for the first bounding box
bboxbrushes[0] = brush;
//make a copy for the other bounding boxes
for ( i = 1; i < cfg.numbboxes; i++ )
{
bboxbrushes[i] = AAS_CopyMapBrush( brush, mapent );
} //end for
//expand every brush for it's bounding box and create windings
for ( i = 0; i < cfg.numbboxes; i++ )
{
AAS_ExpandMapBrush( bboxbrushes[i], cfg.bboxes[i].mins, cfg.bboxes[i].maxs );
bboxbrushes[i]->expansionbbox = cfg.bboxes[i].presencetype;
AAS_MakeBrushWindings( bboxbrushes[i] );
} //end for
} //end else
} //end of the function AAS_CreateMapBrushes

38
src/bspc/aas_map.h Normal file
View File

@@ -0,0 +1,38 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: aas_map.h
// Function:
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1997-12-04
// Tab Size: 3
//===========================================================================
void AAS_CreateMapBrushes( mapbrush_t *brush, entity_t *mapent, int addbevels );

103
src/bspc/aas_prunenodes.c Normal file
View File

@@ -0,0 +1,103 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: aas_prunenodes.c
// Function: Prune Nodes
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1997-12-04
// Tab Size: 3
//===========================================================================
#include "qbsp.h"
#include "..\botlib\aasfile.h"
#include "aas_create.h"
int c_numprunes;
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
tmp_node_t *AAS_PruneNodes_r( tmp_node_t *tmpnode ) {
tmp_area_t *tmparea1, *tmparea2;
//if it is a solid leaf
if ( !tmpnode ) {
return NULL;
}
//
if ( tmpnode->tmparea ) {
return tmpnode;
}
//process the children first
tmpnode->children[0] = AAS_PruneNodes_r( tmpnode->children[0] );
tmpnode->children[1] = AAS_PruneNodes_r( tmpnode->children[1] );
//if both children are areas
if ( tmpnode->children[0] && tmpnode->children[1] &&
tmpnode->children[0]->tmparea && tmpnode->children[1]->tmparea ) {
tmparea1 = tmpnode->children[0]->tmparea;
while ( tmparea1->mergedarea ) tmparea1 = tmparea1->mergedarea;
tmparea2 = tmpnode->children[1]->tmparea;
while ( tmparea2->mergedarea ) tmparea2 = tmparea2->mergedarea;
if ( tmparea1 == tmparea2 ) {
c_numprunes++;
tmpnode->tmparea = tmparea1;
tmpnode->planenum = 0;
AAS_FreeTmpNode( tmpnode->children[0] );
AAS_FreeTmpNode( tmpnode->children[1] );
tmpnode->children[0] = NULL;
tmpnode->children[1] = NULL;
return tmpnode;
} //end if
} //end if
//if both solid leafs
if ( !tmpnode->children[0] && !tmpnode->children[1] ) {
c_numprunes++;
AAS_FreeTmpNode( tmpnode );
return NULL;
} //end if
//
return tmpnode;
} //end of the function AAS_PruneNodes_r
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_PruneNodes( void ) {
Log_Write( "AAS_PruneNodes\r\n" );
AAS_PruneNodes_r( tmpaasworld.nodes );
Log_Print( "%6d nodes pruned\r\n", c_numprunes );
} //end of the function AAS_PruneNodes

39
src/bspc/aas_prunenodes.h Normal file
View File

@@ -0,0 +1,39 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: aas_prunenodes.h
// Function: Prune Nodes
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1997-12-04
// Tab Size: 3
//===========================================================================
void AAS_PruneNodes( void );

1121
src/bspc/aas_store.c Normal file

File diff suppressed because it is too large Load Diff

125
src/bspc/aas_store.h Normal file
View File

@@ -0,0 +1,125 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: aas_store.h
// Function:
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1997-12-04
// Tab Size: 3
//===========================================================================
#define AAS_MAX_BBOXES 5
#define AAS_MAX_VERTEXES 512000
#define AAS_MAX_PLANES 65536
#define AAS_MAX_EDGES 512000
#define AAS_MAX_EDGEINDEXSIZE 512000
#define AAS_MAX_FACES 512000
#define AAS_MAX_FACEINDEXSIZE 512000
#define AAS_MAX_AREAS 65536
#define AAS_MAX_AREASETTINGS 65536
#define AAS_MAX_REACHABILITYSIZE 65536
#define AAS_MAX_NODES 256000
#define AAS_MAX_PORTALS 65536
#define AAS_MAX_PORTALINDEXSIZE 65536
#define AAS_MAX_CLUSTERS 65536
#define BSPCINCLUDE
#include "../botlib/be_aas.h"
#include "../botlib/be_aas_def.h"
/*
typedef struct bspc_aas_s
{
int loaded;
int initialized; //true when AAS has been initialized
int savefile; //set true when file should be saved
//bounding boxes
int numbboxes;
aas_bbox_t *bboxes;
//vertexes
int numvertexes;
aas_vertex_t *vertexes;
//planes
int numplanes;
aas_plane_t *planes;
//edges
int numedges;
aas_edge_t *edges;
//edge index
int edgeindexsize;
aas_edgeindex_t *edgeindex;
//faces
int numfaces;
aas_face_t *faces;
//face index
int faceindexsize;
aas_faceindex_t *faceindex;
//convex areas
int numareas;
aas_area_t *areas;
//convex area settings
int numareasettings;
aas_areasettings_t *areasettings;
//reachablity list
int reachabilitysize;
aas_reachability_t *reachability;
//nodes of the bsp tree
int numnodes;
aas_node_t *nodes;
//cluster portals
int numportals;
aas_portal_t *portals;
//cluster portal index
int portalindexsize;
aas_portalindex_t *portalindex;
//clusters
int numclusters;
aas_cluster_t *clusters;
//
int numreachabilityareas;
float reachabilitytime;
} bspc_aas_t;
extern bspc_aas_t aasworld;
//*/
// Ridah
extern aas_t aasworlds[1];
extern aas_t *aasworld;
// done.
//stores the AAS file from the temporary AAS
void AAS_StoreFile( char *filename );
//returns a number of the given plane
qboolean AAS_FindPlane( vec3_t normal, float dist, int *planenum );
//allocates the maximum AAS memory for storage
void AAS_AllocMaxAAS( void );
//frees the maximum AAS memory for storage
void AAS_FreeMaxAAS( void );

314
src/bspc/be_aas_bspc.c Normal file
View File

@@ -0,0 +1,314 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: b_aas_bspc.c
// Function: Area Awareness System
// Programmer: Mr Elusive (MrElusive@idsoftware.com)
// Last update: 1999-09-14
// Tab Size: 3
//===========================================================================
#include "../game/q_shared.h"
#include "../bspc/l_log.h"
#include "../bspc/l_qfiles.h"
#include "../botlib/l_memory.h"
#include "../botlib/l_script.h"
#include "../botlib/l_precomp.h"
#include "../botlib/l_struct.h"
#include "../botlib/aasfile.h"
#include "../botlib/botlib.h"
#include "../botlib/be_aas.h"
#include "../botlib/be_aas_def.h"
#include "../qcommon/cm_public.h"
//#define BSPC
extern botlib_import_t botimport;
extern qboolean capsule_collision;
//#define AAS_MOVE_DEBUG
botlib_import_t botimport;
clipHandle_t worldmodel;
void Error( char *error, ... );
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_Error( char *fmt, ... ) {
va_list argptr;
char text[1024];
va_start( argptr, fmt );
vsprintf( text, fmt, argptr );
va_end( argptr );
Error( text );
} //end of the function AAS_Error
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int Sys_MilliSeconds( void ) {
return clock() * 1000 / CLOCKS_PER_SEC;
} //end of the function Sys_MilliSeconds
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_DebugLine( vec3_t start, vec3_t end, int color ) {
} //end of the function AAS_DebugLine
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_ClearShownDebugLines( void ) {
} //end of the function AAS_ClearShownDebugLines
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
char *BotImport_BSPEntityData( void ) {
return CM_EntityString();
} //end of the function AAS_GetEntityData
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void BotImport_Trace( bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask ) {
trace_t result;
CM_BoxTrace( &result, start, end, mins, maxs, worldmodel, contentmask, capsule_collision );
bsptrace->allsolid = result.allsolid;
bsptrace->contents = result.contents;
VectorCopy( result.endpos, bsptrace->endpos );
bsptrace->ent = result.entityNum;
bsptrace->fraction = result.fraction;
bsptrace->exp_dist = 0;
bsptrace->plane.dist = result.plane.dist;
VectorCopy( result.plane.normal, bsptrace->plane.normal );
bsptrace->plane.signbits = result.plane.signbits;
bsptrace->plane.type = result.plane.type;
bsptrace->sidenum = 0;
bsptrace->startsolid = result.startsolid;
bsptrace->surface.flags = result.surfaceFlags;
} //end of the function BotImport_Trace
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int BotImport_PointContents( vec3_t p ) {
return CM_PointContents( p, worldmodel );
} //end of the function BotImport_PointContents
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void *BotImport_GetMemory( int size ) {
return GetMemory( size );
} //end of the function BotImport_GetMemory
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void BotImport_Print( int type, char *fmt, ... ) {
va_list argptr;
char buf[1024];
va_start( argptr, fmt );
vsprintf( buf, fmt, argptr );
printf( buf );
if ( buf[0] != '\r' ) {
Log_Write( buf );
}
va_end( argptr );
} //end of the function BotImport_Print
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void BotImport_BSPModelMinsMaxsOrigin( int modelnum, vec3_t angles, vec3_t outmins, vec3_t outmaxs, vec3_t origin ) {
clipHandle_t h;
vec3_t mins, maxs;
float max;
int i;
h = CM_InlineModel( modelnum );
CM_ModelBounds( h, mins, maxs );
//if the model is rotated
if ( ( angles[0] || angles[1] || angles[2] ) ) { // expand for rotation
max = RadiusFromBounds( mins, maxs );
for ( i = 0; i < 3; i++ )
{
mins[i] = ( mins[i] + maxs[i] ) * 0.5 - max;
maxs[i] = ( mins[i] + maxs[i] ) * 0.5 + max;
} //end for
} //end if
if ( outmins ) {
VectorCopy( mins, outmins );
}
if ( outmaxs ) {
VectorCopy( maxs, outmaxs );
}
if ( origin ) {
VectorClear( origin );
}
} //end of the function BotImport_BSPModelMinsMaxsOrigin
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Com_DPrintf( char *fmt, ... ) {
va_list argptr;
char buf[1024];
va_start( argptr, fmt );
vsprintf( buf, fmt, argptr );
printf( buf );
if ( buf[0] != '\r' ) {
Log_Write( buf );
}
va_end( argptr );
} //end of the function Com_DPrintf
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int COM_Compress( char *data_p ) {
return strlen( data_p );
}
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Com_Memset( void* dest, const int val, const size_t count ) {
memset( dest, val, count );
}
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Com_Memcpy( void* dest, const void* src, const size_t count ) {
memcpy( dest, src, count );
}
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_InitBotImport( void ) {
botimport.BSPEntityData = BotImport_BSPEntityData;
botimport.GetMemory = BotImport_GetMemory;
botimport.FreeMemory = FreeMemory;
botimport.Trace = BotImport_Trace;
botimport.PointContents = BotImport_PointContents;
botimport.Print = BotImport_Print;
botimport.BSPModelMinsMaxsOrigin = BotImport_BSPModelMinsMaxsOrigin;
} //end of the function AAS_InitBotImport
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_CalcReachAndClusters( struct quakefile_s *qf ) {
float time;
Log_Print( "loading collision map...\n" );
//
if ( !qf->pakfile[0] ) {
strcpy( qf->pakfile, qf->filename );
}
//load the map
CM_LoadMap( (char *) qf, qfalse, &( *aasworld ).bspchecksum );
//get a handle to the world model
worldmodel = CM_InlineModel( 0 ); // 0 = world, 1 + are bmodels
//initialize bot import structure
AAS_InitBotImport();
//load the BSP entity string
AAS_LoadBSPFile();
//init physics settings
AAS_InitSettings();
//initialize AAS link heap
AAS_InitAASLinkHeap();
//initialize the AAS linked entities for the new map
AAS_InitAASLinkedEntities();
//reset all reachabilities and clusters
( *aasworld ).reachabilitysize = 0;
( *aasworld ).numclusters = 0;
//set all view portals as cluster portals in case we re-calculate the reachabilities and clusters (with -reach)
AAS_SetViewPortalsAsClusterPortals();
//calculate reachabilities
AAS_InitReachability();
time = 0;
while ( AAS_ContinueInitReachability( time ) ) time++;
//calculate clusters
AAS_InitClustering();
} //end of the function AAS_CalcReachAndClusters
// Ridah
void AAS_SetWorldPointer( aas_t *newaasworld ) {
aasworld = newaasworld;
}
// done.

42
src/bspc/be_aas_bspc.h Normal file
View File

@@ -0,0 +1,42 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: b_aas_bspc.h
// Function: Area Awareness System
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1999-02-28
// Tab Size: 3
//===========================================================================
void AAS_CalcReachAndClusters( struct quakefile_s *qf );
// Ridah
void AAS_SetWorldPointer( aas_t *newaasworld );
// done.

1923
src/bspc/brushbsp.c Normal file

File diff suppressed because it is too large Load Diff

1101
src/bspc/bspc.c Normal file

File diff suppressed because it is too large Load Diff

1053
src/bspc/csg.c Normal file

File diff suppressed because it is too large Load Diff

1002
src/bspc/faces.c Normal file

File diff suppressed because it is too large Load Diff

157
src/bspc/glfile.c Normal file
View File

@@ -0,0 +1,157 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "qbsp.h"
int c_glfaces;
int PortalVisibleSides( portal_t *p ) {
int fcon, bcon;
if ( !p->onnode ) {
return 0; // outside
}
fcon = p->nodes[0]->contents;
bcon = p->nodes[1]->contents;
// same contents never create a face
if ( fcon == bcon ) {
return 0;
}
// FIXME: is this correct now?
if ( !fcon ) {
return 1;
}
if ( !bcon ) {
return 2;
}
return 0;
}
void OutputWinding( winding_t *w, FILE *glview ) {
static int level = 128;
vec_t light;
int i;
fprintf( glview, "%i\n", w->numpoints );
level += 28;
light = ( level & 255 ) / 255.0;
for ( i = 0 ; i < w->numpoints ; i++ )
{
fprintf( glview, "%6.3f %6.3f %6.3f %6.3f %6.3f %6.3f\n",
w->p[i][0],
w->p[i][1],
w->p[i][2],
light,
light,
light );
}
fprintf( glview, "\n" );
}
/*
=============
OutputPortal
=============
*/
void OutputPortal( portal_t *p, FILE *glview ) {
winding_t *w;
int sides;
sides = PortalVisibleSides( p );
if ( !sides ) {
return;
}
c_glfaces++;
w = p->winding;
if ( sides == 2 ) { // back side
w = ReverseWinding( w );
}
OutputWinding( w, glview );
if ( sides == 2 ) {
FreeWinding( w );
}
}
/*
=============
WriteGLView_r
=============
*/
void WriteGLView_r( node_t *node, FILE *glview ) {
portal_t *p, *nextp;
if ( node->planenum != PLANENUM_LEAF ) {
WriteGLView_r( node->children[0], glview );
WriteGLView_r( node->children[1], glview );
return;
}
// write all the portals
for ( p = node->portals ; p ; p = nextp )
{
if ( p->nodes[0] == node ) {
OutputPortal( p, glview );
nextp = p->next[0];
} else {
nextp = p->next[1];
}
}
}
/*
=============
WriteGLView
=============
*/
void WriteGLView( tree_t *tree, char *source ) {
char name[1024];
FILE *glview;
c_glfaces = 0;
sprintf( name, "%s%s.gl",outbase, source );
printf( "Writing %s\n", name );
glview = fopen( name, "w" );
if ( !glview ) {
Error( "Couldn't open %s", name );
}
WriteGLView_r( tree->headnode, glview );
fclose( glview );
printf( "%5i c_glfaces\n", c_glfaces );
}

195
src/bspc/l_bsp_ent.c Normal file
View File

@@ -0,0 +1,195 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: l_bsp_ent.c
// Function: bsp entity parsing
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1999-04-05
// Tab Size: 3
// Notes: -
//===========================================================================
#include "l_cmd.h"
#include "l_math.h"
#include "l_mem.h"
#include "l_log.h"
#include "../botlib/l_script.h"
#include "l_bsp_ent.h"
#define MAX_KEY 32
#define MAX_VALUE 1024
int num_entities;
entity_t entities[MAX_MAP_ENTITIES];
void StripTrailing( char *e ) {
char *s;
s = e + strlen( e ) - 1;
while ( s >= e && *s <= 32 )
{
*s = 0;
s--;
}
}
/*
=================
ParseEpair
=================
*/
epair_t *ParseEpair( script_t *script ) {
epair_t *e;
token_t token;
e = GetMemory( sizeof( epair_t ) );
memset( e, 0, sizeof( epair_t ) );
PS_ExpectAnyToken( script, &token );
StripDoubleQuotes( token.string );
if ( strlen( token.string ) >= MAX_KEY - 1 ) {
Error( "ParseEpair: token %s too long", token.string );
}
e->key = copystring( token.string );
PS_ExpectAnyToken( script, &token );
StripDoubleQuotes( token.string );
if ( strlen( token.string ) >= MAX_VALUE - 1 ) {
Error( "ParseEpair: token %s too long", token.string );
}
e->value = copystring( token.string );
// strip trailing spaces
StripTrailing( e->key );
StripTrailing( e->value );
return e;
} //end of the function ParseEpair
/*
================
ParseEntity
================
*/
qboolean ParseEntity( script_t *script ) {
epair_t *e;
entity_t *mapent;
token_t token;
if ( !PS_ReadToken( script, &token ) ) {
return false;
}
if ( strcmp( token.string, "{" ) ) {
Error( "ParseEntity: { not found" );
}
if ( num_entities == MAX_MAP_ENTITIES ) {
Error( "num_entities == MAX_MAP_ENTITIES" );
}
mapent = &entities[num_entities];
num_entities++;
do
{
if ( !PS_ReadToken( script, &token ) ) {
Error( "ParseEntity: EOF without closing brace" );
}
if ( !strcmp( token.string, "}" ) ) {
break;
}
PS_UnreadLastToken( script );
e = ParseEpair( script );
e->next = mapent->epairs;
mapent->epairs = e;
} while ( 1 );
return true;
} //end of the function ParseEntity
void PrintEntity( entity_t *ent ) {
epair_t *ep;
printf( "------- entity %p -------\n", ent );
for ( ep = ent->epairs ; ep ; ep = ep->next )
{
printf( "%s = %s\n", ep->key, ep->value );
}
}
void SetKeyValue( entity_t *ent, char *key, char *value ) {
epair_t *ep;
for ( ep = ent->epairs ; ep ; ep = ep->next )
if ( !strcmp( ep->key, key ) ) {
FreeMemory( ep->value );
ep->value = copystring( value );
return;
}
ep = GetMemory( sizeof( *ep ) );
ep->next = ent->epairs;
ent->epairs = ep;
ep->key = copystring( key );
ep->value = copystring( value );
}
char *ValueForKey( entity_t *ent, char *key ) {
epair_t *ep;
for ( ep = ent->epairs ; ep ; ep = ep->next )
if ( !strcmp( ep->key, key ) ) {
return ep->value;
}
return "";
}
vec_t FloatForKey( entity_t *ent, char *key ) {
char *k;
k = ValueForKey( ent, key );
return atof( k );
}
void GetVectorForKey( entity_t *ent, char *key, vec3_t vec ) {
char *k;
double v1, v2, v3;
k = ValueForKey( ent, key );
// scanf into doubles, then assign, so it is vec_t size independent
v1 = v2 = v3 = 0;
sscanf( k, "%lf %lf %lf", &v1, &v2, &v3 );
vec[0] = v1;
vec[1] = v2;
vec[2] = v3;
}

65
src/bspc/l_bsp_ent.h Normal file
View File

@@ -0,0 +1,65 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#ifndef MAX_MAP_ENTITIES
#define MAX_MAP_ENTITIES 2048
#endif
typedef struct epair_s
{
struct epair_s *next;
char *key;
char *value;
} epair_t;
typedef struct
{
vec3_t origin;
int firstbrush;
int numbrushes;
epair_t *epairs;
// only valid for func_areaportals
int areaportalnum;
int portalareas[2];
int modelnum; //for bsp 2 map conversion
qboolean wasdetail; //for SIN
} entity_t;
extern int num_entities;
extern entity_t entities[MAX_MAP_ENTITIES];
void StripTrailing( char *e );
void SetKeyValue( entity_t *ent, char *key, char *value );
char *ValueForKey( entity_t *ent, char *key ); // will return "" if not present
vec_t FloatForKey( entity_t *ent, char *key );
void GetVectorForKey( entity_t *ent, char *key, vec3_t vec );
qboolean ParseEntity( script_t *script );
epair_t *ParseEpair( script_t *script );
void PrintEntity( entity_t *ent );

608
src/bspc/l_bsp_q1.c Normal file
View File

@@ -0,0 +1,608 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "l_cmd.h"
#include "l_math.h"
#include "l_mem.h"
#include "l_log.h"
#include "../botlib/l_script.h"
#include "l_bsp_q1.h"
#include "l_bsp_ent.h"
//=============================================================================
int q1_nummodels;
q1_dmodel_t *q1_dmodels; //[MAX_MAP_MODELS];
int q1_visdatasize;
byte *q1_dvisdata; //[MAX_MAP_VISIBILITY];
int q1_lightdatasize;
byte *q1_dlightdata; //[MAX_MAP_LIGHTING];
int q1_texdatasize;
byte *q1_dtexdata; //[MAX_MAP_MIPTEX]; // (dmiptexlump_t)
int q1_entdatasize;
char *q1_dentdata; //[MAX_MAP_ENTSTRING];
int q1_numleafs;
q1_dleaf_t *q1_dleafs; //[MAX_MAP_LEAFS];
int q1_numplanes;
q1_dplane_t *q1_dplanes; //[MAX_MAP_PLANES];
int q1_numvertexes;
q1_dvertex_t *q1_dvertexes; //[MAX_MAP_VERTS];
int q1_numnodes;
q1_dnode_t *q1_dnodes; //[MAX_MAP_NODES];
int q1_numtexinfo;
q1_texinfo_t *q1_texinfo; //[MAX_MAP_TEXINFO];
int q1_numfaces;
q1_dface_t *q1_dfaces; //[MAX_MAP_FACES];
int q1_numclipnodes;
q1_dclipnode_t *q1_dclipnodes; //[MAX_MAP_CLIPNODES];
int q1_numedges;
q1_dedge_t *q1_dedges; //[MAX_MAP_EDGES];
int q1_nummarksurfaces;
unsigned short *q1_dmarksurfaces; //[MAX_MAP_MARKSURFACES];
int q1_numsurfedges;
int *q1_dsurfedges; //[MAX_MAP_SURFEDGES];
//=============================================================================
int q1_bspallocated = false;
int q1_allocatedbspmem = 0;
void Q1_AllocMaxBSP( void ) {
//models
q1_nummodels = 0;
q1_dmodels = (q1_dmodel_t *) GetMemory( Q1_MAX_MAP_MODELS * sizeof( q1_dmodel_t ) );
q1_allocatedbspmem = Q1_MAX_MAP_MODELS * sizeof( q1_dmodel_t );
//visibility
q1_visdatasize = 0;
q1_dvisdata = (byte *) GetMemory( Q1_MAX_MAP_VISIBILITY * sizeof( byte ) );
q1_allocatedbspmem += Q1_MAX_MAP_VISIBILITY * sizeof( byte );
//light data
q1_lightdatasize = 0;
q1_dlightdata = (byte *) GetMemory( Q1_MAX_MAP_LIGHTING * sizeof( byte ) );
q1_allocatedbspmem += Q1_MAX_MAP_LIGHTING * sizeof( byte );
//texture data
q1_texdatasize = 0;
q1_dtexdata = (byte *) GetMemory( Q1_MAX_MAP_MIPTEX * sizeof( byte ) ); // (dmiptexlump_t)
q1_allocatedbspmem += Q1_MAX_MAP_MIPTEX * sizeof( byte );
//entities
q1_entdatasize = 0;
q1_dentdata = (char *) GetMemory( Q1_MAX_MAP_ENTSTRING * sizeof( char ) );
q1_allocatedbspmem += Q1_MAX_MAP_ENTSTRING * sizeof( char );
//leaves
q1_numleafs = 0;
q1_dleafs = (q1_dleaf_t *) GetMemory( Q1_MAX_MAP_LEAFS * sizeof( q1_dleaf_t ) );
q1_allocatedbspmem += Q1_MAX_MAP_LEAFS * sizeof( q1_dleaf_t );
//planes
q1_numplanes = 0;
q1_dplanes = (q1_dplane_t *) GetMemory( Q1_MAX_MAP_PLANES * sizeof( q1_dplane_t ) );
q1_allocatedbspmem += Q1_MAX_MAP_PLANES * sizeof( q1_dplane_t );
//vertexes
q1_numvertexes = 0;
q1_dvertexes = (q1_dvertex_t *) GetMemory( Q1_MAX_MAP_VERTS * sizeof( q1_dvertex_t ) );
q1_allocatedbspmem += Q1_MAX_MAP_VERTS * sizeof( q1_dvertex_t );
//nodes
q1_numnodes = 0;
q1_dnodes = (q1_dnode_t *) GetMemory( Q1_MAX_MAP_NODES * sizeof( q1_dnode_t ) );
q1_allocatedbspmem += Q1_MAX_MAP_NODES * sizeof( q1_dnode_t );
//texture info
q1_numtexinfo = 0;
q1_texinfo = (q1_texinfo_t *) GetMemory( Q1_MAX_MAP_TEXINFO * sizeof( q1_texinfo_t ) );
q1_allocatedbspmem += Q1_MAX_MAP_TEXINFO * sizeof( q1_texinfo_t );
//faces
q1_numfaces = 0;
q1_dfaces = (q1_dface_t *) GetMemory( Q1_MAX_MAP_FACES * sizeof( q1_dface_t ) );
q1_allocatedbspmem += Q1_MAX_MAP_FACES * sizeof( q1_dface_t );
//clip nodes
q1_numclipnodes = 0;
q1_dclipnodes = (q1_dclipnode_t *) GetMemory( Q1_MAX_MAP_CLIPNODES * sizeof( q1_dclipnode_t ) );
q1_allocatedbspmem += Q1_MAX_MAP_CLIPNODES * sizeof( q1_dclipnode_t );
//edges
q1_numedges = 0;
q1_dedges = (q1_dedge_t *) GetMemory( Q1_MAX_MAP_EDGES * sizeof( q1_dedge_t ) );
q1_allocatedbspmem += Q1_MAX_MAP_EDGES, sizeof( q1_dedge_t );
//mark surfaces
q1_nummarksurfaces = 0;
q1_dmarksurfaces = (unsigned short *) GetMemory( Q1_MAX_MAP_MARKSURFACES * sizeof( unsigned short ) );
q1_allocatedbspmem += Q1_MAX_MAP_MARKSURFACES * sizeof( unsigned short );
//surface edges
q1_numsurfedges = 0;
q1_dsurfedges = (int *) GetMemory( Q1_MAX_MAP_SURFEDGES * sizeof( int ) );
q1_allocatedbspmem += Q1_MAX_MAP_SURFEDGES * sizeof( int );
//print allocated memory
Log_Print( "allocated " );
PrintMemorySize( q1_allocatedbspmem );
Log_Print( " of BSP memory\n" );
} //end of the function Q1_AllocMaxBSP
void Q1_FreeMaxBSP( void ) {
//models
q1_nummodels = 0;
FreeMemory( q1_dmodels );
q1_dmodels = NULL;
//visibility
q1_visdatasize = 0;
FreeMemory( q1_dvisdata );
q1_dvisdata = NULL;
//light data
q1_lightdatasize = 0;
FreeMemory( q1_dlightdata );
q1_dlightdata = NULL;
//texture data
q1_texdatasize = 0;
FreeMemory( q1_dtexdata );
q1_dtexdata = NULL;
//entities
q1_entdatasize = 0;
FreeMemory( q1_dentdata );
q1_dentdata = NULL;
//leaves
q1_numleafs = 0;
FreeMemory( q1_dleafs );
q1_dleafs = NULL;
//planes
q1_numplanes = 0;
FreeMemory( q1_dplanes );
q1_dplanes = NULL;
//vertexes
q1_numvertexes = 0;
FreeMemory( q1_dvertexes );
q1_dvertexes = NULL;
//nodes
q1_numnodes = 0;
FreeMemory( q1_dnodes );
q1_dnodes = NULL;
//texture info
q1_numtexinfo = 0;
FreeMemory( q1_texinfo );
q1_texinfo = NULL;
//faces
q1_numfaces = 0;
FreeMemory( q1_dfaces );
q1_dfaces = NULL;
//clip nodes
q1_numclipnodes = 0;
FreeMemory( q1_dclipnodes );
q1_dclipnodes = NULL;
//edges
q1_numedges = 0;
FreeMemory( q1_dedges );
q1_dedges = NULL;
//mark surfaces
q1_nummarksurfaces = 0;
FreeMemory( q1_dmarksurfaces );
q1_dmarksurfaces = NULL;
//surface edges
q1_numsurfedges = 0;
FreeMemory( q1_dsurfedges );
q1_dsurfedges = NULL;
//
Log_Print( "freed " );
PrintMemorySize( q1_allocatedbspmem );
Log_Print( " of BSP memory\n" );
q1_allocatedbspmem = 0;
} //end of the function Q1_FreeMaxBSP
//#endif //ME
/*
=============
Q1_SwapBSPFile
Byte swaps all data in a bsp file.
=============
*/
void Q1_SwapBSPFile( qboolean todisk ) {
int i, j, c;
q1_dmodel_t *d;
q1_dmiptexlump_t *mtl;
// models
for ( i = 0 ; i < q1_nummodels ; i++ )
{
d = &q1_dmodels[i];
for ( j = 0 ; j < Q1_MAX_MAP_HULLS ; j++ )
d->headnode[j] = LittleLong( d->headnode[j] );
d->visleafs = LittleLong( d->visleafs );
d->firstface = LittleLong( d->firstface );
d->numfaces = LittleLong( d->numfaces );
for ( j = 0 ; j < 3 ; j++ )
{
d->mins[j] = LittleFloat( d->mins[j] );
d->maxs[j] = LittleFloat( d->maxs[j] );
d->origin[j] = LittleFloat( d->origin[j] );
}
}
//
// vertexes
//
for ( i = 0 ; i < q1_numvertexes ; i++ )
{
for ( j = 0 ; j < 3 ; j++ )
q1_dvertexes[i].point[j] = LittleFloat( q1_dvertexes[i].point[j] );
}
//
// planes
//
for ( i = 0 ; i < q1_numplanes ; i++ )
{
for ( j = 0 ; j < 3 ; j++ )
q1_dplanes[i].normal[j] = LittleFloat( q1_dplanes[i].normal[j] );
q1_dplanes[i].dist = LittleFloat( q1_dplanes[i].dist );
q1_dplanes[i].type = LittleLong( q1_dplanes[i].type );
}
//
// texinfos
//
for ( i = 0 ; i < q1_numtexinfo ; i++ )
{
for ( j = 0 ; j < 8 ; j++ )
q1_texinfo[i].vecs[0][j] = LittleFloat( q1_texinfo[i].vecs[0][j] );
q1_texinfo[i].miptex = LittleLong( q1_texinfo[i].miptex );
q1_texinfo[i].flags = LittleLong( q1_texinfo[i].flags );
}
//
// faces
//
for ( i = 0 ; i < q1_numfaces ; i++ )
{
q1_dfaces[i].texinfo = LittleShort( q1_dfaces[i].texinfo );
q1_dfaces[i].planenum = LittleShort( q1_dfaces[i].planenum );
q1_dfaces[i].side = LittleShort( q1_dfaces[i].side );
q1_dfaces[i].lightofs = LittleLong( q1_dfaces[i].lightofs );
q1_dfaces[i].firstedge = LittleLong( q1_dfaces[i].firstedge );
q1_dfaces[i].numedges = LittleShort( q1_dfaces[i].numedges );
}
//
// nodes
//
for ( i = 0 ; i < q1_numnodes ; i++ )
{
q1_dnodes[i].planenum = LittleLong( q1_dnodes[i].planenum );
for ( j = 0 ; j < 3 ; j++ )
{
q1_dnodes[i].mins[j] = LittleShort( q1_dnodes[i].mins[j] );
q1_dnodes[i].maxs[j] = LittleShort( q1_dnodes[i].maxs[j] );
}
q1_dnodes[i].children[0] = LittleShort( q1_dnodes[i].children[0] );
q1_dnodes[i].children[1] = LittleShort( q1_dnodes[i].children[1] );
q1_dnodes[i].firstface = LittleShort( q1_dnodes[i].firstface );
q1_dnodes[i].numfaces = LittleShort( q1_dnodes[i].numfaces );
}
//
// leafs
//
for ( i = 0 ; i < q1_numleafs ; i++ )
{
q1_dleafs[i].contents = LittleLong( q1_dleafs[i].contents );
for ( j = 0 ; j < 3 ; j++ )
{
q1_dleafs[i].mins[j] = LittleShort( q1_dleafs[i].mins[j] );
q1_dleafs[i].maxs[j] = LittleShort( q1_dleafs[i].maxs[j] );
}
q1_dleafs[i].firstmarksurface = LittleShort( q1_dleafs[i].firstmarksurface );
q1_dleafs[i].nummarksurfaces = LittleShort( q1_dleafs[i].nummarksurfaces );
q1_dleafs[i].visofs = LittleLong( q1_dleafs[i].visofs );
}
//
// clipnodes
//
for ( i = 0 ; i < q1_numclipnodes ; i++ )
{
q1_dclipnodes[i].planenum = LittleLong( q1_dclipnodes[i].planenum );
q1_dclipnodes[i].children[0] = LittleShort( q1_dclipnodes[i].children[0] );
q1_dclipnodes[i].children[1] = LittleShort( q1_dclipnodes[i].children[1] );
}
//
// miptex
//
if ( q1_texdatasize ) {
mtl = (q1_dmiptexlump_t *)q1_dtexdata;
if ( todisk ) {
c = mtl->nummiptex;
} else {
c = LittleLong( mtl->nummiptex );
}
mtl->nummiptex = LittleLong( mtl->nummiptex );
for ( i = 0 ; i < c ; i++ )
mtl->dataofs[i] = LittleLong( mtl->dataofs[i] );
}
//
// marksurfaces
//
for ( i = 0 ; i < q1_nummarksurfaces ; i++ )
q1_dmarksurfaces[i] = LittleShort( q1_dmarksurfaces[i] );
//
// surfedges
//
for ( i = 0 ; i < q1_numsurfedges ; i++ )
q1_dsurfedges[i] = LittleLong( q1_dsurfedges[i] );
//
// edges
//
for ( i = 0 ; i < q1_numedges ; i++ )
{
q1_dedges[i].v[0] = LittleShort( q1_dedges[i].v[0] );
q1_dedges[i].v[1] = LittleShort( q1_dedges[i].v[1] );
}
}
q1_dheader_t *q1_header;
int Q1_CopyLump( int lump, void *dest, int size ) {
int length, ofs;
length = q1_header->lumps[lump].filelen;
ofs = q1_header->lumps[lump].fileofs;
if ( length % size ) {
Error( "Q1_LoadBSPFile: odd lump size" );
}
memcpy( dest, (byte *)q1_header + ofs, length );
return length / size;
}
/*
=============
Q1_LoadBSPFile
=============
*/
void Q1_LoadBSPFile( char *filename, int offset, int length ) {
int i;
//
// load the file header
//
LoadFile( filename, (void **)&q1_header, offset, length );
// swap the header
for ( i = 0 ; i < sizeof( q1_dheader_t ) / 4 ; i++ )
( (int *)q1_header )[i] = LittleLong( ( (int *)q1_header )[i] );
if ( q1_header->version != Q1_BSPVERSION ) {
Error( "%s is version %i, not %i", filename, i, Q1_BSPVERSION );
}
q1_nummodels = Q1_CopyLump( Q1_LUMP_MODELS, q1_dmodels, sizeof( q1_dmodel_t ) );
q1_numvertexes = Q1_CopyLump( Q1_LUMP_VERTEXES, q1_dvertexes, sizeof( q1_dvertex_t ) );
q1_numplanes = Q1_CopyLump( Q1_LUMP_PLANES, q1_dplanes, sizeof( q1_dplane_t ) );
q1_numleafs = Q1_CopyLump( Q1_LUMP_LEAFS, q1_dleafs, sizeof( q1_dleaf_t ) );
q1_numnodes = Q1_CopyLump( Q1_LUMP_NODES, q1_dnodes, sizeof( q1_dnode_t ) );
q1_numtexinfo = Q1_CopyLump( Q1_LUMP_TEXINFO, q1_texinfo, sizeof( q1_texinfo_t ) );
q1_numclipnodes = Q1_CopyLump( Q1_LUMP_CLIPNODES, q1_dclipnodes, sizeof( q1_dclipnode_t ) );
q1_numfaces = Q1_CopyLump( Q1_LUMP_FACES, q1_dfaces, sizeof( q1_dface_t ) );
q1_nummarksurfaces = Q1_CopyLump( Q1_LUMP_MARKSURFACES, q1_dmarksurfaces, sizeof( q1_dmarksurfaces[0] ) );
q1_numsurfedges = Q1_CopyLump( Q1_LUMP_SURFEDGES, q1_dsurfedges, sizeof( q1_dsurfedges[0] ) );
q1_numedges = Q1_CopyLump( Q1_LUMP_EDGES, q1_dedges, sizeof( q1_dedge_t ) );
q1_texdatasize = Q1_CopyLump( Q1_LUMP_TEXTURES, q1_dtexdata, 1 );
q1_visdatasize = Q1_CopyLump( Q1_LUMP_VISIBILITY, q1_dvisdata, 1 );
q1_lightdatasize = Q1_CopyLump( Q1_LUMP_LIGHTING, q1_dlightdata, 1 );
q1_entdatasize = Q1_CopyLump( Q1_LUMP_ENTITIES, q1_dentdata, 1 );
FreeMemory( q1_header ); // everything has been copied out
//
// swap everything
//
Q1_SwapBSPFile( false );
}
//============================================================================
FILE *q1_wadfile;
q1_dheader_t q1_outheader;
void Q1_AddLump( int lumpnum, void *data, int len ) {
q1_lump_t *lump;
lump = &q1_header->lumps[lumpnum];
lump->fileofs = LittleLong( ftell( q1_wadfile ) );
lump->filelen = LittleLong( len );
SafeWrite( q1_wadfile, data, ( len + 3 ) & ~3 );
}
/*
=============
Q1_WriteBSPFile
Swaps the bsp file in place, so it should not be referenced again
=============
*/
void Q1_WriteBSPFile( char *filename ) {
q1_header = &q1_outheader;
memset( q1_header, 0, sizeof( q1_dheader_t ) );
Q1_SwapBSPFile( true );
q1_header->version = LittleLong( Q1_BSPVERSION );
q1_wadfile = SafeOpenWrite( filename );
SafeWrite( q1_wadfile, q1_header, sizeof( q1_dheader_t ) ); // overwritten later
Q1_AddLump( Q1_LUMP_PLANES, q1_dplanes, q1_numplanes * sizeof( q1_dplane_t ) );
Q1_AddLump( Q1_LUMP_LEAFS, q1_dleafs, q1_numleafs * sizeof( q1_dleaf_t ) );
Q1_AddLump( Q1_LUMP_VERTEXES, q1_dvertexes, q1_numvertexes * sizeof( q1_dvertex_t ) );
Q1_AddLump( Q1_LUMP_NODES, q1_dnodes, q1_numnodes * sizeof( q1_dnode_t ) );
Q1_AddLump( Q1_LUMP_TEXINFO, q1_texinfo, q1_numtexinfo * sizeof( q1_texinfo_t ) );
Q1_AddLump( Q1_LUMP_FACES, q1_dfaces, q1_numfaces * sizeof( q1_dface_t ) );
Q1_AddLump( Q1_LUMP_CLIPNODES, q1_dclipnodes, q1_numclipnodes * sizeof( q1_dclipnode_t ) );
Q1_AddLump( Q1_LUMP_MARKSURFACES, q1_dmarksurfaces, q1_nummarksurfaces * sizeof( q1_dmarksurfaces[0] ) );
Q1_AddLump( Q1_LUMP_SURFEDGES, q1_dsurfedges, q1_numsurfedges * sizeof( q1_dsurfedges[0] ) );
Q1_AddLump( Q1_LUMP_EDGES, q1_dedges, q1_numedges * sizeof( q1_dedge_t ) );
Q1_AddLump( Q1_LUMP_MODELS, q1_dmodels, q1_nummodels * sizeof( q1_dmodel_t ) );
Q1_AddLump( Q1_LUMP_LIGHTING, q1_dlightdata, q1_lightdatasize );
Q1_AddLump( Q1_LUMP_VISIBILITY, q1_dvisdata, q1_visdatasize );
Q1_AddLump( Q1_LUMP_ENTITIES, q1_dentdata, q1_entdatasize );
Q1_AddLump( Q1_LUMP_TEXTURES, q1_dtexdata, q1_texdatasize );
fseek( q1_wadfile, 0, SEEK_SET );
SafeWrite( q1_wadfile, q1_header, sizeof( q1_dheader_t ) );
fclose( q1_wadfile );
}
//============================================================================
/*
=============
Q1_PrintBSPFileSizes
Dumps info about current file
=============
*/
void Q1_PrintBSPFileSizes( void ) {
printf( "%5i planes %6i\n"
,q1_numplanes, (int)( q1_numplanes * sizeof( q1_dplane_t ) ) );
printf( "%5i vertexes %6i\n"
,q1_numvertexes, (int)( q1_numvertexes * sizeof( q1_dvertex_t ) ) );
printf( "%5i nodes %6i\n"
,q1_numnodes, (int)( q1_numnodes * sizeof( q1_dnode_t ) ) );
printf( "%5i texinfo %6i\n"
,q1_numtexinfo, (int)( q1_numtexinfo * sizeof( q1_texinfo_t ) ) );
printf( "%5i faces %6i\n"
,q1_numfaces, (int)( q1_numfaces * sizeof( q1_dface_t ) ) );
printf( "%5i clipnodes %6i\n"
,q1_numclipnodes, (int)( q1_numclipnodes * sizeof( q1_dclipnode_t ) ) );
printf( "%5i leafs %6i\n"
,q1_numleafs, (int)( q1_numleafs * sizeof( q1_dleaf_t ) ) );
printf( "%5i marksurfaces %6i\n"
,q1_nummarksurfaces, (int)( q1_nummarksurfaces * sizeof( q1_dmarksurfaces[0] ) ) );
printf( "%5i surfedges %6i\n"
,q1_numsurfedges, (int)( q1_numsurfedges * sizeof( q1_dmarksurfaces[0] ) ) );
printf( "%5i edges %6i\n"
,q1_numedges, (int)( q1_numedges * sizeof( q1_dedge_t ) ) );
if ( !q1_texdatasize ) {
printf( " 0 textures 0\n" );
} else {
printf( "%5i textures %6i\n",( (q1_dmiptexlump_t*)q1_dtexdata )->nummiptex, q1_texdatasize );
}
printf( " lightdata %6i\n", q1_lightdatasize );
printf( " visdata %6i\n", q1_visdatasize );
printf( " entdata %6i\n", q1_entdatasize );
} //end of the function Q1_PrintBSPFileSizes
/*
================
Q1_ParseEntities
Parses the dentdata string into entities
================
*/
void Q1_ParseEntities( void ) {
script_t *script;
num_entities = 0;
script = LoadScriptMemory( q1_dentdata, q1_entdatasize, "*Quake1 bsp file" );
SetScriptFlags( script, SCFL_NOSTRINGWHITESPACES |
SCFL_NOSTRINGESCAPECHARS );
while ( ParseEntity( script ) )
{
} //end while
FreeScript( script );
} //end of the function Q1_ParseEntities
/*
================
Q1_UnparseEntities
Generates the dentdata string from all the entities
================
*/
void Q1_UnparseEntities( void ) {
char *buf, *end;
epair_t *ep;
char line[2048];
int i;
buf = q1_dentdata;
end = buf;
*end = 0;
for ( i = 0 ; i < num_entities ; i++ )
{
ep = entities[i].epairs;
if ( !ep ) {
continue; // ent got removed
}
strcat( end,"{\n" );
end += 2;
for ( ep = entities[i].epairs ; ep ; ep = ep->next )
{
sprintf( line, "\"%s\" \"%s\"\n", ep->key, ep->value );
strcat( end, line );
end += strlen( line );
}
strcat( end,"}\n" );
end += 2;
if ( end > buf + Q1_MAX_MAP_ENTSTRING ) {
Error( "Entity text too long" );
}
}
q1_entdatasize = end - buf + 1;
} //end of the function Q1_UnparseEntities

282
src/bspc/l_bsp_q1.h Normal file
View File

@@ -0,0 +1,282 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
// upper design bounds
#define Q1_MAX_MAP_HULLS 4
#define Q1_MAX_MAP_MODELS 256
#define Q1_MAX_MAP_BRUSHES 4096
#define Q1_MAX_MAP_ENTITIES 1024
#define Q1_MAX_MAP_ENTSTRING 65536
#define Q1_MAX_MAP_PLANES 8192
#define Q1_MAX_MAP_NODES 32767 // because negative shorts are contents
#define Q1_MAX_MAP_CLIPNODES 32767 //
#define Q1_MAX_MAP_LEAFS 32767 //
#define Q1_MAX_MAP_VERTS 65535
#define Q1_MAX_MAP_FACES 65535
#define Q1_MAX_MAP_MARKSURFACES 65535
#define Q1_MAX_MAP_TEXINFO 4096
#define Q1_MAX_MAP_EDGES 256000
#define Q1_MAX_MAP_SURFEDGES 512000
#define Q1_MAX_MAP_MIPTEX 0x200000
#define Q1_MAX_MAP_LIGHTING 0x100000
#define Q1_MAX_MAP_VISIBILITY 0x100000
// key / value pair sizes
#define MAX_KEY 32
#define MAX_VALUE 1024
//=============================================================================
#define Q1_BSPVERSION 29
typedef struct
{
int fileofs, filelen;
} q1_lump_t;
#define Q1_LUMP_ENTITIES 0
#define Q1_LUMP_PLANES 1
#define Q1_LUMP_TEXTURES 2
#define Q1_LUMP_VERTEXES 3
#define Q1_LUMP_VISIBILITY 4
#define Q1_LUMP_NODES 5
#define Q1_LUMP_TEXINFO 6
#define Q1_LUMP_FACES 7
#define Q1_LUMP_LIGHTING 8
#define Q1_LUMP_CLIPNODES 9
#define Q1_LUMP_LEAFS 10
#define Q1_LUMP_MARKSURFACES 11
#define Q1_LUMP_EDGES 12
#define Q1_LUMP_SURFEDGES 13
#define Q1_LUMP_MODELS 14
#define Q1_HEADER_LUMPS 15
typedef struct
{
float mins[3], maxs[3];
float origin[3];
int headnode[Q1_MAX_MAP_HULLS];
int visleafs; // not including the solid leaf 0
int firstface, numfaces;
} q1_dmodel_t;
typedef struct
{
int version;
q1_lump_t lumps[Q1_HEADER_LUMPS];
} q1_dheader_t;
typedef struct
{
int nummiptex;
int dataofs[4]; // [nummiptex]
} q1_dmiptexlump_t;
#define MIPLEVELS 4
typedef struct q1_miptex_s
{
char name[16];
unsigned width, height;
unsigned offsets[MIPLEVELS]; // four mip maps stored
} q1_miptex_t;
typedef struct
{
float point[3];
} q1_dvertex_t;
// 0-2 are axial planes
#define PLANE_X 0
#define PLANE_Y 1
#define PLANE_Z 2
// 3-5 are non-axial planes snapped to the nearest
#define PLANE_ANYX 3
#define PLANE_ANYY 4
#define PLANE_ANYZ 5
typedef struct
{
float normal[3];
float dist;
int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
} q1_dplane_t;
#define Q1_CONTENTS_EMPTY -1
#define Q1_CONTENTS_SOLID -2
#define Q1_CONTENTS_WATER -3
#define Q1_CONTENTS_SLIME -4
#define Q1_CONTENTS_LAVA -5
#define Q1_CONTENTS_SKY -6
// !!! if this is changed, it must be changed in asm_i386.h too !!!
typedef struct
{
int planenum;
short children[2]; // negative numbers are -(leafs+1), not nodes
short mins[3]; // for sphere culling
short maxs[3];
unsigned short firstface;
unsigned short numfaces; // counting both sides
} q1_dnode_t;
typedef struct
{
int planenum;
short children[2]; // negative numbers are contents
} q1_dclipnode_t;
typedef struct q1_texinfo_s
{
float vecs[2][4]; // [s/t][xyz offset]
int miptex;
int flags;
} q1_texinfo_t;
#define TEX_SPECIAL 1 // sky or slime, no lightmap or 256 subdivision
// note that edge 0 is never used, because negative edge nums are used for
// counterclockwise use of the edge in a face
typedef struct
{
unsigned short v[2]; // vertex numbers
} q1_dedge_t;
#define MAXLIGHTMAPS 4
typedef struct
{
short planenum;
short side;
int firstedge; // we must support > 64k edges
short numedges;
short texinfo;
// lighting info
byte styles[MAXLIGHTMAPS];
int lightofs; // start of [numstyles*surfsize] samples
} q1_dface_t;
#define AMBIENT_WATER 0
#define AMBIENT_SKY 1
#define AMBIENT_SLIME 2
#define AMBIENT_LAVA 3
#define NUM_AMBIENTS 4 // automatic ambient sounds
// leaf 0 is the generic Q1_CONTENTS_SOLID leaf, used for all solid areas
// all other leafs need visibility info
typedef struct
{
int contents;
int visofs; // -1 = no visibility info
short mins[3]; // for frustum culling
short maxs[3];
unsigned short firstmarksurface;
unsigned short nummarksurfaces;
byte ambient_level[NUM_AMBIENTS];
} q1_dleaf_t;
//============================================================================
#ifndef QUAKE_GAME
// the utilities get to be lazy and just use large static arrays
extern int q1_nummodels;
extern q1_dmodel_t *q1_dmodels; //[MAX_MAP_MODELS];
extern int q1_visdatasize;
extern byte *q1_dvisdata; //[MAX_MAP_VISIBILITY];
extern int q1_lightdatasize;
extern byte *q1_dlightdata; //[MAX_MAP_LIGHTING];
extern int q1_texdatasize;
extern byte *q1_dtexdata; //[MAX_MAP_MIPTEX]; // (dmiptexlump_t)
extern int q1_entdatasize;
extern char *q1_dentdata; //[MAX_MAP_ENTSTRING];
extern int q1_numleafs;
extern q1_dleaf_t *q1_dleafs; //[MAX_MAP_LEAFS];
extern int q1_numplanes;
extern q1_dplane_t *q1_dplanes; //[MAX_MAP_PLANES];
extern int q1_numvertexes;
extern q1_dvertex_t *q1_dvertexes; //[MAX_MAP_VERTS];
extern int q1_numnodes;
extern q1_dnode_t *q1_dnodes; //[MAX_MAP_NODES];
extern int q1_numtexinfo;
extern q1_texinfo_t *q1_texinfo; //[MAX_MAP_TEXINFO];
extern int q1_numfaces;
extern q1_dface_t *q1_dfaces; //[MAX_MAP_FACES];
extern int q1_numclipnodes;
extern q1_dclipnode_t *q1_dclipnodes; //[MAX_MAP_CLIPNODES];
extern int q1_numedges;
extern q1_dedge_t *q1_dedges; //[MAX_MAP_EDGES];
extern int q1_nummarksurfaces;
extern unsigned short *q1_dmarksurfaces; //[MAX_MAP_MARKSURFACES];
extern int q1_numsurfedges;
extern int *q1_dsurfedges; //[MAX_MAP_SURFEDGES];
void Q1_AllocMaxBSP( void );
void Q1_FreeMaxBSP( void );
void Q1_LoadBSPFile( char *filename, int offset, int length );
void Q1_WriteBSPFile( char *filename );
void Q1_PrintBSPFileSizes( void );
void Q1_ParseEntities( void );
void Q1_UnparseEntities( void );
#endif

1137
src/bspc/l_bsp_q2.c Normal file

File diff suppressed because it is too large Load Diff

104
src/bspc/l_bsp_q2.h Normal file
View File

@@ -0,0 +1,104 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#ifndef ME
#define ME
#endif //ME
extern int nummodels;
extern dmodel_t *dmodels; //[MAX_MAP_MODELS];
extern int visdatasize;
extern byte *dvisdata; //[MAX_MAP_VISIBILITY];
extern dvis_t *dvis;
extern int lightdatasize;
extern byte *dlightdata; //[MAX_MAP_LIGHTING];
extern int entdatasize;
extern char *dentdata; //[MAX_MAP_ENTSTRING];
extern int numleafs;
extern dleaf_t *dleafs; //[MAX_MAP_LEAFS];
extern int numplanes;
extern dplane_t *dplanes; //[MAX_MAP_PLANES];
extern int numvertexes;
extern dvertex_t *dvertexes; //[MAX_MAP_VERTS];
extern int numnodes;
extern dnode_t *dnodes; //[MAX_MAP_NODES];
extern int numtexinfo;
extern texinfo_t texinfo[MAX_MAP_TEXINFO];
extern int numfaces;
extern dface_t *dfaces; //[MAX_MAP_FACES];
extern int numedges;
extern dedge_t *dedges; //[MAX_MAP_EDGES];
extern int numleaffaces;
extern unsigned short *dleaffaces; //[MAX_MAP_LEAFFACES];
extern int numleafbrushes;
extern unsigned short *dleafbrushes; //[MAX_MAP_LEAFBRUSHES];
extern int numsurfedges;
extern int *dsurfedges; //[MAX_MAP_SURFEDGES];
extern int numareas;
extern darea_t *dareas; //[MAX_MAP_AREAS];
extern int numareaportals;
extern dareaportal_t *dareaportals; //[MAX_MAP_AREAPORTALS];
extern int numbrushes;
extern dbrush_t *dbrushes; //[MAX_MAP_BRUSHES];
extern int numbrushsides;
extern dbrushside_t *dbrushsides; //[MAX_MAP_BRUSHSIDES];
extern byte dpop[256];
extern char brushsidetextured[MAX_MAP_BRUSHSIDES];
void Q2_AllocMaxBSP( void );
void Q2_FreeMaxBSP( void );
void Q2_DecompressVis( byte *in, byte *decompressed );
int Q2_CompressVis( byte *vis, byte *dest );
void Q2_LoadBSPFile( char *filename, int offset, int length );
void Q2_LoadBSPFileTexinfo( char *filename ); // just for qdata
void Q2_WriteBSPFile( char *filename );
void Q2_PrintBSPFileSizes( void );
void Q2_ParseEntities( void );
void Q2_UnparseEntities( void );

838
src/bspc/l_bsp_q3.c Normal file
View File

@@ -0,0 +1,838 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "l_cmd.h"
#include "l_math.h"
#include "l_mem.h"
#include "l_log.h"
#include "l_poly.h"
#include "../botlib/l_script.h"
#include "l_qfiles.h"
#include "l_bsp_q3.h"
#include "l_bsp_ent.h"
void Q3_ParseEntities( void );
void Q3_PrintBSPFileSizes( void );
void GetLeafNums( void );
//=============================================================================
#define WCONVEX_EPSILON 0.5
int q3_nummodels;
q3_dmodel_t *q3_dmodels; //[MAX_MAP_MODELS];
int q3_numShaders;
q3_dshader_t *q3_dshaders; //[Q3_MAX_MAP_SHADERS];
int q3_entdatasize;
char *q3_dentdata; //[Q3_MAX_MAP_ENTSTRING];
int q3_numleafs;
q3_dleaf_t *q3_dleafs; //[Q3_MAX_MAP_LEAFS];
int q3_numplanes;
q3_dplane_t *q3_dplanes; //[Q3_MAX_MAP_PLANES];
int q3_numnodes;
q3_dnode_t *q3_dnodes; //[Q3_MAX_MAP_NODES];
int q3_numleafsurfaces;
int *q3_dleafsurfaces; //[Q3_MAX_MAP_LEAFFACES];
int q3_numleafbrushes;
int *q3_dleafbrushes; //[Q3_MAX_MAP_LEAFBRUSHES];
int q3_numbrushes;
q3_dbrush_t *q3_dbrushes; //[Q3_MAX_MAP_BRUSHES];
int q3_numbrushsides;
q3_dbrushside_t *q3_dbrushsides; //[Q3_MAX_MAP_BRUSHSIDES];
int q3_numLightBytes;
byte *q3_lightBytes; //[Q3_MAX_MAP_LIGHTING];
int q3_numGridPoints;
byte *q3_gridData; //[Q3_MAX_MAP_LIGHTGRID];
int q3_numVisBytes;
byte *q3_visBytes; //[Q3_MAX_MAP_VISIBILITY];
int q3_numDrawVerts;
q3_drawVert_t *q3_drawVerts; //[Q3_MAX_MAP_DRAW_VERTS];
int q3_numDrawIndexes;
int *q3_drawIndexes; //[Q3_MAX_MAP_DRAW_INDEXES];
int q3_numDrawSurfaces;
q3_dsurface_t *q3_drawSurfaces; //[Q3_MAX_MAP_DRAW_SURFS];
int q3_numFogs;
q3_dfog_t *q3_dfogs; //[Q3_MAX_MAP_FOGS];
char q3_dbrushsidetextured[Q3_MAX_MAP_BRUSHSIDES];
extern qboolean forcesidesvisible;
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Q3_FreeMaxBSP( void ) {
if ( q3_dmodels ) {
FreeMemory( q3_dmodels );
}
q3_dmodels = NULL;
q3_nummodels = 0;
if ( q3_dshaders ) {
FreeMemory( q3_dshaders );
}
q3_dshaders = NULL;
q3_numShaders = 0;
if ( q3_dentdata ) {
FreeMemory( q3_dentdata );
}
q3_dentdata = NULL;
q3_entdatasize = 0;
if ( q3_dleafs ) {
FreeMemory( q3_dleafs );
}
q3_dleafs = NULL;
q3_numleafs = 0;
if ( q3_dplanes ) {
FreeMemory( q3_dplanes );
}
q3_dplanes = NULL;
q3_numplanes = 0;
if ( q3_dnodes ) {
FreeMemory( q3_dnodes );
}
q3_dnodes = NULL;
q3_numnodes = 0;
if ( q3_dleafsurfaces ) {
FreeMemory( q3_dleafsurfaces );
}
q3_dleafsurfaces = NULL;
q3_numleafsurfaces = 0;
if ( q3_dleafbrushes ) {
FreeMemory( q3_dleafbrushes );
}
q3_dleafbrushes = NULL;
q3_numleafbrushes = 0;
if ( q3_dbrushes ) {
FreeMemory( q3_dbrushes );
}
q3_dbrushes = NULL;
q3_numbrushes = 0;
if ( q3_dbrushsides ) {
FreeMemory( q3_dbrushsides );
}
q3_dbrushsides = NULL;
q3_numbrushsides = 0;
if ( q3_lightBytes ) {
FreeMemory( q3_lightBytes );
}
q3_lightBytes = NULL;
q3_numLightBytes = 0;
if ( q3_gridData ) {
FreeMemory( q3_gridData );
}
q3_gridData = NULL;
q3_numGridPoints = 0;
if ( q3_visBytes ) {
FreeMemory( q3_visBytes );
}
q3_visBytes = NULL;
q3_numVisBytes = 0;
if ( q3_drawVerts ) {
FreeMemory( q3_drawVerts );
}
q3_drawVerts = NULL;
q3_numDrawVerts = 0;
if ( q3_drawIndexes ) {
FreeMemory( q3_drawIndexes );
}
q3_drawIndexes = NULL;
q3_numDrawIndexes = 0;
if ( q3_drawSurfaces ) {
FreeMemory( q3_drawSurfaces );
}
q3_drawSurfaces = NULL;
q3_numDrawSurfaces = 0;
if ( q3_dfogs ) {
FreeMemory( q3_dfogs );
}
q3_dfogs = NULL;
q3_numFogs = 0;
} //end of the function Q3_FreeMaxBSP
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Q3_PlaneFromPoints( vec3_t p0, vec3_t p1, vec3_t p2, vec3_t normal, float *dist ) {
vec3_t t1, t2;
VectorSubtract( p0, p1, t1 );
VectorSubtract( p2, p1, t2 );
CrossProduct( t1, t2, normal );
VectorNormalize( normal );
*dist = DotProduct( p0, normal );
} //end of the function PlaneFromPoints
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Q3_SurfacePlane( q3_dsurface_t *surface, vec3_t normal, float *dist ) {
int i;
float *p0, *p1, *p2;
vec3_t t1, t2;
p0 = q3_drawVerts[surface->firstVert].xyz;
for ( i = 1; i < surface->numVerts - 1; i++ )
{
p1 = q3_drawVerts[surface->firstVert + ( ( i ) % surface->numVerts )].xyz;
p2 = q3_drawVerts[surface->firstVert + ( ( i + 1 ) % surface->numVerts )].xyz;
VectorSubtract( p0, p1, t1 );
VectorSubtract( p2, p1, t2 );
CrossProduct( t1, t2, normal );
VectorNormalize( normal );
if ( VectorLength( normal ) ) {
break;
}
} //end for*/
/*
float dot;
for (i = 0; i < surface->numVerts; i++)
{
p0 = q3_drawVerts[surface->firstVert + ((i) % surface->numVerts)].xyz;
p1 = q3_drawVerts[surface->firstVert + ((i+1) % surface->numVerts)].xyz;
p2 = q3_drawVerts[surface->firstVert + ((i+2) % surface->numVerts)].xyz;
VectorSubtract(p0, p1, t1);
VectorSubtract(p2, p1, t2);
VectorNormalize(t1);
VectorNormalize(t2);
dot = DotProduct(t1, t2);
if (dot > -0.9 && dot < 0.9 &&
VectorLength(t1) > 0.1 && VectorLength(t2) > 0.1) break;
} //end for
CrossProduct(t1, t2, normal);
VectorNormalize(normal);
*/
if ( VectorLength( normal ) < 0.9 ) {
printf( "surface %d bogus normal vector %f %f %f\n", surface - q3_drawSurfaces, normal[0], normal[1], normal[2] );
printf( "t1 = %f %f %f, t2 = %f %f %f\n", t1[0], t1[1], t1[2], t2[0], t2[1], t2[2] );
for ( i = 0; i < surface->numVerts; i++ )
{
p1 = q3_drawVerts[surface->firstVert + ( ( i ) % surface->numVerts )].xyz;
Log_Print( "p%d = %f %f %f\n", i, p1[0], p1[1], p1[2] );
} //end for
} //end if
*dist = DotProduct( p0, normal );
} //end of the function Q3_SurfacePlane
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
q3_dplane_t *q3_surfaceplanes;
void Q3_CreatePlanarSurfacePlanes( void ) {
int i;
q3_dsurface_t *surface;
Log_Print( "creating planar surface planes...\n" );
q3_surfaceplanes = (q3_dplane_t *) GetClearedMemory( q3_numDrawSurfaces * sizeof( q3_dplane_t ) );
for ( i = 0; i < q3_numDrawSurfaces; i++ )
{
surface = &q3_drawSurfaces[i];
if ( surface->surfaceType != MST_PLANAR ) {
continue;
}
Q3_SurfacePlane( surface, q3_surfaceplanes[i].normal, &q3_surfaceplanes[i].dist );
//Log_Print("normal = %f %f %f, dist = %f\n", q3_surfaceplanes[i].normal[0],
// q3_surfaceplanes[i].normal[1],
// q3_surfaceplanes[i].normal[2], q3_surfaceplanes[i].dist);
} //end for
} //end of the function Q3_CreatePlanarSurfacePlanes
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
/*
void Q3_SurfacePlane(q3_dsurface_t *surface, vec3_t normal, float *dist)
{
//take the plane information from the lightmap vector
//VectorCopy(surface->lightmapVecs[2], normal);
//calculate plane dist with first surface vertex
//*dist = DotProduct(q3_drawVerts[surface->firstVert].xyz, normal);
Q3_PlaneFromPoints(q3_drawVerts[surface->firstVert].xyz,
q3_drawVerts[surface->firstVert+1].xyz,
q3_drawVerts[surface->firstVert+2].xyz, normal, dist);
} //end of the function Q3_SurfacePlane*/
//===========================================================================
// returns the amount the face and the winding overlap
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
float Q3_FaceOnWinding( q3_dsurface_t *surface, winding_t *winding ) {
int i;
float dist, area;
q3_dplane_t plane;
vec_t *v1, *v2;
vec3_t normal, edgevec;
winding_t *w;
//copy the winding before chopping
w = CopyWinding( winding );
//retrieve the surface plane
Q3_SurfacePlane( surface, plane.normal, &plane.dist );
//chop the winding with the surface edge planes
for ( i = 0; i < surface->numVerts && w; i++ )
{
v1 = q3_drawVerts[surface->firstVert + ( ( i ) % surface->numVerts )].xyz;
v2 = q3_drawVerts[surface->firstVert + ( ( i + 1 ) % surface->numVerts )].xyz;
//create a plane through the edge from v1 to v2, orthogonal to the
//surface plane and with the normal vector pointing inward
VectorSubtract( v2, v1, edgevec );
CrossProduct( edgevec, plane.normal, normal );
VectorNormalize( normal );
dist = DotProduct( normal, v1 );
//
ChopWindingInPlace( &w, normal, dist, -0.1 ); //CLIP_EPSILON
} //end for
if ( w ) {
area = WindingArea( w );
FreeWinding( w );
return area;
} //end if
return 0;
} //end of the function Q3_FaceOnWinding
//===========================================================================
// creates a winding for the given brush side on the given brush
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
winding_t *Q3_BrushSideWinding( q3_dbrush_t *brush, q3_dbrushside_t *baseside ) {
int i;
q3_dplane_t *baseplane, *plane;
winding_t *w;
q3_dbrushside_t *side;
//create a winding for the brush side with the given planenumber
baseplane = &q3_dplanes[baseside->planeNum];
w = BaseWindingForPlane( baseplane->normal, baseplane->dist );
for ( i = 0; i < brush->numSides && w; i++ )
{
side = &q3_dbrushsides[brush->firstSide + i];
//don't chop with the base plane
if ( side->planeNum == baseside->planeNum ) {
continue;
}
//also don't use planes that are almost equal
plane = &q3_dplanes[side->planeNum];
if ( DotProduct( baseplane->normal, plane->normal ) > 0.999
&& fabs( baseplane->dist - plane->dist ) < 0.01 ) {
continue;
}
//
plane = &q3_dplanes[side->planeNum ^ 1];
ChopWindingInPlace( &w, plane->normal, plane->dist, -0.1 ); //CLIP_EPSILON);
} //end for
return w;
} //end of the function Q3_BrushSideWinding
//===========================================================================
// fix screwed brush texture references
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
qboolean WindingIsTiny( winding_t *w );
void Q3_FindVisibleBrushSides( void ) {
int i, j, k, we, numtextured, numsides;
float dot;
q3_dplane_t *plane;
q3_dbrushside_t *brushside;
q3_dbrush_t *brush;
q3_dsurface_t *surface;
winding_t *w;
memset( q3_dbrushsidetextured, false, Q3_MAX_MAP_BRUSHSIDES );
//
numsides = 0;
//create planes for the planar surfaces
Q3_CreatePlanarSurfacePlanes();
Log_Print( "searching visible brush sides...\n" );
Log_Print( "%6d brush sides", numsides );
//go over all the brushes
for ( i = 0; i < q3_numbrushes; i++ )
{
brush = &q3_dbrushes[i];
//go over all the sides of the brush
for ( j = 0; j < brush->numSides; j++ )
{
qprintf( "\r%6d", numsides++ );
brushside = &q3_dbrushsides[brush->firstSide + j];
//
w = Q3_BrushSideWinding( brush, brushside );
if ( !w ) {
q3_dbrushsidetextured[brush->firstSide + j] = true;
continue;
} //end if
else
{
//RemoveEqualPoints(w, 0.2);
if ( WindingIsTiny( w ) ) {
FreeWinding( w );
q3_dbrushsidetextured[brush->firstSide + j] = true;
continue;
} //end if
else
{
we = WindingError( w );
if ( we == WE_NOTENOUGHPOINTS
|| we == WE_SMALLAREA
|| we == WE_POINTBOGUSRANGE
// || we == WE_NONCONVEX
) {
FreeWinding( w );
q3_dbrushsidetextured[brush->firstSide + j] = true;
continue;
} //end if
} //end else
} //end else
if ( WindingArea( w ) < 20 ) {
q3_dbrushsidetextured[brush->firstSide + j] = true;
continue;
} //end if
//find a face for texturing this brush
for ( k = 0; k < q3_numDrawSurfaces; k++ )
{
surface = &q3_drawSurfaces[k];
if ( surface->surfaceType != MST_PLANAR ) {
continue;
}
//
//Q3_SurfacePlane(surface, plane.normal, &plane.dist);
plane = &q3_surfaceplanes[k];
//the surface plane and the brush side plane should be pretty much the same
if ( fabs( fabs( plane->dist ) - fabs( q3_dplanes[brushside->planeNum].dist ) ) > 5 ) {
continue;
}
dot = DotProduct( plane->normal, q3_dplanes[brushside->planeNum].normal );
if ( dot > -0.9 && dot < 0.9 ) {
continue;
}
//if the face is partly or totally on the brush side
if ( Q3_FaceOnWinding( surface, w ) ) {
q3_dbrushsidetextured[brush->firstSide + j] = true;
//Log_Write("Q3_FaceOnWinding");
break;
} //end if
} //end for
FreeWinding( w );
} //end for
} //end for
qprintf( "\r%6d brush sides\n", numsides );
numtextured = 0;
for ( i = 0; i < q3_numbrushsides; i++ )
{
if ( forcesidesvisible ) {
q3_dbrushsidetextured[i] = true;
}
if ( q3_dbrushsidetextured[i] ) {
numtextured++;
}
} //end for
Log_Print( "%d brush sides textured out of %d\n", numtextured, q3_numbrushsides );
} //end of the function Q3_FindVisibleBrushSides
/*
=============
Q3_SwapBlock
If all values are 32 bits, this can be used to swap everything
=============
*/
void Q3_SwapBlock( int *block, int sizeOfBlock ) {
int i;
sizeOfBlock >>= 2;
for ( i = 0 ; i < sizeOfBlock ; i++ ) {
block[i] = LittleLong( block[i] );
}
} //end of the function Q3_SwapBlock
/*
=============
Q3_SwapBSPFile
Byte swaps all data in a bsp file.
=============
*/
void Q3_SwapBSPFile( void ) {
int i;
// models
Q3_SwapBlock( (int *)q3_dmodels, q3_nummodels * sizeof( q3_dmodels[0] ) );
// shaders (don't swap the name)
for ( i = 0 ; i < q3_numShaders ; i++ ) {
q3_dshaders[i].contentFlags = LittleLong( q3_dshaders[i].contentFlags );
q3_dshaders[i].surfaceFlags = LittleLong( q3_dshaders[i].surfaceFlags );
}
// planes
Q3_SwapBlock( (int *)q3_dplanes, q3_numplanes * sizeof( q3_dplanes[0] ) );
// nodes
Q3_SwapBlock( (int *)q3_dnodes, q3_numnodes * sizeof( q3_dnodes[0] ) );
// leafs
Q3_SwapBlock( (int *)q3_dleafs, q3_numleafs * sizeof( q3_dleafs[0] ) );
// leaffaces
Q3_SwapBlock( (int *)q3_dleafsurfaces, q3_numleafsurfaces * sizeof( q3_dleafsurfaces[0] ) );
// leafbrushes
Q3_SwapBlock( (int *)q3_dleafbrushes, q3_numleafbrushes * sizeof( q3_dleafbrushes[0] ) );
// brushes
Q3_SwapBlock( (int *)q3_dbrushes, q3_numbrushes * sizeof( q3_dbrushes[0] ) );
// brushsides
Q3_SwapBlock( (int *)q3_dbrushsides, q3_numbrushsides * sizeof( q3_dbrushsides[0] ) );
// vis
( (int *)&q3_visBytes )[0] = LittleLong( ( (int *)&q3_visBytes )[0] );
( (int *)&q3_visBytes )[1] = LittleLong( ( (int *)&q3_visBytes )[1] );
// drawverts (don't swap colors )
for ( i = 0 ; i < q3_numDrawVerts ; i++ ) {
q3_drawVerts[i].lightmap[0] = LittleFloat( q3_drawVerts[i].lightmap[0] );
q3_drawVerts[i].lightmap[1] = LittleFloat( q3_drawVerts[i].lightmap[1] );
q3_drawVerts[i].st[0] = LittleFloat( q3_drawVerts[i].st[0] );
q3_drawVerts[i].st[1] = LittleFloat( q3_drawVerts[i].st[1] );
q3_drawVerts[i].xyz[0] = LittleFloat( q3_drawVerts[i].xyz[0] );
q3_drawVerts[i].xyz[1] = LittleFloat( q3_drawVerts[i].xyz[1] );
q3_drawVerts[i].xyz[2] = LittleFloat( q3_drawVerts[i].xyz[2] );
q3_drawVerts[i].normal[0] = LittleFloat( q3_drawVerts[i].normal[0] );
q3_drawVerts[i].normal[1] = LittleFloat( q3_drawVerts[i].normal[1] );
q3_drawVerts[i].normal[2] = LittleFloat( q3_drawVerts[i].normal[2] );
}
// drawindexes
Q3_SwapBlock( (int *)q3_drawIndexes, q3_numDrawIndexes * sizeof( q3_drawIndexes[0] ) );
// drawsurfs
Q3_SwapBlock( (int *)q3_drawSurfaces, q3_numDrawSurfaces * sizeof( q3_drawSurfaces[0] ) );
// fogs
for ( i = 0 ; i < q3_numFogs ; i++ ) {
q3_dfogs[i].brushNum = LittleLong( q3_dfogs[i].brushNum );
}
}
/*
=============
Q3_CopyLump
=============
*/
int Q3_CopyLump( q3_dheader_t *header, int lump, void **dest, int size ) {
int length, ofs;
length = header->lumps[lump].filelen;
ofs = header->lumps[lump].fileofs;
if ( length % size ) {
Error( "Q3_LoadBSPFile: odd lump size" );
}
*dest = GetMemory( length );
memcpy( *dest, (byte *)header + ofs, length );
return length / size;
}
/*
=============
Q3_LoadBSPFile
=============
*/
void Q3_LoadBSPFile( struct quakefile_s *qf ) {
q3_dheader_t *header;
// load the file header
//LoadFile(filename, (void **)&header, offset, length);
//
LoadQuakeFile( qf, (void **)&header );
// swap the header
Q3_SwapBlock( (int *)header, sizeof( *header ) );
if ( header->ident != Q3_BSP_IDENT ) {
Error( "%s is not a IBSP file", qf->filename );
}
if ( header->version != Q3_BSP_VERSION ) {
Error( "%s is version %i, not %i", qf->filename, header->version, Q3_BSP_VERSION );
}
q3_numShaders = Q3_CopyLump( header, Q3_LUMP_SHADERS, (void *) &q3_dshaders, sizeof( q3_dshader_t ) );
q3_nummodels = Q3_CopyLump( header, Q3_LUMP_MODELS, (void *) &q3_dmodels, sizeof( q3_dmodel_t ) );
q3_numplanes = Q3_CopyLump( header, Q3_LUMP_PLANES, (void *) &q3_dplanes, sizeof( q3_dplane_t ) );
q3_numleafs = Q3_CopyLump( header, Q3_LUMP_LEAFS, (void *) &q3_dleafs, sizeof( q3_dleaf_t ) );
q3_numnodes = Q3_CopyLump( header, Q3_LUMP_NODES, (void *) &q3_dnodes, sizeof( q3_dnode_t ) );
q3_numleafsurfaces = Q3_CopyLump( header, Q3_LUMP_LEAFSURFACES, (void *) &q3_dleafsurfaces, sizeof( q3_dleafsurfaces[0] ) );
q3_numleafbrushes = Q3_CopyLump( header, Q3_LUMP_LEAFBRUSHES, (void *) &q3_dleafbrushes, sizeof( q3_dleafbrushes[0] ) );
q3_numbrushes = Q3_CopyLump( header, Q3_LUMP_BRUSHES, (void *) &q3_dbrushes, sizeof( q3_dbrush_t ) );
q3_numbrushsides = Q3_CopyLump( header, Q3_LUMP_BRUSHSIDES, (void *) &q3_dbrushsides, sizeof( q3_dbrushside_t ) );
q3_numDrawVerts = Q3_CopyLump( header, Q3_LUMP_DRAWVERTS, (void *) &q3_drawVerts, sizeof( q3_drawVert_t ) );
q3_numDrawSurfaces = Q3_CopyLump( header, Q3_LUMP_SURFACES, (void *) &q3_drawSurfaces, sizeof( q3_dsurface_t ) );
q3_numFogs = Q3_CopyLump( header, Q3_LUMP_FOGS, (void *) &q3_dfogs, sizeof( q3_dfog_t ) );
q3_numDrawIndexes = Q3_CopyLump( header, Q3_LUMP_DRAWINDEXES, (void *) &q3_drawIndexes, sizeof( q3_drawIndexes[0] ) );
q3_numVisBytes = Q3_CopyLump( header, Q3_LUMP_VISIBILITY, (void *) &q3_visBytes, 1 );
q3_numLightBytes = Q3_CopyLump( header, Q3_LUMP_LIGHTMAPS, (void *) &q3_lightBytes, 1 );
q3_entdatasize = Q3_CopyLump( header, Q3_LUMP_ENTITIES, (void *) &q3_dentdata, 1 );
q3_numGridPoints = Q3_CopyLump( header, Q3_LUMP_LIGHTGRID, (void *) &q3_gridData, 8 );
FreeMemory( header ); // everything has been copied out
// swap everything
Q3_SwapBSPFile();
Q3_FindVisibleBrushSides();
//Q3_PrintBSPFileSizes();
}
//============================================================================
/*
=============
Q3_AddLump
=============
*/
void Q3_AddLump( FILE *bspfile, q3_dheader_t *header, int lumpnum, void *data, int len ) {
q3_lump_t *lump;
lump = &header->lumps[lumpnum];
lump->fileofs = LittleLong( ftell( bspfile ) );
lump->filelen = LittleLong( len );
SafeWrite( bspfile, data, ( len + 3 ) & ~3 );
}
/*
=============
Q3_WriteBSPFile
Swaps the bsp file in place, so it should not be referenced again
=============
*/
void Q3_WriteBSPFile( char *filename ) {
q3_dheader_t outheader, *header;
FILE *bspfile;
header = &outheader;
memset( header, 0, sizeof( q3_dheader_t ) );
Q3_SwapBSPFile();
header->ident = LittleLong( Q3_BSP_IDENT );
header->version = LittleLong( Q3_BSP_VERSION );
bspfile = SafeOpenWrite( filename );
SafeWrite( bspfile, header, sizeof( q3_dheader_t ) ); // overwritten later
Q3_AddLump( bspfile, header, Q3_LUMP_SHADERS, q3_dshaders, q3_numShaders * sizeof( q3_dshader_t ) );
Q3_AddLump( bspfile, header, Q3_LUMP_PLANES, q3_dplanes, q3_numplanes * sizeof( q3_dplane_t ) );
Q3_AddLump( bspfile, header, Q3_LUMP_LEAFS, q3_dleafs, q3_numleafs * sizeof( q3_dleaf_t ) );
Q3_AddLump( bspfile, header, Q3_LUMP_NODES, q3_dnodes, q3_numnodes * sizeof( q3_dnode_t ) );
Q3_AddLump( bspfile, header, Q3_LUMP_BRUSHES, q3_dbrushes, q3_numbrushes * sizeof( q3_dbrush_t ) );
Q3_AddLump( bspfile, header, Q3_LUMP_BRUSHSIDES, q3_dbrushsides, q3_numbrushsides * sizeof( q3_dbrushside_t ) );
Q3_AddLump( bspfile, header, Q3_LUMP_LEAFSURFACES, q3_dleafsurfaces, q3_numleafsurfaces * sizeof( q3_dleafsurfaces[0] ) );
Q3_AddLump( bspfile, header, Q3_LUMP_LEAFBRUSHES, q3_dleafbrushes, q3_numleafbrushes * sizeof( q3_dleafbrushes[0] ) );
Q3_AddLump( bspfile, header, Q3_LUMP_MODELS, q3_dmodels, q3_nummodels * sizeof( q3_dmodel_t ) );
Q3_AddLump( bspfile, header, Q3_LUMP_DRAWVERTS, q3_drawVerts, q3_numDrawVerts * sizeof( q3_drawVert_t ) );
Q3_AddLump( bspfile, header, Q3_LUMP_SURFACES, q3_drawSurfaces, q3_numDrawSurfaces * sizeof( q3_dsurface_t ) );
Q3_AddLump( bspfile, header, Q3_LUMP_VISIBILITY, q3_visBytes, q3_numVisBytes );
Q3_AddLump( bspfile, header, Q3_LUMP_LIGHTMAPS, q3_lightBytes, q3_numLightBytes );
Q3_AddLump( bspfile, header, Q3_LUMP_LIGHTGRID, q3_gridData, 8 * q3_numGridPoints );
Q3_AddLump( bspfile, header, Q3_LUMP_ENTITIES, q3_dentdata, q3_entdatasize );
Q3_AddLump( bspfile, header, Q3_LUMP_FOGS, q3_dfogs, q3_numFogs * sizeof( q3_dfog_t ) );
Q3_AddLump( bspfile, header, Q3_LUMP_DRAWINDEXES, q3_drawIndexes, q3_numDrawIndexes * sizeof( q3_drawIndexes[0] ) );
fseek( bspfile, 0, SEEK_SET );
SafeWrite( bspfile, header, sizeof( q3_dheader_t ) );
fclose( bspfile );
}
//============================================================================
/*
=============
Q3_PrintBSPFileSizes
Dumps info about current file
=============
*/
void Q3_PrintBSPFileSizes( void ) {
if ( !num_entities ) {
Q3_ParseEntities();
}
Log_Print( "%6i models %7i\n"
,q3_nummodels, (int)( q3_nummodels * sizeof( q3_dmodel_t ) ) );
Log_Print( "%6i shaders %7i\n"
,q3_numShaders, (int)( q3_numShaders * sizeof( q3_dshader_t ) ) );
Log_Print( "%6i brushes %7i\n"
,q3_numbrushes, (int)( q3_numbrushes * sizeof( q3_dbrush_t ) ) );
Log_Print( "%6i brushsides %7i\n"
,q3_numbrushsides, (int)( q3_numbrushsides * sizeof( q3_dbrushside_t ) ) );
Log_Print( "%6i fogs %7i\n"
,q3_numFogs, (int)( q3_numFogs * sizeof( q3_dfog_t ) ) );
Log_Print( "%6i planes %7i\n"
,q3_numplanes, (int)( q3_numplanes * sizeof( q3_dplane_t ) ) );
Log_Print( "%6i entdata %7i\n", num_entities, q3_entdatasize );
Log_Print( "\n" );
Log_Print( "%6i nodes %7i\n"
,q3_numnodes, (int)( q3_numnodes * sizeof( q3_dnode_t ) ) );
Log_Print( "%6i leafs %7i\n"
,q3_numleafs, (int)( q3_numleafs * sizeof( q3_dleaf_t ) ) );
Log_Print( "%6i leafsurfaces %7i\n"
,q3_numleafsurfaces, (int)( q3_numleafsurfaces * sizeof( q3_dleafsurfaces[0] ) ) );
Log_Print( "%6i leafbrushes %7i\n"
,q3_numleafbrushes, (int)( q3_numleafbrushes * sizeof( q3_dleafbrushes[0] ) ) );
Log_Print( "%6i drawverts %7i\n"
,q3_numDrawVerts, (int)( q3_numDrawVerts * sizeof( q3_drawVerts[0] ) ) );
Log_Print( "%6i drawindexes %7i\n"
,q3_numDrawIndexes, (int)( q3_numDrawIndexes * sizeof( q3_drawIndexes[0] ) ) );
Log_Print( "%6i drawsurfaces %7i\n"
,q3_numDrawSurfaces, (int)( q3_numDrawSurfaces * sizeof( q3_drawSurfaces[0] ) ) );
Log_Print( "%6i lightmaps %7i\n"
,q3_numLightBytes / ( LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT * 3 ), q3_numLightBytes );
Log_Print( " visibility %7i\n"
, q3_numVisBytes );
}
/*
================
Q3_ParseEntities
Parses the q3_dentdata string into entities
================
*/
void Q3_ParseEntities( void ) {
script_t *script;
num_entities = 0;
script = LoadScriptMemory( q3_dentdata, q3_entdatasize, "*Quake3 bsp file" );
SetScriptFlags( script, SCFL_NOSTRINGWHITESPACES |
SCFL_NOSTRINGESCAPECHARS );
while ( ParseEntity( script ) )
{
} //end while
FreeScript( script );
} //end of the function Q3_ParseEntities
/*
================
Q3_UnparseEntities
Generates the q3_dentdata string from all the entities
================
*/
void Q3_UnparseEntities( void ) {
char *buf, *end;
epair_t *ep;
char line[2048];
int i;
buf = q3_dentdata;
end = buf;
*end = 0;
for ( i = 0 ; i < num_entities ; i++ )
{
ep = entities[i].epairs;
if ( !ep ) {
continue; // ent got removed
}
strcat( end,"{\n" );
end += 2;
for ( ep = entities[i].epairs ; ep ; ep = ep->next )
{
sprintf( line, "\"%s\" \"%s\"\n", ep->key, ep->value );
strcat( end, line );
end += strlen( line );
}
strcat( end,"}\n" );
end += 2;
if ( end > buf + Q3_MAX_MAP_ENTSTRING ) {
Error( "Entity text too long" );
}
}
q3_entdatasize = end - buf + 1;
} //end of the function Q3_UnparseEntities

88
src/bspc/l_bsp_q3.h Normal file
View File

@@ -0,0 +1,88 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "q3files.h"
//#include "surfaceflags.h"
extern int q3_nummodels;
extern q3_dmodel_t *q3_dmodels; //[MAX_MAP_MODELS];
extern int q3_numShaders;
extern q3_dshader_t *q3_dshaders; //[Q3_MAX_MAP_SHADERS];
extern int q3_entdatasize;
extern char *q3_dentdata; //[Q3_MAX_MAP_ENTSTRING];
extern int q3_numleafs;
extern q3_dleaf_t *q3_dleafs; //[Q3_MAX_MAP_LEAFS];
extern int q3_numplanes;
extern q3_dplane_t *q3_dplanes; //[Q3_MAX_MAP_PLANES];
extern int q3_numnodes;
extern q3_dnode_t *q3_dnodes; //[Q3_MAX_MAP_NODES];
extern int q3_numleafsurfaces;
extern int *q3_dleafsurfaces; //[Q3_MAX_MAP_LEAFFACES];
extern int q3_numleafbrushes;
extern int *q3_dleafbrushes; //[Q3_MAX_MAP_LEAFBRUSHES];
extern int q3_numbrushes;
extern q3_dbrush_t *q3_dbrushes; //[Q3_MAX_MAP_BRUSHES];
extern int q3_numbrushsides;
extern q3_dbrushside_t *q3_dbrushsides; //[Q3_MAX_MAP_BRUSHSIDES];
extern int q3_numLightBytes;
extern byte *q3_lightBytes; //[Q3_MAX_MAP_LIGHTING];
extern int q3_numGridPoints;
extern byte *q3_gridData; //[Q3_MAX_MAP_LIGHTGRID];
extern int q3_numVisBytes;
extern byte *q3_visBytes; //[Q3_MAX_MAP_VISIBILITY];
extern int q3_numDrawVerts;
extern q3_drawVert_t *q3_drawVerts; //[Q3_MAX_MAP_DRAW_VERTS];
extern int q3_numDrawIndexes;
extern int *q3_drawIndexes; //[Q3_MAX_MAP_DRAW_INDEXES];
extern int q3_numDrawSurfaces;
extern q3_dsurface_t *q3_drawSurfaces; //[Q3_MAX_MAP_DRAW_SURFS];
extern int q3_numFogs;
extern q3_dfog_t *q3_dfogs; //[Q3_MAX_MAP_FOGS];
extern char q3_dbrushsidetextured[Q3_MAX_MAP_BRUSHSIDES];
void Q3_LoadBSPFile( struct quakefile_s *qf );
void Q3_FreeMaxBSP( void );
void Q3_ParseEntities( void );

1186
src/bspc/l_bsp_sin.c Normal file

File diff suppressed because it is too large Load Diff

113
src/bspc/l_bsp_sin.h Normal file
View File

@@ -0,0 +1,113 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "sinfiles.h"
#define SINGAME_BSPHEADER ( ( 'P' << 24 ) + ( 'S' << 16 ) + ( 'B' << 8 ) + 'R' ) //RBSP
#define SINGAME_BSPVERSION 1
#define SIN_BSPHEADER ( ( 'P' << 24 ) + ( 'S' << 16 ) + ( 'B' << 8 ) + 'I' ) //IBSP
#define SIN_BSPVERSION 41
extern int sin_nummodels;
extern sin_dmodel_t *sin_dmodels; //[MAX_MAP_MODELS];
extern int sin_visdatasize;
extern byte *sin_dvisdata; //[MAX_MAP_VISIBILITY];
extern sin_dvis_t *sin_dvis; // = (dvis_t *)sin_sin_dvisdata;
extern int sin_lightdatasize;
extern byte *sin_dlightdata; //[MAX_MAP_LIGHTING];
extern int sin_entdatasize;
extern char *sin_dentdata; //[MAX_MAP_ENTSTRING];
extern int sin_numleafs;
extern sin_dleaf_t *sin_dleafs; //[MAX_MAP_LEAFS];
extern int sin_numplanes;
extern sin_dplane_t *sin_dplanes; //[MAX_MAP_PLANES];
extern int sin_numvertexes;
extern sin_dvertex_t *sin_dvertexes; //[MAX_MAP_VERTS];
extern int sin_numnodes;
extern sin_dnode_t *sin_dnodes; //[MAX_MAP_NODES];
extern int sin_numtexinfo;
extern sin_texinfo_t *sin_texinfo; //[MAX_MAP_sin_texinfo];
extern int sin_numfaces;
extern sin_dface_t *sin_dfaces; //[MAX_MAP_FACES];
extern int sin_numedges;
extern sin_dedge_t *sin_dedges; //[MAX_MAP_EDGES];
extern int sin_numleaffaces;
extern unsigned short *sin_dleaffaces; //[MAX_MAP_LEAFFACES];
extern int sin_numleafbrushes;
extern unsigned short *sin_dleafbrushes; //[MAX_MAP_LEAFBRUSHES];
extern int sin_numsurfedges;
extern int *sin_dsurfedges; //[MAX_MAP_SURFEDGES];
extern int sin_numbrushes;
extern sin_dbrush_t *sin_dbrushes; //[MAX_MAP_BRUSHES];
extern int sin_numbrushsides;
extern sin_dbrushside_t *sin_dbrushsides; //[MAX_MAP_BRUSHSIDES];
extern int sin_numareas;
extern sin_darea_t *sin_dareas; //[MAX_MAP_AREAS];
extern int sin_numareaportals;
extern sin_dareaportal_t *sin_dareaportals; //[MAX_MAP_AREAPORTALS];
extern int sin_numlightinfo;
extern sin_lightvalue_t *sin_lightinfo; //[MAX_MAP_LIGHTINFO];
extern byte sin_dpop[256];
extern char sin_dbrushsidetextured[SIN_MAX_MAP_BRUSHSIDES];
void Sin_AllocMaxBSP( void );
void Sin_FreeMaxBSP( void );
void Sin_DecompressVis( byte *in, byte *decompressed );
int Sin_CompressVis( byte *vis, byte *dest );
void Sin_LoadBSPFile( char *filename, int offset, int length );
void Sin_LoadBSPFileTexinfo( char *filename ); // just for qdata
void Sin_WriteBSPFile( char *filename );
void Sin_PrintBSPFileSizes( void );
void Sin_ParseEntities( void );
void Sin_UnparseEntities( void );

1182
src/bspc/l_cmd.c Normal file

File diff suppressed because it is too large Load Diff

164
src/bspc/l_cmd.h Normal file
View File

@@ -0,0 +1,164 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
// cmdlib.h
#ifndef SIN
#define SIN
#endif //SIN
#ifndef __CMDLIB__
#define __CMDLIB__
#ifdef _WIN32
#pragma warning(disable : 4244) // MIPS
#pragma warning(disable : 4136) // X86
#pragma warning(disable : 4051) // ALPHA
#pragma warning(disable : 4018) // signed/unsigned mismatch
#pragma warning(disable : 4305) // truncate from double to float
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <time.h>
#include <stdarg.h>
#ifndef __BYTEBOOL__
#define __BYTEBOOL__
typedef enum {false, true} qboolean;
typedef unsigned char byte;
#endif
// the dec offsetof macro doesnt work very well...
#define myoffsetof( type,identifier ) ( (size_t)&( (type *)0 )->identifier )
// set these before calling CheckParm
extern int myargc;
extern char **myargv;
char *strupr( char *in );
char *strlower( char *in );
int Q_strncasecmp( char *s1, char *s2, int n );
int Q_strcasecmp( char *s1, char *s2 );
void Q_getwd( char *out );
int Q_filelength( FILE *f );
int FileTime( char *path );
void Q_mkdir( char *path );
extern char qdir[1024];
extern char gamedir[1024];
void SetQdirFromPath( char *path );
char *ExpandArg( char *path ); // from cmd line
char *ExpandPath( char *path ); // from scripts
char *ExpandPathAndArchive( char *path );
double I_FloatTime( void );
void Error( char *error, ... );
void Warning( char *warning, ... );
int CheckParm( char *check );
FILE *SafeOpenWrite( char *filename );
FILE *SafeOpenRead( char *filename );
void SafeRead( FILE *f, void *buffer, int count );
void SafeWrite( FILE *f, void *buffer, int count );
int LoadFile( char *filename, void **bufferptr, int offset, int length );
int TryLoadFile( char *filename, void **bufferptr );
void SaveFile( char *filename, void *buffer, int count );
qboolean FileExists( char *filename );
void DefaultExtension( char *path, char *extension );
void DefaultPath( char *path, char *basepath );
void StripFilename( char *path );
void StripExtension( char *path );
void ExtractFilePath( char *path, char *dest );
void ExtractFileBase( char *path, char *dest );
void ExtractFileExtension( char *path, char *dest );
int ParseNum( char *str );
short BigShort( short l );
short LittleShort( short l );
int BigLong( int l );
int LittleLong( int l );
float BigFloat( float l );
float LittleFloat( float l );
#ifdef SIN
unsigned short BigUnsignedShort( unsigned short l );
unsigned short LittleUnsignedShort( unsigned short l );
unsigned BigUnsigned( unsigned l );
unsigned LittleUnsigned( unsigned l );
#endif
char *COM_Parse( char *data );
extern char com_token[1024];
extern qboolean com_eof;
char *copystring( char *s );
void CRC_Init( unsigned short *crcvalue );
void CRC_ProcessByte( unsigned short *crcvalue, byte data );
unsigned short CRC_Value( unsigned short crcvalue );
void CreatePath( char *path );
void QCopyFile( char *from, char *to );
extern qboolean archive;
extern char archivedir[1024];
extern qboolean verbose;
void qprintf( char *format, ... );
void ExpandWildcards( int *argc, char ***argv );
// for compression routines
typedef struct
{
byte *data;
int count;
} cblock_t;
#endif

220
src/bspc/l_log.c Normal file
View File

@@ -0,0 +1,220 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: l_log.c
// Function: log file stuff
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1997-12-31
// Tab Size: 3
//===========================================================================
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "qbsp.h"
#define MAX_LOGFILENAMESIZE 1024
typedef struct logfile_s
{
char filename[MAX_LOGFILENAMESIZE];
FILE *fp;
int numwrites;
} logfile_t;
logfile_t logfile;
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Log_Open( char *filename ) {
if ( !filename || !strlen( filename ) ) {
printf( "openlog <filename>\n" );
return;
} //end if
if ( logfile.fp ) {
printf( "log file %s is already opened\n", logfile.filename );
return;
} //end if
logfile.fp = fopen( filename, "wb" );
if ( !logfile.fp ) {
printf( "can't open the log file %s\n", filename );
return;
} //end if
strncpy( logfile.filename, filename, MAX_LOGFILENAMESIZE );
printf( "Opened log %s\n", logfile.filename );
} //end of the function Log_Create
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Log_Close( void ) {
if ( !logfile.fp ) {
printf( "no log file to close\n" );
return;
} //end if
if ( fclose( logfile.fp ) ) {
printf( "can't close log file %s\n", logfile.filename );
return;
} //end if
logfile.fp = NULL;
printf( "Closed log %s\n", logfile.filename );
} //end of the function Log_Close
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Log_Shutdown( void ) {
if ( logfile.fp ) {
Log_Close();
}
} //end of the function Log_Shutdown
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Log_UnifyEndOfLine( char *buf ) {
int i;
for ( i = 0; buf[i]; i++ )
{
if ( buf[i] == '\n' ) {
if ( i <= 0 || buf[i - 1] != '\r' ) {
memmove( &buf[i + 1], &buf[i], strlen( &buf[i] ) + 1 );
buf[i] = '\r';
i++;
} //end if
} //end if
} //end for
} //end of the function Log_UnifyEndOfLine
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Log_Print( char *fmt, ... ) {
va_list ap;
char buf[2048];
va_start( ap, fmt );
vsprintf( buf, fmt, ap );
va_end( ap );
if ( verbose ) {
#ifdef WINBSPC
WinBSPCPrint( buf );
#else
printf( "%s", buf );
#endif //WINBSPS
} //end if
if ( logfile.fp ) {
Log_UnifyEndOfLine( buf );
fprintf( logfile.fp, "%s", buf );
fflush( logfile.fp );
} //end if
} //end of the function Log_Print
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Log_Write( char *fmt, ... ) {
va_list ap;
char buf[2048];
if ( !logfile.fp ) {
return;
}
va_start( ap, fmt );
vsprintf( buf, fmt, ap );
va_end( ap );
Log_UnifyEndOfLine( buf );
fprintf( logfile.fp, "%s", buf );
fflush( logfile.fp );
} //end of the function Log_Write
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Log_WriteTimeStamped( char *fmt, ... ) {
va_list ap;
if ( !logfile.fp ) {
return;
}
/* fprintf(logfile.fp, "%d %02d:%02d:%02d:%02d ",
logfile.numwrites,
(int) (botlibglobals.time / 60 / 60),
(int) (botlibglobals.time / 60),
(int) (botlibglobals.time),
(int) ((int) (botlibglobals.time * 100)) -
((int) botlibglobals.time) * 100);*/
va_start( ap, fmt );
vfprintf( logfile.fp, fmt, ap );
va_end( ap );
logfile.numwrites++;
fflush( logfile.fp );
} //end of the function Log_Write
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
FILE *Log_FileStruct( void ) {
return logfile.fp;
} //end of the function Log_FileStruct
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Log_Flush( void ) {
if ( logfile.fp ) {
fflush( logfile.fp );
}
} //end of the function Log_Flush

57
src/bspc/l_log.h Normal file
View File

@@ -0,0 +1,57 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: l_log.h
// Function: log file stuff
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1997-12-31
// Tab Size: 3
//===========================================================================
//open a log file
void Log_Open( char *filename );
//close the current log file
void Log_Close( void );
//close log file if present
void Log_Shutdown( void );
//print on stdout and write to the current opened log file
void Log_Print( char *fmt, ... );
//write to the current opened log file
void Log_Write( char *fmt, ... );
//write to the current opened log file with a time stamp
void Log_WriteTimeStamped( char *fmt, ... );
//returns the log file structure
FILE *Log_FileStruct( void );
//flush log file
void Log_Flush( void );
#ifdef WINBSPC
void WinBSPCPrint( char *str );
#endif //WINBSPC

279
src/bspc/l_math.c Normal file
View File

@@ -0,0 +1,279 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
// mathlib.c -- math primitives
#include "l_cmd.h"
#include "l_math.h"
vec3_t vec3_origin = {0,0,0};
void AngleVectors( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up ) {
float angle;
static float sr, sp, sy, cr, cp, cy;
// static to help MS compiler fp bugs
angle = angles[YAW] * ( M_PI * 2 / 360 );
sy = sin( angle );
cy = cos( angle );
angle = angles[PITCH] * ( M_PI * 2 / 360 );
sp = sin( angle );
cp = cos( angle );
angle = angles[ROLL] * ( M_PI * 2 / 360 );
sr = sin( angle );
cr = cos( angle );
if ( forward ) {
forward[0] = cp * cy;
forward[1] = cp * sy;
forward[2] = -sp;
}
if ( right ) {
right[0] = ( -1 * sr * sp * cy + - 1 * cr * -sy );
right[1] = ( -1 * sr * sp * sy + - 1 * cr * cy );
right[2] = -1 * sr * cp;
}
if ( up ) {
up[0] = ( cr * sp * cy + - sr * -sy );
up[1] = ( cr * sp * sy + - sr * cy );
up[2] = cr * cp;
}
}
/*
=================
RadiusFromBounds
=================
*/
float RadiusFromBounds( const vec3_t mins, const vec3_t maxs ) {
int i;
vec3_t corner;
float a, b;
for ( i = 0 ; i < 3 ; i++ ) {
a = fabs( mins[i] );
b = fabs( maxs[i] );
corner[i] = a > b ? a : b;
}
return VectorLength( corner );
}
/*
================
R_ConcatRotations
================
*/
void R_ConcatRotations( float in1[3][3], float in2[3][3], float out[3][3] ) {
out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
in1[0][2] * in2[2][0];
out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
in1[0][2] * in2[2][1];
out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
in1[0][2] * in2[2][2];
out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
in1[1][2] * in2[2][0];
out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
in1[1][2] * in2[2][1];
out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
in1[1][2] * in2[2][2];
out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
in1[2][2] * in2[2][0];
out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
in1[2][2] * in2[2][1];
out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
in1[2][2] * in2[2][2];
}
void AxisClear( vec3_t axis[3] ) {
axis[0][0] = 1;
axis[0][1] = 0;
axis[0][2] = 0;
axis[1][0] = 0;
axis[1][1] = 1;
axis[1][2] = 0;
axis[2][0] = 0;
axis[2][1] = 0;
axis[2][2] = 1;
}
double VectorLength( vec3_t v ) {
int i;
double length;
length = 0;
for ( i = 0 ; i < 3 ; i++ )
length += v[i] * v[i];
length = sqrt( length ); // FIXME
return length;
}
float VectorLengthSquared( vec3_t v ) {
return DotProduct( v, v );
}
qboolean VectorCompare( vec3_t v1, vec3_t v2 ) {
int i;
for ( i = 0 ; i < 3 ; i++ )
if ( fabs( v1[i] - v2[i] ) > EQUAL_EPSILON ) {
return false;
}
return true;
}
vec_t Q_rint( vec_t in ) {
return floor( in + 0.5 );
}
void CrossProduct( const vec3_t v1, const vec3_t v2, vec3_t cross ) {
cross[0] = v1[1] * v2[2] - v1[2] * v2[1];
cross[1] = v1[2] * v2[0] - v1[0] * v2[2];
cross[2] = v1[0] * v2[1] - v1[1] * v2[0];
}
void _VectorMA( vec3_t va, double scale, vec3_t vb, vec3_t vc ) {
vc[0] = va[0] + scale * vb[0];
vc[1] = va[1] + scale * vb[1];
vc[2] = va[2] + scale * vb[2];
}
vec_t _DotProduct( vec3_t v1, vec3_t v2 ) {
return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
}
void _VectorSubtract( vec3_t va, vec3_t vb, vec3_t out ) {
out[0] = va[0] - vb[0];
out[1] = va[1] - vb[1];
out[2] = va[2] - vb[2];
}
void _VectorAdd( vec3_t va, vec3_t vb, vec3_t out ) {
out[0] = va[0] + vb[0];
out[1] = va[1] + vb[1];
out[2] = va[2] + vb[2];
}
void _VectorCopy( vec3_t in, vec3_t out ) {
out[0] = in[0];
out[1] = in[1];
out[2] = in[2];
}
void _VectorScale( vec3_t v, vec_t scale, vec3_t out ) {
out[0] = v[0] * scale;
out[1] = v[1] * scale;
out[2] = v[2] * scale;
}
vec_t VectorNormalize( vec3_t inout ) {
vec_t length, ilength;
length = sqrt( inout[0] * inout[0] + inout[1] * inout[1] + inout[2] * inout[2] );
if ( length == 0 ) {
VectorClear( inout );
return 0;
}
ilength = 1.0 / length;
inout[0] = inout[0] * ilength;
inout[1] = inout[1] * ilength;
inout[2] = inout[2] * ilength;
return length;
}
vec_t VectorNormalize2( const vec3_t in, vec3_t out ) {
vec_t length, ilength;
length = sqrt( in[0] * in[0] + in[1] * in[1] + in[2] * in[2] );
if ( length == 0 ) {
VectorClear( out );
return 0;
}
ilength = 1.0 / length;
out[0] = in[0] * ilength;
out[1] = in[1] * ilength;
out[2] = in[2] * ilength;
return length;
}
vec_t ColorNormalize( vec3_t in, vec3_t out ) {
float max, scale;
max = in[0];
if ( in[1] > max ) {
max = in[1];
}
if ( in[2] > max ) {
max = in[2];
}
if ( max == 0 ) {
return 0;
}
scale = 1.0 / max;
VectorScale( in, scale, out );
return max;
}
void VectorInverse( vec3_t v ) {
v[0] = -v[0];
v[1] = -v[1];
v[2] = -v[2];
}
void ClearBounds( vec3_t mins, vec3_t maxs ) {
mins[0] = mins[1] = mins[2] = 99999;
maxs[0] = maxs[1] = maxs[2] = -99999;
}
void AddPointToBounds( const vec3_t v, vec3_t mins, vec3_t maxs ) {
int i;
vec_t val;
for ( i = 0 ; i < 3 ; i++ )
{
val = v[i];
if ( val < mins[i] ) {
mins[i] = val;
}
if ( val > maxs[i] ) {
maxs[i] = val;
}
}
}

100
src/bspc/l_math.h Normal file
View File

@@ -0,0 +1,100 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#ifndef __MATHLIB__
#define __MATHLIB__
// mathlib.h
#include <math.h>
#ifdef DOUBLEVEC_T
typedef double vec_t;
#else
typedef float vec_t;
#endif
typedef vec_t vec3_t[3];
typedef vec_t vec4_t[4];
#define SIDE_FRONT 0
#define SIDE_ON 2
#define SIDE_BACK 1
#define SIDE_CROSS -2
#define PITCH 0
#define YAW 1
#define ROLL 2
#define Q_PI 3.14159265358979323846
#define DEG2RAD( a ) ( a * M_PI ) / 180.0F
#ifndef M_PI
#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h
#endif
extern vec3_t vec3_origin;
#define EQUAL_EPSILON 0.001
qboolean VectorCompare( vec3_t v1, vec3_t v2 );
#define DotProduct( x,y ) ( x[0] * y[0] + x[1] * y[1] + x[2] * y[2] )
#define VectorSubtract( a,b,c ) {c[0] = a[0] - b[0]; c[1] = a[1] - b[1]; c[2] = a[2] - b[2];}
#define VectorAdd( a,b,c ) {c[0] = a[0] + b[0]; c[1] = a[1] + b[1]; c[2] = a[2] + b[2];}
#define VectorCopy( a,b ) {b[0] = a[0]; b[1] = a[1]; b[2] = a[2];}
#define Vector4Copy( a,b ) {b[0] = a[0]; b[1] = a[1]; b[2] = a[2]; b[3] = a[3];}
#define VectorScale( v, s, o ) ( ( o )[0] = ( v )[0] * ( s ),( o )[1] = ( v )[1] * ( s ),( o )[2] = ( v )[2] * ( s ) )
#define VectorClear( x ) {x[0] = x[1] = x[2] = 0;}
#define VectorNegate( x, y ) {y[0] = -x[0]; y[1] = -x[1]; y[2] = -x[2];}
#define VectorMA( v, s, b, o ) ( ( o )[0] = ( v )[0] + ( b )[0] * ( s ),( o )[1] = ( v )[1] + ( b )[1] * ( s ),( o )[2] = ( v )[2] + ( b )[2] * ( s ) )
vec_t Q_rint( vec_t in );
vec_t _DotProduct( vec3_t v1, vec3_t v2 );
void _VectorSubtract( vec3_t va, vec3_t vb, vec3_t out );
void _VectorAdd( vec3_t va, vec3_t vb, vec3_t out );
void _VectorCopy( vec3_t in, vec3_t out );
void _VectorScale( vec3_t v, vec_t scale, vec3_t out );
void _VectorMA( vec3_t va, double scale, vec3_t vb, vec3_t vc );
double VectorLength( vec3_t v );
void CrossProduct( const vec3_t v1, const vec3_t v2, vec3_t cross );
vec_t VectorNormalize( vec3_t inout );
vec_t ColorNormalize( vec3_t in, vec3_t out );
vec_t VectorNormalize2( const vec3_t v, vec3_t out );
void VectorInverse( vec3_t v );
void ClearBounds( vec3_t mins, vec3_t maxs );
void AddPointToBounds( const vec3_t v, vec3_t mins, vec3_t maxs );
void AngleVectors( const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up );
void R_ConcatRotations( float in1[3][3], float in2[3][3], float out[3][3] );
void RotatePoint( vec3_t point, float matrix[3][3] );
void CreateRotationMatrix( vec3_t angles, float matrix[3][3] );
#endif

484
src/bspc/l_mem.c Normal file
View File

@@ -0,0 +1,484 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: l_mem.c
// Function:
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1999-06-02
// Tab Size: 3
//===========================================================================
#include "qbsp.h"
#include "l_log.h"
int allocedmemory;
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void PrintMemorySize( unsigned long size ) {
unsigned long number1, number2, number3;
number1 = size >> 20;
number2 = ( size & 0xFFFFF ) >> 10;
number3 = ( size & 0x3FF );
if ( number1 ) {
Log_Print( "%ld MB", number1 );
}
if ( number1 && number2 ) {
Log_Print( " and " );
}
if ( number2 ) {
Log_Print( "%ld KB", number2 );
}
if ( number2 && number3 ) {
Log_Print( " and " );
}
if ( number3 ) {
Log_Print( "%ld bytes", number3 );
}
} //end of the function PrintFileSize
#ifndef MEMDEBUG
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int MemorySize( void *ptr ) {
#if defined( WIN32 ) || defined( _WIN32 )
#ifdef __WATCOMC__
//Intel 32 bits memory addressing, 16 bytes aligned
return ( _msize( ptr ) + 15 ) >> 4 << 4;
#else
return _msize( ptr );
#endif
#else
return 0;
#endif
} //end of the function MemorySize
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void *GetClearedMemory( int size ) {
void *ptr;
ptr = (void *) malloc( size );
if ( !ptr ) {
Error( "out of memory" );
}
memset( ptr, 0, size );
allocedmemory += MemorySize( ptr );
return ptr;
} //end of the function GetClearedMemory
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void *GetMemory( unsigned long size ) {
void *ptr;
ptr = malloc( size );
if ( !ptr ) {
Error( "out of memory" );
}
allocedmemory += MemorySize( ptr );
return ptr;
} //end of the function GetMemory
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int fmemsize;
void FreeMemory( void *ptr ) {
// RF, modified this for better memory trash testing
fmemsize = MemorySize( ptr );
allocedmemory -= fmemsize;
// RF, somehow this crashes windows if size is less than or equal 8
if ( fmemsize <= 8 ) {
return;
}
// RF, set this memory to something that will cause problems if accessed again
memset( ptr, 0xAA, fmemsize );
free( ptr );
} //end of the function FreeMemory
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int TotalAllocatedMemory( void ) {
return allocedmemory;
} //end of the function TotalAllocatedMemory
#else
#define MEM_ID 0x12345678l
int totalmemorysize;
int numblocks;
typedef struct memoryblock_s
{
unsigned long int id;
void *ptr;
int size;
#ifdef MEMDEBUG
char *label;
char *file;
int line;
#endif //MEMDEBUG
struct memoryblock_s *prev, *next;
} memoryblock_t;
memoryblock_t *memory;
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void LinkMemoryBlock( memoryblock_t * block )
{
block->prev = NULL;
block->next = memory;
if ( memory ) {
memory->prev = block;
}
memory = block;
} //end of the function LinkMemoryBlock
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void UnlinkMemoryBlock( memoryblock_t * block )
{
if ( block->prev ) {
block->prev->next = block->next;
} else { memory = block->next;}
if ( block->next ) {
block->next->prev = block->prev;
}
} //end of the function UnlinkMemoryBlock
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
#ifdef MEMDEBUG
void *GetMemoryDebug( unsigned long size, char *label, char *file, int line )
#else
void *GetMemory( unsigned long size )
#endif //MEMDEBUG
{
void *ptr;
memoryblock_t *block;
ptr = malloc( size + sizeof( memoryblock_t ) );
block = (memoryblock_t *) ptr;
block->id = MEM_ID;
block->ptr = (char *) ptr + sizeof( memoryblock_t );
block->size = size + sizeof( memoryblock_t );
#ifdef MEMDEBUG
block->label = label;
block->file = file;
block->line = line;
#endif //MEMDEBUG
LinkMemoryBlock( block );
totalmemorysize += block->size;
numblocks++;
return block->ptr;
} //end of the function GetMemoryDebug
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
#ifdef MEMDEBUG
void *GetClearedMemoryDebug( unsigned long size, char *label, char *file, int line )
#else
void *GetClearedMemory( unsigned long size )
#endif //MEMDEBUG
{
void *ptr;
#ifdef MEMDEBUG
ptr = GetMemoryDebug( size, label, file, line );
#else
ptr = GetMemory( size );
#endif //MEMDEBUG
memset( ptr, 0, size );
return ptr;
} //end of the function GetClearedMemoryLabelled
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void *GetClearedHunkMemory( unsigned long size )
{
return GetClearedMemory( size );
} //end of the function GetClearedHunkMemory
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void *GetHunkMemory( unsigned long size )
{
return GetMemory( size );
} //end of the function GetHunkMemory
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
memoryblock_t *BlockFromPointer( void *ptr, char *str )
{
memoryblock_t *block;
if ( !ptr ) {
#ifdef MEMDEBUG
//char *crash = (char *) NULL;
//crash[0] = 1;
Error( "%s: NULL pointer\n", str );
#endif MEMDEBUG
return NULL;
} //end if
block = ( memoryblock_t * )( (char *) ptr - sizeof( memoryblock_t ) );
if ( block->id != MEM_ID ) {
Error( "%s: invalid memory block\n", str );
} //end if
if ( block->ptr != ptr ) {
Error( "%s: memory block pointer invalid\n", str );
} //end if
return block;
} //end of the function BlockFromPointer
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void FreeMemory( void *ptr )
{
memoryblock_t *block;
block = BlockFromPointer( ptr, "FreeMemory" );
if ( !block ) {
return;
}
UnlinkMemoryBlock( block );
totalmemorysize -= block->size;
numblocks--;
//
free( block );
} //end of the function FreeMemory
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int MemoryByteSize( void *ptr )
{
memoryblock_t *block;
block = BlockFromPointer( ptr, "MemoryByteSize" );
if ( !block ) {
return 0;
}
return block->size;
} //end of the function MemoryByteSize
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int MemorySize( void *ptr )
{
return MemoryByteSize( ptr );
} //end of the function MemorySize
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void PrintUsedMemorySize( void )
{
printf( "total botlib memory: %d KB\n", totalmemorysize >> 10 );
printf( "total memory blocks: %d\n", numblocks );
} //end of the function PrintUsedMemorySize
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void PrintMemoryLabels( void )
{
memoryblock_t *block;
int i;
PrintUsedMemorySize();
i = 0;
for ( block = memory; block; block = block->next )
{
#ifdef MEMDEBUG
Log_Write( "%6d, %p, %8d: %24s line %6d: %s", i, block->ptr, block->size, block->file, block->line, block->label );
#endif //MEMDEBUG
i++;
} //end for
} //end of the function PrintMemoryLabels
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void DumpMemory( void )
{
memoryblock_t *block;
for ( block = memory; block; block = memory )
{
FreeMemory( block->ptr );
} //end for
totalmemorysize = 0;
} //end of the function DumpMemory
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int TotalAllocatedMemory( void )
{
return totalmemorysize;
} //end of the function TotalAllocatedMemory
#endif
//===========================================================================
// Q3 Hunk and Z_ memory management
//===========================================================================
typedef struct memhunk_s
{
void *ptr;
struct memhunk_s *next;
} memhunk_t;
memhunk_t *memhunk_high;
memhunk_t *memhunk_low;
int memhunk_high_size = 16 * 1024 * 1024;
int memhunk_low_size = 0;
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Hunk_ClearHigh( void )
{
memhunk_t *h, *nexth;
for ( h = memhunk_high; h; h = nexth )
{
nexth = h->next;
FreeMemory( h );
} //end for
memhunk_high = NULL;
memhunk_high_size = 16 * 1024 * 1024;
} //end of the function Hunk_ClearHigh
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void *Hunk_Alloc( int size )
{
memhunk_t *h;
if ( !size ) {
return (void *) memhunk_high_size;
}
//
h = GetClearedMemory( size + sizeof( memhunk_t ) );
h->ptr = (char *) h + sizeof( memhunk_t );
h->next = memhunk_high;
memhunk_high = h;
memhunk_high_size -= size;
return h->ptr;
} //end of the function Hunk_Alloc
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void *Z_Malloc( int size )
{
return GetClearedMemory( size );
} //end of the function Z_Malloc
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Z_Free( void *ptr )
{
FreeMemory( ptr );
} //end of the function Z_Free

58
src/bspc/l_mem.h Normal file
View File

@@ -0,0 +1,58 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//=============================================================================
// memory.h
//#define MEMDEBUG
#undef MEMDEBUG
#ifndef MEMDEBUG
void *GetClearedMemory( int size );
void *GetMemory( unsigned long size );
#else
#define GetMemory( size ) GetMemoryDebug( size, # size, __FILE__, __LINE__ );
#define GetClearedMemory( size ) GetClearedMemoryDebug( size, # size, __FILE__, __LINE__ );
//allocate a memory block of the given size
void *GetMemoryDebug( unsigned long size, char *label, char *file, int line );
//allocate a memory block of the given size and clear it
void *GetClearedMemoryDebug( unsigned long size, char *label, char *file, int line );
//
void PrintMemoryLabels( void );
#endif //MEMDEBUG
void FreeMemory( void *ptr );
int MemorySize( void *ptr );
void PrintMemorySize( unsigned long size );
int TotalAllocatedMemory( void );

1433
src/bspc/l_poly.c Normal file

File diff suppressed because it is too large Load Diff

136
src/bspc/l_poly.h Normal file
View File

@@ -0,0 +1,136 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: l_poly.h
// Function:
// Programmer: id Sofware
// Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1997-12-04
// Tab Size: 3
//===========================================================================
//a winding gives the bounding points of a convex polygon
typedef struct
{
int numpoints;
vec3_t p[4]; //variable sized
} winding_t;
#define MAX_POINTS_ON_WINDING 96
//you can define on_epsilon in the makefile as tighter
#ifndef ON_EPSILON
#define ON_EPSILON 0.1
#endif
//winding errors
#define WE_NONE 0
#define WE_NOTENOUGHPOINTS 1
#define WE_SMALLAREA 2
#define WE_POINTBOGUSRANGE 3
#define WE_POINTOFFPLANE 4
#define WE_DEGENERATEEDGE 5
#define WE_NONCONVEX 6
//allocates a winding
winding_t *AllocWinding( int points );
//returns the area of the winding
vec_t WindingArea( winding_t *w );
//gives the center of the winding
void WindingCenter( winding_t *w, vec3_t center );
//clips the given winding to the given plane and gives the front
//and back part of the clipped winding
void ClipWindingEpsilon( winding_t *in, vec3_t normal, vec_t dist,
vec_t epsilon, winding_t **front, winding_t **back );
//returns the fragment of the given winding that is on the front
//side of the cliping plane. The original is freed.
winding_t *ChopWinding( winding_t *in, vec3_t normal, vec_t dist );
//returns a copy of the given winding
winding_t *CopyWinding( winding_t *w );
//returns the reversed winding of the given one
winding_t *ReverseWinding( winding_t *w );
//returns a base winding for the given plane
winding_t *BaseWindingForPlane( vec3_t normal, vec_t dist );
//checks the winding for errors
void CheckWinding( winding_t *w );
//returns the plane normal and dist the winding is in
void WindingPlane( winding_t *w, vec3_t normal, vec_t *dist );
//removes colinear points from the winding
void RemoveColinearPoints( winding_t *w );
//returns on which side of the plane the winding is situated
int WindingOnPlaneSide( winding_t *w, vec3_t normal, vec_t dist );
//frees the winding
void FreeWinding( winding_t *w );
//gets the bounds of the winding
void WindingBounds( winding_t *w, vec3_t mins, vec3_t maxs );
//chops the winding with the given plane, the original winding is freed if clipped
void ChopWindingInPlace( winding_t **w, vec3_t normal, vec_t dist, vec_t epsilon );
//prints the winding points on STDOUT
void pw( winding_t *w );
//try to merge the two windings which are in the given plane
//the original windings are undisturbed
//the merged winding is returned when merging was possible
//NULL is returned otherwise
winding_t *TryMergeWinding( winding_t *f1, winding_t *f2, vec3_t planenormal );
//brute force winding merging... creates a convex winding out of
//the two whatsoever
winding_t *MergeWindings( winding_t *w1, winding_t *w2, vec3_t planenormal );
//#ifdef ME
void ResetWindings( void );
//returns the amount of winding memory
int WindingMemory( void );
int WindingPeakMemory( void );
int ActiveWindings( void );
//returns the winding error string
char *WindingErrorString( void );
//returns one of the WE_ flags when the winding has errors
int WindingError( winding_t *w );
//removes equal points from the winding
void RemoveEqualPoints( winding_t *w, float epsilon );
//returns a winding with a point added at the given spot to the
//given winding, original winding is NOT freed
winding_t *AddWindingPoint( winding_t *w, vec3_t point, int spot );
//returns true if the point is on one of the winding 'edges'
//when the point is on one of the edged the number of the first
//point of the edge is stored in 'spot'
int PointOnWinding( winding_t *w, vec3_t normal, float dist, vec3_t point, int *spot );
//find a plane seperating the two windings
//true is returned when the windings area adjacent
//the seperating plane normal and distance area stored in 'normal' and 'dist'
//this plane will contain both the piece of common edge of the two windings
//and the vector 'dir'
int FindPlaneSeperatingWindings( winding_t *w1, winding_t *w2, vec3_t dir,
vec3_t normal, float *dist );
//
int WindingsNonConvex( winding_t *w1, winding_t *w2,
vec3_t normal1, vec3_t normal2,
float dist1, float dist2 );
//#endif //ME

701
src/bspc/l_qfiles.c Normal file
View File

@@ -0,0 +1,701 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: l_qfiles.h
// Function: -
// Programmer: Mr Elusive
// Last update: 1999-11-29
// Tab Size: 3
//===========================================================================
#if defined( WIN32 ) | defined( _WIN32 )
#include <windows.h>
#include <sys/types.h>
#include <sys/stat.h>
#else
#include <glob.h>
#include <sys/stat.h>
#include <unistd.h>
#endif
#include "qbsp.h"
//file extensions with their type
typedef struct qfile_exttype_s
{
char *extension;
int type;
} qfile_exttyp_t;
qfile_exttyp_t quakefiletypes[] =
{
{QFILEEXT_UNKNOWN, QFILETYPE_UNKNOWN},
{QFILEEXT_PAK, QFILETYPE_PAK},
{QFILEEXT_PK3, QFILETYPE_PK3},
{QFILEEXT_SIN, QFILETYPE_PAK},
{QFILEEXT_BSP, QFILETYPE_BSP},
{QFILEEXT_MAP, QFILETYPE_MAP},
{QFILEEXT_MDL, QFILETYPE_MDL},
{QFILEEXT_MD2, QFILETYPE_MD2},
{QFILEEXT_MD3, QFILETYPE_MD3},
{QFILEEXT_WAL, QFILETYPE_WAL},
{QFILEEXT_WAV, QFILETYPE_WAV},
{QFILEEXT_AAS, QFILETYPE_AAS},
{NULL, 0}
};
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int QuakeFileExtensionType( char *extension ) {
int i;
for ( i = 0; quakefiletypes[i].extension; i++ )
{
if ( !stricmp( extension, quakefiletypes[i].extension ) ) {
return quakefiletypes[i].type;
} //end if
} //end for
return QFILETYPE_UNKNOWN;
} //end of the function QuakeFileExtensionType
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
char *QuakeFileTypeExtension( int type ) {
int i;
for ( i = 0; quakefiletypes[i].extension; i++ )
{
if ( quakefiletypes[i].type == type ) {
return quakefiletypes[i].extension;
} //end if
} //end for
return QFILEEXT_UNKNOWN;
} //end of the function QuakeFileExtension
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int QuakeFileType( char *filename ) {
char ext[_MAX_PATH] = ".";
ExtractFileExtension( filename, ext + 1 );
return QuakeFileExtensionType( ext );
} //end of the function QuakeFileTypeFromFileName
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
char *StringContains( char *str1, char *str2, int casesensitive ) {
int len, i, j;
len = strlen( str1 ) - strlen( str2 );
for ( i = 0; i <= len; i++, str1++ )
{
for ( j = 0; str2[j]; j++ )
{
if ( casesensitive ) {
if ( str1[j] != str2[j] ) {
break;
}
} //end if
else
{
if ( toupper( str1[j] ) != toupper( str2[j] ) ) {
break;
}
} //end else
} //end for
if ( !str2[j] ) {
return str1;
}
} //end for
return NULL;
} //end of the function StringContains
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int FileFilter( char *filter, char *filename, int casesensitive ) {
char buf[1024];
char *ptr;
int i, found;
while ( *filter )
{
if ( *filter == '*' ) {
filter++;
for ( i = 0; *filter; i++ )
{
if ( *filter == '*' || *filter == '?' ) {
break;
}
buf[i] = *filter;
filter++;
} //end for
buf[i] = '\0';
if ( strlen( buf ) ) {
ptr = StringContains( filename, buf, casesensitive );
if ( !ptr ) {
return false;
}
filename = ptr + strlen( buf );
} //end if
} //end if
else if ( *filter == '?' ) {
filter++;
filename++;
} //end else if
else if ( *filter == '[' && *( filter + 1 ) == '[' ) {
filter++;
} //end if
else if ( *filter == '[' ) {
filter++;
found = false;
while ( *filter && !found )
{
if ( *filter == ']' && *( filter + 1 ) != ']' ) {
break;
}
if ( *( filter + 1 ) == '-' && *( filter + 2 ) && ( *( filter + 2 ) != ']' || *( filter + 3 ) == ']' ) ) {
if ( casesensitive ) {
if ( *filename >= *filter && *filename <= *( filter + 2 ) ) {
found = true;
}
} //end if
else
{
if ( toupper( *filename ) >= toupper( *filter ) &&
toupper( *filename ) <= toupper( *( filter + 2 ) ) ) {
found = true;
}
} //end else
filter += 3;
} //end if
else
{
if ( casesensitive ) {
if ( *filter == *filename ) {
found = true;
}
} //end if
else
{
if ( toupper( *filter ) == toupper( *filename ) ) {
found = true;
}
} //end else
filter++;
} //end else
} //end while
if ( !found ) {
return false;
}
while ( *filter )
{
if ( *filter == ']' && *( filter + 1 ) != ']' ) {
break;
}
filter++;
} //end while
filter++;
filename++;
} //end else if
else
{
if ( casesensitive ) {
if ( *filter != *filename ) {
return false;
}
} //end if
else
{
if ( toupper( *filter ) != toupper( *filename ) ) {
return false;
}
} //end else
filter++;
filename++;
} //end else
} //end while
return true;
} //end of the function FileFilter
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
quakefile_t *FindQuakeFilesInZip( char *zipfile, char *filter ) {
unzFile uf;
int err;
unz_global_info gi;
char filename_inzip[MAX_PATH];
unz_file_info file_info;
int i;
quakefile_t *qfiles, *lastqf, *qf;
uf = unzOpen( zipfile );
err = unzGetGlobalInfo( uf, &gi );
if ( err != UNZ_OK ) {
return NULL;
}
unzGoToFirstFile( uf );
qfiles = NULL;
lastqf = NULL;
for ( i = 0; i < gi.number_entry; i++ )
{
err = unzGetCurrentFileInfo( uf, &file_info, filename_inzip, sizeof( filename_inzip ), NULL,0,NULL,0 );
if ( err != UNZ_OK ) {
break;
}
ConvertPath( filename_inzip );
if ( FileFilter( filter, filename_inzip, false ) ) {
qf = malloc( sizeof( quakefile_t ) );
if ( !qf ) {
Error( "out of memory" );
}
memset( qf, 0, sizeof( quakefile_t ) );
strcpy( qf->pakfile, zipfile );
strcpy( qf->filename, zipfile );
strcpy( qf->origname, filename_inzip );
qf->zipfile = true;
//memcpy( &buildBuffer[i].zipfileinfo, (unz_s*)uf, sizeof(unz_s));
memcpy( &qf->zipinfo, (unz_s*)uf, sizeof( unz_s ) );
qf->offset = 0;
qf->length = file_info.uncompressed_size;
qf->type = QuakeFileType( filename_inzip );
//add the file ot the list
qf->next = NULL;
if ( lastqf ) {
lastqf->next = qf;
} else { qfiles = qf;}
lastqf = qf;
} //end if
unzGoToNextFile( uf );
} //end for
unzClose( uf );
return qfiles;
} //end of the function FindQuakeFilesInZip
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
quakefile_t *FindQuakeFilesInPak( char *pakfile, char *filter ) {
FILE *fp;
dpackheader_t packheader;
dsinpackfile_t *packfiles;
dpackfile_t *idpackfiles;
quakefile_t *qfiles, *lastqf, *qf;
int numpackdirs, i;
qfiles = NULL;
lastqf = NULL;
//open the pak file
fp = fopen( pakfile, "rb" );
if ( !fp ) {
Warning( "can't open pak file %s", pakfile );
return NULL;
} //end if
//read pak header, check for valid pak id and seek to the dir entries
if ( ( fread( &packheader, 1, sizeof( dpackheader_t ), fp ) != sizeof( dpackheader_t ) )
|| ( packheader.ident != IDPAKHEADER && packheader.ident != SINPAKHEADER )
|| ( fseek( fp, LittleLong( packheader.dirofs ), SEEK_SET ) )
) {
fclose( fp );
Warning( "invalid pak file %s", pakfile );
return NULL;
} //end if
//if it is a pak file from id software
if ( packheader.ident == IDPAKHEADER ) {
//number of dir entries in the pak file
numpackdirs = LittleLong( packheader.dirlen ) / sizeof( dpackfile_t );
idpackfiles = (dpackfile_t *) malloc( numpackdirs * sizeof( dpackfile_t ) );
if ( !idpackfiles ) {
Error( "out of memory" );
}
//read the dir entry
if ( fread( idpackfiles, sizeof( dpackfile_t ), numpackdirs, fp ) != numpackdirs ) {
fclose( fp );
free( idpackfiles );
Warning( "can't read the Quake pak file dir entries from %s", pakfile );
return NULL;
} //end if
fclose( fp );
//convert to sin pack files
packfiles = (dsinpackfile_t *) malloc( numpackdirs * sizeof( dsinpackfile_t ) );
if ( !packfiles ) {
Error( "out of memory" );
}
for ( i = 0; i < numpackdirs; i++ )
{
strcpy( packfiles[i].name, idpackfiles[i].name );
packfiles[i].filepos = LittleLong( idpackfiles[i].filepos );
packfiles[i].filelen = LittleLong( idpackfiles[i].filelen );
} //end for
free( idpackfiles );
} //end if
else //its a Sin pack file
{
//number of dir entries in the pak file
numpackdirs = LittleLong( packheader.dirlen ) / sizeof( dsinpackfile_t );
packfiles = (dsinpackfile_t *) malloc( numpackdirs * sizeof( dsinpackfile_t ) );
if ( !packfiles ) {
Error( "out of memory" );
}
//read the dir entry
if ( fread( packfiles, sizeof( dsinpackfile_t ), numpackdirs, fp ) != numpackdirs ) {
fclose( fp );
free( packfiles );
Warning( "can't read the Sin pak file dir entries from %s", pakfile );
return NULL;
} //end if
fclose( fp );
for ( i = 0; i < numpackdirs; i++ )
{
packfiles[i].filepos = LittleLong( packfiles[i].filepos );
packfiles[i].filelen = LittleLong( packfiles[i].filelen );
} //end for
} //end else
//
for ( i = 0; i < numpackdirs; i++ )
{
ConvertPath( packfiles[i].name );
if ( FileFilter( filter, packfiles[i].name, false ) ) {
qf = malloc( sizeof( quakefile_t ) );
if ( !qf ) {
Error( "out of memory" );
}
memset( qf, 0, sizeof( quakefile_t ) );
strcpy( qf->pakfile, pakfile );
strcpy( qf->filename, pakfile );
strcpy( qf->origname, packfiles[i].name );
qf->zipfile = false;
qf->offset = packfiles[i].filepos;
qf->length = packfiles[i].filelen;
qf->type = QuakeFileType( packfiles[i].name );
//add the file ot the list
qf->next = NULL;
if ( lastqf ) {
lastqf->next = qf;
} else { qfiles = qf;}
lastqf = qf;
} //end if
} //end for
free( packfiles );
return qfiles;
} //end of the function FindQuakeFilesInPak
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
quakefile_t *FindQuakeFilesWithPakFilter( char *pakfilter, char *filter ) {
#if defined( WIN32 ) | defined( _WIN32 )
WIN32_FIND_DATA filedata;
HWND handle;
struct _stat statbuf;
#else
glob_t globbuf;
struct stat statbuf;
int j;
#endif
quakefile_t *qfiles, *lastqf, *qf;
char pakfile[_MAX_PATH], filename[_MAX_PATH], *str;
int done;
qfiles = NULL;
lastqf = NULL;
if ( pakfilter && strlen( pakfilter ) ) {
#if defined( WIN32 ) | defined( _WIN32 )
handle = FindFirstFile( pakfilter, &filedata );
done = ( handle == INVALID_HANDLE_VALUE );
while ( !done )
{
_splitpath( pakfilter, pakfile, NULL, NULL, NULL );
_splitpath( pakfilter, NULL, &pakfile[strlen( pakfile )], NULL, NULL );
AppendPathSeperator( pakfile, _MAX_PATH );
strcat( pakfile, filedata.cFileName );
_stat( pakfile, &statbuf );
#else
glob( pakfilter, 0, NULL, &globbuf );
for ( j = 0; j < globbuf.gl_pathc; j++ )
{
strcpy( pakfile, globbuf.gl_pathv[j] );
stat( pakfile, &statbuf );
#endif
//if the file with .pak or .pk3 is a folder
if ( statbuf.st_mode & S_IFDIR ) {
strcpy( filename, pakfilter );
AppendPathSeperator( filename, _MAX_PATH );
strcat( filename, filter );
qf = FindQuakeFilesWithPakFilter( NULL, filename );
if ( lastqf ) {
lastqf->next = qf;
} else { qfiles = qf;}
lastqf = qf;
while ( lastqf->next ) lastqf = lastqf->next;
} //end if
else
{
#if defined( WIN32 ) | defined( _WIN32 )
str = StringContains( pakfile, ".pk3", false );
#else
str = StringContains( pakfile, ".pk3", true );
#endif
if ( str && str == pakfile + strlen( pakfile ) - strlen( ".pk3" ) ) {
qf = FindQuakeFilesInZip( pakfile, filter );
} //end if
else
{
qf = FindQuakeFilesInPak( pakfile, filter );
} //end else
//
if ( qf ) {
if ( lastqf ) {
lastqf->next = qf;
} else { qfiles = qf;}
lastqf = qf;
while ( lastqf->next ) lastqf = lastqf->next;
} //end if
} //end else
//
#if defined( WIN32 ) | defined( _WIN32 )
//find the next file
done = !FindNextFile( handle, &filedata );
} //end while
#else
} //end for
globfree( &globbuf );
#endif
} //end if
else
{
#if defined( WIN32 ) | defined( _WIN32 )
handle = FindFirstFile( filter, &filedata );
done = ( handle == INVALID_HANDLE_VALUE );
while ( !done )
{
_splitpath( filter, filename, NULL, NULL, NULL );
_splitpath( filter, NULL, &filename[strlen( filename )], NULL, NULL );
AppendPathSeperator( filename, _MAX_PATH );
strcat( filename, filedata.cFileName );
#else
glob( filter, 0, NULL, &globbuf );
for ( j = 0; j < globbuf.gl_pathc; j++ )
{
strcpy( filename, globbuf.gl_pathv[j] );
#endif
//
qf = malloc( sizeof( quakefile_t ) );
if ( !qf ) {
Error( "out of memory" );
}
memset( qf, 0, sizeof( quakefile_t ) );
strcpy( qf->pakfile, "" );
strcpy( qf->filename, filename );
strcpy( qf->origname, filename );
qf->offset = 0;
qf->length = 0;
qf->type = QuakeFileType( filename );
//add the file ot the list
qf->next = NULL;
if ( lastqf ) {
lastqf->next = qf;
} else { qfiles = qf;}
lastqf = qf;
#if defined( WIN32 ) | defined( _WIN32 )
//find the next file
done = !FindNextFile( handle, &filedata );
} //end while
#else
} //end for
globfree( &globbuf );
#endif
} //end else
return qfiles;
} //end of the function FindQuakeFilesWithPakFilter
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
quakefile_t *FindQuakeFiles( char *filter ) {
char *str;
char newfilter[_MAX_PATH];
char pakfilter[_MAX_PATH];
char filefilter[_MAX_PATH];
strcpy( newfilter, filter );
ConvertPath( newfilter );
strcpy( pakfilter, newfilter );
str = StringContains( pakfilter, ".pak", false );
if ( !str ) {
str = StringContains( pakfilter, ".pk3", false );
}
if ( str ) {
str += strlen( ".pak" );
if ( *str ) {
*str++ = '\0';
while ( *str == '\\' || *str == '/' ) str++;
strcpy( filefilter, str );
return FindQuakeFilesWithPakFilter( pakfilter, filefilter );
} //end if
} //end else
return FindQuakeFilesWithPakFilter( NULL, newfilter );
} //end of the function FindQuakeFiles
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int LoadQuakeFile( quakefile_t *qf, void **bufferptr ) {
FILE *fp;
void *buffer;
int length;
unzFile zf;
if ( qf->zipfile ) {
//open the zip file
zf = unzOpen( qf->pakfile );
//set the file pointer
qf->zipinfo.file = ( (unz_s *) zf )->file;
//open the Quake file in the zip file
unzOpenCurrentFile( &qf->zipinfo );
//allocate memory for the buffer
length = qf->length;
buffer = GetMemory( length + 1 );
//read the Quake file from the zip file
length = unzReadCurrentFile( &qf->zipinfo, buffer, length );
//close the Quake file in the zip file
unzCloseCurrentFile( &qf->zipinfo );
//close the zip file
unzClose( zf );
*bufferptr = buffer;
return length;
} //end if
else
{
fp = SafeOpenRead( qf->filename );
if ( qf->offset ) {
fseek( fp, qf->offset, SEEK_SET );
}
length = qf->length;
if ( !length ) {
length = Q_filelength( fp );
}
buffer = GetMemory( length + 1 );
( (char *)buffer )[length] = 0;
SafeRead( fp, buffer, length );
fclose( fp );
*bufferptr = buffer;
return length;
} //end else
} //end of the function LoadQuakeFile
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int ReadQuakeFile( quakefile_t *qf, void *buffer, int offset, int length ) {
FILE *fp;
int read;
unzFile zf;
char tmpbuf[1024];
if ( qf->zipfile ) {
//open the zip file
zf = unzOpen( qf->pakfile );
//set the file pointer
qf->zipinfo.file = ( (unz_s *) zf )->file;
//open the Quake file in the zip file
unzOpenCurrentFile( &qf->zipinfo );
//
while ( offset > 0 )
{
read = offset;
if ( read > sizeof( tmpbuf ) ) {
read = sizeof( tmpbuf );
}
unzReadCurrentFile( &qf->zipinfo, tmpbuf, read );
offset -= read;
} //end while
//read the Quake file from the zip file
length = unzReadCurrentFile( &qf->zipinfo, buffer, length );
//close the Quake file in the zip file
unzCloseCurrentFile( &qf->zipinfo );
//close the zip file
unzClose( zf );
return length;
} //end if
else
{
fp = SafeOpenRead( qf->filename );
if ( qf->offset ) {
fseek( fp, qf->offset, SEEK_SET );
}
if ( offset ) {
fseek( fp, offset, SEEK_CUR );
}
SafeRead( fp, buffer, length );
fclose( fp );
return length;
} //end else
} //end of the function ReadQuakeFile

106
src/bspc/l_qfiles.h Normal file
View File

@@ -0,0 +1,106 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: l_qfiles.h
// Function: -
// Programmer: Mr Elusive
// Last update: 1999-12-01
// Tab Size: 3
//===========================================================================
#include "../qcommon/unzip.h"
#define QFILETYPE_UNKNOWN 0x8000
#define QFILETYPE_PAK 0x0001
#define QFILETYPE_PK3 0x0002
#define QFILETYPE_BSP 0x0004
#define QFILETYPE_MAP 0x0008
#define QFILETYPE_MDL 0x0010
#define QFILETYPE_MD2 0x0020
#define QFILETYPE_MD3 0x0040
#define QFILETYPE_WAL 0x0080
#define QFILETYPE_WAV 0x0100
#define QFILETYPE_AAS 0x4000
#define QFILEEXT_UNKNOWN ""
#define QFILEEXT_PAK ".PAK"
#define QFILEEXT_PK3 ".PK3"
#define QFILEEXT_SIN ".SIN"
#define QFILEEXT_BSP ".BSP"
#define QFILEEXT_MAP ".MAP"
#define QFILEEXT_MDL ".MDL"
#define QFILEEXT_MD2 ".MD2"
#define QFILEEXT_MD3 ".MD3"
#define QFILEEXT_WAL ".WAL"
#define QFILEEXT_WAV ".WAV"
#define QFILEEXT_AAS ".AAS"
//maximum path length
#ifndef _MAX_PATH
#define _MAX_PATH 1024
#endif
//for Sin packs
#define MAX_PAK_FILENAME_LENGTH 120
#define SINPAKHEADER ( ( 'K' << 24 ) + ( 'A' << 16 ) + ( 'P' << 8 ) + 'S' )
typedef struct
{
char name[MAX_PAK_FILENAME_LENGTH];
int filepos, filelen;
} dsinpackfile_t;
typedef struct quakefile_s
{
char pakfile[_MAX_PATH];
char filename[_MAX_PATH];
char origname[_MAX_PATH];
int zipfile;
int type;
int offset;
int length;
unz_s zipinfo;
struct quakefile_s *next;
} quakefile_t;
//returns the file extension for the given type
char *QuakeFileTypeExtension( int type );
//returns the file type for the given extension
int QuakeFileExtensionType( char *extension );
//return the Quake file type for the given file
int QuakeFileType( char *filename );
//returns true if the filename complies to the filter
int FileFilter( char *filter, char *filename, int casesensitive );
//find Quake files using the given filter
quakefile_t *FindQuakeFiles( char *filter );
//load the given Quake file, returns the length of the file
int LoadQuakeFile( quakefile_t *qf, void **bufferptr );
//read part of a Quake file into the buffer
int ReadQuakeFile( quakefile_t *qf, void *buffer, int offset, int length );

1528
src/bspc/l_threads.c Normal file

File diff suppressed because it is too large Load Diff

52
src/bspc/l_threads.h Normal file
View File

@@ -0,0 +1,52 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
extern int numthreads;
void ThreadSetDefault( void );
int GetThreadWork( void );
void RunThreadsOnIndividual( int workcnt, qboolean showpacifier, void ( *func )( int ) );
void RunThreadsOn( int workcnt, qboolean showpacifier, void ( *func )( int ) );
//mutex
void ThreadSetupLock( void );
void ThreadShutdownLock( void );
void ThreadLock( void );
void ThreadUnlock( void );
//semaphore
void ThreadSetupSemaphore( void );
void ThreadShutdownSemaphore( void );
void ThreadSemaphoreWait( void );
void ThreadSemaphoreIncrease( int count );
//add/remove threads
void AddThread( void ( *func )( int ) );
void RemoveThread( int threadid );
void WaitForAllThreadsFinished( void );
int GetNumThreads( void );

262
src/bspc/l_utils.c Normal file
View File

@@ -0,0 +1,262 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: l_utils.c
// Function: several utils
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1997-12-31
// Tab Size: 3
//===========================================================================
//#ifndef BOTLIB
//#define BOTLIB
//#endif //BOTLIB
#ifdef BOTLIB
#include "q_shared.h"
#include "qfiles.h"
#include "botlib.h"
#include "l_log.h"
#include "l_libvar.h"
#include "l_memory.h"
//#include "l_utils.h"
#include "be_interface.h"
#else //BOTLIB
#include "qbsp.h"
#include "l_mem.h"
#endif //BOTLIB
#ifdef BOTLIB
//========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//========================================================================
void Vector2Angles( vec3_t value1, vec3_t angles ) {
float forward;
float yaw, pitch;
if ( value1[1] == 0 && value1[0] == 0 ) {
yaw = 0;
if ( value1[2] > 0 ) {
pitch = 90;
} else { pitch = 270;}
} //end if
else
{
yaw = (int) ( atan2( value1[1], value1[0] ) * 180 / M_PI );
if ( yaw < 0 ) {
yaw += 360;
}
forward = sqrt( value1[0] * value1[0] + value1[1] * value1[1] );
pitch = (int) ( atan2( value1[2], forward ) * 180 / M_PI );
if ( pitch < 0 ) {
pitch += 360;
}
} //end else
angles[PITCH] = -pitch;
angles[YAW] = yaw;
angles[ROLL] = 0;
} //end of the function Vector2Angles
#endif //BOTLIB
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void ConvertPath( char *path ) {
while ( *path )
{
if ( *path == '/' || *path == '\\' ) {
*path = PATHSEPERATOR_CHAR;
}
path++;
} //end while
} //end of the function ConvertPath
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AppendPathSeperator( char *path, int length ) {
int pathlen = strlen( path );
if ( strlen( path ) && length - pathlen > 1 && path[pathlen - 1] != '/' && path[pathlen - 1] != '\\' ) {
path[pathlen] = PATHSEPERATOR_CHAR;
path[pathlen + 1] = '\0';
} //end if
} //end of the function AppenPathSeperator
//===========================================================================
// returns pointer to file handle
// sets offset to and length of 'filename' in the pak file
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
qboolean FindFileInPak( char *pakfile, char *filename, foundfile_t *file ) {
FILE *fp;
dpackheader_t packheader;
dpackfile_t *packfiles;
int numdirs, i;
char path[MAX_PATH];
//open the pak file
fp = fopen( pakfile, "rb" );
if ( !fp ) {
return false;
} //end if
//read pak header, check for valid pak id and seek to the dir entries
if ( ( fread( &packheader, 1, sizeof( dpackheader_t ), fp ) != sizeof( dpackheader_t ) )
|| ( packheader.ident != IDPAKHEADER )
|| ( fseek( fp, LittleLong( packheader.dirofs ), SEEK_SET ) )
) {
fclose( fp );
return false;
} //end if
//number of dir entries in the pak file
numdirs = LittleLong( packheader.dirlen ) / sizeof( dpackfile_t );
packfiles = (dpackfile_t *) GetMemory( numdirs * sizeof( dpackfile_t ) );
//read the dir entry
if ( fread( packfiles, sizeof( dpackfile_t ), numdirs, fp ) != numdirs ) {
fclose( fp );
FreeMemory( packfiles );
return false;
} //end if
fclose( fp );
//
strcpy( path, filename );
ConvertPath( path );
//find the dir entry in the pak file
for ( i = 0; i < numdirs; i++ )
{
//convert the dir entry name
ConvertPath( packfiles[i].name );
//compare the dir entry name with the filename
if ( Q_strcasecmp( packfiles[i].name, path ) == 0 ) {
strcpy( file->filename, pakfile );
file->offset = LittleLong( packfiles[i].filepos );
file->length = LittleLong( packfiles[i].filelen );
FreeMemory( packfiles );
return true;
} //end if
} //end for
FreeMemory( packfiles );
return false;
} //end of the function FindFileInPak
//===========================================================================
// find a Quake2 file
// returns full path in 'filename'
// sets offset and length of the file
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
qboolean FindQuakeFile2( char *basedir, char *gamedir, char *filename, foundfile_t *file ) {
int dir, i;
//NOTE: 3 is necessary (LCC bug???)
char gamedirs[3][MAX_PATH] = {"","",""};
char filedir[MAX_PATH] = "";
//
if ( gamedir ) {
strncpy( gamedirs[0], gamedir, MAX_PATH );
}
strncpy( gamedirs[1], "baseq2", MAX_PATH );
//
//find the file in the two game directories
for ( dir = 0; dir < 2; dir++ )
{
//check if the file is in a directory
filedir[0] = 0;
if ( basedir && strlen( basedir ) ) {
strncpy( filedir, basedir, MAX_PATH );
AppendPathSeperator( filedir, MAX_PATH );
} //end if
if ( strlen( gamedirs[dir] ) ) {
strncat( filedir, gamedirs[dir], MAX_PATH - strlen( filedir ) );
AppendPathSeperator( filedir, MAX_PATH );
} //end if
strncat( filedir, filename, MAX_PATH - strlen( filedir ) );
ConvertPath( filedir );
Log_Write( "accessing %s", filedir );
if ( !access( filedir, 0x04 ) ) {
strcpy( file->filename, filedir );
file->length = 0;
file->offset = 0;
return true;
} //end if
//check if the file is in a pak?.pak
for ( i = 0; i < 10; i++ )
{
filedir[0] = 0;
if ( basedir && strlen( basedir ) ) {
strncpy( filedir, basedir, MAX_PATH );
AppendPathSeperator( filedir, MAX_PATH );
} //end if
if ( strlen( gamedirs[dir] ) ) {
strncat( filedir, gamedirs[dir], MAX_PATH - strlen( filedir ) );
AppendPathSeperator( filedir, MAX_PATH );
} //end if
sprintf( &filedir[strlen( filedir )], "pak%d.pak\0", i );
if ( !access( filedir, 0x04 ) ) {
Log_Write( "searching %s in %s", filename, filedir );
if ( FindFileInPak( filedir, filename, file ) ) {
return true;
}
} //end if
} //end for
} //end for
file->offset = 0;
file->length = 0;
return false;
} //end of the function FindQuakeFile2
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
#ifdef BOTLIB
qboolean FindQuakeFile( char *filename, foundfile_t *file ) {
return FindQuakeFile2( LibVarGetString( "basedir" ),
LibVarGetString( "gamedir" ), filename, file );
} //end of the function FindQuakeFile
#else //BOTLIB
qboolean FindQuakeFile( char *basedir, char *gamedir, char *filename, foundfile_t *file ) {
return FindQuakeFile2( basedir, gamedir, filename, file );
} //end of the function FindQuakeFile
#endif //BOTLIB

94
src/bspc/l_utils.h Normal file
View File

@@ -0,0 +1,94 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: l_utils.h
// Function: several utils
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1997-12-31
// Tab Size: 3
//===========================================================================
#ifndef MAX_PATH
#define MAX_PATH 64
#endif
#ifndef PATH_SEPERATORSTR
#if defined( WIN32 ) | defined( _WIN32 ) | defined( __NT__ ) | defined( __WINDOWS__ ) | defined( __WINDOWS_386__ )
#define PATHSEPERATOR_STR "\\"
#else
#define PATHSEPERATOR_STR "/"
#endif
#endif
#ifndef PATH_SEPERATORCHAR
#if defined( WIN32 ) | defined( _WIN32 ) | defined( __NT__ ) | defined( __WINDOWS__ ) | defined( __WINDOWS_386__ )
#define PATHSEPERATOR_CHAR '\\'
#else
#define PATHSEPERATOR_CHAR '/'
#endif
#endif
//random in the range [0, 1]
#define random() ( ( rand() & 0x7fff ) / ( (float)0x7fff ) )
//random in the range [-1, 1]
#define crandom() ( 2.0 * ( random() - 0.5 ) )
//min and max
#define Maximum( x,y ) ( x > y ? x : y )
#define Minimum( x,y ) ( x < y ? x : y )
//absolute value
#define FloatAbs( x ) ( *(float *) &( ( *(int *) &( x ) ) & 0x7FFFFFFF ) )
#define IntAbs( x ) ( ~( x ) )
//coordinates
#define _X 0
#define _Y 1
#define _Z 2
typedef struct foundfile_s
{
int offset;
int length;
char filename[MAX_PATH]; //screw LCC, array must be at end of struct
} foundfile_t;
void Vector2Angles( vec3_t value1, vec3_t angles );
//set the correct path seperators
void ConvertPath( char *path );
//append a path seperator to the given path not exceeding the length
void AppendPathSeperator( char *path, int length );
//find a file in a pak file
qboolean FindFileInPak( char *pakfile, char *filename, foundfile_t *file );
//find a quake file
#ifdef BOTLIB
qboolean FindQuakeFile( char *filename, foundfile_t *file );
#else //BOTLIB
qboolean FindQuakeFile( char *basedir, char *gamedir, char *filename, foundfile_t *file );
#endif //BOTLIB

108
src/bspc/leakfile.c Normal file
View File

@@ -0,0 +1,108 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "qbsp.h"
/*
==============================================================================
LEAF FILE GENERATION
Save out name.line for qe3 to read
==============================================================================
*/
/*
=============
LeakFile
Finds the shortest possible chain of portals
that leads from the outside leaf to a specifically
occupied leaf
=============
*/
void LeakFile( tree_t *tree ) {
vec3_t mid;
FILE *linefile;
char filename[1024];
node_t *node;
int count;
if ( !tree->outside_node.occupied ) {
return;
}
qprintf( "--- LeakFile ---\n" );
//
// write the points to the file
//
sprintf( filename, "%s.lin", source );
qprintf( "%s\n", filename );
linefile = fopen( filename, "w" );
if ( !linefile ) {
Error( "Couldn't open %s\n", filename );
}
count = 0;
node = &tree->outside_node;
while ( node->occupied > 1 )
{
int next;
portal_t *p, *nextportal;
node_t *nextnode;
int s;
// find the best portal exit
next = node->occupied;
for ( p = node->portals ; p ; p = p->next[!s] )
{
s = ( p->nodes[0] == node );
if ( p->nodes[s]->occupied
&& p->nodes[s]->occupied < next ) {
nextportal = p;
nextnode = p->nodes[s];
next = nextnode->occupied;
}
}
node = nextnode;
WindingCenter( nextportal->winding, mid );
fprintf( linefile, "%f %f %f\n", mid[0], mid[1], mid[2] );
count++;
}
// add the occupant center
GetVectorForKey( node->occupant, "origin", mid );
fprintf( linefile, "%f %f %f\n", mid[0], mid[1], mid[2] );
qprintf( "%5i point linefile\n", count + 1 );
fclose( linefile );
}

1351
src/bspc/map.c Normal file

File diff suppressed because it is too large Load Diff

1205
src/bspc/map_q1.c Normal file

File diff suppressed because it is too large Load Diff

1149
src/bspc/map_q2.c Normal file

File diff suppressed because it is too large Load Diff

711
src/bspc/map_q3.c Normal file
View File

@@ -0,0 +1,711 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: map_q3.c
// Function: map loading
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1999-07-02
// Tab Size: 3
//===========================================================================
#include "qbsp.h"
#include "l_mem.h"
#include "..\botlib\aasfile.h" //aas_bbox_t
#include "aas_store.h" //AAS_MAX_BBOXES
#include "aas_cfg.h"
#include "aas_map.h" //AAS_CreateMapBrushes
#include "l_bsp_q3.h"
#include "..\qcommon\cm_patch.h"
#include "..\game\surfaceflags.h"
#define NODESTACKSIZE 1024
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void PrintContents( int contents );
int Q3_BrushContents( mapbrush_t *b ) {
int contents, i, mixed, hint;
side_t *s;
s = &b->original_sides[0];
contents = s->contents;
//
mixed = false;
hint = false;
for ( i = 1; i < b->numsides; i++ )
{
s = &b->original_sides[i];
if ( s->contents != contents ) {
mixed = true;
}
if ( s->surf & ( SURF_HINT | SURF_SKIP ) ) {
hint = true;
}
contents |= s->contents;
} //end for
//
if ( hint ) {
if ( contents ) {
Log_Write( "WARNING: hint brush with contents: " );
PrintContents( contents );
Log_Write( "\r\n" );
//
Log_Write( "brush contents is: " );
PrintContents( b->contents );
Log_Write( "\r\n" );
} //end if
return 0;
} //end if
//Log_Write("brush %d contents ", nummapbrushes);
//PrintContents(contents);
//Log_Write("\r\n");
//remove ladder and fog contents
contents &= ~( CONTENTS_LADDER | CONTENTS_FOG );
//
if ( mixed ) {
Log_Write( "Entity %i, Brush %i: mixed face contents "
, b->entitynum, b->brushnum );
PrintContents( contents );
Log_Write( "\r\n" );
//
Log_Write( "brush contents is: " );
PrintContents( b->contents );
Log_Write( "\r\n" );
//
if ( contents & CONTENTS_DONOTENTER ) {
return CONTENTS_DONOTENTER; //Log_Print("mixed contents with donotenter\n");
}
/*
Log_Print("contents:"); PrintContents(contents);
Log_Print("\ncontents:"); PrintContents(s->contents);
Log_Print("\n");
Log_Print("texture name = %s\n", texinfo[s->texinfo].texture);
*/
//if liquid brush
if ( contents & ( CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER ) ) {
return ( contents & ( CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER ) );
} //end if
if ( contents & CONTENTS_PLAYERCLIP ) {
return ( contents & CONTENTS_PLAYERCLIP );
}
return ( contents & CONTENTS_SOLID );
} //end if
/*
if (contents & CONTENTS_AREAPORTAL)
{
static int num;
Log_Write("Entity %i, Brush %i: area portal %d\r\n", b->entitynum, b->brushnum, num++);
} //end if*/
if ( contents == ( contents & CONTENTS_STRUCTURAL ) ) {
//Log_Print("brush %i is only structural\n", b->brushnum);
contents = 0;
} //end if
if ( contents & CONTENTS_DONOTENTER ) {
Log_Print( "brush %i is a donotenter brush, c = %X\n", b->brushnum, contents );
} //end if
return contents;
} //end of the function Q3_BrushContents
#define BBOX_NORMAL_EPSILON 0.0001
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Q3_DPlanes2MapPlanes( void ) {
int i;
for ( i = 0; i < q3_numplanes; i++ )
{
dplanes2mapplanes[i] = FindFloatPlane( q3_dplanes[i].normal, q3_dplanes[i].dist );
} //end for
} //end of the function Q3_DPlanes2MapPlanes
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Q3_BSPBrushToMapBrush( q3_dbrush_t *bspbrush, entity_t *mapent ) {
mapbrush_t *b;
int i, k, n;
side_t *side, *s2;
int planenum;
q3_dbrushside_t *bspbrushside;
q3_dplane_t *bspplane;
int contentFlags = 0;
if ( nummapbrushes >= MAX_MAPFILE_BRUSHES ) {
Error( "nummapbrushes >= MAX_MAPFILE_BRUSHES" );
}
b = &mapbrushes[nummapbrushes];
b->original_sides = &brushsides[nummapbrushsides];
b->entitynum = mapent - entities;
b->brushnum = nummapbrushes - mapent->firstbrush;
b->leafnum = dbrushleafnums[bspbrush - q3_dbrushes];
for ( n = 0; n < bspbrush->numSides; n++ )
{
//pointer to the bsp brush side
bspbrushside = &q3_dbrushsides[bspbrush->firstSide + n];
if ( nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES ) {
Error( "MAX_MAPFILE_BRUSHSIDES" );
} //end if
//pointer to the map brush side
side = &brushsides[nummapbrushsides];
//if the BSP brush side is textured
if ( q3_dbrushsidetextured[bspbrush->firstSide + n] ) {
side->flags |= SFL_TEXTURED | SFL_VISIBLE;
} else { side->flags &= ~SFL_TEXTURED;}
//NOTE: all Quake3 sides are assumed textured
//side->flags |= SFL_TEXTURED|SFL_VISIBLE;
//
if ( bspbrushside->shaderNum < 0 ) {
side->contents = 0;
side->surf = 0;
} //end if
else
{
side->contents = q3_dshaders[bspbrushside->shaderNum].contentFlags;
side->surf = q3_dshaders[bspbrushside->shaderNum].surfaceFlags;
if ( strstr( q3_dshaders[bspbrushside->shaderNum].shader, "common/hint" ) ) {
//Log_Print("found hint side\n");
side->surf |= SURF_HINT;
} //end if
// Ridah, mark ladder brushes
if ( strstr( q3_dshaders[bspbrushside->shaderNum].shader, "common/ladder" ) ) {
//Log_Print("found ladder side\n");
side->contents |= CONTENTS_LADDER;
contentFlags |= CONTENTS_LADDER;
} //end if
// done.
} //end else
//
if ( !( strstr( q3_dshaders[bspbrushside->shaderNum].shader, "common/slip" ) ) ) {
side->flags |= SFL_VISIBLE;
} else if ( side->surf & SURF_NODRAW ) {
side->flags |= SFL_TEXTURED | SFL_VISIBLE;
} //end if
/*
if (side->contents & (CONTENTS_TRANSLUCENT|CONTENTS_STRUCTURAL))
{
side->flags |= SFL_TEXTURED|SFL_VISIBLE;
} //end if*/
// hints and skips are never detail, and have no content
if ( side->surf & ( SURF_HINT | SURF_SKIP ) ) {
side->contents = 0;
//Log_Print("found hint brush side\n");
}
/*
if ((side->surf & SURF_NODRAW) && (side->surf & SURF_NOIMPACT))
{
side->contents = 0;
side->surf &= ~CONTENTS_DETAIL;
Log_Print("probably found hint brush in a BSP without hints being used\n");
} //end if*/
//ME: get a plane for this side
bspplane = &q3_dplanes[bspbrushside->planeNum];
planenum = FindFloatPlane( bspplane->normal, bspplane->dist );
//
// see if the plane has been used already
//
//ME: this really shouldn't happen!!!
//ME: otherwise the bsp file is corrupted??
//ME: still it seems to happen, maybe Johny Boy's
//ME: brush bevel adding is crappy ?
for ( k = 0; k < b->numsides; k++ )
{
s2 = b->original_sides + k;
// if (DotProduct (mapplanes[s2->planenum].normal, mapplanes[planenum].normal) > 0.999
// && fabs(mapplanes[s2->planenum].dist - mapplanes[planenum].dist) < 0.01 )
if ( s2->planenum == planenum ) {
Log_Print( "Entity %i, Brush %i: duplicate plane\n"
, b->entitynum, b->brushnum );
break;
}
if ( s2->planenum == ( planenum ^ 1 ) ) {
Log_Print( "Entity %i, Brush %i: mirrored plane\n"
, b->entitynum, b->brushnum );
break;
}
}
if ( k != b->numsides ) {
continue; // duplicated
}
//
// keep this side
//
//ME: reset pointer to side, why? hell I dunno (pointer is set above already)
side = b->original_sides + b->numsides;
//ME: store the plane number
side->planenum = planenum;
//ME: texinfo is already stored when bsp is loaded
//NOTE: check for TEXINFO_NODE, otherwise crash in Q3_BrushContents
//if (bspbrushside->texinfo < 0) side->texinfo = 0;
//else side->texinfo = bspbrushside->texinfo;
// save the td off in case there is an origin brush and we
// have to recalculate the texinfo
// ME: don't need to recalculate because it's already done
// (for non-world entities) in the BSP file
// side_brushtextures[nummapbrushsides] = td;
nummapbrushsides++;
b->numsides++;
} //end for
// get the content for the entire brush
//Quake3 bsp brushes don't have a contents
b->contents = q3_dshaders[bspbrush->shaderNum].contentFlags | contentFlags;
// Ridah, Wolf has ladders (if we call Q3_BrushContents(), we'll get the solid area bug
b->contents &= ~( /*CONTENTS_LADDER|*/ CONTENTS_FOG | CONTENTS_STRUCTURAL );
//b->contents = Q3_BrushContents(b);
//
// Ridah, CONTENTS_MOSTERCLIP should prevent AAS from being created, but not clip players/AI in the game
if ( b->contents & CONTENTS_MONSTERCLIP ) {
b->contents |= CONTENTS_PLAYERCLIP;
}
// func_explosive's not solid
if ( !strcmp( "func_explosive", ValueForKey( &entities[b->entitynum], "classname" ) ) ||
!strcmp( "func_invisible_user", ValueForKey( &entities[b->entitynum], "classname" ) ) ||
!strcmp( "func_static", ValueForKey( &entities[b->entitynum], "classname" ) ) ) {
Log_Print( "Ignoring %s brush..\n", ValueForKey( &entities[b->entitynum], "classname" ) );
b->numsides = 0;
b->contents = 0;
return;
}
if ( BrushExists( b ) ) {
c_squattbrushes++;
b->numsides = 0;
return;
} //end if
//if we're creating AAS
if ( create_aas ) {
//create the AAS brushes from this brush, don't add brush bevels
AAS_CreateMapBrushes( b, mapent, false );
return;
} //end if
// allow detail brushes to be removed
if ( nodetail && ( b->contents & CONTENTS_DETAIL ) ) {
b->numsides = 0;
return;
} //end if
// allow water brushes to be removed
if ( nowater && ( b->contents & ( CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER ) ) ) {
b->numsides = 0;
return;
} //end if
// create windings for sides and bounds for brush
MakeBrushWindings( b );
//mark brushes without winding or with a tiny window as bevels
MarkBrushBevels( b );
// brushes that will not be visible at all will never be
// used as bsp splitters
if ( b->contents & ( CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP ) ) {
c_clipbrushes++;
for ( i = 0; i < b->numsides; i++ )
b->original_sides[i].texinfo = TEXINFO_NODE;
} //end for
//
// origin brushes are removed, but they set
// the rotation origin for the rest of the brushes
// in the entity. After the entire entity is parsed,
// the planenums and texinfos will be adjusted for
// the origin brush
//
//ME: not needed because the entities in the BSP file already
// have an origin set
// if (b->contents & CONTENTS_ORIGIN)
// {
// char string[32];
// vec3_t origin;
//
// if (num_entities == 1)
// {
// Error ("Entity %i, Brush %i: origin brushes not allowed in world"
// , b->entitynum, b->brushnum);
// return;
// }
//
// VectorAdd (b->mins, b->maxs, origin);
// VectorScale (origin, 0.5, origin);
//
// sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
// SetKeyValue (&entities[b->entitynum], "origin", string);
//
// VectorCopy (origin, entities[b->entitynum].origin);
//
// // don't keep this brush
// b->numsides = 0;
//
// return;
// }
//ME: the bsp brushes already have bevels, so we won't try to
// add them again (especially since Johny Boy's bevel adding might
// be crappy)
// AddBrushBevels(b);
nummapbrushes++;
mapent->numbrushes++;
} //end of the function Q3_BSPBrushToMapBrush
//===========================================================================
//===========================================================================
void Q3_ParseBSPBrushes( entity_t *mapent ) {
int i;
/*
//give all the brushes that belong to this entity the number of the
//BSP model used by this entity
Q3_SetBrushModelNumbers(mapent);
//now parse all the brushes with the correct mapent->modelnum
for (i = 0; i < q3_numbrushes; i++)
{
if (brushmodelnumbers[i] == mapent->modelnum)
{
Q3_BSPBrushToMapBrush(&q3_dbrushes[i], mapent);
} //end if
} //end for
*/
for ( i = 0; i < q3_dmodels[mapent->modelnum].numBrushes; i++ )
{
Q3_BSPBrushToMapBrush( &q3_dbrushes[q3_dmodels[mapent->modelnum].firstBrush + i], mapent );
} //end for
} //end of the function Q3_ParseBSPBrushes
//===========================================================================
//===========================================================================
qboolean Q3_ParseBSPEntity( int entnum ) {
entity_t *mapent;
char *model;
int startbrush, startsides;
startbrush = nummapbrushes;
startsides = nummapbrushsides;
mapent = &entities[entnum]; //num_entities];
mapent->firstbrush = nummapbrushes;
mapent->numbrushes = 0;
mapent->modelnum = -1; //-1 = no BSP model
model = ValueForKey( mapent, "model" );
if ( model && strlen( model ) ) {
if ( *model == '*' ) {
//get the model number of this entity (skip the leading *)
mapent->modelnum = atoi( &model[1] );
} //end if
} //end if
GetVectorForKey( mapent, "origin", mapent->origin );
//if this is the world entity it has model number zero
//the world entity has no model key
if ( !strcmp( "worldspawn", ValueForKey( mapent, "classname" ) ) ) {
mapent->modelnum = 0;
} //end if
//if the map entity has a BSP model (a modelnum of -1 is used for
//entities that aren't using a BSP model)
if ( mapent->modelnum >= 0 ) {
//parse the bsp brushes
Q3_ParseBSPBrushes( mapent );
} //end if
//
//the origin of the entity is already taken into account
//
//func_group entities can't be in the bsp file
//
//check out the func_areaportal entities
if ( !strcmp( "func_areaportal", ValueForKey( mapent, "classname" ) ) ) {
c_areaportals++;
mapent->areaportalnum = c_areaportals;
return true;
} //end if
return true;
} //end of the function Q3_ParseBSPEntity
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
#define MAX_PATCH_VERTS 1024
void AAS_CreateCurveBrushes( void ) {
int i, j, n, planenum, numcurvebrushes = 0;
q3_dsurface_t *surface;
q3_drawVert_t *dv_p;
vec3_t points[MAX_PATCH_VERTS];
int width, height, c;
patchCollide_t *pc;
facet_t *facet;
mapbrush_t *brush;
side_t *side;
entity_t *mapent;
winding_t *winding;
qprintf( "nummapbrushsides = %d\n", nummapbrushsides );
mapent = &entities[0];
for ( i = 0; i < q3_numDrawSurfaces; i++ )
{
surface = &q3_drawSurfaces[i];
if ( !surface->patchWidth ) {
continue;
}
//if the curve is not solid
if ( !( q3_dshaders[surface->shaderNum].contentFlags & ( CONTENTS_SOLID | CONTENTS_PLAYERCLIP ) ) ) {
//Log_Print("skipped non-solid curve\n");
continue;
} //end if
//
width = surface->patchWidth;
height = surface->patchHeight;
c = width * height;
if ( c > MAX_PATCH_VERTS ) {
Error( "ParseMesh: MAX_PATCH_VERTS" );
} //end if
dv_p = q3_drawVerts + surface->firstVert;
for ( j = 0 ; j < c ; j++, dv_p++ )
{
points[j][0] = dv_p->xyz[0];
points[j][1] = dv_p->xyz[1];
points[j][2] = dv_p->xyz[2];
} //end for
// create the internal facet structure
pc = CM_GeneratePatchCollide( width, height, points );
//
for ( j = 0; j < pc->numFacets; j++ )
{
facet = &pc->facets[j];
//
brush = &mapbrushes[nummapbrushes];
brush->original_sides = &brushsides[nummapbrushsides];
brush->entitynum = 0;
brush->brushnum = nummapbrushes - mapent->firstbrush;
//
brush->numsides = facet->numBorders + 2;
nummapbrushsides += brush->numsides;
brush->contents = CONTENTS_SOLID;
//
//qprintf("\r%6d curve brushes", nummapbrushsides);//++numcurvebrushes);
qprintf( "\r%6d curve brushes", ++numcurvebrushes );
//
planenum = FindFloatPlane( pc->planes[facet->surfacePlane].plane, pc->planes[facet->surfacePlane].plane[3] );
//
side = &brush->original_sides[0];
side->planenum = planenum;
side->contents = CONTENTS_SOLID;
side->flags |= SFL_TEXTURED | SFL_VISIBLE | SFL_CURVE;
side->surf = 0;
//
side = &brush->original_sides[1];
if ( create_aas ) {
//the plane is expanded later so it's not a problem that
//these first two opposite sides are coplanar
side->planenum = planenum ^ 1;
} //end if
else
{
side->planenum = FindFloatPlane( mapplanes[planenum ^ 1].normal, mapplanes[planenum ^ 1].dist + 1 );
side->flags |= SFL_TEXTURED | SFL_VISIBLE;
} //end else
side->contents = CONTENTS_SOLID;
side->flags |= SFL_CURVE;
side->surf = 0;
//
winding = BaseWindingForPlane( mapplanes[side->planenum].normal, mapplanes[side->planenum].dist );
for ( n = 0; n < facet->numBorders; n++ )
{
//never use the surface plane as a border
if ( facet->borderPlanes[n] == facet->surfacePlane ) {
continue;
}
//
side = &brush->original_sides[2 + n];
side->planenum = FindFloatPlane( pc->planes[facet->borderPlanes[n]].plane, pc->planes[facet->borderPlanes[n]].plane[3] );
if ( facet->borderInward[n] ) {
side->planenum ^= 1;
}
side->contents = CONTENTS_SOLID;
side->flags |= SFL_TEXTURED | SFL_CURVE;
side->surf = 0;
//chop the winding in place
if ( winding ) {
ChopWindingInPlace( &winding, mapplanes[side->planenum ^ 1].normal, mapplanes[side->planenum ^ 1].dist, 0.1 ); //CLIP_EPSILON);
}
} //end for
//VectorCopy(pc->bounds[0], brush->mins);
//VectorCopy(pc->bounds[1], brush->maxs);
if ( !winding ) {
Log_Print( "WARNING: AAS_CreateCurveBrushes: no winding\n" );
brush->numsides = 0;
continue;
} //end if
brush->original_sides[0].winding = winding;
WindingBounds( winding, brush->mins, brush->maxs );
for ( n = 0; n < 3; n++ )
{
//IDBUG: all the indexes into the mins and maxs were zero (not using i)
if ( brush->mins[n] < -MAX_MAP_BOUNDS || brush->maxs[n] > MAX_MAP_BOUNDS ) {
Log_Print( "entity %i, brush %i: bounds out of range\n", brush->entitynum, brush->brushnum );
Log_Print( "brush->mins[%d] = %f, brush->maxs[%d] = %f\n", n, brush->mins[n], n, brush->maxs[n] );
brush->numsides = 0; //remove the brush
break;
} //end if
if ( brush->mins[n] > MAX_MAP_BOUNDS || brush->maxs[n] < -MAX_MAP_BOUNDS ) {
Log_Print( "entity %i, brush %i: no visible sides on brush\n", brush->entitynum, brush->brushnum );
Log_Print( "brush->mins[%d] = %f, brush->maxs[%d] = %f\n", n, brush->mins[n], n, brush->maxs[n] );
brush->numsides = 0; //remove the brush
break;
} //end if
} //end for
if ( create_aas ) {
//NOTE: brush bevels now already added
//AddBrushBevels(brush);
AAS_CreateMapBrushes( brush, mapent, false );
} //end if
else
{
// create windings for sides and bounds for brush
MakeBrushWindings( brush );
AddBrushBevels( brush );
nummapbrushes++;
mapent->numbrushes++;
} //end else
} //end for
} //end for
//qprintf("\r%6d curve brushes", nummapbrushsides);//++numcurvebrushes);
qprintf( "\r%6d curve brushes\n", numcurvebrushes );
} //end of the function AAS_CreateCurveBrushes
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_ExpandMapBrush( mapbrush_t *brush, vec3_t mins, vec3_t maxs );
void Q3_LoadMapFromBSP( struct quakefile_s *qf ) {
int i;
vec3_t mins = {-1,-1,-1}, maxs = {1, 1, 1};
Log_Print( "-- Q3_LoadMapFromBSP --\n" );
//loaded map type
loadedmaptype = MAPTYPE_QUAKE3;
Log_Print( "Loading map from %s...\n", qf->filename );
//load the bsp file
Q3_LoadBSPFile( qf );
//create an index from bsp planes to map planes
//DPlanes2MapPlanes();
//clear brush model numbers
for ( i = 0; i < MAX_MAPFILE_BRUSHES; i++ )
brushmodelnumbers[i] = -1;
nummapbrushsides = 0;
num_entities = 0;
Q3_ParseEntities();
//
for ( i = 0; i < num_entities; i++ )
{
Q3_ParseBSPEntity( i );
} //end for
AAS_CreateCurveBrushes();
//get the map mins and maxs from the world model
ClearBounds( map_mins, map_maxs );
for ( i = 0; i < entities[0].numbrushes; i++ )
{
if ( mapbrushes[i].numsides <= 0 ) {
continue;
}
if ( mapbrushes[i].mins[0] > 4096 ) {
continue; //no valid points
}
AddPointToBounds( mapbrushes[i].mins, map_mins, map_maxs );
AddPointToBounds( mapbrushes[i].maxs, map_mins, map_maxs );
} //end for
/*/
for (i = 0; i < nummapbrushes; i++)
{
//if (!mapbrushes[i].original_sides) continue;
//AddBrushBevels(&mapbrushes[i]);
//AAS_ExpandMapBrush(&mapbrushes[i], mins, maxs);
} //end for*/
/*
for (i = 0; i < nummapbrushsides; i++)
{
Log_Write("side %d flags = %d", i, brushsides[i].flags);
} //end for
for (i = 0; i < nummapbrushes; i++)
{
Log_Write("brush contents: ");
PrintContents(mapbrushes[i].contents);
Log_Print("\n");
} //end for*/
} //end of the function Q3_LoadMapFromBSP
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Q3_ResetMapLoading( void ) {
//reset for map loading from bsp
memset( nodestack, 0, NODESTACKSIZE * sizeof( int ) );
nodestackptr = NULL;
nodestacksize = 0;
memset( brushmodelnumbers, 0, MAX_MAPFILE_BRUSHES * sizeof( int ) );
} //end of the function Q3_ResetMapLoading

1199
src/bspc/map_sin.c Normal file

File diff suppressed because it is too large Load Diff

50
src/bspc/nodraw.c Normal file
View File

@@ -0,0 +1,50 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "qbsp.h"
vec3_t draw_mins, draw_maxs;
qboolean drawflag;
void Draw_ClearWindow( void ) {
}
//============================================================
#define GLSERV_PORT 25001
void GLS_BeginScene( void ) {
}
void GLS_Winding( winding_t *w, int code ) {
}
void GLS_EndScene( void ) {
}

1308
src/bspc/portals.c Normal file

File diff suppressed because it is too large Load Diff

287
src/bspc/prtfile.c Normal file
View File

@@ -0,0 +1,287 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
// NO LONGER USED
#if 0
#include "qbsp.h"
extern dleaf_t dleafs[MAX_MAP_LEAFS];
/*
==============================================================================
PORTAL FILE GENERATION
Save out name.prt for qvis to read
==============================================================================
*/
#define PORTALFILE "PRT1"
FILE *pf;
int num_visclusters; // clusters the player can be in
int num_visportals;
void WriteFloat2( FILE *f, vec_t v ) {
if ( fabs( v - Q_rint( v ) ) < 0.001 ) {
fprintf( f,"%i ",(int)Q_rint( v ) );
} else {
fprintf( f,"%f ",v );
}
}
/*
=================
WritePortalFile_r
=================
*/
void WritePortalFile_r( node_t *node ) {
int i, s;
portal_t *p;
winding_t *w;
vec3_t normal;
vec_t dist;
// decision node
if ( node->planenum != PLANENUM_LEAF && !node->detail_seperator ) {
WritePortalFile_r( node->children[0] );
WritePortalFile_r( node->children[1] );
return;
}
if ( node->contents & CONTENTS_SOLID ) {
return;
}
for ( p = node->portals ; p ; p = p->next[s] )
{
w = p->winding;
s = ( p->nodes[1] == node );
if ( w && p->nodes[0] == node ) {
if ( !Portal_VisFlood( p ) ) {
continue;
}
// write out to the file
// sometimes planes get turned around when they are very near
// the changeover point between different axis. interpret the
// plane the same way vis will, and flip the side orders if needed
// FIXME: is this still relevent?
WindingPlane( w, normal, &dist );
if ( DotProduct( p->plane.normal, normal ) < 0.99 ) { // backwards...
fprintf( pf,"%i %i %i ",w->numpoints, p->nodes[1]->cluster, p->nodes[0]->cluster );
} else {
fprintf( pf,"%i %i %i ",w->numpoints, p->nodes[0]->cluster, p->nodes[1]->cluster );
}
for ( i = 0 ; i < w->numpoints ; i++ )
{
fprintf( pf,"(" );
WriteFloat2( pf, w->p[i][0] );
WriteFloat2( pf, w->p[i][1] );
WriteFloat2( pf, w->p[i][2] );
fprintf( pf,") " );
}
fprintf( pf,"\n" );
}
}
}
/*
================
FillLeafNumbers_r
All of the leafs under node will have the same cluster
================
*/
void FillLeafNumbers_r( node_t *node, int num ) {
if ( node->planenum == PLANENUM_LEAF ) {
if ( node->contents & CONTENTS_SOLID ) {
node->cluster = -1;
} else {
node->cluster = num;
}
return;
}
node->cluster = num;
FillLeafNumbers_r( node->children[0], num );
FillLeafNumbers_r( node->children[1], num );
}
/*
================
NumberLeafs_r
================
*/
void NumberLeafs_r( node_t *node ) {
portal_t *p;
if ( node->planenum != PLANENUM_LEAF && !node->detail_seperator ) { // decision node
node->cluster = -99;
NumberLeafs_r( node->children[0] );
NumberLeafs_r( node->children[1] );
return;
}
// either a leaf or a detail cluster
if ( node->contents & CONTENTS_SOLID ) { // solid block, viewpoint never inside
node->cluster = -1;
return;
}
FillLeafNumbers_r( node, num_visclusters );
num_visclusters++;
// count the portals
for ( p = node->portals ; p ; )
{
if ( p->nodes[0] == node ) { // only write out from first leaf
if ( Portal_VisFlood( p ) ) {
num_visportals++;
}
p = p->next[0];
} else {
p = p->next[1];
}
}
}
/*
================
CreateVisPortals_r
================
*/
void CreateVisPortals_r( node_t *node ) {
// stop as soon as we get to a detail_seperator, which
// means that everything below is in a single cluster
if ( node->planenum == PLANENUM_LEAF || node->detail_seperator ) {
return;
}
MakeNodePortal( node );
SplitNodePortals( node );
CreateVisPortals_r( node->children[0] );
CreateVisPortals_r( node->children[1] );
}
/*
================
FinishVisPortals_r
================
*/
void FinishVisPortals2_r( node_t *node ) {
if ( node->planenum == PLANENUM_LEAF ) {
return;
}
MakeNodePortal( node );
SplitNodePortals( node );
FinishVisPortals2_r( node->children[0] );
FinishVisPortals2_r( node->children[1] );
}
void FinishVisPortals_r( node_t *node ) {
if ( node->planenum == PLANENUM_LEAF ) {
return;
}
if ( node->detail_seperator ) {
FinishVisPortals2_r( node );
return;
}
FinishVisPortals_r( node->children[0] );
FinishVisPortals_r( node->children[1] );
}
int clusterleaf;
void SaveClusters_r( node_t *node ) {
if ( node->planenum == PLANENUM_LEAF ) {
dleafs[clusterleaf++].cluster = node->cluster;
return;
}
SaveClusters_r( node->children[0] );
SaveClusters_r( node->children[1] );
}
/*
================
WritePortalFile
================
*/
void WritePortalFile( tree_t *tree ) {
char filename[1024];
node_t *headnode;
qprintf( "--- WritePortalFile ---\n" );
headnode = tree->headnode;
num_visclusters = 0;
num_visportals = 0;
Tree_FreePortals_r( headnode );
MakeHeadnodePortals( tree );
CreateVisPortals_r( headnode );
// set the cluster field in every leaf and count the total number of portals
NumberLeafs_r( headnode );
// write the file
sprintf( filename, "%s.prt", source );
printf( "writing %s\n", filename );
pf = fopen( filename, "w" );
if ( !pf ) {
Error( "Error opening %s", filename );
}
fprintf( pf, "%s\n", PORTALFILE );
fprintf( pf, "%i\n", num_visclusters );
fprintf( pf, "%i\n", num_visportals );
qprintf( "%5i visclusters\n", num_visclusters );
qprintf( "%5i visportals\n", num_visportals );
WritePortalFile_r( headnode );
fclose( pf );
// we need to store the clusters out now because ordering
// issues made us do this after writebsp...
clusterleaf = 1;
SaveClusters_r( headnode );
}
#endif

494
src/bspc/q2files.h Normal file
View File

@@ -0,0 +1,494 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//
// qfiles.h: quake file formats
// This file must be identical in the quake and utils directories
//
/*
========================================================================
The .pak files are just a linear collapse of a directory tree
========================================================================
*/
#define IDPAKHEADER ( ( 'K' << 24 ) + ( 'C' << 16 ) + ( 'A' << 8 ) + 'P' )
typedef struct
{
char name[56];
int filepos, filelen;
} dpackfile_t;
typedef struct
{
int ident; // == IDPAKHEADER
int dirofs;
int dirlen;
} dpackheader_t;
#define MAX_FILES_IN_PACK 4096
/*
========================================================================
PCX files are used for as many images as possible
========================================================================
*/
typedef struct
{
char manufacturer;
char version;
char encoding;
char bits_per_pixel;
unsigned short xmin,ymin,xmax,ymax;
unsigned short hres,vres;
unsigned char palette[48];
char reserved;
char color_planes;
unsigned short bytes_per_line;
unsigned short palette_type;
char filler[58];
unsigned char data; // unbounded
} pcx_t;
/*
========================================================================
.MD2 triangle model file format
========================================================================
*/
#define IDALIASHEADER ( ( '2' << 24 ) + ( 'P' << 16 ) + ( 'D' << 8 ) + 'I' )
#define ALIAS_VERSION 8
#define MAX_TRIANGLES 4096
#define MAX_VERTS 2048
#define MAX_FRAMES 512
#define MAX_MD2SKINS 32
#define MAX_SKINNAME 64
typedef struct
{
short s;
short t;
} dstvert_t;
typedef struct
{
short index_xyz[3];
short index_st[3];
} dtriangle_t;
typedef struct
{
byte v[3]; // scaled byte to fit in frame mins/maxs
byte lightnormalindex;
} dtrivertx_t;
#define DTRIVERTX_V0 0
#define DTRIVERTX_V1 1
#define DTRIVERTX_V2 2
#define DTRIVERTX_LNI 3
#define DTRIVERTX_SIZE 4
typedef struct
{
float scale[3]; // multiply byte verts by this
float translate[3]; // then add this
char name[16]; // frame name from grabbing
dtrivertx_t verts[1]; // variable sized
} daliasframe_t;
// the glcmd format:
// a positive integer starts a tristrip command, followed by that many
// vertex structures.
// a negative integer starts a trifan command, followed by -x vertexes
// a zero indicates the end of the command list.
// a vertex consists of a floating point s, a floating point t,
// and an integer vertex index.
typedef struct
{
int ident;
int version;
int skinwidth;
int skinheight;
int framesize; // byte size of each frame
int num_skins;
int num_xyz;
int num_st; // greater than num_xyz for seams
int num_tris;
int num_glcmds; // dwords in strip/fan command list
int num_frames;
int ofs_skins; // each skin is a MAX_SKINNAME string
int ofs_st; // byte offset from start for stverts
int ofs_tris; // offset for dtriangles
int ofs_frames; // offset for first frame
int ofs_glcmds;
int ofs_end; // end of file
} dmdl_t;
/*
========================================================================
.SP2 sprite file format
========================================================================
*/
#define IDSPRITEHEADER ( ( '2' << 24 ) + ( 'S' << 16 ) + ( 'D' << 8 ) + 'I' )
// little-endian "IDS2"
#define SPRITE_VERSION 2
typedef struct
{
int width, height;
int origin_x, origin_y; // raster coordinates inside pic
char name[MAX_SKINNAME]; // name of pcx file
} dsprframe_t;
typedef struct {
int ident;
int version;
int numframes;
dsprframe_t frames[1]; // variable sized
} dsprite_t;
/*
==============================================================================
.WAL texture file format
==============================================================================
*/
#define MIPLEVELS 4
typedef struct miptex_s
{
char name[32];
unsigned width, height;
unsigned offsets[MIPLEVELS]; // four mip maps stored
char animname[32]; // next frame in animation chain
int flags;
int contents;
int value;
} miptex_t;
/*
==============================================================================
.BSP file format
==============================================================================
*/
#define IDBSPHEADER ( ( 'P' << 24 ) + ( 'S' << 16 ) + ( 'B' << 8 ) + 'I' )
// little-endian "IBSP"
#define BSPVERSION 38
// upper design bounds
// leaffaces, leafbrushes, planes, and verts are still bounded by
// 16 bit short limits
#define MAX_MAP_MODELS 1024
#define MAX_MAP_BRUSHES 8192
#define MAX_MAP_ENTITIES 2048
#define MAX_MAP_ENTSTRING 0x40000
#define MAX_MAP_TEXINFO 8192
#define MAX_MAP_AREAS 256
#define MAX_MAP_AREAPORTALS 1024
#define MAX_MAP_PLANES 65536
#define MAX_MAP_NODES 65536
#define MAX_MAP_BRUSHSIDES 65536
#define MAX_MAP_LEAFS 65536
#define MAX_MAP_VERTS 65536
#define MAX_MAP_FACES 65536
#define MAX_MAP_LEAFFACES 65536
#define MAX_MAP_LEAFBRUSHES 65536
#define MAX_MAP_PORTALS 65536
#define MAX_MAP_EDGES 128000
#define MAX_MAP_SURFEDGES 256000
#define MAX_MAP_LIGHTING 0x320000
#define MAX_MAP_VISIBILITY 0x280000
// key / value pair sizes
#define MAX_KEY 32
#define MAX_VALUE 1024
//=============================================================================
typedef struct
{
int fileofs, filelen;
} lump_t;
#define LUMP_ENTITIES 0
#define LUMP_PLANES 1
#define LUMP_VERTEXES 2
#define LUMP_VISIBILITY 3
#define LUMP_NODES 4
#define LUMP_TEXINFO 5
#define LUMP_FACES 6
#define LUMP_LIGHTING 7
#define LUMP_LEAFS 8
#define LUMP_LEAFFACES 9
#define LUMP_LEAFBRUSHES 10
#define LUMP_EDGES 11
#define LUMP_SURFEDGES 12
#define LUMP_MODELS 13
#define LUMP_BRUSHES 14
#define LUMP_BRUSHSIDES 15
#define LUMP_POP 16
#define LUMP_AREAS 17
#define LUMP_AREAPORTALS 18
#define HEADER_LUMPS 19
typedef struct
{
int ident;
int version;
lump_t lumps[HEADER_LUMPS];
} dheader_t;
typedef struct
{
float mins[3], maxs[3];
float origin[3]; // for sounds or lights
int headnode;
int firstface, numfaces; // submodels just draw faces
// without walking the bsp tree
} dmodel_t;
typedef struct
{
float point[3];
} dvertex_t;
// 0-2 are axial planes
#define PLANE_X 0
#define PLANE_Y 1
#define PLANE_Z 2
// 3-5 are non-axial planes snapped to the nearest
#define PLANE_ANYX 3
#define PLANE_ANYY 4
#define PLANE_ANYZ 5
// planes (x&~1) and (x&~1)+1 are allways opposites
typedef struct
{
float normal[3];
float dist;
int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
} dplane_t;
// contents flags are seperate bits
// a given brush can contribute multiple content bits
// multiple brushes can be in a single leaf
// these definitions also need to be in q_shared.h!
// lower bits are stronger, and will eat weaker brushes completely
#define CONTENTS_SOLID 1 // an eye is never valid in a solid
#define CONTENTS_WINDOW 2 // translucent, but not watery
#define CONTENTS_AUX 4
#define CONTENTS_LAVA 8
#define CONTENTS_SLIME 16
#define CONTENTS_WATER 32
#define CONTENTS_MIST 64
#define LAST_VISIBLE_CONTENTS 64
// remaining contents are non-visible, and don't eat brushes
#define CONTENTS_AREAPORTAL 0x8000
#define CONTENTS_PLAYERCLIP 0x10000
#define CONTENTS_MONSTERCLIP 0x20000
// currents can be added to any other contents, and may be mixed
#define CONTENTS_CURRENT_0 0x40000
#define CONTENTS_CURRENT_90 0x80000
#define CONTENTS_CURRENT_180 0x100000
#define CONTENTS_CURRENT_270 0x200000
#define CONTENTS_CURRENT_UP 0x400000
#define CONTENTS_CURRENT_DOWN 0x800000
#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity
#define CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game
#define CONTENTS_DEADMONSTER 0x4000000
#define CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs
//renamed because it's in conflict with the Q3A translucent contents
#define CONTENTS_Q2TRANSLUCENT 0x10000000 // auto set if any surface has trans
#define CONTENTS_LADDER 0x20000000
#define SURF_LIGHT 0x1 // value will hold the light strength
#define SURF_SLICK 0x2 // effects game physics
#define SURF_SKY 0x4 // don't draw, but add to skybox
#define SURF_WARP 0x8 // turbulent water warp
#define SURF_TRANS33 0x10
#define SURF_TRANS66 0x20
#define SURF_FLOWING 0x40 // scroll towards angle
#define SURF_NODRAW 0x80 // don't bother referencing the texture
#define SURF_HINT 0x100 // make a primary bsp splitter
#define SURF_SKIP 0x200 // completely ignore, allowing non-closed brushes
typedef struct
{
int planenum;
int children[2]; // negative numbers are -(leafs+1), not nodes
short mins[3]; // for frustom culling
short maxs[3];
unsigned short firstface;
unsigned short numfaces; // counting both sides
} dnode_t;
typedef struct texinfo_s
{
float vecs[2][4]; // [s/t][xyz offset]
int flags; // miptex flags + overrides
int value; // light emission, etc
char texture[32]; // texture name (textures/*.wal)
int nexttexinfo; // for animations, -1 = end of chain
} texinfo_t;
// note that edge 0 is never used, because negative edge nums are used for
// counterclockwise use of the edge in a face
typedef struct
{
unsigned short v[2]; // vertex numbers
} dedge_t;
#define MAXLIGHTMAPS 4
typedef struct
{
unsigned short planenum;
short side;
int firstedge; // we must support > 64k edges
short numedges;
short texinfo;
// lighting info
byte styles[MAXLIGHTMAPS];
int lightofs; // start of [numstyles*surfsize] samples
} dface_t;
typedef struct
{
int contents; // OR of all brushes (not needed?)
short cluster;
short area;
short mins[3]; // for frustum culling
short maxs[3];
unsigned short firstleafface;
unsigned short numleaffaces;
unsigned short firstleafbrush;
unsigned short numleafbrushes;
} dleaf_t;
typedef struct
{
unsigned short planenum; // facing out of the leaf
short texinfo;
} dbrushside_t;
typedef struct
{
int firstside;
int numsides;
int contents;
} dbrush_t;
#define ANGLE_UP -1
#define ANGLE_DOWN -2
// the visibility lump consists of a header with a count, then
// byte offsets for the PVS and PHS of each cluster, then the raw
// compressed bit vectors
#define DVIS_PVS 0
#define DVIS_PHS 1
typedef struct
{
int numclusters;
int bitofs[8][2]; // bitofs[numclusters][2]
} dvis_t;
// each area has a list of portals that lead into other areas
// when portals are closed, other areas may not be visible or
// hearable even if the vis info says that it should be
typedef struct
{
int portalnum;
int otherarea;
} dareaportal_t;
typedef struct
{
int numareaportals;
int firstareaportal;
} darea_t;

381
src/bspc/q3files.h Normal file
View File

@@ -0,0 +1,381 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#ifndef __QFILES_H__
#define __QFILES_H__
//
// qfiles.h: quake file formats
// This file must be identical in the quake and utils directories
//
// surface geometry should not exceed these limits
#define SHADER_MAX_VERTEXES 1000
#define SHADER_MAX_INDEXES ( 6 * SHADER_MAX_VERTEXES )
// the maximum size of game reletive pathnames
#define MAX_QPATH 64
/*
========================================================================
PCX files are used for 8 bit images
========================================================================
*
typedef struct {
char manufacturer;
char version;
char encoding;
char bits_per_pixel;
unsigned short xmin,ymin,xmax,ymax;
unsigned short hres,vres;
unsigned char palette[48];
char reserved;
char color_planes;
unsigned short bytes_per_line;
unsigned short palette_type;
char filler[58];
unsigned char data; // unbounded
} pcx_t;
/*
========================================================================
TGA files are used for 24/32 bit images
========================================================================
*
typedef struct _TargaHeader {
unsigned char id_length, colormap_type, image_type;
unsigned short colormap_index, colormap_length;
unsigned char colormap_size;
unsigned short x_origin, y_origin, width, height;
unsigned char pixel_size, attributes;
} TargaHeader;
*/
/*
========================================================================
.MD3 triangle model file format
========================================================================
*/
#define MD3_IDENT ( ( '3' << 24 ) + ( 'P' << 16 ) + ( 'D' << 8 ) + 'I' )
#define MD3_VERSION 15
// limits
#define MD3_MAX_LODS 4
#define MD3_MAX_TRIANGLES 8192 // per surface
#define MD3_MAX_VERTS 4096 // per surface
#define MD3_MAX_SHADERS 256 // per surface
#define MD3_MAX_FRAMES 1024 // per model
#define MD3_MAX_SURFACES 32 // per model
#define MD3_MAX_TAGS 16 // per frame
// vertex scales
#define MD3_XYZ_SCALE ( 1.0 / 64 )
typedef struct md3Frame_s {
vec3_t bounds[2];
vec3_t localOrigin;
float radius;
char name[16];
} md3Frame_t;
typedef struct md3Tag_s {
char name[MAX_QPATH]; // tag name
vec3_t origin;
vec3_t axis[3];
} md3Tag_t;
/*
** md3Surface_t
**
** CHUNK SIZE
** header sizeof( md3Surface_t )
** shaders sizeof( md3Shader_t ) * numShaders
** triangles[0] sizeof( md3Triangle_t ) * numTriangles
** st sizeof( md3St_t ) * numVerts
** XyzNormals sizeof( md3XyzNormal_t ) * numVerts * numFrames
*/
typedef struct {
int ident; //
char name[MAX_QPATH]; // polyset name
int flags;
int numFrames; // all surfaces in a model should have the same
int numShaders; // all surfaces in a model should have the same
int numVerts;
int numTriangles;
int ofsTriangles;
int ofsShaders; // offset from start of md3Surface_t
int ofsSt; // texture coords are common for all frames
int ofsXyzNormals; // numVerts * numFrames
int ofsEnd; // next surface follows
} md3Surface_t;
typedef struct {
char name[MAX_QPATH];
int shaderIndex; // for in-game use
} md3Shader_t;
typedef struct {
int indexes[3];
} md3Triangle_t;
typedef struct {
float st[2];
} md3St_t;
typedef struct {
short xyz[3];
short normal;
} md3XyzNormal_t;
typedef struct {
int ident;
int version;
char name[MAX_QPATH]; // model name
int flags;
int numFrames;
int numTags;
int numSurfaces;
int numSkins;
int ofsFrames; // offset for first frame
int ofsTags; // numFrames * numTags
int ofsSurfaces; // first surface, others follow
int ofsEnd; // end of file
} md3Header_t;
/*
==============================================================================
.BSP file format
==============================================================================
*/
#define Q3_BSP_IDENT ( ( 'P' << 24 ) + ( 'S' << 16 ) + ( 'B' << 8 ) + 'I' )
// little-endian "IBSP"
#define Q3_BSP_VERSION 47
// there shouldn't be any problem with increasing these values at the
// expense of more memory allocation in the utilities
#define Q3_MAX_MAP_MODELS 0x400
#define Q3_MAX_MAP_BRUSHES 0x8000
#define Q3_MAX_MAP_ENTITIES 0x800
#define Q3_MAX_MAP_ENTSTRING 0x10000
#define Q3_MAX_MAP_SHADERS 0x400
#define Q3_MAX_MAP_AREAS 0x100 // MAX_MAP_AREA_BYTES in q_shared must match!
#define Q3_MAX_MAP_FOGS 0x100
#define Q3_MAX_MAP_PLANES 0x10000
#define Q3_MAX_MAP_NODES 0x10000
#define Q3_MAX_MAP_BRUSHSIDES 0x10000
#define Q3_MAX_MAP_LEAFS 0x10000
#define Q3_MAX_MAP_LEAFFACES 0x10000
#define Q3_MAX_MAP_LEAFBRUSHES 0x10000
#define Q3_MAX_MAP_PORTALS 0x10000
#define Q3_MAX_MAP_LIGHTING 0x400000
#define Q3_MAX_MAP_LIGHTGRID 0x400000
#define Q3_MAX_MAP_VISIBILITY 0x200000
#define Q3_MAX_MAP_DRAW_SURFS 0x20000
#define Q3_MAX_MAP_DRAW_VERTS 0x80000
#define Q3_MAX_MAP_DRAW_INDEXES 0x80000
// key / value pair sizes in the entities lump
#define Q3_MAX_KEY 32
#define Q3_MAX_VALUE 1024
// the editor uses these predefined yaw angles to orient entities up or down
#define ANGLE_UP -1
#define ANGLE_DOWN -2
#define LIGHTMAP_WIDTH 128
#define LIGHTMAP_HEIGHT 128
//=============================================================================
typedef struct {
int fileofs, filelen;
} q3_lump_t;
#define Q3_LUMP_ENTITIES 0
#define Q3_LUMP_SHADERS 1
#define Q3_LUMP_PLANES 2
#define Q3_LUMP_NODES 3
#define Q3_LUMP_LEAFS 4
#define Q3_LUMP_LEAFSURFACES 5
#define Q3_LUMP_LEAFBRUSHES 6
#define Q3_LUMP_MODELS 7
#define Q3_LUMP_BRUSHES 8
#define Q3_LUMP_BRUSHSIDES 9
#define Q3_LUMP_DRAWVERTS 10
#define Q3_LUMP_DRAWINDEXES 11
#define Q3_LUMP_FOGS 12
#define Q3_LUMP_SURFACES 13
#define Q3_LUMP_LIGHTMAPS 14
#define Q3_LUMP_LIGHTGRID 15
#define Q3_LUMP_VISIBILITY 16
#define Q3_HEADER_LUMPS 17
typedef struct {
int ident;
int version;
q3_lump_t lumps[Q3_HEADER_LUMPS];
} q3_dheader_t;
typedef struct {
float mins[3], maxs[3];
int firstSurface, numSurfaces;
int firstBrush, numBrushes;
} q3_dmodel_t;
typedef struct {
char shader[MAX_QPATH];
int surfaceFlags;
int contentFlags;
} q3_dshader_t;
// planes (x&~1) and (x&~1)+1 are allways opposites
typedef struct {
float normal[3];
float dist;
} q3_dplane_t;
typedef struct {
int planeNum;
int children[2]; // negative numbers are -(leafs+1), not nodes
int mins[3]; // for frustom culling
int maxs[3];
} q3_dnode_t;
typedef struct {
int cluster; // -1 = opaque cluster (do I still store these?)
int area;
int mins[3]; // for frustum culling
int maxs[3];
int firstLeafSurface;
int numLeafSurfaces;
int firstLeafBrush;
int numLeafBrushes;
} q3_dleaf_t;
typedef struct {
int planeNum; // positive plane side faces out of the leaf
int shaderNum;
} q3_dbrushside_t;
typedef struct {
int firstSide;
int numSides;
int shaderNum; // the shader that determines the contents flags
} q3_dbrush_t;
typedef struct {
char shader[MAX_QPATH];
int brushNum;
int visibleSide; // the brush side that ray tests need to clip against (-1 == none)
} q3_dfog_t;
typedef struct {
vec3_t xyz;
float st[2];
float lightmap[2];
vec3_t normal;
byte color[4];
} q3_drawVert_t;
typedef enum {
MST_BAD,
MST_PLANAR,
MST_PATCH,
MST_TRIANGLE_SOUP,
MST_FLARE
} q3_mapSurfaceType_t;
typedef struct {
int shaderNum;
int fogNum;
int surfaceType;
int firstVert;
int numVerts;
int firstIndex;
int numIndexes;
int lightmapNum;
int lightmapX, lightmapY;
int lightmapWidth, lightmapHeight;
vec3_t lightmapOrigin;
vec3_t lightmapVecs[3]; // for patches, [0] and [1] are lodbounds
int patchWidth;
int patchHeight;
} q3_dsurface_t;
#endif

496
src/bspc/qbsp.h Normal file
View File

@@ -0,0 +1,496 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#if defined( WIN32 ) || defined( _WIN32 )
#include <io.h>
#endif
#include <malloc.h>
#include "l_cmd.h"
#include "l_math.h"
#include "l_poly.h"
#include "l_threads.h"
#include "../botlib/l_script.h"
#include "l_bsp_ent.h"
#include "q2files.h"
#include "l_mem.h"
#include "l_utils.h"
#include "l_log.h"
#include "l_qfiles.h"
//Mr Elusive shit
#define ME
#define DEBUG
#define NODELIST
#define SIN
#define MAX_BRUSH_SIDES 128 //maximum number of sides per brush
#define CLIP_EPSILON 0.1
#define MAX_MAP_BOUNDS 65535
#define BOGUS_RANGE ( MAX_MAP_BOUNDS + 128 ) //somewhere outside the map
#define TEXINFO_NODE -1 //side is allready on a node
#define PLANENUM_LEAF -1 //used for leaf nodes
#define MAXEDGES 20 //maximum number of face edges
#define MAX_NODE_BRUSHES 8 //maximum brushes in a node
//side flags
#define SFL_TESTED 1
#define SFL_VISIBLE 2
#define SFL_BEVEL 4
#define SFL_TEXTURED 8
#define SFL_CURVE 16
//map plane
typedef struct plane_s
{
vec3_t normal;
vec_t dist;
int type;
int signbits;
struct plane_s *hash_chain;
} plane_t;
//brush texture
typedef struct
{
vec_t shift[2];
vec_t rotate;
vec_t scale[2];
char name[32];
int flags;
int value;
} brush_texture_t;
//brush side
typedef struct side_s
{
int planenum; // map plane this side is in
int texinfo; // texture reference
winding_t *winding; // winding of this side
struct side_s *original; // bspbrush_t sides will reference the mapbrush_t sides
int lightinfo; // for SIN only
int contents; // from miptex
int surf; // from miptex
unsigned short flags; // side flags
} side_t; //sizeof(side_t) = 36
//map brush
typedef struct mapbrush_s
{
int entitynum;
int brushnum;
int contents;
#ifdef ME
int expansionbbox; //bbox used for expansion of the brush
int leafnum;
int modelnum;
#endif
vec3_t mins, maxs;
int numsides;
side_t *original_sides;
} mapbrush_t;
//bsp face
typedef struct face_s
{
struct face_s *next; // on node
// the chain of faces off of a node can be merged or split,
// but each face_t along the way will remain in the chain
// until the entire tree is freed
struct face_s *merged; // if set, this face isn't valid anymore
struct face_s *split[2]; // if set, this face isn't valid anymore
struct portal_s *portal;
int texinfo;
#ifdef SIN
int lightinfo;
#endif
int planenum;
int contents; // faces in different contents can't merge
int outputnumber;
winding_t *w;
int numpoints;
qboolean badstartvert; // tjunctions cannot be fixed without a midpoint vertex
int vertexnums[MAXEDGES];
} face_t;
//bsp brush
typedef struct bspbrush_s
{
struct bspbrush_s *next;
vec3_t mins, maxs;
int side, testside; // side of node during construction
mapbrush_t *original;
int numsides;
side_t sides[6]; // variably sized
} bspbrush_t; //sizeof(bspbrush_t) = 44 + numsides * sizeof(side_t)
//bsp node
typedef struct node_s
{
//both leafs and nodes
int planenum; // -1 = leaf node
struct node_s *parent;
vec3_t mins, maxs; // valid after portalization
bspbrush_t *volume; // one for each leaf/node
// nodes only
qboolean detail_seperator; // a detail brush caused the split
side_t *side; // the side that created the node
struct node_s *children[2];
face_t *faces;
// leafs only
bspbrush_t *brushlist; // fragments of all brushes in this leaf
int contents; // OR of all brush contents
int occupied; // 1 or greater can reach entity
entity_t *occupant; // for leak file testing
int cluster; // for portalfile writing
int area; // for areaportals
struct portal_s *portals; // also on nodes during construction
#ifdef NODELIST
struct node_s *next; //next node in the nodelist
#endif
#ifdef ME
int expansionbboxes; //OR of all bboxes used for expansion of the brushes
int modelnum;
#endif
} node_t; //sizeof(node_t) = 80 bytes
//bsp portal
typedef struct portal_s
{
plane_t plane;
node_t *onnode; // NULL = outside box
node_t *nodes[2]; // [0] = front side of plane
struct portal_s *next[2];
winding_t *winding;
qboolean sidefound; // false if ->side hasn't been checked
side_t *side; // NULL = non-visible
face_t *face[2]; // output face in bsp file
#ifdef ME
struct tmp_face_s *tmpface; //pointer to the tmpface created for this portal
int planenum; //number of the map plane used by the portal
#endif
} portal_t;
//bsp tree
typedef struct
{
node_t *headnode;
node_t outside_node;
vec3_t mins, maxs;
} tree_t;
//=============================================================================
// bspc.c
//=============================================================================
extern qboolean noprune;
extern qboolean nodetail;
extern qboolean fulldetail;
extern qboolean nomerge;
extern qboolean nosubdiv;
extern qboolean nowater;
extern qboolean noweld;
extern qboolean noshare;
extern qboolean notjunc;
extern qboolean onlyents;
#ifdef ME
extern qboolean nocsg;
extern qboolean create_aas;
extern qboolean freetree;
extern qboolean lessbrushes;
extern qboolean nobrushmerge;
extern qboolean cancelconversion;
extern qboolean noliquids;
extern qboolean capsule_collision;
#endif //ME
extern float subdivide_size;
extern vec_t microvolume;
extern char outbase[32];
extern char source[1024];
//=============================================================================
// map.c
//=============================================================================
#define MAX_MAPFILE_PLANES 128000
#define MAX_MAPFILE_BRUSHES 65535 //16384
#define MAX_MAPFILE_BRUSHSIDES ( MAX_MAPFILE_BRUSHES * 8 )
#define MAX_MAPFILE_TEXINFO 8192
extern int entity_num;
extern plane_t mapplanes[MAX_MAPFILE_PLANES];
extern int nummapplanes;
extern int mapplaneusers[MAX_MAPFILE_PLANES];
extern int nummapbrushes;
extern mapbrush_t mapbrushes[MAX_MAPFILE_BRUSHES];
extern vec3_t map_mins, map_maxs;
extern int nummapbrushsides;
extern side_t brushsides[MAX_MAPFILE_BRUSHSIDES];
extern brush_texture_t side_brushtextures[MAX_MAPFILE_BRUSHSIDES];
#ifdef ME
typedef struct
{
float vecs[2][4]; // [s/t][xyz offset]
int flags; // miptex flags + overrides
int value;
char texture[64]; // texture name (textures/*.wal)
int nexttexinfo; // for animations, -1 = end of chain
} map_texinfo_t;
extern map_texinfo_t map_texinfo[MAX_MAPFILE_TEXINFO];
extern int map_numtexinfo;
#define NODESTACKSIZE 1024
#define MAPTYPE_QUAKE1 1
#define MAPTYPE_QUAKE2 2
#define MAPTYPE_QUAKE3 3
#define MAPTYPE_HALFLIFE 4
#define MAPTYPE_SIN 5
extern int nodestack[NODESTACKSIZE];
extern int *nodestackptr;
extern int nodestacksize;
extern int brushmodelnumbers[MAX_MAPFILE_BRUSHES];
extern int dbrushleafnums[MAX_MAPFILE_BRUSHES];
extern int dplanes2mapplanes[MAX_MAPFILE_PLANES];
extern int loadedmaptype;
#endif //ME
extern int c_boxbevels;
extern int c_edgebevels;
extern int c_areaportals;
extern int c_clipbrushes;
extern int c_squattbrushes;
//finds a float plane for the given normal and distance
int FindFloatPlane( vec3_t normal, vec_t dist );
//returns the plane type for the given normal
int PlaneTypeForNormal( vec3_t normal );
//returns the plane defined by the three given points
int PlaneFromPoints( int *p0, int *p1, int *p2 );
//add bevels to the map brush
void AddBrushBevels( mapbrush_t *b );
//makes brush side windings for the brush
qboolean MakeBrushWindings( mapbrush_t *ob );
//marks brush bevels of the brush as bevel
void MarkBrushBevels( mapbrush_t *brush );
//returns true if the map brush already exists
int BrushExists( mapbrush_t *brush );
//loads a map from a bsp file
int LoadMapFromBSP( struct quakefile_s *qf );
//resets map loading
void ResetMapLoading( void );
//print some map info
void PrintMapInfo( void );
//writes a map file (type depending on loaded map type)
void WriteMapFile( char *filename );
//=============================================================================
// map_q2.c
//=============================================================================
void Q2_ResetMapLoading( void );
//loads a Quake2 map file
void Q2_LoadMapFile( char *filename );
//loads a map from a Quake2 bsp file
void Q2_LoadMapFromBSP( char *filename, int offset, int length );
//=============================================================================
// map_q1.c
//=============================================================================
void Q1_ResetMapLoading( void );
//loads a Quake2 map file
void Q1_LoadMapFile( char *filename );
//loads a map from a Quake1 bsp file
void Q1_LoadMapFromBSP( char *filename, int offset, int length );
//=============================================================================
// map_q3.c
//=============================================================================
void Q3_ResetMapLoading( void );
//loads a map from a Quake3 bsp file
void Q3_LoadMapFromBSP( struct quakefile_s *qf );
//=============================================================================
// map_sin.c
//=============================================================================
void Sin_ResetMapLoading( void );
//loads a Sin map file
void Sin_LoadMapFile( char *filename );
//loads a map from a Sin bsp file
void Sin_LoadMapFromBSP( char *filename, int offset, int length );
//=============================================================================
// map_hl.c
//=============================================================================
void HL_ResetMapLoading( void );
//loads a Half-Life map file
void HL_LoadMapFile( char *filename );
//loads a map from a Half-Life bsp file
void HL_LoadMapFromBSP( char *filename, int offset, int length );
//=============================================================================
// textures.c
//=============================================================================
typedef struct
{
char name[64];
int flags;
int value;
int contents;
char animname[64];
} textureref_t;
#define MAX_MAP_TEXTURES 1024
extern textureref_t textureref[MAX_MAP_TEXTURES];
int FindMiptex( char *name );
int TexinfoForBrushTexture( plane_t *plane, brush_texture_t *bt, vec3_t origin );
void TextureAxisFromPlane( plane_t *pln, vec3_t xv, vec3_t yv );
//=============================================================================
// csg
//=============================================================================
bspbrush_t *MakeBspBrushList( int startbrush, int endbrush, vec3_t clipmins, vec3_t clipmaxs );
bspbrush_t *ChopBrushes( bspbrush_t *head );
bspbrush_t *InitialBrushList( bspbrush_t *list );
bspbrush_t *OptimizedBrushList( bspbrush_t *list );
void WriteBrushMap( char *name, bspbrush_t *list );
void CheckBSPBrush( bspbrush_t *brush );
void BSPBrushWindings( bspbrush_t *brush );
bspbrush_t *TryMergeBrushes( bspbrush_t *brush1, bspbrush_t *brush2 );
tree_t *ProcessWorldBrushes( int brush_start, int brush_end );
//=============================================================================
// brushbsp
//=============================================================================
#define PSIDE_FRONT 1
#define PSIDE_BACK 2
#define PSIDE_BOTH ( PSIDE_FRONT | PSIDE_BACK )
#define PSIDE_FACING 4
void WriteBrushList( char *name, bspbrush_t *brush, qboolean onlyvis );
bspbrush_t *CopyBrush( bspbrush_t *brush );
void SplitBrush( bspbrush_t *brush, int planenum, bspbrush_t **front, bspbrush_t **back );
node_t *AllocNode( void );
bspbrush_t *AllocBrush( int numsides );
int CountBrushList( bspbrush_t *brushes );
void FreeBrush( bspbrush_t *brushes );
vec_t BrushVolume( bspbrush_t *brush );
void BoundBrush( bspbrush_t *brush );
void FreeBrushList( bspbrush_t *brushes );
tree_t *BrushBSP( bspbrush_t *brushlist, vec3_t mins, vec3_t maxs );
bspbrush_t *BrushFromBounds( vec3_t mins, vec3_t maxs );
int BrushMostlyOnSide( bspbrush_t *brush, plane_t *plane );
qboolean WindingIsHuge( winding_t *w );
qboolean WindingIsTiny( winding_t *w );
void ResetBrushBSP( void );
//=============================================================================
// portals.c
//=============================================================================
int VisibleContents( int contents );
void MakeHeadnodePortals( tree_t *tree );
void MakeNodePortal( node_t *node );
void SplitNodePortals( node_t *node );
qboolean Portal_VisFlood( portal_t *p );
qboolean FloodEntities( tree_t *tree );
void FillOutside( node_t *headnode );
void FloodAreas( tree_t *tree );
void MarkVisibleSides( tree_t *tree, int start, int end );
void FreePortal( portal_t *p );
void EmitAreaPortals( node_t *headnode );
void MakeTreePortals( tree_t *tree );
//=============================================================================
// glfile.c
//=============================================================================
void OutputWinding( winding_t *w, FILE *glview );
void WriteGLView( tree_t *tree, char *source );
//=============================================================================
// gldraw.c
//=============================================================================
extern vec3_t draw_mins, draw_maxs;
extern qboolean drawflag;
void Draw_ClearWindow( void );
void DrawWinding( winding_t *w );
void GLS_BeginScene( void );
void GLS_Winding( winding_t *w, int code );
void GLS_EndScene( void );
//=============================================================================
// leakfile.c
//=============================================================================
void LeakFile( tree_t *tree );
//=============================================================================
// tree.c
//=============================================================================
tree_t *Tree_Alloc( void );
void Tree_Free( tree_t *tree );
void Tree_Free_r( node_t *node );
void Tree_Print_r( node_t *node, int depth );
void Tree_FreePortals_r( node_t *node );
void Tree_PruneNodes_r( node_t *node );
void Tree_PruneNodes( node_t *node );
//=============================================================================
// faces.c
//=============================================================================
face_t *AllocFace( void );
void FreeFace( face_t *f );
void MakeFaces( node_t *headnode );
void FixTjuncs( node_t *headnode );
int GetEdge2( int v1, int v2, face_t *f );
void MergeNodeFaces( node_t *node );

495
src/bspc/qfiles.h Normal file
View File

@@ -0,0 +1,495 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//
// qfiles.h: quake file formats
// This file must be identical in the quake and utils directories
//
/*
========================================================================
The .pak files are just a linear collapse of a directory tree
========================================================================
*/
#define IDPAKHEADER ( ( 'K' << 24 ) + ( 'C' << 16 ) + ( 'A' << 8 ) + 'P' )
typedef struct
{
char name[56];
int filepos, filelen;
} dpackfile_t;
typedef struct
{
int ident; // == IDPAKHEADER
int dirofs;
int dirlen;
} dpackheader_t;
#define MAX_FILES_IN_PACK 4096
/*
========================================================================
PCX files are used for as many images as possible
========================================================================
*/
typedef struct
{
char manufacturer;
char version;
char encoding;
char bits_per_pixel;
unsigned short xmin,ymin,xmax,ymax;
unsigned short hres,vres;
unsigned char palette[48];
char reserved;
char color_planes;
unsigned short bytes_per_line;
unsigned short palette_type;
char filler[58];
unsigned char data; // unbounded
} pcx_t;
/*
========================================================================
.MD2 triangle model file format
========================================================================
*/
#define IDALIASHEADER ( ( '2' << 24 ) + ( 'P' << 16 ) + ( 'D' << 8 ) + 'I' )
#define ALIAS_VERSION 8
#define MAX_TRIANGLES 4096
#define MAX_VERTS 2048
#define MAX_FRAMES 512
#define MAX_MD2SKINS 32
#define MAX_SKINNAME 64
typedef struct
{
short s;
short t;
} dstvert_t;
typedef struct
{
short index_xyz[3];
short index_st[3];
} dtriangle_t;
typedef struct
{
byte v[3]; // scaled byte to fit in frame mins/maxs
byte lightnormalindex;
} dtrivertx_t;
#define DTRIVERTX_V0 0
#define DTRIVERTX_V1 1
#define DTRIVERTX_V2 2
#define DTRIVERTX_LNI 3
#define DTRIVERTX_SIZE 4
typedef struct
{
float scale[3]; // multiply byte verts by this
float translate[3]; // then add this
char name[16]; // frame name from grabbing
dtrivertx_t verts[1]; // variable sized
} daliasframe_t;
// the glcmd format:
// a positive integer starts a tristrip command, followed by that many
// vertex structures.
// a negative integer starts a trifan command, followed by -x vertexes
// a zero indicates the end of the command list.
// a vertex consists of a floating point s, a floating point t,
// and an integer vertex index.
typedef struct
{
int ident;
int version;
int skinwidth;
int skinheight;
int framesize; // byte size of each frame
int num_skins;
int num_xyz;
int num_st; // greater than num_xyz for seams
int num_tris;
int num_glcmds; // dwords in strip/fan command list
int num_frames;
int ofs_skins; // each skin is a MAX_SKINNAME string
int ofs_st; // byte offset from start for stverts
int ofs_tris; // offset for dtriangles
int ofs_frames; // offset for first frame
int ofs_glcmds;
int ofs_end; // end of file
} dmdl_t;
/*
========================================================================
.SP2 sprite file format
========================================================================
*/
#define IDSPRITEHEADER ( ( '2' << 24 ) + ( 'S' << 16 ) + ( 'D' << 8 ) + 'I' )
// little-endian "IDS2"
#define SPRITE_VERSION 2
typedef struct
{
int width, height;
int origin_x, origin_y; // raster coordinates inside pic
char name[MAX_SKINNAME]; // name of pcx file
} dsprframe_t;
typedef struct {
int ident;
int version;
int numframes;
dsprframe_t frames[1]; // variable sized
} dsprite_t;
/*
==============================================================================
.WAL texture file format
==============================================================================
*/
#define MIPLEVELS 4
typedef struct miptex_s
{
char name[32];
unsigned width, height;
unsigned offsets[MIPLEVELS]; // four mip maps stored
char animname[32]; // next frame in animation chain
int flags;
int contents;
int value;
} miptex_t;
/*
==============================================================================
.BSP file format
==============================================================================
*/
#define IDBSPHEADER ( ( 'P' << 24 ) + ( 'S' << 16 ) + ( 'B' << 8 ) + 'I' )
// little-endian "IBSP"
#define BSPVERSION 38
// upper design bounds
// leaffaces, leafbrushes, planes, and verts are still bounded by
// 16 bit short limits
#define MAX_MAP_MODELS 1024
#define MAX_MAP_BRUSHES 8192
#define MAX_MAP_ENTITIES 2048
#define MAX_MAP_ENTSTRING 0x40000
#define MAX_MAP_TEXINFO 8192
#define MAX_MAP_AREAS 256
#define MAX_MAP_AREAPORTALS 1024
#define MAX_MAP_PLANES 65536
#define MAX_MAP_NODES 65536
#define MAX_MAP_BRUSHSIDES 65536
#define MAX_MAP_LEAFS 65536
#define MAX_MAP_VERTS 65536
#define MAX_MAP_FACES 65536
#define MAX_MAP_LEAFFACES 65536
#define MAX_MAP_LEAFBRUSHES 65536
#define MAX_MAP_PORTALS 65536
#define MAX_MAP_EDGES 128000
#define MAX_MAP_SURFEDGES 256000
#define MAX_MAP_LIGHTING 0x320000
#define MAX_MAP_VISIBILITY 0x280000
// key / value pair sizes
#define MAX_KEY 32
#define MAX_VALUE 1024
//=============================================================================
typedef struct
{
int fileofs, filelen;
} lump_t;
#define LUMP_ENTITIES 0
#define LUMP_PLANES 1
#define LUMP_VERTEXES 2
#define LUMP_VISIBILITY 3
#define LUMP_NODES 4
#define LUMP_TEXINFO 5
#define LUMP_FACES 6
#define LUMP_LIGHTING 7
#define LUMP_LEAFS 8
#define LUMP_LEAFFACES 9
#define LUMP_LEAFBRUSHES 10
#define LUMP_EDGES 11
#define LUMP_SURFEDGES 12
#define LUMP_MODELS 13
#define LUMP_BRUSHES 14
#define LUMP_BRUSHSIDES 15
#define LUMP_POP 16
#define LUMP_AREAS 17
#define LUMP_AREAPORTALS 18
#define HEADER_LUMPS 19
typedef struct
{
int ident;
int version;
lump_t lumps[HEADER_LUMPS];
} dheader_t;
typedef struct
{
float mins[3], maxs[3];
float origin[3]; // for sounds or lights
int headnode;
int firstface, numfaces; // submodels just draw faces
// without walking the bsp tree
} dmodel_t;
typedef struct
{
float point[3];
} dvertex_t;
// 0-2 are axial planes
#define PLANE_X 0
#define PLANE_Y 1
#define PLANE_Z 2
// 3-5 are non-axial planes snapped to the nearest
#define PLANE_ANYX 3
#define PLANE_ANYY 4
#define PLANE_ANYZ 5
// planes (x&~1) and (x&~1)+1 are allways opposites
typedef struct
{
float normal[3];
float dist;
int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
} dplane_t;
// contents flags are seperate bits
// a given brush can contribute multiple content bits
// multiple brushes can be in a single leaf
// these definitions also need to be in q_shared.h!
// lower bits are stronger, and will eat weaker brushes completely
#define CONTENTS_SOLID 1 // an eye is never valid in a solid
#define CONTENTS_WINDOW 2 // translucent, but not watery
#define CONTENTS_AUX 4
#define CONTENTS_LAVA 8
#define CONTENTS_SLIME 16
#define CONTENTS_WATER 32
#define CONTENTS_MIST 64
#define LAST_VISIBLE_CONTENTS 64
// remaining contents are non-visible, and don't eat brushes
#define CONTENTS_AREAPORTAL 0x8000
#define CONTENTS_PLAYERCLIP 0x10000
#define CONTENTS_MONSTERCLIP 0x20000
// currents can be added to any other contents, and may be mixed
#define CONTENTS_CURRENT_0 0x40000
#define CONTENTS_CURRENT_90 0x80000
#define CONTENTS_CURRENT_180 0x100000
#define CONTENTS_CURRENT_270 0x200000
#define CONTENTS_CURRENT_UP 0x400000
#define CONTENTS_CURRENT_DOWN 0x800000
#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity
#define CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game
#define CONTENTS_DEADMONSTER 0x4000000
#define CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs
//renamed because it's in conflict with the Q3A translucent contents
#define CONTENTS_Q2TRANSLUCENT 0x10000000 // auto set if any surface has trans
#define CONTENTS_LADDER 0x20000000
#define SURF_LIGHT 0x1 // value will hold the light strength
#define SURF_SLICK 0x2 // effects game physics
#define SURF_SKY 0x4 // don't draw, but add to skybox
#define SURF_WARP 0x8 // turbulent water warp
#define SURF_TRANS33 0x10
#define SURF_TRANS66 0x20
#define SURF_FLOWING 0x40 // scroll towards angle
#define SURF_NODRAW 0x80 // don't bother referencing the texture
#define SURF_HINT 0x100 // make a primary bsp splitter
#define SURF_SKIP 0x200 // completely ignore, allowing non-closed brushes
#define SURF_MONSTERSLICK 0x4000000 // slick surf that only affects ai's
typedef struct
{
int planenum;
int children[2]; // negative numbers are -(leafs+1), not nodes
short mins[3]; // for frustom culling
short maxs[3];
unsigned short firstface;
unsigned short numfaces; // counting both sides
} dnode_t;
typedef struct texinfo_s
{
float vecs[2][4]; // [s/t][xyz offset]
int flags; // miptex flags + overrides
int value; // light emission, etc
char texture[32]; // texture name (textures/*.wal)
int nexttexinfo; // for animations, -1 = end of chain
} texinfo_t;
// note that edge 0 is never used, because negative edge nums are used for
// counterclockwise use of the edge in a face
typedef struct
{
unsigned short v[2]; // vertex numbers
} dedge_t;
#define MAXLIGHTMAPS 4
typedef struct
{
unsigned short planenum;
short side;
int firstedge; // we must support > 64k edges
short numedges;
short texinfo;
// lighting info
byte styles[MAXLIGHTMAPS];
int lightofs; // start of [numstyles*surfsize] samples
} dface_t;
typedef struct
{
int contents; // OR of all brushes (not needed?)
short cluster;
short area;
short mins[3]; // for frustum culling
short maxs[3];
unsigned short firstleafface;
unsigned short numleaffaces;
unsigned short firstleafbrush;
unsigned short numleafbrushes;
} dleaf_t;
typedef struct
{
unsigned short planenum; // facing out of the leaf
short texinfo;
} dbrushside_t;
typedef struct
{
int firstside;
int numsides;
int contents;
} dbrush_t;
#define ANGLE_UP -1
#define ANGLE_DOWN -2
// the visibility lump consists of a header with a count, then
// byte offsets for the PVS and PHS of each cluster, then the raw
// compressed bit vectors
#define DVIS_PVS 0
#define DVIS_PHS 1
typedef struct
{
int numclusters;
int bitofs[8][2]; // bitofs[numclusters][2]
} dvis_t;
// each area has a list of portals that lead into other areas
// when portals are closed, other areas may not be visible or
// hearable even if the vis info says that it should be
typedef struct
{
int portalnum;
int otherarea;
} dareaportal_t;
typedef struct
{
int numareaportals;
int firstareaportal;
} darea_t;

372
src/bspc/sinfiles.h Normal file
View File

@@ -0,0 +1,372 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
/*
==============================================================================
.BSP file format
==============================================================================
*/
#define SIN
#define SINBSPVERSION 41
// upper design bounds
// leaffaces, leafbrushes, planes, and verts are still bounded by
// 16 bit short limits
#define SIN_MAX_MAP_MODELS 1024
#define SIN_MAX_MAP_BRUSHES 8192
#define SIN_MAX_MAP_ENTITIES 2048
#define SIN_MAX_MAP_ENTSTRING 0x40000
#define SIN_MAX_MAP_TEXINFO 8192
#define SIN_MAX_MAP_AREAS 256
#define SIN_MAX_MAP_AREAPORTALS 1024
#define SIN_MAX_MAP_PLANES 65536
#define SIN_MAX_MAP_NODES 65536
#define SIN_MAX_MAP_BRUSHSIDES 65536
#define SIN_MAX_MAP_LEAFS 65536
#define SIN_MAX_MAP_VERTS 65536
#define SIN_MAX_MAP_FACES 65536
#define SIN_MAX_MAP_LEAFFACES 65536
#define SIN_MAX_MAP_LEAFBRUSHES 65536
#define SIN_MAX_MAP_PORTALS 65536
#define SIN_MAX_MAP_EDGES 128000
#define SIN_MAX_MAP_SURFEDGES 256000
#define SIN_MAX_MAP_LIGHTING 0x320000
#define SIN_MAX_MAP_VISIBILITY 0x280000
#ifdef SIN
#define SIN_MAX_MAP_LIGHTINFO 8192
#endif
#ifdef SIN
#undef SIN_MAX_MAP_LIGHTING //undef the Quake2 bsp version
#define SIN_MAX_MAP_LIGHTING 0x300000
#endif
#ifdef SIN
#undef SIN_MAX_MAP_VISIBILITY //undef the Quake2 bsp version
#define SIN_MAX_MAP_VISIBILITY 0x280000
#endif
//=============================================================================
typedef struct
{
int fileofs, filelen;
} sin_lump_t;
#define SIN_LUMP_ENTITIES 0
#define SIN_LUMP_PLANES 1
#define SIN_LUMP_VERTEXES 2
#define SIN_LUMP_VISIBILITY 3
#define SIN_LUMP_NODES 4
#define SIN_LUMP_TEXINFO 5
#define SIN_LUMP_FACES 6
#define SIN_LUMP_LIGHTING 7
#define SIN_LUMP_LEAFS 8
#define SIN_LUMP_LEAFFACES 9
#define SIN_LUMP_LEAFBRUSHES 10
#define SIN_LUMP_EDGES 11
#define SIN_LUMP_SURFEDGES 12
#define SIN_LUMP_MODELS 13
#define SIN_LUMP_BRUSHES 14
#define SIN_LUMP_BRUSHSIDES 15
#define SIN_LUMP_POP 16
#define SIN_LUMP_AREAS 17
#define SIN_LUMP_AREAPORTALS 18
#ifdef SIN
#define SIN_LUMP_LIGHTINFO 19
#define SINHEADER_LUMPS 20
#endif
typedef struct
{
int ident;
int version;
sin_lump_t lumps[SINHEADER_LUMPS];
} sin_dheader_t;
typedef struct
{
float mins[3], maxs[3];
float origin[3]; // for sounds or lights
int headnode;
int firstface, numfaces; // submodels just draw faces
// without walking the bsp tree
} sin_dmodel_t;
typedef struct
{
float point[3];
} sin_dvertex_t;
// 0-2 are axial planes
#define PLANE_X 0
#define PLANE_Y 1
#define PLANE_Z 2
// 3-5 are non-axial planes snapped to the nearest
#define PLANE_ANYX 3
#define PLANE_ANYY 4
#define PLANE_ANYZ 5
// planes (x&~1) and (x&~1)+1 are allways opposites
typedef struct
{
float normal[3];
float dist;
int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
} sin_dplane_t;
// contents flags are seperate bits
// a given brush can contribute multiple content bits
// multiple brushes can be in a single leaf
// these definitions also need to be in q_shared.h!
// lower bits are stronger, and will eat weaker brushes completely
#ifdef SIN
#define CONTENTS_FENCE 4
#endif
// remaining contents are non-visible, and don't eat brushes
#ifdef SIN
#define CONTENTS_DUMMYFENCE 0x1000
#endif
#ifdef SIN
#define SURF_MASKED 0x2 // surface texture is masked
#endif
#define SURF_SKY 0x4 // don't draw, but add to skybox
#define SURF_WARP 0x8 // turbulent water warp
#ifdef SIN
#define SURF_NONLIT 0x10 // surface is not lit
#define SURF_NOFILTER 0x20 // surface is not bi-linear filtered
#endif
#define SURF_FLOWING 0x40 // scroll towards angle
#define SURF_NODRAW 0x80 // don't bother referencing the texture
#define SURF_HINT 0x100 // make a primary bsp splitter
#define SURF_SKIP 0x200 // completely ignore, allowing non-closed brushes
#ifdef SIN
#define SURF_CONVEYOR 0x40 // surface is not lit
#endif
#ifdef SIN
#define SURF_WAVY 0x400 // surface has waves
#define SURF_RICOCHET 0x800 // projectiles bounce literally bounce off this surface
#define SURF_PRELIT 0x1000 // surface has intensity information for pre-lighting
#define SURF_MIRROR 0x2000 // surface is a mirror
#define SURF_CONSOLE 0x4000 // surface is a console
#define SURF_USECOLOR 0x8000 // surface is lit with non-lit * color
#define SURF_HARDWAREONLY 0x10000 // surface has been damaged
#define SURF_DAMAGE 0x20000 // surface can be damaged
#define SURF_WEAK 0x40000 // surface has weak hit points
#define SURF_NORMAL 0x80000 // surface has normal hit points
#define SURF_ADD 0x100000 // surface will be additive
#define SURF_ENVMAPPED 0x200000 // surface is envmapped
#define SURF_RANDOMANIMATE 0x400000 // surface start animating on a random frame
#define SURF_ANIMATE 0x800000 // surface animates
#define SURF_RNDTIME 0x1000000 // time between animations is random
#define SURF_TRANSLATE 0x2000000 // surface translates
#define SURF_NOMERGE 0x4000000 // surface is not merged in csg phase
#define SURF_TYPE_BIT0 0x8000000 // 0 bit of surface type
#define SURF_TYPE_BIT1 0x10000000 // 1 bit of surface type
#define SURF_TYPE_BIT2 0x20000000 // 2 bit of surface type
#define SURF_TYPE_BIT3 0x40000000 // 3 bit of surface type
#define SURF_START_BIT 27
#define SURFACETYPE_FROM_FLAGS( x ) ( ( x >> ( SURF_START_BIT ) ) & 0xf )
#define SURF_TYPE_SHIFT( x ) ( ( x ) << ( SURF_START_BIT ) ) // macro for getting proper bit mask
#define SURF_TYPE_NONE SURF_TYPE_SHIFT( 0 )
#define SURF_TYPE_WOOD SURF_TYPE_SHIFT( 1 )
#define SURF_TYPE_METAL SURF_TYPE_SHIFT( 2 )
#define SURF_TYPE_STONE SURF_TYPE_SHIFT( 3 )
#define SURF_TYPE_CONCRETE SURF_TYPE_SHIFT( 4 )
#define SURF_TYPE_DIRT SURF_TYPE_SHIFT( 5 )
#define SURF_TYPE_FLESH SURF_TYPE_SHIFT( 6 )
#define SURF_TYPE_GRILL SURF_TYPE_SHIFT( 7 )
#define SURF_TYPE_GLASS SURF_TYPE_SHIFT( 8 )
#define SURF_TYPE_FABRIC SURF_TYPE_SHIFT( 9 )
#define SURF_TYPE_MONITOR SURF_TYPE_SHIFT( 10 )
#define SURF_TYPE_GRAVEL SURF_TYPE_SHIFT( 11 )
#define SURF_TYPE_VEGETATION SURF_TYPE_SHIFT( 12 )
#define SURF_TYPE_PAPER SURF_TYPE_SHIFT( 13 )
#define SURF_TYPE_DUCT SURF_TYPE_SHIFT( 14 )
#define SURF_TYPE_WATER SURF_TYPE_SHIFT( 15 )
#endif
typedef struct
{
int planenum;
int children[2]; // negative numbers are -(leafs+1), not nodes
short mins[3]; // for frustom culling
short maxs[3];
unsigned short firstface;
unsigned short numfaces; // counting both sides
} sin_dnode_t;
#ifdef SIN
typedef struct sin_lightvalue_s
{
int value; // light emission, etc
vec3_t color;
float direct;
float directangle;
float directstyle;
char directstylename[32];
} sin_lightvalue_t;
typedef struct sin_texinfo_s
{
float vecs[2][4]; // [s/t][xyz offset]
int flags; // miptex flags + overrides
char texture[64]; // texture name (textures/*.wal)
int nexttexinfo; // for animations, -1 = end of chain
float trans_mag;
int trans_angle;
int base_angle;
float animtime;
float nonlit;
float translucence;
float friction;
float restitution;
vec3_t color;
char groupname[32];
} sin_texinfo_t;
#endif //SIN
// note that edge 0 is never used, because negative edge nums are used for
// counterclockwise use of the edge in a face
typedef struct
{
unsigned short v[2]; // vertex numbers
} sin_dedge_t;
#ifdef MAXLIGHTMAPS
#undef MAXLIGHTMAPS
#endif
#define MAXLIGHTMAPS 16
typedef struct
{
unsigned short planenum;
short side;
int firstedge; // we must support > 64k edges
short numedges;
short texinfo;
// lighting info
byte styles[MAXLIGHTMAPS];
int lightofs; // start of [numstyles*surfsize] samples
#ifdef SIN
int lightinfo;
#endif
} sin_dface_t;
typedef struct
{
int contents; // OR of all brushes (not needed?)
short cluster;
short area;
short mins[3]; // for frustum culling
short maxs[3];
unsigned short firstleafface;
unsigned short numleaffaces;
unsigned short firstleafbrush;
unsigned short numleafbrushes;
} sin_dleaf_t;
typedef struct
{
unsigned short planenum; // facing out of the leaf
short texinfo;
#ifdef SIN
int lightinfo;
#endif
} sin_dbrushside_t;
typedef struct
{
int firstside;
int numsides;
int contents;
} sin_dbrush_t;
#define ANGLE_UP -1
#define ANGLE_DOWN -2
// the visibility lump consists of a header with a count, then
// byte offsets for the PVS and PHS of each cluster, then the raw
// compressed bit vectors
#define DVIS_PVS 0
#define DVIS_PHS 1
typedef struct
{
int numclusters;
int bitofs[8][2]; // bitofs[numclusters][2]
} sin_dvis_t;
// each area has a list of portals that lead into other areas
// when portals are closed, other areas may not be visible or
// hearable even if the vis info says that it should be
typedef struct
{
int portalnum;
int otherarea;
} sin_dareaportal_t;
typedef struct
{
int numareaportals;
int firstareaportal;
} sin_darea_t;

249
src/bspc/textures.c Normal file
View File

@@ -0,0 +1,249 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: textures.c
// Function: textures
// Programmer: Mr Elusive (MrElusive@worldentity.com)
// Last update: 1999-08-10
// Tab Size: 3
//===========================================================================
#include "qbsp.h"
#include "l_bsp_q2.h"
int nummiptex;
textureref_t textureref[MAX_MAP_TEXTURES];
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int FindMiptex( char *name ) {
int i;
char path[1024];
miptex_t *mt;
for ( i = 0; i < nummiptex; i++ )
{
if ( !strcmp( name, textureref[i].name ) ) {
return i;
} //end if
} //end for
if ( nummiptex == MAX_MAP_TEXTURES ) {
Error( "MAX_MAP_TEXTURES" );
}
strcpy( textureref[i].name, name );
// load the miptex to get the flags and values
sprintf( path, "%stextures/%s.wal", gamedir, name );
if ( TryLoadFile( path, (void **)&mt ) != -1 ) {
textureref[i].value = LittleLong( mt->value );
textureref[i].flags = LittleLong( mt->flags );
textureref[i].contents = LittleLong( mt->contents );
strcpy( textureref[i].animname, mt->animname );
FreeMemory( mt );
} //end if
nummiptex++;
if ( textureref[i].animname[0] ) {
FindMiptex( textureref[i].animname );
}
return i;
} //end of the function FindMipTex
//===========================================================================
//textureAxisFromPlane
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
vec3_t baseaxis[18] =
{
{0,0,1}, {1,0,0}, {0,-1,0}, // floor
{0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling
{1,0,0}, {0,1,0}, {0,0,-1}, // west wall
{-1,0,0}, {0,1,0}, {0,0,-1}, // east wall
{0,1,0}, {1,0,0}, {0,0,-1}, // south wall
{0,-1,0}, {1,0,0}, {0,0,-1} // north wall
};
void TextureAxisFromPlane( plane_t *pln, vec3_t xv, vec3_t yv ) {
int bestaxis;
vec_t dot,best;
int i;
best = 0;
bestaxis = 0;
for ( i = 0 ; i < 6 ; i++ )
{
dot = DotProduct( pln->normal, baseaxis[i * 3] );
if ( dot > best ) {
best = dot;
bestaxis = i;
}
}
VectorCopy( baseaxis[bestaxis * 3 + 1], xv );
VectorCopy( baseaxis[bestaxis * 3 + 2], yv );
} //end of the function TextureAxisFromPlane
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int TexinfoForBrushTexture( plane_t *plane, brush_texture_t *bt, vec3_t origin ) {
vec3_t vecs[2];
int sv, tv;
vec_t ang, sinv, cosv;
vec_t ns, nt;
texinfo_t tx, *tc;
int i, j, k;
float shift[2];
brush_texture_t anim;
int mt;
if ( !bt->name[0] ) {
return 0;
}
memset( &tx, 0, sizeof( tx ) );
strcpy( tx.texture, bt->name );
TextureAxisFromPlane( plane, vecs[0], vecs[1] );
shift[0] = DotProduct( origin, vecs[0] );
shift[1] = DotProduct( origin, vecs[1] );
if ( !bt->scale[0] ) {
bt->scale[0] = 1;
}
if ( !bt->scale[1] ) {
bt->scale[1] = 1;
}
// rotate axis
if ( bt->rotate == 0 ) {
sinv = 0 ; cosv = 1;
} else if ( bt->rotate == 90 ) {
sinv = 1 ; cosv = 0;
} else if ( bt->rotate == 180 ) {
sinv = 0 ; cosv = -1;
} else if ( bt->rotate == 270 ) {
sinv = -1 ; cosv = 0;
} else
{
ang = bt->rotate / 180 * Q_PI;
sinv = sin( ang );
cosv = cos( ang );
}
if ( vecs[0][0] ) {
sv = 0;
} else if ( vecs[0][1] ) {
sv = 1;
} else {
sv = 2;
}
if ( vecs[1][0] ) {
tv = 0;
} else if ( vecs[1][1] ) {
tv = 1;
} else {
tv = 2;
}
for ( i = 0 ; i < 2 ; i++ )
{
ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
nt = sinv * vecs[i][sv] + cosv * vecs[i][tv];
vecs[i][sv] = ns;
vecs[i][tv] = nt;
}
for ( i = 0 ; i < 2 ; i++ )
for ( j = 0 ; j < 3 ; j++ )
tx.vecs[i][j] = vecs[i][j] / bt->scale[i];
tx.vecs[0][3] = bt->shift[0] + shift[0];
tx.vecs[1][3] = bt->shift[1] + shift[1];
tx.flags = bt->flags;
tx.value = bt->value;
//
// find the texinfo
//
tc = texinfo;
for ( i = 0 ; i < numtexinfo ; i++, tc++ )
{
if ( tc->flags != tx.flags ) {
continue;
}
if ( tc->value != tx.value ) {
continue;
}
for ( j = 0 ; j < 2 ; j++ )
{
if ( strcmp( tc->texture, tx.texture ) ) {
goto skip;
}
for ( k = 0 ; k < 4 ; k++ )
{
if ( tc->vecs[j][k] != tx.vecs[j][k] ) {
goto skip;
}
}
}
return i;
skip:;
}
*tc = tx;
numtexinfo++;
// load the next animation
mt = FindMiptex( bt->name );
if ( textureref[mt].animname[0] ) {
anim = *bt;
strcpy( anim.name, textureref[mt].animname );
tc->nexttexinfo = TexinfoForBrushTexture( plane, &anim, origin );
} else {
tc->nexttexinfo = -1;
}
return i;
} //end of the function TexinfoForBrushTexture

298
src/bspc/tree.c Normal file
View File

@@ -0,0 +1,298 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: textures.c
// Function: textures
// Programmer: Mr Elusive (MrElusive@worldentity.com)
// Last update: 1999-08-10
// Tab Size: 3
//===========================================================================
#include "qbsp.h"
extern int c_nodes;
int c_pruned;
int freedtreemem = 0;
void RemovePortalFromNode( portal_t *portal, node_t *l );
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
node_t *NodeForPoint( node_t *node, vec3_t origin ) {
plane_t *plane;
vec_t d;
while ( node->planenum != PLANENUM_LEAF )
{
plane = &mapplanes[node->planenum];
d = DotProduct( origin, plane->normal ) - plane->dist;
if ( d >= 0 ) {
node = node->children[0];
} else {
node = node->children[1];
}
}
return node;
} //end of the function NodeForPoint
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Tree_FreePortals_r( node_t *node ) {
portal_t *p, *nextp;
int s;
// free children
if ( node->planenum != PLANENUM_LEAF ) {
Tree_FreePortals_r( node->children[0] );
Tree_FreePortals_r( node->children[1] );
}
// free portals
for ( p = node->portals; p; p = nextp )
{
s = ( p->nodes[1] == node );
nextp = p->next[s];
RemovePortalFromNode( p, p->nodes[!s] );
#ifdef ME
if ( p->winding ) {
freedtreemem += MemorySize( p->winding );
}
freedtreemem += MemorySize( p );
#endif //ME
FreePortal( p );
}
node->portals = NULL;
} //end of the function Tree_FreePortals_r
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Tree_Free_r( node_t *node ) {
// face_t *f, *nextf;
bspbrush_t *brush, *nextbrush;
//free children
if ( node->planenum != PLANENUM_LEAF ) {
Tree_Free_r( node->children[0] );
Tree_Free_r( node->children[1] );
} //end if
//free bspbrushes
// FreeBrushList (node->brushlist);
for ( brush = node->brushlist; brush; brush = nextbrush )
{
nextbrush = brush->next;
#ifdef ME
freedtreemem += MemorySize( brush );
#endif //ME
FreeBrush( brush );
} //end for
node->brushlist = NULL;
/*
NOTE: only used when creating Q2 bsp
// free faces
for (f = node->faces; f; f = nextf)
{
nextf = f->next;
#ifdef ME
if (f->w) freedtreemem += MemorySize(f->w);
freedtreemem += sizeof(face_t);
#endif //ME
FreeFace(f);
} //end for
*/
// free the node
if ( node->volume ) {
#ifdef ME
freedtreemem += MemorySize( node->volume );
#endif //ME
FreeBrush( node->volume );
} //end if
if ( numthreads == 1 ) {
c_nodes--;
}
#ifdef ME
freedtreemem += MemorySize( node );
#endif //ME
FreeMemory( node );
} //end of the function Tree_Free_r
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Tree_Free( tree_t *tree ) {
//if no tree just return
if ( !tree ) {
return;
}
//
freedtreemem = 0;
//
Tree_FreePortals_r( tree->headnode );
Tree_Free_r( tree->headnode );
#ifdef ME
freedtreemem += MemorySize( tree );
#endif //ME
FreeMemory( tree );
#ifdef ME
Log_Print( "freed " );
PrintMemorySize( freedtreemem );
Log_Print( " of tree memory\n" );
#endif //ME
} //end of the function Tree_Free
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
tree_t *Tree_Alloc( void ) {
tree_t *tree;
tree = GetMemory( sizeof( *tree ) );
memset( tree, 0, sizeof( *tree ) );
ClearBounds( tree->mins, tree->maxs );
return tree;
} //end of the function Tree_Alloc
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Tree_Print_r( node_t *node, int depth ) {
int i;
plane_t *plane;
bspbrush_t *bb;
for ( i = 0 ; i < depth ; i++ )
printf( " " );
if ( node->planenum == PLANENUM_LEAF ) {
if ( !node->brushlist ) {
printf( "NULL\n" );
} else
{
for ( bb = node->brushlist ; bb ; bb = bb->next )
printf( "%i ", bb->original->brushnum );
printf( "\n" );
}
return;
}
plane = &mapplanes[node->planenum];
printf( "#%i (%5.2f %5.2f %5.2f):%5.2f\n", node->planenum,
plane->normal[0], plane->normal[1], plane->normal[2],
plane->dist );
Tree_Print_r( node->children[0], depth + 1 );
Tree_Print_r( node->children[1], depth + 1 );
} //end of the function Tree_Print_r
//===========================================================================
// NODES THAT DON'T SEPERATE DIFFERENT CONTENTS CAN BE PRUNED
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Tree_PruneNodes_r( node_t *node ) {
bspbrush_t *b, *next;
if ( node->planenum == PLANENUM_LEAF ) {
return;
}
Tree_PruneNodes_r( node->children[0] );
Tree_PruneNodes_r( node->children[1] );
if ( create_aas ) {
if ( ( node->children[0]->contents & CONTENTS_LADDER ) ||
( node->children[1]->contents & CONTENTS_LADDER ) ) {
return;
}
}
if ( ( node->children[0]->contents & CONTENTS_SOLID )
&& ( node->children[1]->contents & CONTENTS_SOLID ) ) {
if ( node->faces ) {
Error( "node->faces seperating CONTENTS_SOLID" );
}
if ( node->children[0]->faces || node->children[1]->faces ) {
Error( "!node->faces with children" );
}
// FIXME: free stuff
node->planenum = PLANENUM_LEAF;
node->contents = CONTENTS_SOLID;
node->detail_seperator = false;
if ( node->brushlist ) {
Error( "PruneNodes: node->brushlist" );
}
// combine brush lists
node->brushlist = node->children[1]->brushlist;
for ( b = node->children[0]->brushlist; b; b = next )
{
next = b->next;
b->next = node->brushlist;
node->brushlist = b;
} //end for
//free the child nodes
FreeMemory( node->children[0] );
FreeMemory( node->children[1] );
//two nodes are cut away
c_pruned += 2;
} //end if
} //end of the function Tree_PruneNodes_r
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Tree_PruneNodes( node_t *node ) {
Log_Print( "------- Prune Nodes --------\n" );
c_pruned = 0;
Tree_PruneNodes_r( node );
Log_Print( "%5i pruned nodes\n", c_pruned );
} //end of the function Tree_PruneNodes

632
src/bspc/writebsp.c Normal file
View File

@@ -0,0 +1,632 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
// NO LONGER IN PROJECT
#if 0
#include "qbsp.h"
int c_nofaces;
int c_facenodes;
extern int numplanes;
extern int numfaces;
extern int numleaffaces;
extern int numleafs;
extern int numleafbrushes;
extern int numsurfedges;
extern int numnodes;
extern int nummodels;
extern int numbrushsides;
extern int numbrushes;
extern int numvertexes;
extern int numedges;
extern dplane_t dplanes[MAX_MAP_PLANES];
extern dleaf_t dleafs[MAX_MAP_LEAFS];
extern dleaf_t dleafs[MAX_MAP_LEAFS];
extern dface_t dfaces[MAX_MAP_FACES];
extern unsigned short dleafbrushes[MAX_MAP_LEAFBRUSHES];
extern unsigned short dleaffaces[MAX_MAP_LEAFFACES];
extern int dsurfedges[MAX_MAP_SURFEDGES];
extern dnode_t dnodes[MAX_MAP_NODES];
extern dmodel_t dmodels[MAX_MAP_MODELS];
extern dbrush_t dbrushes[MAX_MAP_BRUSHES];
extern dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES];
/*
=========================================================
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;
//ME: this causes a crash??
// 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++;
if ( numplanes >= MAX_MAP_PLANES ) {
Error( "MAX_MAP_PLANES" );
}
}
}
//========================================================
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( 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" );
}
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( node->mins, n->mins );
VectorCopy( 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;
qprintf( "--- WriteBSP ---\n" );
oldfaces = numfaces;
dmodels[nummodels].headnode = EmitDrawNode_r( headnode );
// EmitAreaPortals (headnode);
qprintf( "%5i nodes with faces\n", c_facenodes );
qprintf( "%5i nodes without faces\n", c_nofaces );
qprintf( "%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;
}
#ifdef ME
//for collision detection, bounding boxes are axial :)
//brushes are convex so just add dot or line touching planes on the sides of
//the brush parallell to the axis planes
#endif
// 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] = 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 ) {
#if 0
char path[1024];
int len;
byte *buf;
#endif
EmitBrushes();
EmitPlanes();
Q2_UnparseEntities();
// load the pop
#if 0
sprintf( path, "%s/pics/pop.lmp", gamedir );
len = LoadFile( path, &buf );
memcpy( dpop, buf, sizeof( dpop ) );
FreeMemory( buf );
#endif
}
/*
==================
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++;
}
#endif