📄 cmodel.c
字号:
/*
Copyright (C) 1997-2001 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// cmodel.c -- model loading
#include "qcommon.h"
typedef struct
{
cplane_t *plane;
int children[2]; // negative numbers are leafs
} cnode_t;
typedef struct
{
cplane_t *plane;
mapsurface_t *surface;
} cbrushside_t;
typedef struct
{
int contents;
int cluster;
int area;
unsigned short firstleafbrush;
unsigned short numleafbrushes;
} cleaf_t;
typedef struct
{
int contents;
int numsides;
int firstbrushside;
int checkcount; // to avoid repeated testings
} cbrush_t;
typedef struct
{
int numareaportals;
int firstareaportal;
int floodnum; // if two areas have equal floodnums, they are connected
int floodvalid;
} carea_t;
int checkcount;
char map_name[MAX_QPATH];
int numbrushsides;
cbrushside_t map_brushsides[MAX_MAP_BRUSHSIDES];
int numtexinfo;
mapsurface_t map_surfaces[MAX_MAP_TEXINFO];
int numplanes;
cplane_t map_planes[MAX_MAP_PLANES+6]; // extra for box hull
int numnodes;
cnode_t map_nodes[MAX_MAP_NODES+6]; // extra for box hull
int numleafs = 1; // allow leaf funcs to be called without a map
cleaf_t map_leafs[MAX_MAP_LEAFS];
int emptyleaf, solidleaf;
int numleafbrushes;
unsigned short map_leafbrushes[MAX_MAP_LEAFBRUSHES];
int numcmodels;
cmodel_t map_cmodels[MAX_MAP_MODELS];
int numbrushes;
cbrush_t map_brushes[MAX_MAP_BRUSHES];
int numvisibility;
byte map_visibility[MAX_MAP_VISIBILITY];
dvis_t *map_vis = (dvis_t *)map_visibility;
int numentitychars;
char map_entitystring[MAX_MAP_ENTSTRING];
int numareas = 1;
carea_t map_areas[MAX_MAP_AREAS];
int numareaportals;
dareaportal_t map_areaportals[MAX_MAP_AREAPORTALS];
int numclusters = 1;
mapsurface_t nullsurface;
int floodvalid;
qboolean portalopen[MAX_MAP_AREAPORTALS];
cvar_t *map_noareas;
void CM_InitBoxHull (void);
void FloodAreaConnections (void);
int c_pointcontents;
int c_traces, c_brush_traces;
/*
===============================================================================
MAP LOADING
===============================================================================
*/
byte *cmod_base;
/*
=================
CMod_LoadSubmodels
=================
*/
void CMod_LoadSubmodels (lump_t *l)
{
dmodel_t *in;
cmodel_t *out;
int i, j, count;
in = (void *)(cmod_base + l->fileofs);
if (l->filelen % sizeof(*in))
Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
count = l->filelen / sizeof(*in);
if (count < 1)
Com_Error (ERR_DROP, "Map with no models");
if (count > MAX_MAP_MODELS)
Com_Error (ERR_DROP, "Map has too many models");
numcmodels = count;
for ( i=0 ; i<count ; i++, in++, out++)
{
out = &map_cmodels[i];
for (j=0 ; j<3 ; j++)
{ // spread the mins / maxs by a pixel
out->mins[j] = LittleFloat (in->mins[j]) - 1;
out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
out->origin[j] = LittleFloat (in->origin[j]);
}
out->headnode = LittleLong (in->headnode);
}
}
/*
=================
CMod_LoadSurfaces
=================
*/
void CMod_LoadSurfaces (lump_t *l)
{
texinfo_t *in;
mapsurface_t *out;
int i, count;
in = (void *)(cmod_base + l->fileofs);
if (l->filelen % sizeof(*in))
Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
count = l->filelen / sizeof(*in);
if (count < 1)
Com_Error (ERR_DROP, "Map with no surfaces");
if (count > MAX_MAP_TEXINFO)
Com_Error (ERR_DROP, "Map has too many surfaces");
numtexinfo = count;
out = map_surfaces;
for ( i=0 ; i<count ; i++, in++, out++)
{
strncpy (out->c.name, in->texture, sizeof(out->c.name)-1);
strncpy (out->rname, in->texture, sizeof(out->rname)-1);
out->c.flags = LittleLong (in->flags);
out->c.value = LittleLong (in->value);
}
}
/*
=================
CMod_LoadNodes
=================
*/
void CMod_LoadNodes (lump_t *l)
{
dnode_t *in;
int child;
cnode_t *out;
int i, j, count;
in = (void *)(cmod_base + l->fileofs);
if (l->filelen % sizeof(*in))
Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
count = l->filelen / sizeof(*in);
if (count < 1)
Com_Error (ERR_DROP, "Map has no nodes");
if (count > MAX_MAP_NODES)
Com_Error (ERR_DROP, "Map has too many nodes");
out = map_nodes;
numnodes = count;
for (i=0 ; i<count ; i++, out++, in++)
{
out->plane = map_planes + LittleLong(in->planenum);
for (j=0 ; j<2 ; j++)
{
child = LittleLong (in->children[j]);
out->children[j] = child;
}
}
}
/*
=================
CMod_LoadBrushes
=================
*/
void CMod_LoadBrushes (lump_t *l)
{
dbrush_t *in;
cbrush_t *out;
int i, count;
in = (void *)(cmod_base + l->fileofs);
if (l->filelen % sizeof(*in))
Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
count = l->filelen / sizeof(*in);
if (count > MAX_MAP_BRUSHES)
Com_Error (ERR_DROP, "Map has too many brushes");
out = map_brushes;
numbrushes = count;
for (i=0 ; i<count ; i++, out++, in++)
{
out->firstbrushside = LittleLong(in->firstside);
out->numsides = LittleLong(in->numsides);
out->contents = LittleLong(in->contents);
}
}
/*
=================
CMod_LoadLeafs
=================
*/
void CMod_LoadLeafs (lump_t *l)
{
int i;
cleaf_t *out;
dleaf_t *in;
int count;
in = (void *)(cmod_base + l->fileofs);
if (l->filelen % sizeof(*in))
Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
count = l->filelen / sizeof(*in);
if (count < 1)
Com_Error (ERR_DROP, "Map with no leafs");
// need to save space for box planes
if (count > MAX_MAP_PLANES)
Com_Error (ERR_DROP, "Map has too many planes");
out = map_leafs;
numleafs = count;
numclusters = 0;
for ( i=0 ; i<count ; i++, in++, out++)
{
out->contents = LittleLong (in->contents);
out->cluster = LittleShort (in->cluster);
out->area = LittleShort (in->area);
out->firstleafbrush = LittleShort (in->firstleafbrush);
out->numleafbrushes = LittleShort (in->numleafbrushes);
if (out->cluster >= numclusters)
numclusters = out->cluster + 1;
}
if (map_leafs[0].contents != CONTENTS_SOLID)
Com_Error (ERR_DROP, "Map leaf 0 is not CONTENTS_SOLID");
solidleaf = 0;
emptyleaf = -1;
for (i=1 ; i<numleafs ; i++)
{
if (!map_leafs[i].contents)
{
emptyleaf = i;
break;
}
}
if (emptyleaf == -1)
Com_Error (ERR_DROP, "Map does not have an empty leaf");
}
/*
=================
CMod_LoadPlanes
=================
*/
void CMod_LoadPlanes (lump_t *l)
{
int i, j;
cplane_t *out;
dplane_t *in;
int count;
int bits;
in = (void *)(cmod_base + l->fileofs);
if (l->filelen % sizeof(*in))
Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
count = l->filelen / sizeof(*in);
if (count < 1)
Com_Error (ERR_DROP, "Map with no planes");
// need to save space for box planes
if (count > MAX_MAP_PLANES)
Com_Error (ERR_DROP, "Map has too many planes");
out = map_planes;
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 = LittleLong (in->type);
out->signbits = bits;
}
}
/*
=================
CMod_LoadLeafBrushes
=================
*/
void CMod_LoadLeafBrushes (lump_t *l)
{
int i;
unsigned short *out;
unsigned short *in;
int count;
in = (void *)(cmod_base + l->fileofs);
if (l->filelen % sizeof(*in))
Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
count = l->filelen / sizeof(*in);
if (count < 1)
Com_Error (ERR_DROP, "Map with no planes");
// need to save space for box planes
if (count > MAX_MAP_LEAFBRUSHES)
Com_Error (ERR_DROP, "Map has too many leafbrushes");
out = map_leafbrushes;
numleafbrushes = count;
for ( i=0 ; i<count ; i++, in++, out++)
*out = LittleShort (*in);
}
/*
=================
CMod_LoadBrushSides
=================
*/
void CMod_LoadBrushSides (lump_t *l)
{
int i, j;
cbrushside_t *out;
dbrushside_t *in;
int count;
int num;
in = (void *)(cmod_base + l->fileofs);
if (l->filelen % sizeof(*in))
Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
count = l->filelen / sizeof(*in);
// need to save space for box planes
if (count > MAX_MAP_BRUSHSIDES)
Com_Error (ERR_DROP, "Map has too many planes");
out = map_brushsides;
numbrushsides = count;
for ( i=0 ; i<count ; i++, in++, out++)
{
num = LittleShort (in->planenum);
out->plane = &map_planes[num];
j = LittleShort (in->texinfo);
if (j >= numtexinfo)
Com_Error (ERR_DROP, "Bad brushside texinfo");
out->surface = &map_surfaces[j];
}
}
/*
=================
CMod_LoadAreas
=================
*/
void CMod_LoadAreas (lump_t *l)
{
int i;
carea_t *out;
darea_t *in;
int count;
in = (void *)(cmod_base + l->fileofs);
if (l->filelen % sizeof(*in))
Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
count = l->filelen / sizeof(*in);
if (count > MAX_MAP_AREAS)
Com_Error (ERR_DROP, "Map has too many areas");
out = map_areas;
numareas = count;
for ( i=0 ; i<count ; i++, in++, out++)
{
out->numareaportals = LittleLong (in->numareaportals);
out->firstareaportal = LittleLong (in->firstareaportal);
out->floodvalid = 0;
out->floodnum = 0;
}
}
/*
=================
CMod_LoadAreaPortals
=================
*/
void CMod_LoadAreaPortals (lump_t *l)
{
int i;
dareaportal_t *out;
dareaportal_t *in;
int count;
in = (void *)(cmod_base + l->fileofs);
if (l->filelen % sizeof(*in))
Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
count = l->filelen / sizeof(*in);
if (count > MAX_MAP_AREAS)
Com_Error (ERR_DROP, "Map has too many areas");
out = map_areaportals;
numareaportals = count;
for ( i=0 ; i<count ; i++, in++, out++)
{
out->portalnum = LittleLong (in->portalnum);
out->otherarea = LittleLong (in->otherarea);
}
}
/*
=================
CMod_LoadVisibility
=================
*/
void CMod_LoadVisibility (lump_t *l)
{
int i;
numvisibility = l->filelen;
if (l->filelen > MAX_MAP_VISIBILITY)
Com_Error (ERR_DROP, "Map has too large visibility lump");
memcpy (map_visibility, cmod_base + l->fileofs, l->filelen);
map_vis->numclusters = LittleLong (map_vis->numclusters);
for (i=0 ; i<map_vis->numclusters ; i++)
{
map_vis->bitofs[i][0] = LittleLong (map_vis->bitofs[i][0]);
map_vis->bitofs[i][1] = LittleLong (map_vis->bitofs[i][1]);
}
}
/*
=================
CMod_LoadEntityString
=================
*/
void CMod_LoadEntityString (lump_t *l)
{
numentitychars = l->filelen;
if (l->filelen > MAX_MAP_ENTSTRING)
Com_Error (ERR_DROP, "Map has too large entity lump");
memcpy (map_entitystring, cmod_base + l->fileofs, l->filelen);
}
/*
==================
CM_LoadMap
Loads in the map and all submodels
==================
*/
cmodel_t *CM_LoadMap (char *name, qboolean clientload, unsigned *checksum)
{
unsigned *buf;
int i;
dheader_t header;
int length;
static unsigned last_checksum;
map_noareas = Cvar_Get ("map_noareas", "0", 0);
if ( !strcmp (map_name, name) && (clientload || !Cvar_VariableValue ("flushmap")) )
{
*checksum = last_checksum;
if (!clientload)
{
memset (portalopen, 0, sizeof(portalopen));
FloodAreaConnections ();
}
return &map_cmodels[0]; // still have the right version
}
// free old stuff
numplanes = 0;
numnodes = 0;
numleafs = 0;
numcmodels = 0;
numvisibility = 0;
numentitychars = 0;
map_entitystring[0] = 0;
map_name[0] = 0;
if (!name || !name[0])
{
numleafs = 1;
numclusters = 1;
numareas = 1;
*checksum = 0;
return &map_cmodels[0]; // cinematic servers won't have anything at all
}
//
// load the file
//
length = FS_LoadFile (name, (void **)&buf);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -