cmodel.cpp

来自「hl2 source code. Do not use it illegal.」· C++ 代码 · 共 1,817 行 · 第 1/3 页

CPP
1,817
字号
// cmodel.cpp -- model loading
#include "qfiles.h"
#include "cmdlib.h"
#include "mathlib.h"
#include "cmodel_engine.h"
#include "engine.h"

typedef struct
{
	cplane_t	*plane;
	int			children[2];		// negative numbers are leafs
} cnode_t;

typedef struct
{
	cplane_t	*plane;
	csurface_t	*surface;
} cbrushside_t;

typedef struct cleaf_s
{
	int			contents;
	int			cluster;
	int			area;
	unsigned short	firstleafbrush;
	unsigned short	numleafbrushes;
} cleaf_t;

typedef struct cbrush_s
{
	int			contents;
	int			numsides;
	int			firstbrushside;
	int			checkcount;		// to avoid repeated testings
} cbrush_t;

typedef struct carea_s
{
	int		numareaportals;
	int		firstareaportal;
	int		floodnum;			// if two areas have equal floodnums, they are connected
	int		floodvalid;
} carea_t;

static int			checkcount;

static char			map_name[MAX_QPATH];

static int			numbrushsides;
static cbrushside_t map_brushsides[MAX_MAP_BRUSHSIDES];

static int			numtexinfo;
static csurface_t	map_surfaces[MAX_MAP_TEXINFO];

static int			numplanes;
static cplane_t		map_planes[MAX_MAP_PLANES+6];		// extra for box hull

static int			numnodes;
static cnode_t		map_nodes[MAX_MAP_NODES+6];		// extra for box hull

static int			numleafs = 1;	// allow leaf funcs to be called without a map
static cleaf_t		map_leafs[MAX_MAP_LEAFS];
static int			emptyleaf, solidleaf;

static int			numleafbrushes;
static unsigned short	map_leafbrushes[MAX_MAP_LEAFBRUSHES];

static int			numcmodels;
static cmodel_t		map_cmodels[MAX_MAP_MODELS];

static int			numbrushes;
static cbrush_t		map_brushes[MAX_MAP_BRUSHES];

static int			numvisibility;
static byte			map_visibility[MAX_MAP_VISIBILITY];
static dvis_t		*map_vis = (dvis_t *)map_visibility;

static int			numentitychars;
static char			map_entitystring[MAX_MAP_ENTSTRING];

static int			numareas = 1;
static carea_t		map_areas[MAX_MAP_AREAS];

static int			numareaportals;
static dareaportal_t map_areaportals[MAX_MAP_AREAPORTALS];

static int			numclusters = 1;

static csurface_t	nullsurface;

static int			floodvalid;

static qboolean		portalopen[MAX_MAP_AREAPORTALS];


static cvar_t		map_noareas;

void	CM_InitBoxHull (void);
void	FloodAreaConnections (void);


static int		c_pointcontents;
static int		c_traces, c_brush_traces;

typedef struct cmodel_collision_s
{
	cmodel_t	*pmodels;
	int			modelCount;
	cplane_t	*pplanes;
	int			planeCount;
	cnode_t		*pnodes;
	int			nodeCount;
	cleaf_t		*pleafs;
	int			leafCount;
} cmodel_collision_t;

void CM_GetCollisionModel( cmodel_collision_t *pcollide )
{
	pcollide->pmodels = map_cmodels;
	pcollide->modelCount = numcmodels;
	pcollide->pplanes = map_planes;
	pcollide->planeCount = numplanes;
	pcollide->pnodes = map_nodes;
	pcollide->nodeCount = numnodes;
	pcollide->pleafs = map_leafs;
	pcollide->leafCount = numleafs;
}

/*
===============================================================================

					MAP LOADING

===============================================================================
*/

