📄 tr_bsp.c
字号:
else
out->children[j] = s_worldData.nodes + numNodes + (-1 - p);
}
}
// load leafs
inLeaf = (void *)(fileBase + leafLump->fileofs);
for ( i=0 ; i<numLeafs ; i++, inLeaf++, out++)
{
for (j=0 ; j<3 ; j++)
{
out->mins[j] = LittleLong (inLeaf->mins[j]);
out->maxs[j] = LittleLong (inLeaf->maxs[j]);
}
out->cluster = LittleLong(inLeaf->cluster);
out->area = LittleLong(inLeaf->area);
if ( out->cluster >= s_worldData.numClusters ) {
s_worldData.numClusters = out->cluster + 1;
}
out->firstmarksurface = s_worldData.marksurfaces +
LittleLong(inLeaf->firstLeafSurface);
out->nummarksurfaces = LittleLong(inLeaf->numLeafSurfaces);
}
// chain decendants
R_SetParent (s_worldData.nodes, NULL);
}
//=============================================================================
/*
=================
R_LoadShaders
=================
*/
static void R_LoadShaders( lump_t *l ) {
int i, count;
dshader_t *in, *out;
in = (void *)(fileBase + l->fileofs);
if (l->filelen % sizeof(*in))
ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
count = l->filelen / sizeof(*in);
out = ri.Hunk_Alloc ( count*sizeof(*out), h_low );
s_worldData.shaders = out;
s_worldData.numShaders = count;
Com_Memcpy( out, in, count*sizeof(*out) );
for ( i=0 ; i<count ; i++ ) {
out[i].surfaceFlags = LittleLong( out[i].surfaceFlags );
out[i].contentFlags = LittleLong( out[i].contentFlags );
}
}
/*
=================
R_LoadMarksurfaces
=================
*/
static void R_LoadMarksurfaces (lump_t *l)
{
int i, j, count;
int *in;
msurface_t **out;
in = (void *)(fileBase + l->fileofs);
if (l->filelen % sizeof(*in))
ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
count = l->filelen / sizeof(*in);
out = ri.Hunk_Alloc ( count*sizeof(*out), h_low);
s_worldData.marksurfaces = out;
s_worldData.nummarksurfaces = count;
for ( i=0 ; i<count ; i++)
{
j = LittleLong(in[i]);
out[i] = s_worldData.surfaces + j;
}
}
/*
=================
R_LoadPlanes
=================
*/
static void R_LoadPlanes( lump_t *l ) {
int i, j;
cplane_t *out;
dplane_t *in;
int count;
int bits;
in = (void *)(fileBase + l->fileofs);
if (l->filelen % sizeof(*in))
ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
count = l->filelen / sizeof(*in);
out = ri.Hunk_Alloc ( count*2*sizeof(*out), h_low);
s_worldData.planes = out;
s_worldData.numplanes = count;
for ( i=0 ; i<count ; i++, in++, out++) {
bits = 0;
for (j=0 ; j<3 ; j++) {
out->normal[j] = LittleFloat (in->normal[j]);
if (out->normal[j] < 0) {
bits |= 1<<j;
}
}
out->dist = LittleFloat (in->dist);
out->type = PlaneTypeForNormal( out->normal );
out->signbits = bits;
}
}
/*
=================
R_LoadFogs
=================
*/
static void R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump ) {
int i;
fog_t *out;
dfog_t *fogs;
dbrush_t *brushes, *brush;
dbrushside_t *sides;
int count, brushesCount, sidesCount;
int sideNum;
int planeNum;
shader_t *shader;
float d;
int firstSide;
fogs = (void *)(fileBase + l->fileofs);
if (l->filelen % sizeof(*fogs)) {
ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
}
count = l->filelen / sizeof(*fogs);
// create fog strucutres for them
s_worldData.numfogs = count + 1;
s_worldData.fogs = ri.Hunk_Alloc ( s_worldData.numfogs*sizeof(*out), h_low);
out = s_worldData.fogs + 1;
if ( !count ) {
return;
}
brushes = (void *)(fileBase + brushesLump->fileofs);
if (brushesLump->filelen % sizeof(*brushes)) {
ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
}
brushesCount = brushesLump->filelen / sizeof(*brushes);
sides = (void *)(fileBase + sidesLump->fileofs);
if (sidesLump->filelen % sizeof(*sides)) {
ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
}
sidesCount = sidesLump->filelen / sizeof(*sides);
for ( i=0 ; i<count ; i++, fogs++) {
out->originalBrushNumber = LittleLong( fogs->brushNum );
if ( (unsigned)out->originalBrushNumber >= brushesCount ) {
ri.Error( ERR_DROP, "fog brushNumber out of range" );
}
brush = brushes + out->originalBrushNumber;
firstSide = LittleLong( brush->firstSide );
if ( (unsigned)firstSide > sidesCount - 6 ) {
ri.Error( ERR_DROP, "fog brush sideNumber out of range" );
}
// brushes are always sorted with the axial sides first
sideNum = firstSide + 0;
planeNum = LittleLong( sides[ sideNum ].planeNum );
out->bounds[0][0] = -s_worldData.planes[ planeNum ].dist;
sideNum = firstSide + 1;
planeNum = LittleLong( sides[ sideNum ].planeNum );
out->bounds[1][0] = s_worldData.planes[ planeNum ].dist;
sideNum = firstSide + 2;
planeNum = LittleLong( sides[ sideNum ].planeNum );
out->bounds[0][1] = -s_worldData.planes[ planeNum ].dist;
sideNum = firstSide + 3;
planeNum = LittleLong( sides[ sideNum ].planeNum );
out->bounds[1][1] = s_worldData.planes[ planeNum ].dist;
sideNum = firstSide + 4;
planeNum = LittleLong( sides[ sideNum ].planeNum );
out->bounds[0][2] = -s_worldData.planes[ planeNum ].dist;
sideNum = firstSide + 5;
planeNum = LittleLong( sides[ sideNum ].planeNum );
out->bounds[1][2] = s_worldData.planes[ planeNum ].dist;
// get information from the shader for fog parameters
shader = R_FindShader( fogs->shader, LIGHTMAP_NONE, qtrue );
out->parms = shader->fogParms;
out->colorInt = ColorBytes4 ( shader->fogParms.color[0] * tr.identityLight,
shader->fogParms.color[1] * tr.identityLight,
shader->fogParms.color[2] * tr.identityLight, 1.0 );
d = shader->fogParms.depthForOpaque < 1 ? 1 : shader->fogParms.depthForOpaque;
out->tcScale = 1.0f / ( d * 8 );
// set the gradient vector
sideNum = LittleLong( fogs->visibleSide );
if ( sideNum == -1 ) {
out->hasSurface = qfalse;
} else {
out->hasSurface = qtrue;
planeNum = LittleLong( sides[ firstSide + sideNum ].planeNum );
VectorSubtract( vec3_origin, s_worldData.planes[ planeNum ].normal, out->surface );
out->surface[3] = -s_worldData.planes[ planeNum ].dist;
}
out++;
}
}
/*
================
R_LoadLightGrid
================
*/
void R_LoadLightGrid( lump_t *l ) {
int i;
vec3_t maxs;
int numGridPoints;
world_t *w;
float *wMins, *wMaxs;
w = &s_worldData;
w->lightGridInverseSize[0] = 1.0f / w->lightGridSize[0];
w->lightGridInverseSize[1] = 1.0f / w->lightGridSize[1];
w->lightGridInverseSize[2] = 1.0f / w->lightGridSize[2];
wMins = w->bmodels[0].bounds[0];
wMaxs = w->bmodels[0].bounds[1];
for ( i = 0 ; i < 3 ; i++ ) {
w->lightGridOrigin[i] = w->lightGridSize[i] * ceil( wMins[i] / w->lightGridSize[i] );
maxs[i] = w->lightGridSize[i] * floor( wMaxs[i] / w->lightGridSize[i] );
w->lightGridBounds[i] = (maxs[i] - w->lightGridOrigin[i])/w->lightGridSize[i] + 1;
}
numGridPoints = w->lightGridBounds[0] * w->lightGridBounds[1] * w->lightGridBounds[2];
if ( l->filelen != numGridPoints * 8 ) {
ri.Printf( PRINT_WARNING, "WARNING: light grid mismatch\n" );
w->lightGridData = NULL;
return;
}
w->lightGridData = ri.Hunk_Alloc( l->filelen, h_low );
Com_Memcpy( w->lightGridData, (void *)(fileBase + l->fileofs), l->filelen );
// deal with overbright bits
for ( i = 0 ; i < numGridPoints ; i++ ) {
R_ColorShiftLightingBytes( &w->lightGridData[i*8], &w->lightGridData[i*8] );
R_ColorShiftLightingBytes( &w->lightGridData[i*8+3], &w->lightGridData[i*8+3] );
}
}
/*
================
R_LoadEntities
================
*/
void R_LoadEntities( lump_t *l ) {
char *p, *token, *s;
char keyname[MAX_TOKEN_CHARS];
char value[MAX_TOKEN_CHARS];
world_t *w;
w = &s_worldData;
w->lightGridSize[0] = 64;
w->lightGridSize[1] = 64;
w->lightGridSize[2] = 128;
p = (char *)(fileBase + l->fileofs);
// store for reference by the cgame
w->entityString = ri.Hunk_Alloc( l->filelen + 1, h_low );
strcpy( w->entityString, p );
w->entityParsePoint = w->entityString;
token = COM_ParseExt( &p, qtrue );
if (!*token || *token != '{') {
return;
}
// only parse the world spawn
while ( 1 ) {
// parse key
token = COM_ParseExt( &p, qtrue );
if ( !*token || *token == '}' ) {
break;
}
Q_strncpyz(keyname, token, sizeof(keyname));
// parse value
token = COM_ParseExt( &p, qtrue );
if ( !*token || *token == '}' ) {
break;
}
Q_strncpyz(value, token, sizeof(value));
// check for remapping of shaders for vertex lighting
s = "vertexremapshader";
if (!Q_strncmp(keyname, s, strlen(s)) ) {
s = strchr(value, ';');
if (!s) {
ri.Printf( PRINT_WARNING, "WARNING: no semi colon in vertexshaderremap '%s'\n", value );
break;
}
*s++ = 0;
if (r_vertexLight->integer) {
R_RemapShader(value, s, "0");
}
continue;
}
// check for remapping of shaders
s = "remapshader";
if (!Q_strncmp(keyname, s, strlen(s)) ) {
s = strchr(value, ';');
if (!s) {
ri.Printf( PRINT_WARNING, "WARNING: no semi colon in shaderremap '%s'\n", value );
break;
}
*s++ = 0;
R_RemapShader(value, s, "0");
continue;
}
// check for a different grid size
if (!Q_stricmp(keyname, "gridsize")) {
sscanf(value, "%f %f %f", &w->lightGridSize[0], &w->lightGridSize[1], &w->lightGridSize[2] );
continue;
}
}
}
/*
=================
R_GetEntityToken
=================
*/
qboolean R_GetEntityToken( char *buffer, int size ) {
const char *s;
s = COM_Parse( &s_worldData.entityParsePoint );
Q_strncpyz( buffer, s, size );
if ( !s_worldData.entityParsePoint || !s[0] ) {
s_worldData.entityParsePoint = s_worldData.entityString;
return qfalse;
} else {
return qtrue;
}
}
/*
=================
RE_LoadWorldMap
Called directly from cgame
=================
*/
void RE_LoadWorldMap( const char *name ) {
int i;
dheader_t *header;
byte *buffer;
byte *startMarker;
if ( tr.worldMapLoaded ) {
ri.Error( ERR_DROP, "ERROR: attempted to redundantly load world map\n" );
}
// set default sun direction to be used if it isn't
// overridden by a shader
tr.sunDirection[0] = 0.45f;
tr.sunDirection[1] = 0.3f;
tr.sunDirection[2] = 0.9f;
VectorNormalize( tr.sunDirection );
tr.worldMapLoaded = qtrue;
// load it
ri.FS_ReadFile( name, (void **)&buffer );
if ( !buffer ) {
ri.Error (ERR_DROP, "RE_LoadWorldMap: %s not found", name);
}
// clear tr.world so if the level fails to load, the next
// try will not look at the partially loaded version
tr.world = NULL;
Com_Memset( &s_worldData, 0, sizeof( s_worldData ) );
Q_strncpyz( s_worldData.name, name, sizeof( s_worldData.name ) );
Q_strncpyz( s_worldData.baseName, COM_SkipPath( s_worldData.name ), sizeof( s_worldData.name ) );
COM_StripExtension( s_worldData.baseName, s_worldData.baseName );
startMarker = ri.Hunk_Alloc(0, h_low);
c_gridVerts = 0;
header = (dheader_t *)buffer;
fileBase = (byte *)header;
i = LittleLong (header->version);
if ( i != BSP_VERSION ) {
ri.Error (ERR_DROP, "RE_LoadWorldMap: %s has wrong version number (%i should be %i)",
name, i, BSP_VERSION);
}
// swap all the lumps
for (i=0 ; i<sizeof(dheader_t)/4 ; i++) {
((int *)header)[i] = LittleLong ( ((int *)header)[i]);
}
// load into heap
R_LoadShaders( &header->lumps[LUMP_SHADERS] );
R_LoadLightmaps( &header->lumps[LUMP_LIGHTMAPS] );
R_LoadPlanes (&header->lumps[LUMP_PLANES]);
R_LoadFogs( &header->lumps[LUMP_FOGS], &header->lumps[LUMP_BRUSHES], &header->lumps[LUMP_BRUSHSIDES] );
R_LoadSurfaces( &header->lumps[LUMP_SURFACES], &header->lumps[LUMP_DRAWVERTS], &header->lumps[LUMP_DRAWINDEXES] );
R_LoadMarksurfaces (&header->lumps[LUMP_LEAFSURFACES]);
R_LoadNodesAndLeafs (&header->lumps[LUMP_NODES], &header->lumps[LUMP_LEAFS]);
R_LoadSubmodels (&header->lumps[LUMP_MODELS]);
R_LoadVisibility( &header->lumps[LUMP_VISIBILITY] );
R_LoadEntities( &header->lumps[LUMP_ENTITIES] );
R_LoadLightGrid( &header->lumps[LUMP_LIGHTGRID] );
s_worldData.dataSize = (byte *)ri.Hunk_Alloc(0, h_low) - startMarker;
// only set tr.world now that we know the entire level has loaded properly
tr.world = &s_worldData;
ri.FS_FreeFile( buffer );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -