summaryrefslogtreecommitdiff
path: root/source/sw_model.c
diff options
context:
space:
mode:
authorAndrey Nazarov <skuller@skuller.net>2007-08-14 20:18:08 +0000
committerAndrey Nazarov <skuller@skuller.net>2007-08-14 20:18:08 +0000
commitf294db4ccf45f6274e65260dd6f9a2c5faa94313 (patch)
treee8cf1ba2bfe9c8417eec17faf912442f52fc4ef2 /source/sw_model.c
Initial import of the new Q2PRO tree.
Diffstat (limited to 'source/sw_model.c')
-rw-r--r--source/sw_model.c1237
1 files changed, 1237 insertions, 0 deletions
diff --git a/source/sw_model.c b/source/sw_model.c
new file mode 100644
index 0000000..15664a4
--- /dev/null
+++ b/source/sw_model.c
@@ -0,0 +1,1237 @@
+/*
+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.
+
+*/
+// models.c -- model loading and caching
+
+// models are the only shared resource between a client and server running
+// on the same machine.
+
+#include "sw_local.h"
+
+model_t *loadmodel;
+
+void Mod_LoadSpriteModel (model_t *mod, void *buffer);
+void Mod_LoadBrushModel (model_t *mod, void *buffer);
+void Mod_LoadAliasModel (model_t *mod, void *buffer);
+model_t *Mod_LoadModel (model_t *mod, qboolean crash);
+
+byte mod_novis[MAX_MAP_LEAFS/8];
+
+#define MAX_MOD_KNOWN 256
+model_t mod_known[MAX_MOD_KNOWN];
+int mod_numknown;
+
+// the inline * models from the current map are kept seperate
+model_t mod_inline[MAX_MOD_KNOWN];
+
+int registration_sequence;
+int modfilelen;
+
+/*
+================
+R_ModelForHandle
+================
+*/
+model_t *R_ModelForHandle( qhandle_t hModel ) {
+ if( !hModel ) {
+ return NULL;
+ }
+
+ if( hModel < 0 ) {
+ // inline model
+ if( !r_worldmodel ) {
+ return NULL;
+ }
+ hModel = -hModel;
+ if( hModel >= r_worldmodel->numsubmodels ) {
+ Com_Error( ERR_DROP, "R_ModelForHandle: out of range inline hModel: %i", hModel );
+ }
+ return &mod_inline[hModel];
+ }
+
+ if( hModel >= mod_numknown + 1 ) {
+ Com_Error( ERR_DROP, "R_ModelForHandle: out of range hModel: %i", hModel );
+ }
+ return &mod_known[hModel - 1];
+}
+
+//===============================================================================
+
+
+/*
+================
+Mod_Modellist_f
+================
+*/
+void Mod_Modellist_f (void)
+{
+ int i;
+ model_t *mod;
+ int total;
+
+ total = 0;
+ Com_Printf("Loaded models:\n");
+ for (i=0, mod=mod_known ; i < mod_numknown ; i++, mod++)
+ {
+ if (!mod->name[0])
+ continue;
+ Com_Printf( "%8i : %s\n",mod->pool.cursize, mod->name);
+ total += mod->pool.cursize;
+ }
+ Com_Printf( "Total resident: %i\n", total);
+}
+
+/*
+===============
+Mod_Init
+===============
+*/
+void Mod_Init (void)
+{
+ memset (mod_novis, 0xff, sizeof(mod_novis));
+}
+
+/*
+==================
+Mod_ForName
+
+Loads in a model for the given name
+==================
+*/
+qhandle_t Mod_ForName (const char *name, qboolean crash)
+{
+ model_t *mod;
+ byte *buf;
+ int i;
+
+ if (!name || !name[0])
+ Com_Error (ERR_DROP,"Mod_ForName: NULL name");
+
+ //
+ // inline models are grabbed only from worldmodel
+ //
+ if (name[0] == '*')
+ {
+ i = atoi(name+1);
+ if (i < 1 || !r_worldmodel || i >= r_worldmodel->numsubmodels)
+ Com_Error (ERR_DROP, "bad inline model number");
+ return -i;
+ }
+
+ //
+ // search the currently loaded models
+ //
+ for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
+ if (!strcmp (mod->name, name) )
+ return i + 1;
+
+ //
+ // find a free model slot spot
+ //
+ for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
+ {
+ if (!mod->name[0])
+ break; // free spot
+ }
+ if (i == mod_numknown)
+ {
+ if (mod_numknown == MAX_MOD_KNOWN)
+ Com_Error (ERR_DROP, "mod_numknown == MAX_MOD_KNOWN");
+ mod_numknown++;
+ }
+ Q_strncpyz( mod->name, name, sizeof( mod->name ) );
+
+ //
+ // load the file
+ //
+ modfilelen = fs.LoadFile (mod->name, (void **)&buf);
+ if (!buf)
+ {
+ if (crash)
+ Com_Error (ERR_DROP,"Mod_NumForName: %s not found", mod->name);
+ memset (mod->name, 0, sizeof(mod->name));
+ return 0;
+ }
+
+ loadmodel = mod;
+
+ //
+ // fill it in
+ //
+
+ // call the apropriate loader
+ switch (LittleLong(*(unsigned *)buf))
+ {
+ case IDALIASHEADER:
+ sys.HunkBegin (&loadmodel->pool, 0x200000);
+ Mod_LoadAliasModel (mod, buf);
+ break;
+
+ case IDSPRITEHEADER:
+ sys.HunkBegin (&loadmodel->pool, 0x10000);
+ Mod_LoadSpriteModel (mod, buf);
+ break;
+
+ case IDBSPHEADER:
+ sys.HunkBegin (&loadmodel->pool, 0x1000000);
+ Mod_LoadBrushModel (mod, buf);
+ break;
+
+ default:
+ Com_Error (ERR_DROP,"Mod_NumForName: unknown fileid for %s", mod->name);
+ break;
+ }
+
+
+
+ fs.FreeFile (buf);
+
+ return ( mod - mod_known ) + 1;
+}
+
+
+/*
+===============
+Mod_PointInLeaf
+===============
+*/
+mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
+{
+ mnode_t *node;
+ float d;
+ mplane_t *plane;
+
+ if (!model || !model->nodes)
+ Com_Error (ERR_DROP, "Mod_PointInLeaf: bad model");
+
+ node = model->nodes;
+ while (1)
+ {
+ if (node->contents != -1)
+ return (mleaf_t *)node;
+ plane = node->plane;
+ d = DotProduct (p,plane->normal) - plane->dist;
+ if (d > 0)
+ node = node->children[0];
+ else
+ node = node->children[1];
+ }
+
+ return NULL; // never reached
+}
+
+
+/*
+===================
+Mod_DecompressVis
+===================
+*/
+byte *Mod_DecompressVis (byte *in, model_t *model)
+{
+ static byte decompressed[MAX_MAP_LEAFS/8];
+ int c;
+ byte *out;
+ int row;
+
+ row = (model->vis->numclusters+7)>>3;
+ out = decompressed;
+
+#if 0
+ memcpy (out, in, row);
+#else
+ if (!in)
+ { // no vis info, so make all visible
+ while (row)
+ {
+ *out++ = 0xff;
+ row--;
+ }
+ return decompressed;
+ }
+
+ do
+ {
+ if (*in)
+ {
+ *out++ = *in++;
+ continue;
+ }
+
+ c = in[1];
+ in += 2;
+ while (c)
+ {
+ *out++ = 0;
+ c--;
+ }
+ } while (out - decompressed < row);
+#endif
+
+ return decompressed;
+}
+
+/*
+==============
+Mod_ClusterPVS
+==============
+*/
+byte *Mod_ClusterPVS (int cluster, model_t *model)
+{
+ if (cluster == -1 || !model->vis)
+ return mod_novis;
+ return Mod_DecompressVis ( (byte *)model->vis + model->vis->bitofs[cluster][DVIS_PVS],
+ model);
+}
+
+/*
+===============================================================================
+
+ BRUSHMODEL LOADING
+
+===============================================================================
+*/
+
+byte *mod_base;
+
+
+/*
+=================
+Mod_LoadLighting
+
+Converts the 24 bit lighting down to 8 bit
+by taking the brightest component
+=================
+*/
+void Mod_LoadLighting (lump_t *l)
+{
+ int i, size;
+ byte *in;
+
+ if (!l->filelen)
+ {
+ loadmodel->lightdata = NULL;
+ return;
+ }
+ size = l->filelen/3;
+ loadmodel->lightdata = sys.HunkAlloc (&loadmodel->pool, size);
+ in = (void *)(mod_base + l->fileofs);
+ for (i=0 ; i<size ; i++, in+=3)
+ {
+ if (in[0] > in[1] && in[0] > in[2])
+ loadmodel->lightdata[i] = in[0];
+ else if (in[1] > in[0] && in[1] > in[2])
+ loadmodel->lightdata[i] = in[1];
+ else
+ loadmodel->lightdata[i] = in[2];
+ }
+}
+
+/*
+=================
+Mod_LoadVisibility
+=================
+*/
+void Mod_LoadVisibility (lump_t *l)
+{
+ int i;
+
+ if (!l->filelen)
+ {
+ loadmodel->vis = NULL;
+ return;
+ }
+ loadmodel->vis = sys.HunkAlloc (&loadmodel->pool, l->filelen);
+ memcpy (loadmodel->vis, mod_base + l->fileofs, l->filelen);
+
+ loadmodel->vis->numclusters = LittleLong (loadmodel->vis->numclusters);
+ for (i=0 ; i<loadmodel->vis->numclusters ; i++)
+ {
+ loadmodel->vis->bitofs[i][0] = LittleLong (loadmodel->vis->bitofs[i][0]);
+ loadmodel->vis->bitofs[i][1] = LittleLong (loadmodel->vis->bitofs[i][1]);
+ }
+}
+
+
+/*
+=================
+Mod_LoadVertexes
+=================
+*/
+void Mod_LoadVertexes (lump_t *l)
+{
+ dvertex_t *in;
+ mvertex_t *out;
+ int i, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = sys.HunkAlloc (&loadmodel->pool, (count+8)*sizeof(*out)); // extra for skybox
+
+ loadmodel->vertexes = out;
+ loadmodel->numvertexes = count;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ {
+ out->position[0] = LittleFloat (in->point[0]);
+ out->position[1] = LittleFloat (in->point[1]);
+ out->position[2] = LittleFloat (in->point[2]);
+ }
+}
+
+/*
+=================
+Mod_LoadSubmodels
+=================
+*/
+void Mod_LoadSubmodels (lump_t *l)
+{
+ dmodel_t *in;
+ dmodel_t *out;
+ int i, j, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = sys.HunkAlloc (&loadmodel->pool, count*sizeof(*out));
+
+ loadmodel->submodels = out;
+ loadmodel->numsubmodels = count;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ {
+ 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);
+ out->firstface = LittleLong (in->firstface);
+ out->numfaces = LittleLong (in->numfaces);
+ }
+}
+
+/*
+=================
+Mod_LoadEdges
+=================
+*/
+void Mod_LoadEdges (lump_t *l)
+{
+ dedge_t *in;
+ medge_t *out;
+ int i, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = sys.HunkAlloc (&loadmodel->pool, (count + 13) * sizeof(*out)); // extra for skybox
+
+ loadmodel->edges = out;
+ loadmodel->numedges = count;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ {
+ out->v[0] = (unsigned short)LittleShort(in->v[0]);
+ out->v[1] = (unsigned short)LittleShort(in->v[1]);
+ }
+}
+
+/*
+=================
+Mod_LoadTexinfo
+=================
+*/
+void Mod_LoadTexinfo (lump_t *l)
+{
+ texinfo_t *in;
+ mtexinfo_t *out, *step;
+ int i, j, count;
+ float len1, len2;
+ char name[MAX_QPATH];
+ int next;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = sys.HunkAlloc (&loadmodel->pool, (count+6)*sizeof(*out)); // extra for skybox
+
+ loadmodel->texinfo = out;
+ loadmodel->numtexinfo = count;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ {
+ for (j=0 ; j<8 ; j++)
+ out->vecs[0][j] = LittleFloat (in->vecs[0][j]);
+ len1 = VectorLength (out->vecs[0]);
+ len2 = VectorLength (out->vecs[1]);
+ len1 = (len1 + len2)/2;
+ if (len1 < 0.32)
+ out->mipadjust = 4;
+ else if (len1 < 0.49)
+ out->mipadjust = 3;
+ else if (len1 < 0.99)
+ out->mipadjust = 2;
+ else
+ out->mipadjust = 1;
+#if 0
+ if (len1 + len2 < 0.001)
+ out->mipadjust = 1; // don't crash
+ else
+ out->mipadjust = 1 / floor( (len1+len2)/2 + 0.1 );
+#endif
+
+ out->flags = LittleLong (in->flags);
+
+ next = LittleLong (in->nexttexinfo);
+ if (next > 0)
+ out->next = loadmodel->texinfo + next;
+
+ Com_sprintf (name, sizeof(name), "textures/%s.wal", in->texture);
+ out->image = R_FindImage (name, it_wall);
+ if (!out->image)
+ {
+ out->image = r_notexture_mip; // texture not found
+ out->flags = 0;
+ }
+ }
+
+ // count animation frames
+ for (i=0 ; i<count ; i++)
+ {
+ out = &loadmodel->texinfo[i];
+ out->numframes = 1;
+ for (step = out->next ; step && step != out ; step=step->next)
+ out->numframes++;
+ }
+}
+
+/*
+================
+CalcSurfaceExtents
+
+Fills in s->texturemins[] and s->extents[]
+================
+*/
+void CalcSurfaceExtents (msurface_t *s)
+{
+ float mins[2], maxs[2], val;
+ int i,j, e;
+ mvertex_t *v;
+ mtexinfo_t *tex;
+ int bmins[2], bmaxs[2];
+
+ mins[0] = mins[1] = 999999;
+ maxs[0] = maxs[1] = -99999;
+
+ tex = s->texinfo;
+
+ for (i=0 ; i<s->numedges ; i++)
+ {
+ e = loadmodel->surfedges[s->firstedge+i];
+ if (e >= 0)
+ v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
+ else
+ v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
+
+ for (j=0 ; j<2 ; j++)
+ {
+ val = v->position[0] * tex->vecs[j][0] +
+ v->position[1] * tex->vecs[j][1] +
+ v->position[2] * tex->vecs[j][2] +
+ tex->vecs[j][3];
+ if (val < mins[j])
+ mins[j] = val;
+ if (val > maxs[j])
+ maxs[j] = val;
+ }
+ }
+
+ for (i=0 ; i<2 ; i++)
+ {
+ bmins[i] = floor(mins[i]/16);
+ bmaxs[i] = ceil(maxs[i]/16);
+
+ s->texturemins[i] = bmins[i] * 16;
+ s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
+ if (s->extents[i] < 16)
+ s->extents[i] = 16; // take at least one cache block
+ if ( !(tex->flags & (SURF_WARP|SURF_SKY)) && s->extents[i] > 256)
+ Com_Error (ERR_DROP,"Bad surface extents");
+ }
+}
+
+
+/*
+=================
+Mod_LoadFaces
+=================
+*/
+void Mod_LoadFaces (lump_t *l)
+{
+ dface_t *in;
+ msurface_t *out;
+ int i, count, surfnum;
+ int planenum, side;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = sys.HunkAlloc (&loadmodel->pool, (count+6)*sizeof(*out)); // extra for skybox
+
+ loadmodel->surfaces = out;
+ loadmodel->numsurfaces = count;
+
+ for ( surfnum=0 ; surfnum<count ; surfnum++, in++, out++)
+ {
+ out->firstedge = LittleLong(in->firstedge);
+ out->numedges = LittleShort(in->numedges);
+ if (out->numedges < 3)
+ Com_Error (ERR_DROP,"Surface with %d edges", out->numedges);
+ out->flags = 0;
+
+ planenum = LittleShort(in->planenum);
+ side = LittleShort(in->side);
+ if (side)
+ out->flags |= SURF_PLANEBACK;
+
+ out->plane = loadmodel->planes + planenum;
+
+ out->texinfo = loadmodel->texinfo + LittleShort (in->texinfo);
+
+ CalcSurfaceExtents (out);
+
+ // lighting info is converted from 24 bit on disk to 8 bit
+
+ for (i=0 ; i<MAXLIGHTMAPS ; i++)
+ out->styles[i] = in->styles[i];
+ i = LittleLong(in->lightofs);
+ if (i == -1)
+ out->samples = NULL;
+ else
+ out->samples = loadmodel->lightdata + i/3;
+
+ // set the drawing flags flag
+
+ if (!out->texinfo->image)
+ continue;
+ if (out->texinfo->flags & SURF_SKY)
+ {
+ out->flags |= SURF_DRAWSKY;
+ continue;
+ }
+
+ if (out->texinfo->flags & SURF_WARP)
+ {
+ out->flags |= SURF_DRAWTURB;
+ for (i=0 ; i<2 ; i++)
+ {
+ out->extents[i] = 16384;
+ out->texturemins[i] = -8192;
+ }
+ continue;
+ }
+//==============
+//PGM
+ // this marks flowing surfaces as turbulent, but with the new
+ // SURF_FLOW flag.
+ if (out->texinfo->flags & SURF_FLOWING)
+ {
+ out->flags |= SURF_DRAWTURB | SURF_FLOW;
+ for (i=0 ; i<2 ; i++)
+ {
+ out->extents[i] = 16384;
+ out->texturemins[i] = -8192;
+ }
+ continue;
+ }
+//PGM
+//==============
+ }
+}
+
+
+/*
+=================
+Mod_SetParent
+=================
+*/
+void Mod_SetParent (mnode_t *node, mnode_t *parent)
+{
+ node->parent = parent;
+ if (node->contents != -1)
+ return;
+ Mod_SetParent (node->children[0], node);
+ Mod_SetParent (node->children[1], node);
+}
+
+/*
+=================
+Mod_LoadNodes
+=================
+*/
+void Mod_LoadNodes (lump_t *l)
+{
+ int i, j, count, p;
+ dnode_t *in;
+ mnode_t *out;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = sys.HunkAlloc (&loadmodel->pool, count*sizeof(*out));
+
+ loadmodel->nodes = out;
+ loadmodel->numnodes = count;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ {
+ for (j=0 ; j<3 ; j++)
+ {
+ out->minmaxs[j] = LittleShort (in->mins[j]);
+ out->minmaxs[3+j] = LittleShort (in->maxs[j]);
+ }
+
+ p = LittleLong(in->planenum);
+ out->plane = loadmodel->planes + p;
+
+ out->firstsurface = LittleShort (in->firstface);
+ out->numsurfaces = LittleShort (in->numfaces);
+ out->contents = CONTENTS_NODE; // differentiate from leafs
+
+ for (j=0 ; j<2 ; j++)
+ {
+ p = LittleLong (in->children[j]);
+ if (p >= 0)
+ out->children[j] = loadmodel->nodes + p;
+ else
+ out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
+ }
+ }
+
+ Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
+}
+
+/*
+=================
+Mod_LoadLeafs
+=================
+*/
+void Mod_LoadLeafs (lump_t *l)
+{
+ dleaf_t *in;
+ mleaf_t *out;
+ int i, j, count;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = sys.HunkAlloc (&loadmodel->pool, count*sizeof(*out));
+
+ loadmodel->leafs = out;
+ loadmodel->numleafs = count;
+
+ for ( i=0 ; i<count ; i++, in++, out++)
+ {
+ for (j=0 ; j<3 ; j++)
+ {
+ out->minmaxs[j] = LittleShort (in->mins[j]);
+ out->minmaxs[3+j] = LittleShort (in->maxs[j]);
+ }
+
+ out->contents = LittleLong(in->contents);
+ out->cluster = LittleShort(in->cluster);
+ out->area = LittleShort(in->area);
+
+ out->firstmarksurface = loadmodel->marksurfaces +
+ LittleShort(in->firstleafface);
+ out->nummarksurfaces = LittleShort(in->numleaffaces);
+ }
+}
+
+
+/*
+=================
+Mod_LoadMarksurfaces
+=================
+*/
+void Mod_LoadMarksurfaces (lump_t *l)
+{
+ int i, j, count;
+ short *in;
+ msurface_t **out;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = sys.HunkAlloc (&loadmodel->pool, count*sizeof(*out));
+
+ loadmodel->marksurfaces = out;
+ loadmodel->nummarksurfaces = count;
+
+ for ( i=0 ; i<count ; i++)
+ {
+ j = LittleShort(in[i]);
+ if (j >= loadmodel->numsurfaces)
+ Com_Error (ERR_DROP,"Mod_ParseMarksurfaces: bad surface number");
+ out[i] = loadmodel->surfaces + j;
+ }
+}
+
+/*
+=================
+Mod_LoadSurfedges
+=================
+*/
+void Mod_LoadSurfedges (lump_t *l)
+{
+ int i, count;
+ int *in, *out;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = sys.HunkAlloc (&loadmodel->pool, (count+24)*sizeof(*out)); // extra for skybox
+
+ loadmodel->surfedges = out;
+ loadmodel->numsurfedges = count;
+
+ for ( i=0 ; i<count ; i++)
+ out[i] = LittleLong (in[i]);
+}
+
+/*
+=================
+Mod_LoadPlanes
+=================
+*/
+void Mod_LoadPlanes (lump_t *l)
+{
+ int i, j;
+ mplane_t *out;
+ dplane_t *in;
+ int count;
+ int bits;
+
+ in = (void *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Com_Error (ERR_DROP,"MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = sys.HunkAlloc (&loadmodel->pool, (count+6)*sizeof(*out)); // extra for skybox
+
+ loadmodel->planes = out;
+ loadmodel->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;
+ }
+}
+
+
+/*
+=================
+Mod_LoadBrushModel
+=================
+*/
+void Mod_LoadBrushModel (model_t *mod, void *buffer)
+{
+ int i;
+ dheader_t *header;
+ dmodel_t *bm;
+
+ loadmodel->type = mod_brush;
+ if (loadmodel != mod_known)
+ Com_Error (ERR_DROP, "Loaded a brush model after the world");
+
+ header = (dheader_t *)buffer;
+
+ i = LittleLong (header->version);
+ if (i != BSPVERSION)
+ Com_Error (ERR_DROP,"Mod_LoadBrushModel: %s has wrong version number (%i should be %i)", mod->name, i, BSPVERSION);
+
+// swap all the lumps
+ mod_base = (byte *)header;
+
+ for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
+ ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
+
+// load into heap
+
+ Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
+ Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
+ Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
+ Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
+ Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
+ Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
+ Mod_LoadFaces (&header->lumps[LUMP_FACES]);
+ Mod_LoadMarksurfaces (&header->lumps[LUMP_LEAFFACES]);
+ Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
+ Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
+ Mod_LoadNodes (&header->lumps[LUMP_NODES]);
+ Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
+
+//
+// set up the submodels
+//
+ for (i=0 ; i<mod->numsubmodels ; i++)
+ {
+ model_t *starmod;
+
+ bm = &mod->submodels[i];
+ starmod = &mod_inline[i];
+
+ *starmod = *loadmodel;
+
+ starmod->firstmodelsurface = bm->firstface;
+ starmod->nummodelsurfaces = bm->numfaces;
+ starmod->firstnode = bm->headnode;
+ if (starmod->firstnode >= loadmodel->numnodes)
+ Com_Error (ERR_DROP, "Inline model %i has bad firstnode", i);
+
+ VectorCopy (bm->maxs, starmod->maxs);
+ VectorCopy (bm->mins, starmod->mins);
+
+ if (i == 0)
+ *loadmodel = *starmod;
+ }
+
+ R_InitSkyBox ();
+}
+
+/*
+==============================================================================
+
+ALIAS MODELS
+
+==============================================================================
+*/
+
+/*
+=================
+Mod_LoadAliasModel
+=================
+*/
+void Mod_LoadAliasModel (model_t *mod, void *buffer)
+{
+ int i, j;
+ dmdl_t *pinmodel, *pheader;
+ dstvert_t *pinst, *poutst;
+ dtriangle_t *pintri, *pouttri;
+ daliasframe_t *pinframe, *poutframe;
+ int *pincmd, *poutcmd;
+ int version;
+
+ pinmodel = (dmdl_t *)buffer;
+
+ version = LittleLong (pinmodel->version);
+ if (version != ALIAS_VERSION)
+ Com_Error (ERR_DROP, "%s has wrong version number (%i should be %i)",
+ mod->name, version, ALIAS_VERSION);
+
+ pheader = sys.HunkAlloc (&mod->pool, LittleLong(pinmodel->ofs_end));
+
+ // byte swap the header fields and sanity check
+ for (i=0 ; i<sizeof(dmdl_t)/4 ; i++)
+ ((int *)pheader)[i] = LittleLong (((int *)buffer)[i]);
+
+ if (pheader->skinheight > MAX_LBM_HEIGHT)
+ Com_Error (ERR_DROP, "model %s has a skin taller than %d", mod->name,
+ MAX_LBM_HEIGHT);
+
+ if (pheader->num_xyz <= 0)
+ Com_Error (ERR_DROP, "model %s has no vertices", mod->name);
+
+ if (pheader->num_xyz > MAX_VERTS)
+ Com_Error (ERR_DROP, "model %s has too many vertices", mod->name);
+
+ if (pheader->num_st <= 0)
+ Com_Error (ERR_DROP, "model %s has no st vertices", mod->name);
+
+ if (pheader->num_tris <= 0)
+ Com_Error (ERR_DROP, "model %s has no triangles", mod->name);
+
+ if (pheader->num_frames <= 0)
+ Com_Error (ERR_DROP, "model %s has no frames", mod->name);
+
+//
+// load base s and t vertices (not used in gl version)
+//
+ pinst = (dstvert_t *) ((byte *)pinmodel + pheader->ofs_st);
+ poutst = (dstvert_t *) ((byte *)pheader + pheader->ofs_st);
+
+ for (i=0 ; i<pheader->num_st ; i++)
+ {
+ poutst[i].s = LittleShort (pinst[i].s);
+ poutst[i].t = LittleShort (pinst[i].t);
+ }
+
+//
+// load triangle lists
+//
+ pintri = (dtriangle_t *) ((byte *)pinmodel + pheader->ofs_tris);
+ pouttri = (dtriangle_t *) ((byte *)pheader + pheader->ofs_tris);
+
+ for (i=0 ; i<pheader->num_tris ; i++)
+ {
+ for (j=0 ; j<3 ; j++)
+ {
+ pouttri[i].index_xyz[j] = LittleShort (pintri[i].index_xyz[j]);
+ pouttri[i].index_st[j] = LittleShort (pintri[i].index_st[j]);
+ }
+ }
+
+//
+// load the frames
+//
+ for (i=0 ; i<pheader->num_frames ; i++)
+ {
+ pinframe = (daliasframe_t *) ((byte *)pinmodel
+ + pheader->ofs_frames + i * pheader->framesize);
+ poutframe = (daliasframe_t *) ((byte *)pheader
+ + pheader->ofs_frames + i * pheader->framesize);
+
+ memcpy (poutframe->name, pinframe->name, sizeof(poutframe->name));
+ for (j=0 ; j<3 ; j++)
+ {
+ poutframe->scale[j] = LittleFloat (pinframe->scale[j]);
+ poutframe->translate[j] = LittleFloat (pinframe->translate[j]);
+ }
+ // verts are all 8 bit, so no swapping needed
+ memcpy (poutframe->verts, pinframe->verts,
+ pheader->num_xyz*sizeof(dtrivertx_t));
+
+ }
+
+ mod->type = mod_alias;
+
+ //
+ // load the glcmds
+ //
+ pincmd = (int *) ((byte *)pinmodel + pheader->ofs_glcmds);
+ poutcmd = (int *) ((byte *)pheader + pheader->ofs_glcmds);
+ for (i=0 ; i<pheader->num_glcmds ; i++)
+ poutcmd[i] = LittleLong (pincmd[i]);
+
+
+ // register all skins
+ memcpy ((char *)pheader + pheader->ofs_skins, (char *)pinmodel + pheader->ofs_skins,
+ pheader->num_skins*MAX_SKINNAME);
+ for (i=0 ; i<pheader->num_skins ; i++)
+ {
+ mod->skins[i] = R_FindImage ((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME, it_skin);
+ }
+}
+
+/*
+==============================================================================
+
+SPRITE MODELS
+
+==============================================================================
+*/
+
+/*
+=================
+Mod_LoadSpriteModel
+=================
+*/
+void Mod_LoadSpriteModel (model_t *mod, void *buffer)
+{
+ dsprite_t *sprin, *sprout;
+ int i;
+
+ sprin = (dsprite_t *)buffer;
+ sprout = sys.HunkAlloc(&mod->pool, modfilelen);
+
+ sprout->ident = LittleLong (sprin->ident);
+ sprout->version = LittleLong (sprin->version);
+ sprout->numframes = LittleLong (sprin->numframes);
+
+ if (sprout->version != SPRITE_VERSION)
+ Com_Error (ERR_DROP, "%s has wrong version number (%i should be %i)",
+ mod->name, sprout->version, SPRITE_VERSION);
+
+ if (sprout->numframes > MAX_MD2SKINS)
+ Com_Error (ERR_DROP, "%s has too many frames (%i > %i)",
+ mod->name, sprout->numframes, MAX_MD2SKINS);
+
+ // byte swap everything
+ for (i=0 ; i<sprout->numframes ; i++)
+ {
+ sprout->frames[i].width = LittleLong (sprin->frames[i].width);
+ sprout->frames[i].height = LittleLong (sprin->frames[i].height);
+ sprout->frames[i].origin_x = LittleLong (sprin->frames[i].origin_x);
+ sprout->frames[i].origin_y = LittleLong (sprin->frames[i].origin_y);
+ memcpy (sprout->frames[i].name, sprin->frames[i].name, MAX_SKINNAME);
+ mod->skins[i] = R_FindImage (sprout->frames[i].name, it_sprite);
+ }
+
+ mod->type = mod_sprite;
+}
+
+//=============================================================================
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+R_BeginRegistration
+
+Specifies the model that will be used as the world
+@@@@@@@@@@@@@@@@@@@@@
+*/
+void R_BeginRegistration( const char *model ) {
+ char fullname[MAX_QPATH];
+ cvar_t *flushmap;
+
+ registration_sequence++;
+ r_oldviewcluster = -1; // force markleafs
+ Com_sprintf (fullname, sizeof(fullname), "maps/%s.bsp", model);
+
+ D_FlushCaches ();
+ // explicitly free the old map if different
+ // this guarantees that mod_known[0] is the world map
+ flushmap = cvar.Get ("flushmap", "0", 0);
+ if ( mod_known[0].name[0] && ( strcmp(mod_known[0].name, fullname) || flushmap->integer ))
+ Mod_Free (&mod_known[0]);
+ r_worldmodel = R_ModelForHandle ( R_RegisterModel( fullname ) );
+ R_NewMap ();
+}
+
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+R_RegisterModel
+
+@@@@@@@@@@@@@@@@@@@@@
+*/
+qhandle_t R_RegisterModel( const char *name ) {
+ model_t *mod;
+ qhandle_t hModel;
+ int i;
+ dsprite_t *sprout;
+ dmdl_t *pheader;
+
+ hModel = Mod_ForName (name, qfalse);
+ if( ( mod = R_ModelForHandle( hModel ) ) != NULL )
+ {
+ mod->registration_sequence = registration_sequence;
+
+ // register any images used by the models
+ if (mod->type == mod_sprite)
+ {
+ sprout = (dsprite_t *)mod->pool.base;
+ for (i=0 ; i<sprout->numframes ; i++)
+ mod->skins[i] = R_FindImage (sprout->frames[i].name, it_sprite);
+ }
+ else if (mod->type == mod_alias)
+ {
+ pheader = (dmdl_t *)mod->pool.base;
+ for (i=0 ; i<pheader->num_skins ; i++)
+ mod->skins[i] = R_FindImage ((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME, it_skin);
+//PGM
+ mod->numframes = pheader->num_frames;
+//PGM
+ }
+ else if (mod->type == mod_brush)
+ {
+ for (i=0 ; i<mod->numtexinfo ; i++)
+ mod->texinfo[i].image->registration_sequence = registration_sequence;
+ }
+ }
+ return hModel;
+}
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+R_EndRegistration
+
+@@@@@@@@@@@@@@@@@@@@@
+*/
+void R_EndRegistration (void)
+{
+ int i;
+ model_t *mod;
+
+ for (i=0, mod=mod_known ; i<mod_numknown ; i++, mod++)
+ {
+ if (!mod->name[0])
+ continue;
+ if (mod->registration_sequence != registration_sequence)
+ { // don't need this model
+ Mod_Free( mod );
+ }
+ else
+ { // make sure it is paged in
+ Com_PageInMemory (mod->pool.base, mod->pool.cursize);
+ }
+ }
+
+ R_FreeUnusedImages ();
+}
+
+
+//=============================================================================
+
+/*
+================
+Mod_Free
+================
+*/
+void Mod_Free (model_t *mod)
+{
+ sys.HunkFree (&mod->pool);
+ memset (mod, 0, sizeof(*mod));
+}
+
+/*
+================
+Mod_FreeAll
+================
+*/
+void Mod_FreeAll (void)
+{
+ int i;
+ model_t *mod;
+
+ for (i=0, mod = mod_known ; i<mod_numknown ; i++, mod++)
+ {
+ if (mod->name[0])
+ Mod_Free (mod);
+ }
+}