static byte	*cmod_base;
/*
=================
CMod_LoadSubmodels
=================
*/
void CMod_LoadSubmodels (lump_t *l)
{
	dmodel_t	*in;
	cmodel_t	*out;
	int			i, j, count;

	in = (dmodel_t *)(cmod_base + l->fileofs);
	if (l->filelen % sizeof(*in))
		engine.Error("MOD_LoadBmodel: funny lump size");
	count = l->filelen / sizeof(*in);

	if (count < 1)
		engine.Error( "Map with no models" );
	if (count > MAX_MAP_MODELS)
		engine.Error( "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, dtexdata_t *pTexData, int texDataCount,
					   char* pStringData, const int* pStringTable )
{
	texinfo_t	*in;
	csurface_t	*out;
	int			i, count;

	in = (texinfo_t *)(cmod_base + l->fileofs);
	if (l->filelen % sizeof(*in))
		engine.Error( "MOD_LoadBmodel: funny lump size");
	count = l->filelen / sizeof(*in);
	if (count < 1)
		engine.Error( "Map with no surfaces");
	if (count > MAX_MAP_TEXINFO)
		engine.Error( "Map has too many surfaces");

	numtexinfo = count;
	out = map_surfaces;

	for ( i=0 ; i<count ; i++, in++, out++)
	{
		if ( in->texdata < texDataCount )
		{
			int texNameId = pTexData[in->texdata].nameStringTableID;
			strncpy( out->name, &pStringData[pStringTable[texNameId]], sizeof(out->name)-1);
		}
		out->flags = LittleLong (in->flags);
	}
}


/*
=================
CMod_LoadNodes

=================
*/
void CMod_LoadNodes (lump_t *l)
{
	dnode_t		*in;
	int			child;
	cnode_t		*out;
	int			i, j, count;
	
	in = (dnode_t *)(cmod_base + l->fileofs);
	if (l->filelen % sizeof(*in))
		engine.Error( "MOD_LoadBmodel: funny lump size");
	count = l->filelen / sizeof(*in);

	if (count < 1)
		engine.Error( "Map has no nodes");
	if (count > MAX_MAP_NODES)
		engine.Error( "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 = (dbrush_t *)(cmod_base + l->fileofs);
	if (l->filelen % sizeof(*in))
		engine.Error( "MOD_LoadBmodel: funny lump size");
	count = l->filelen / sizeof(*in);

	if (count > MAX_MAP_BRUSHES)
		engine.Error( "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 = (dleaf_t *)(cmod_base + l->fileofs);
	if (l->filelen % sizeof(*in))
		engine.Error( "MOD_LoadBmodel: funny lump size");
	count = l->filelen / sizeof(*in);

	if (count < 1)
		engine.Error( "Map with no leafs");
	// need to save space for box planes
	if (count > MAX_MAP_PLANES)
		engine.Error( "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 = (unsigned short)LittleShort (in->firstleafbrush);
		out->numleafbrushes = (unsigned short)LittleShort (in->numleafbrushes);

		if (out->cluster >= numclusters)
			numclusters = out->cluster + 1;
	}

	if (map_leafs[0].contents != CONTENTS_SOLID)
		engine.Error( "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)
		engine.Error( "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 = (dplane_t *)(cmod_base + l->fileofs);
	if (l->filelen % sizeof(*in))
		engine.Error( "MOD_LoadBmodel: funny lump size");
	count = l->filelen / sizeof(*in);

	if (count < 1)
		engine.Error( "Map with no planes");
	// need to save space for box planes
	if (count > MAX_MAP_PLANES)
		engine.Error( "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 = (unsigned short *)(cmod_base + l->fileofs);
	if (l->filelen % sizeof(*in))
		engine.Error( "MOD_LoadBmodel: funny lump size");
	count = l->filelen / sizeof(*in);

	if (count < 1)
		engine.Error( "Map with no planes");
	// need to save space for box planes
	if (count > MAX_MAP_LEAFBRUSHES)
		engine.Error( "Map has too many leafbrushes");

	out = map_leafbrushes;
	numleafbrushes = count;

	for ( i=0 ; i<count ; i++, in++, out++)
		*out = (unsigned short)LittleShort (*in);
}

/*
=================
CMod_LoadBrushSides
=================
*/
void CMod_LoadBrushSides (lump_t *l)
{
	int			i, j;
	cbrushside_t	*out;
	dbrushside_t 	*in;
	int			count;
	int			num;

	in = (dbrushside_t *)(cmod_base + l->fileofs);
	if (l->filelen % sizeof(*in))
		engine.Error( "MOD_LoadBmodel: funny lump size");
	count = l->filelen / sizeof(*in);

	// need to save space for box planes
	if (count > MAX_MAP_BRUSHSIDES)
		engine.Error( "Map has too many planes");

	out = map_brushsides;	
	numbrushsides = count;

	for ( i=0 ; i<count ; i++, in++, out++)
	{
		num = (unsigned short)LittleShort (in->planenum);
		out->plane = &map_planes[num];
		j = LittleShort (in->texinfo);
		if (j >= numtexinfo)
			engine.Error( "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 = (darea_t *)(cmod_base + l->fileofs);
	if (l->filelen % sizeof(*in))
		engine.Error( "MOD_LoadBmodel: funny lump size");
	count = l->filelen / sizeof(*in);

	if (count > MAX_MAP_AREAS)
		engine.Error( "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 = (dareaportal_t *)(cmod_base + l->fileofs);
	if (l->filelen % sizeof(*in))
		engine.Error( "MOD_LoadBmodel: funny lump size");
	count = l->filelen / sizeof(*in);

	if (count > MAX_MAP_AREAS)
		engine.Error( "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)
		engine.Error( "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)
		engine.Error( "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;

	// UNDONE: Don't load the map twice - call this from a function that loads once,
	// parses this part first, then parses/copies the renderer data

	// JAY: Later
//	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 = engine.LoadFile( name, (void **)&buf );
	if (!buf)
		engine.Error( "Couldn't load %s", name);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?