yquake2remaster/src/client/refresh/r_model.c

1080 lines
20 KiB
C
Raw Normal View History

/*
2010-10-21 08:12:50 +00:00
* 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.
*
* =======================================================================
*
2010-10-21 08:21:13 +00:00
* Model loading and caching. Includes the .bsp file format
2010-10-21 08:12:50 +00:00
*
* =======================================================================
2012-04-29 13:57:33 +00:00
*/
2009-03-05 11:03:08 +00:00
#include "header/local.h"
2012-07-21 12:09:45 +00:00
#define MAX_MOD_KNOWN 512
2010-10-21 08:12:50 +00:00
model_t *loadmodel;
int modfilelen;
2012-07-21 12:09:45 +00:00
byte mod_novis[MAX_MAP_LEAFS / 8];
model_t mod_known[MAX_MOD_KNOWN];
2010-10-21 08:12:50 +00:00
int mod_numknown;
int registration_sequence;
byte *mod_base;
2012-07-21 12:09:45 +00:00
void LoadSP2(model_t *mod, void *buffer);
void Mod_LoadBrushModel(model_t *mod, void *buffer);
void LoadMD2(model_t *mod, void *buffer);
model_t *Mod_LoadModel(model_t *mod, qboolean crash);
void LM_BuildPolygonFromSurface(msurface_t *fa);
void LM_CreateSurfaceLightmap(msurface_t *surf);
void LM_EndBuildingLightmaps(void);
void LM_BeginBuildingLightmaps(model_t *m);
2010-10-21 08:12:50 +00:00
/* the inline * models from the current map are kept seperate */
2012-07-21 12:09:45 +00:00
model_t mod_inline[MAX_MOD_KNOWN];
2010-10-21 08:12:50 +00:00
mleaf_t *
2012-07-21 12:09:45 +00:00
Mod_PointInLeaf(vec3_t p, model_t *model)
{
2012-07-21 12:09:45 +00:00
mnode_t *node;
2010-10-21 08:12:50 +00:00
float d;
2012-07-21 12:09:45 +00:00
cplane_t *plane;
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
if (!model || !model->nodes)
2010-10-21 08:12:50 +00:00
{
VID_Error(ERR_DROP, "Mod_PointInLeaf: bad model");
2010-10-21 08:12:50 +00:00
}
node = model->nodes;
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
while (1)
{
2012-07-21 12:09:45 +00:00
if (node->contents != -1)
2010-10-21 08:12:50 +00:00
{
2012-07-21 12:09:45 +00:00
return (mleaf_t *)node;
2010-10-21 08:12:50 +00:00
}
plane = node->plane;
2012-07-21 12:09:45 +00:00
d = DotProduct(p, plane->normal) - plane->dist;
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
if (d > 0)
2010-10-21 08:12:50 +00:00
{
2012-07-21 12:09:45 +00:00
node = node->children[0];
2010-10-21 08:12:50 +00:00
}
else
2010-10-21 08:12:50 +00:00
{
2012-07-21 12:09:45 +00:00
node = node->children[1];
2010-10-21 08:12:50 +00:00
}
}
2012-07-21 12:09:45 +00:00
return NULL; /* never reached */
2010-10-21 08:12:50 +00:00
}
2010-10-21 08:12:50 +00:00
byte *
2012-07-21 12:09:45 +00:00
Mod_DecompressVis(byte *in, model_t *model)
{
2012-07-21 12:09:45 +00:00
static byte decompressed[MAX_MAP_LEAFS / 8];
2010-10-21 08:12:50 +00:00
int c;
2012-07-21 12:09:45 +00:00
byte *out;
2010-10-21 08:12:50 +00:00
int row;
2012-07-21 12:09:45 +00:00
row = (model->vis->numclusters + 7) >> 3;
out = decompressed;
2012-07-21 12:09:45 +00:00
if (!in)
2012-04-29 13:57:33 +00:00
{
2010-10-21 08:12:50 +00:00
/* no vis info, so make all visible */
2012-07-21 12:09:45 +00:00
while (row)
{
*out++ = 0xff;
row--;
}
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
return decompressed;
}
do
{
2012-07-21 12:09:45 +00:00
if (*in)
{
*out++ = *in++;
continue;
}
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
c = in[1];
in += 2;
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
while (c)
{
*out++ = 0;
c--;
}
2010-10-21 08:12:50 +00:00
}
2012-07-21 12:09:45 +00:00
while (out - decompressed < row);
2012-07-21 12:09:45 +00:00
return decompressed;
}
2010-10-21 08:12:50 +00:00
byte *
2012-07-21 12:09:45 +00:00
Mod_ClusterPVS(int cluster, model_t *model)
2010-10-21 08:12:50 +00:00
{
2012-07-21 12:09:45 +00:00
if ((cluster == -1) || !model->vis)
2010-10-21 08:12:50 +00:00
{
2012-07-21 12:09:45 +00:00
return mod_novis;
2010-10-21 08:12:50 +00:00
}
2012-07-21 12:09:45 +00:00
return Mod_DecompressVis((byte *)model->vis +
model->vis->bitofs[cluster][DVIS_PVS],
model);
2010-10-21 08:12:50 +00:00
}
2010-10-21 08:12:50 +00:00
void
2012-07-21 12:09:45 +00:00
Mod_Modellist_f(void)
{
2010-10-21 08:12:50 +00:00
int i;
model_t *mod;
int total;
total = 0;
VID_Printf(PRINT_ALL, "Loaded models:\n");
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++)
{
2012-07-21 12:09:45 +00:00
if (!mod->name[0])
2010-10-21 08:12:50 +00:00
{
continue;
2010-10-21 08:12:50 +00:00
}
VID_Printf(PRINT_ALL, "%8i : %s\n", mod->extradatasize, mod->name);
total += mod->extradatasize;
}
2010-10-21 08:12:50 +00:00
VID_Printf(PRINT_ALL, "Total resident: %i\n", total);
}
2010-10-21 08:12:50 +00:00
void
2012-07-21 12:09:45 +00:00
Mod_Init(void)
{
2012-07-21 12:09:45 +00:00
memset(mod_novis, 0xff, sizeof(mod_novis));
}
/*
2010-10-21 08:12:50 +00:00
* Loads in a model for the given name
*/
model_t *
2012-07-21 12:09:45 +00:00
Mod_ForName(char *name, qboolean crash)
{
2010-10-21 08:12:50 +00:00
model_t *mod;
unsigned *buf;
2010-10-21 08:12:50 +00:00
int i;
2012-07-21 12:09:45 +00:00
if (!name[0])
{
VID_Error(ERR_DROP, "Mod_ForName: NULL name");
}
2010-10-21 08:12:50 +00:00
/* inline models are grabbed only from worldmodel */
2012-07-21 12:09:45 +00:00
if (name[0] == '*')
{
2012-07-21 12:09:45 +00:00
i = (int)strtol(name + 1, (char **)NULL, 10);
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
if ((i < 1) || !r_worldmodel || (i >= r_worldmodel->numsubmodels))
2010-10-21 08:12:50 +00:00
{
VID_Error(ERR_DROP, "bad inline model number");
2010-10-21 08:12:50 +00:00
}
2012-07-21 12:09:45 +00:00
return &mod_inline[i];
}
2010-10-21 08:12:50 +00:00
/* search the currently loaded models */
2012-07-21 12:09:45 +00:00
for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++)
{
2012-07-21 12:09:45 +00:00
if (!mod->name[0])
2010-10-21 08:12:50 +00:00
{
continue;
}
2012-07-21 12:09:45 +00:00
if (!strcmp(mod->name, name))
2010-10-21 08:12:50 +00:00
{
2012-07-21 12:09:45 +00:00
return mod;
2010-10-21 08:12:50 +00:00
}
}
2010-10-21 08:12:50 +00:00
/* find a free model slot spot */
2012-07-21 12:09:45 +00:00
for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++)
2010-10-21 08:12:50 +00:00
{
2012-07-21 12:09:45 +00:00
if (!mod->name[0])
2010-10-21 08:12:50 +00:00
{
break; /* free spot */
}
}
2012-07-21 12:09:45 +00:00
if (i == mod_numknown)
{
2012-07-21 12:09:45 +00:00
if (mod_numknown == MAX_MOD_KNOWN)
2010-10-21 08:12:50 +00:00
{
VID_Error(ERR_DROP, "mod_numknown == MAX_MOD_KNOWN");
2010-10-21 08:12:50 +00:00
}
2010-10-21 08:12:50 +00:00
mod_numknown++;
}
2012-07-21 12:09:45 +00:00
strcpy(mod->name, name);
2010-10-21 08:12:50 +00:00
/* load the file */
modfilelen = FS_LoadFile(mod->name, (void **)&buf);
2012-07-21 12:09:45 +00:00
if (!buf)
2010-10-21 08:12:50 +00:00
{
2012-07-21 12:09:45 +00:00
if (crash)
2010-10-21 08:12:50 +00:00
{
VID_Error(ERR_DROP, "Mod_NumForName: %s not found", mod->name);
2010-10-21 08:12:50 +00:00
}
2012-07-21 12:09:45 +00:00
memset(mod->name, 0, sizeof(mod->name));
return NULL;
2010-10-21 08:12:50 +00:00
}
2010-10-21 08:12:50 +00:00
loadmodel = mod;
2010-10-21 08:12:50 +00:00
/* call the apropriate loader */
2012-07-21 12:09:45 +00:00
switch (LittleLong(*(unsigned *)buf))
2010-10-21 08:12:50 +00:00
{
case IDALIASHEADER:
2012-07-21 12:09:45 +00:00
loadmodel->extradata = Hunk_Begin(0x200000);
LoadMD2(mod, buf);
2010-10-21 08:12:50 +00:00
break;
case IDSPRITEHEADER:
2012-07-21 12:09:45 +00:00
loadmodel->extradata = Hunk_Begin(0x10000);
LoadSP2(mod, buf);
2010-10-21 08:12:50 +00:00
break;
case IDBSPHEADER:
2012-07-21 12:09:45 +00:00
loadmodel->extradata = Hunk_Begin(0x1000000);
Mod_LoadBrushModel(mod, buf);
2010-10-21 08:12:50 +00:00
break;
default:
VID_Error(ERR_DROP,
2012-07-21 12:09:45 +00:00
"Mod_NumForName: unknown fileid for %s",
mod->name);
2010-10-21 08:12:50 +00:00
break;
}
2010-10-21 08:12:50 +00:00
loadmodel->extradatasize = Hunk_End();
FS_FreeFile(buf);
2012-07-21 12:09:45 +00:00
return mod;
2010-10-21 08:12:50 +00:00
}
void
2012-07-21 12:09:45 +00:00
Mod_LoadLighting(lump_t *l)
{
2012-07-21 12:09:45 +00:00
if (!l->filelen)
{
loadmodel->lightdata = NULL;
return;
}
2012-07-21 12:09:45 +00:00
loadmodel->lightdata = Hunk_Alloc(l->filelen);
memcpy(loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
2010-10-21 08:12:50 +00:00
}
2010-10-21 08:12:50 +00:00
void
2012-07-21 12:09:45 +00:00
Mod_LoadVisibility(lump_t *l)
{
2010-10-21 08:12:50 +00:00
int i;
2012-07-21 12:09:45 +00:00
if (!l->filelen)
{
loadmodel->vis = NULL;
return;
}
2012-07-21 12:09:45 +00:00
loadmodel->vis = Hunk_Alloc(l->filelen);
memcpy(loadmodel->vis, mod_base + l->fileofs, l->filelen);
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
loadmodel->vis->numclusters = LittleLong(loadmodel->vis->numclusters);
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
for (i = 0; i < loadmodel->vis->numclusters; i++)
{
2012-07-21 12:09:45 +00:00
loadmodel->vis->bitofs[i][0] = LittleLong(loadmodel->vis->bitofs[i][0]);
loadmodel->vis->bitofs[i][1] = LittleLong(loadmodel->vis->bitofs[i][1]);
}
}
2010-10-21 08:12:50 +00:00
void
2012-07-21 12:09:45 +00:00
Mod_LoadVertexes(lump_t *l)
{
2012-07-21 12:09:45 +00:00
dvertex_t *in;
mvertex_t *out;
2010-10-21 08:12:50 +00:00
int i, count;
2012-07-21 12:09:45 +00:00
in = (void *)(mod_base + l->fileofs);
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
if (l->filelen % sizeof(*in))
2010-10-21 08:12:50 +00:00
{
VID_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",
2012-07-21 12:09:45 +00:00
loadmodel->name);
2010-10-21 08:12:50 +00:00
}
2012-07-21 12:09:45 +00:00
count = l->filelen / sizeof(*in);
out = Hunk_Alloc(count * sizeof(*out));
loadmodel->vertexes = out;
loadmodel->numvertexes = count;
2012-07-21 12:09:45 +00:00
for (i = 0; i < count; i++, in++, out++)
{
2012-07-21 12:09:45 +00:00
out->position[0] = LittleFloat(in->point[0]);
out->position[1] = LittleFloat(in->point[1]);
out->position[2] = LittleFloat(in->point[2]);
}
}
2010-10-21 08:12:50 +00:00
float
2012-07-21 12:09:45 +00:00
Mod_RadiusFromBounds(vec3_t mins, vec3_t maxs)
{
2010-10-21 08:12:50 +00:00
int i;
vec3_t corner;
2012-07-21 12:09:45 +00:00
for (i = 0; i < 3; i++)
{
2012-07-21 12:09:45 +00:00
corner[i] = fabs(mins[i]) > fabs(maxs[i]) ? fabs(mins[i]) : fabs(maxs[i]);
}
2012-07-21 12:09:45 +00:00
return VectorLength(corner);
}
2010-10-21 08:12:50 +00:00
void
2012-07-21 12:09:45 +00:00
Mod_LoadSubmodels(lump_t *l)
{
2012-07-21 12:09:45 +00:00
dmodel_t *in;
mmodel_t *out;
2010-10-21 08:12:50 +00:00
int i, j, count;
2012-07-21 12:09:45 +00:00
in = (void *)(mod_base + l->fileofs);
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
if (l->filelen % sizeof(*in))
2010-10-21 08:12:50 +00:00
{
VID_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",
2012-07-21 12:09:45 +00:00
loadmodel->name);
2010-10-21 08:12:50 +00:00
}
2012-07-21 12:09:45 +00:00
count = l->filelen / sizeof(*in);
out = Hunk_Alloc(count * sizeof(*out));
loadmodel->submodels = out;
loadmodel->numsubmodels = count;
2012-07-21 12:09:45 +00:00
for (i = 0; i < count; i++, in++, out++)
{
2012-07-21 12:09:45 +00:00
for (j = 0; j < 3; j++)
2012-04-29 13:57:33 +00:00
{
2010-10-21 08:12:50 +00:00
/* spread the mins / maxs by a pixel */
2012-07-21 12:09:45 +00:00
out->mins[j] = LittleFloat(in->mins[j]) - 1;
out->maxs[j] = LittleFloat(in->maxs[j]) + 1;
out->origin[j] = LittleFloat(in->origin[j]);
}
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
out->radius = Mod_RadiusFromBounds(out->mins, out->maxs);
out->headnode = LittleLong(in->headnode);
out->firstface = LittleLong(in->firstface);
out->numfaces = LittleLong(in->numfaces);
}
}
2010-10-21 08:12:50 +00:00
void
2012-07-21 12:09:45 +00:00
Mod_LoadEdges(lump_t *l)
{
dedge_t *in;
medge_t *out;
2010-10-21 08:12:50 +00:00
int i, count;
2012-07-21 12:09:45 +00:00
in = (void *)(mod_base + l->fileofs);
2012-07-21 12:09:45 +00:00
if (l->filelen % sizeof(*in))
2010-10-21 08:12:50 +00:00
{
VID_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",
2012-07-21 12:09:45 +00:00
loadmodel->name);
2010-10-21 08:12:50 +00:00
}
2012-07-21 12:09:45 +00:00
count = l->filelen / sizeof(*in);
out = Hunk_Alloc((count + 1) * sizeof(*out));
loadmodel->edges = out;
loadmodel->numedges = count;
2012-07-21 12:09:45 +00:00
for (i = 0; i < count; i++, in++, out++)
{
2012-07-21 12:09:45 +00:00
out->v[0] = (unsigned short)LittleShort(in->v[0]);
out->v[1] = (unsigned short)LittleShort(in->v[1]);
}
}
2010-10-21 08:12:50 +00:00
void
2012-07-21 12:09:45 +00:00
Mod_LoadTexinfo(lump_t *l)
{
texinfo_t *in;
mtexinfo_t *out, *step;
2010-10-21 08:12:50 +00:00
int i, j, count;
2012-07-21 12:09:45 +00:00
char name[MAX_QPATH];
2010-10-21 08:12:50 +00:00
int next;
2012-07-21 12:09:45 +00:00
in = (void *)(mod_base + l->fileofs);
2012-07-21 12:09:45 +00:00
if (l->filelen % sizeof(*in))
2010-10-21 08:12:50 +00:00
{
VID_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",
2012-07-21 12:09:45 +00:00
loadmodel->name);
2010-10-21 08:12:50 +00:00
}
2012-07-21 12:09:45 +00:00
count = l->filelen / sizeof(*in);
out = Hunk_Alloc(count * sizeof(*out));
loadmodel->texinfo = out;
loadmodel->numtexinfo = count;
2012-07-21 12:09:45 +00:00
for (i = 0; i < count; i++, in++, out++)
{
for (j = 0; j < 4; j++)
2010-10-21 08:12:50 +00:00
{
2012-07-21 12:09:45 +00:00
out->vecs[0][j] = LittleFloat(in->vecs[0][j]);
out->vecs[1][j] = LittleFloat(in->vecs[1][j]);
2010-10-21 08:12:50 +00:00
}
2012-07-21 12:09:45 +00:00
out->flags = LittleLong(in->flags);
next = LittleLong(in->nexttexinfo);
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
if (next > 0)
2010-10-21 08:12:50 +00:00
{
out->next = loadmodel->texinfo + next;
2010-10-21 08:12:50 +00:00
}
else
2010-10-21 08:12:50 +00:00
{
out->next = NULL;
}
2012-07-21 12:09:45 +00:00
Com_sprintf(name, sizeof(name), "textures/%s.wal", in->texture);
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
out->image = R_FindImage(name, it_wall);
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
if (!out->image)
{
VID_Printf(PRINT_ALL, "Couldn't load %s\n", name);
out->image = r_notexture;
}
}
2010-10-21 08:12:50 +00:00
/* count animation frames */
2012-07-21 12:09:45 +00:00
for (i = 0; i < count; i++)
{
2012-07-21 12:09:45 +00:00
out = &loadmodel->texinfo[i];
out->numframes = 1;
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
for (step = out->next; step && step != out; step = step->next)
2010-10-21 08:12:50 +00:00
{
out->numframes++;
2010-10-21 08:12:50 +00:00
}
}
}
/*
2010-10-21 08:12:50 +00:00
* Fills in s->texturemins[] and s->extents[]
*/
void
2012-07-21 12:09:45 +00:00
Mod_CalcSurfaceExtents(msurface_t *s)
{
2012-07-21 12:09:45 +00:00
float mins[2], maxs[2], val;
2010-10-21 08:12:50 +00:00
int i, j, e;
2012-07-21 12:09:45 +00:00
mvertex_t *v;
mtexinfo_t *tex;
int bmins[2], bmaxs[2];
2012-07-21 12:09:45 +00:00
mins[0] = mins[1] = 999999;
maxs[0] = maxs[1] = -99999;
tex = s->texinfo;
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
for (i = 0; i < s->numedges; i++)
{
2012-07-21 12:09:45 +00:00
e = loadmodel->surfedges[s->firstedge + i];
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
if (e >= 0)
2010-10-21 08:12:50 +00:00
{
2012-07-21 12:09:45 +00:00
v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
2010-10-21 08:12:50 +00:00
}
else
{
2012-07-21 12:09:45 +00:00
v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
}
2012-07-21 12:09:45 +00:00
for (j = 0; j < 2; j++)
2010-10-21 08:12:50 +00:00
{
2012-07-21 12:09:45 +00:00
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];
2012-07-21 12:09:45 +00:00
if (val < mins[j])
2010-10-21 08:12:50 +00:00
{
2012-07-21 12:09:45 +00:00
mins[j] = val;
2010-10-21 08:12:50 +00:00
}
2012-07-21 12:09:45 +00:00
if (val > maxs[j])
2010-10-21 08:12:50 +00:00
{
2012-07-21 12:09:45 +00:00
maxs[j] = val;
2010-10-21 08:12:50 +00:00
}
}
}
2012-07-21 12:09:45 +00:00
for (i = 0; i < 2; i++)
2010-10-21 08:12:50 +00:00
{
2012-07-21 12:09:45 +00:00
bmins[i] = floor(mins[i] / 16);
bmaxs[i] = ceil(maxs[i] / 16);
2012-07-21 12:09:45 +00:00
s->texturemins[i] = bmins[i] * 16;
s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
2010-10-21 08:12:50 +00:00
}
}
2010-10-21 08:12:50 +00:00
void
2012-07-21 12:09:45 +00:00
Mod_LoadFaces(lump_t *l)
{
2012-07-21 12:09:45 +00:00
dface_t *in;
msurface_t *out;
2010-10-21 08:12:50 +00:00
int i, count, surfnum;
int planenum, side;
int ti;
2012-07-21 12:09:45 +00:00
in = (void *)(mod_base + l->fileofs);
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
if (l->filelen % sizeof(*in))
2010-10-21 08:12:50 +00:00
{
VID_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",
2012-07-21 12:09:45 +00:00
loadmodel->name);
2010-10-21 08:12:50 +00:00
}
2012-07-21 12:09:45 +00:00
count = l->filelen / sizeof(*in);
out = Hunk_Alloc(count * sizeof(*out));
loadmodel->surfaces = out;
loadmodel->numsurfaces = count;
currentmodel = loadmodel;
2012-07-21 12:09:45 +00:00
LM_BeginBuildingLightmaps(loadmodel);
2012-07-21 12:09:45 +00:00
for (surfnum = 0; surfnum < count; surfnum++, in++, out++)
{
2012-07-21 12:09:45 +00:00
out->firstedge = LittleLong(in->firstedge);
out->numedges = LittleShort(in->numedges);
out->flags = 0;
out->polys = NULL;
2012-07-21 12:09:45 +00:00
planenum = LittleShort(in->planenum);
side = LittleShort(in->side);
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
if (side)
2010-10-21 08:12:50 +00:00
{
out->flags |= SURF_PLANEBACK;
}
out->plane = loadmodel->planes + planenum;
2012-07-21 12:09:45 +00:00
ti = LittleShort(in->texinfo);
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
if ((ti < 0) || (ti >= loadmodel->numtexinfo))
2010-10-21 08:12:50 +00:00
{
VID_Error(ERR_DROP, "MOD_LoadBmodel: bad texinfo number");
2010-10-21 08:12:50 +00:00
}
out->texinfo = loadmodel->texinfo + ti;
2012-07-21 12:09:45 +00:00
Mod_CalcSurfaceExtents(out);
2010-10-21 08:12:50 +00:00
/* lighting info */
2012-07-21 12:09:45 +00:00
for (i = 0; i < MAXLIGHTMAPS; i++)
2010-10-21 08:12:50 +00:00
{
2012-07-21 12:09:45 +00:00
out->styles[i] = in->styles[i];
2010-10-21 08:12:50 +00:00
}
2012-07-21 12:09:45 +00:00
i = LittleLong(in->lightofs);
2012-07-21 12:09:45 +00:00
if (i == -1)
2010-10-21 08:12:50 +00:00
{
out->samples = NULL;
2010-10-21 08:12:50 +00:00
}
else
2010-10-21 08:12:50 +00:00
{
out->samples = loadmodel->lightdata + i;
2010-10-21 08:12:50 +00:00
}
/* set the drawing flags */
2012-07-21 12:09:45 +00:00
if (out->texinfo->flags & SURF_WARP)
{
out->flags |= SURF_DRAWTURB;
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
for (i = 0; i < 2; i++)
{
2012-07-21 12:09:45 +00:00
out->extents[i] = 16384;
out->texturemins[i] = -8192;
}
2012-07-21 12:09:45 +00:00
R_SubdivideSurface(out); /* cut up polygon for warps */
2010-10-21 08:12:50 +00:00
}
2010-10-21 08:12:50 +00:00
/* create lightmaps and polygons */
2012-07-21 12:09:45 +00:00
if (!(out->texinfo->flags &
(SURF_SKY | SURF_TRANS33 | SURF_TRANS66 | SURF_WARP)))
2010-10-21 08:12:50 +00:00
{
2012-07-21 12:09:45 +00:00
LM_CreateSurfaceLightmap(out);
2010-10-21 08:12:50 +00:00
}
2012-07-21 12:09:45 +00:00
if (!(out->texinfo->flags & SURF_WARP))
2010-10-21 08:12:50 +00:00
{
2012-07-21 12:09:45 +00:00
LM_BuildPolygonFromSurface(out);
2010-10-21 08:12:50 +00:00
}
}
LM_EndBuildingLightmaps();
}
2010-10-21 08:12:50 +00:00
void
2012-07-21 12:09:45 +00:00
Mod_SetParent(mnode_t *node, mnode_t *parent)
{
node->parent = parent;
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
if (node->contents != -1)
2010-10-21 08:12:50 +00:00
{
return;
2010-10-21 08:12:50 +00:00
}
2012-07-21 12:09:45 +00:00
Mod_SetParent(node->children[0], node);
Mod_SetParent(node->children[1], node);
}
2010-10-21 08:12:50 +00:00
void
2012-07-21 12:09:45 +00:00
Mod_LoadNodes(lump_t *l)
{
2010-10-21 08:12:50 +00:00
int i, j, count, p;
2012-07-21 12:09:45 +00:00
dnode_t *in;
mnode_t *out;
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
in = (void *)(mod_base + l->fileofs);
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
if (l->filelen % sizeof(*in))
2010-10-21 08:12:50 +00:00
{
VID_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",
2012-07-21 12:09:45 +00:00
loadmodel->name);
2010-10-21 08:12:50 +00:00
}
2012-07-21 12:09:45 +00:00
count = l->filelen / sizeof(*in);
out = Hunk_Alloc(count * sizeof(*out));
loadmodel->nodes = out;
loadmodel->numnodes = count;
2012-07-21 12:09:45 +00:00
for (i = 0; i < count; i++, in++, out++)
{
2012-07-21 12:09:45 +00:00
for (j = 0; j < 3; j++)
{
2012-07-21 12:09:45 +00:00
out->minmaxs[j] = LittleShort(in->mins[j]);
out->minmaxs[3 + j] = LittleShort(in->maxs[j]);
}
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
p = LittleLong(in->planenum);
out->plane = loadmodel->planes + p;
2012-07-21 12:09:45 +00:00
out->firstsurface = LittleShort(in->firstface);
out->numsurfaces = LittleShort(in->numfaces);
2010-10-21 08:12:50 +00:00
out->contents = -1; /* differentiate from leafs */
2012-07-21 12:09:45 +00:00
for (j = 0; j < 2; j++)
{
2012-07-21 12:09:45 +00:00
p = LittleLong(in->children[j]);
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
if (p >= 0)
2010-10-21 08:12:50 +00:00
{
2012-07-21 12:09:45 +00:00
out->children[j] = loadmodel->nodes + p;
2010-10-21 08:12:50 +00:00
}
else
2010-10-21 08:12:50 +00:00
{
2012-07-21 12:09:45 +00:00
out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
2010-10-21 08:12:50 +00:00
}
}
}
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
Mod_SetParent(loadmodel->nodes, NULL); /* sets nodes and leafs */
}
2010-10-21 08:12:50 +00:00
void
2012-07-21 12:09:45 +00:00
Mod_LoadLeafs(lump_t *l)
{
2012-07-21 12:09:45 +00:00
dleaf_t *in;
mleaf_t *out;
2010-10-21 08:12:50 +00:00
int i, j, count, p;
2012-07-21 12:09:45 +00:00
in = (void *)(mod_base + l->fileofs);
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
if (l->filelen % sizeof(*in))
2010-10-21 08:12:50 +00:00
{
VID_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",
2012-07-21 12:09:45 +00:00
loadmodel->name);
2010-10-21 08:12:50 +00:00
}
2012-07-21 12:09:45 +00:00
count = l->filelen / sizeof(*in);
out = Hunk_Alloc(count * sizeof(*out));
loadmodel->leafs = out;
loadmodel->numleafs = count;
2012-07-21 12:09:45 +00:00
for (i = 0; i < count; i++, in++, out++)
{
2012-07-21 12:09:45 +00:00
for (j = 0; j < 3; j++)
{
2012-07-21 12:09:45 +00:00
out->minmaxs[j] = LittleShort(in->mins[j]);
out->minmaxs[3 + j] = LittleShort(in->maxs[j]);
}
2012-07-21 12:09:45 +00:00
p = LittleLong(in->contents);
out->contents = p;
2012-07-21 12:09:45 +00:00
out->cluster = LittleShort(in->cluster);
out->area = LittleShort(in->area);
out->firstmarksurface = loadmodel->marksurfaces +
2012-07-21 12:09:45 +00:00
LittleShort(in->firstleafface);
out->nummarksurfaces = LittleShort(in->numleaffaces);
2010-10-21 08:12:50 +00:00
}
}
2010-10-21 08:12:50 +00:00
void
2012-07-21 12:09:45 +00:00
Mod_LoadMarksurfaces(lump_t *l)
2010-10-21 08:12:50 +00:00
{
int i, j, count;
2012-07-21 12:09:45 +00:00
short *in;
msurface_t **out;
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
in = (void *)(mod_base + l->fileofs);
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
if (l->filelen % sizeof(*in))
2010-10-21 08:12:50 +00:00
{
VID_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",
2012-07-21 12:09:45 +00:00
loadmodel->name);
2010-10-21 08:12:50 +00:00
}
2012-07-21 12:09:45 +00:00
count = l->filelen / sizeof(*in);
out = Hunk_Alloc(count * sizeof(*out));
loadmodel->marksurfaces = out;
loadmodel->nummarksurfaces = count;
2012-07-21 12:09:45 +00:00
for (i = 0; i < count; i++)
{
2012-07-21 12:09:45 +00:00
j = LittleShort(in[i]);
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
if ((j < 0) || (j >= loadmodel->numsurfaces))
2010-10-21 08:12:50 +00:00
{
VID_Error(ERR_DROP, "Mod_ParseMarksurfaces: bad surface number");
2010-10-21 08:12:50 +00:00
}
2012-07-21 12:09:45 +00:00
out[i] = loadmodel->surfaces + j;
}
}
2010-10-21 08:12:50 +00:00
void
2012-07-21 12:09:45 +00:00
Mod_LoadSurfedges(lump_t *l)
2010-10-21 08:12:50 +00:00
{
int i, count;
2012-07-21 12:09:45 +00:00
int *in, *out;
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
in = (void *)(mod_base + l->fileofs);
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
if (l->filelen % sizeof(*in))
2010-10-21 08:12:50 +00:00
{
VID_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",
2012-07-21 12:09:45 +00:00
loadmodel->name);
2010-10-21 08:12:50 +00:00
}
2012-07-21 12:09:45 +00:00
count = l->filelen / sizeof(*in);
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
if ((count < 1) || (count >= MAX_MAP_SURFEDGES))
2010-10-21 08:12:50 +00:00
{
VID_Error(ERR_DROP, "MOD_LoadBmodel: bad surfedges count in %s: %i",
2012-07-21 12:09:45 +00:00
loadmodel->name, count);
2010-10-21 08:12:50 +00:00
}
2012-07-21 12:09:45 +00:00
out = Hunk_Alloc(count * sizeof(*out));
loadmodel->surfedges = out;
loadmodel->numsurfedges = count;
2012-07-21 12:09:45 +00:00
for (i = 0; i < count; i++)
2010-10-21 08:12:50 +00:00
{
2012-07-21 12:09:45 +00:00
out[i] = LittleLong(in[i]);
2010-10-21 08:12:50 +00:00
}
}
2010-10-21 08:12:50 +00:00
void
2012-07-21 12:09:45 +00:00
Mod_LoadPlanes(lump_t *l)
{
2010-10-21 08:12:50 +00:00
int i, j;
2012-07-21 12:09:45 +00:00
cplane_t *out;
dplane_t *in;
2010-10-21 08:12:50 +00:00
int count;
int bits;
2012-07-21 12:09:45 +00:00
in = (void *)(mod_base + l->fileofs);
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
if (l->filelen % sizeof(*in))
2010-10-21 08:12:50 +00:00
{
VID_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",
2012-07-21 12:09:45 +00:00
loadmodel->name);
2010-10-21 08:12:50 +00:00
}
2012-07-21 12:09:45 +00:00
count = l->filelen / sizeof(*in);
out = Hunk_Alloc(count * 2 * sizeof(*out));
2010-10-21 08:12:50 +00:00
loadmodel->planes = out;
loadmodel->numplanes = count;
2012-07-21 12:09:45 +00:00
for (i = 0; i < count; i++, in++, out++)
{
bits = 0;
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
for (j = 0; j < 3; j++)
{
2012-07-21 12:09:45 +00:00
out->normal[j] = LittleFloat(in->normal[j]);
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
if (out->normal[j] < 0)
2010-10-21 08:12:50 +00:00
{
bits |= 1 << j;
}
}
2012-07-21 12:09:45 +00:00
out->dist = LittleFloat(in->dist);
out->type = LittleLong(in->type);
out->signbits = bits;
}
}
2010-10-21 08:12:50 +00:00
void
2012-07-21 12:09:45 +00:00
Mod_LoadBrushModel(model_t *mod, void *buffer)
{
2010-10-21 08:12:50 +00:00
int i;
2012-07-21 12:09:45 +00:00
dheader_t *header;
mmodel_t *bm;
2010-10-21 08:12:50 +00:00
loadmodel->type = mod_brush;
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
if (loadmodel != mod_known)
2010-10-21 08:12:50 +00:00
{
VID_Error(ERR_DROP, "Loaded a brush model after the world");
2010-10-21 08:12:50 +00:00
}
2012-07-21 12:09:45 +00:00
header = (dheader_t *)buffer;
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
i = LittleLong(header->version);
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
if (i != BSPVERSION)
2010-10-21 08:12:50 +00:00
{
VID_Error(ERR_DROP, "Mod_LoadBrushModel: %s has wrong version number (%i should be %i)",
2012-07-21 12:09:45 +00:00
mod->name, i, BSPVERSION);
2010-10-21 08:12:50 +00:00
}
/* swap all the lumps */
2012-07-21 12:09:45 +00:00
mod_base = (byte *)header;
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
for (i = 0; i < sizeof(dheader_t) / 4; i++)
2010-10-21 08:12:50 +00:00
{
2012-07-21 12:09:45 +00:00
((int *)header)[i] = LittleLong(((int *)header)[i]);
2010-10-21 08:12:50 +00:00
}
/* load into heap */
2012-07-21 12:09:45 +00:00
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]);
2010-10-21 08:12:50 +00:00
mod->numframes = 2; /* regular and alternate animation */
/* set up the submodels */
2012-07-21 12:09:45 +00:00
for (i = 0; i < mod->numsubmodels; i++)
2010-10-21 08:12:50 +00:00
{
model_t *starmod;
2012-07-21 12:09:45 +00:00
bm = &mod->submodels[i];
starmod = &mod_inline[i];
*starmod = *loadmodel;
2010-10-21 08:12:50 +00:00
starmod->firstmodelsurface = bm->firstface;
starmod->nummodelsurfaces = bm->numfaces;
starmod->firstnode = bm->headnode;
2012-07-21 12:09:45 +00:00
if (starmod->firstnode >= loadmodel->numnodes)
2010-10-21 08:12:50 +00:00
{
VID_Error(ERR_DROP, "Inline model %i has bad firstnode", i);
2010-10-21 08:12:50 +00:00
}
2012-07-21 12:09:45 +00:00
VectorCopy(bm->maxs, starmod->maxs);
VectorCopy(bm->mins, starmod->mins);
starmod->radius = bm->radius;
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
if (i == 0)
2010-10-21 08:12:50 +00:00
{
*loadmodel = *starmod;
2010-10-21 08:12:50 +00:00
}
starmod->numleafs = bm->visleafs;
}
}
void
2012-07-21 12:09:45 +00:00
Mod_Free(model_t *mod)
{
2012-07-21 12:09:45 +00:00
Hunk_Free(mod->extradata);
memset(mod, 0, sizeof(*mod));
}
void
2012-07-21 12:09:45 +00:00
Mod_FreeAll(void)
{
int i;
2012-07-21 12:09:45 +00:00
for (i = 0; i < mod_numknown; i++)
{
2012-07-21 12:09:45 +00:00
if (mod_known[i].extradatasize)
{
2012-07-21 12:09:45 +00:00
Mod_Free(&mod_known[i]);
}
}
}
2012-04-29 13:57:33 +00:00
/*
2010-10-21 08:12:50 +00:00
* Specifies the model that will be used as the world
*/
void
2012-07-21 12:09:45 +00:00
R_BeginRegistration(char *model)
{
2012-07-21 12:09:45 +00:00
char fullname[MAX_QPATH];
cvar_t *flushmap;
registration_sequence++;
2010-10-21 08:12:50 +00:00
r_oldviewcluster = -1; /* force markleafs */
2012-07-21 12:09:45 +00:00
Com_sprintf(fullname, sizeof(fullname), "maps/%s.bsp", model);
2010-10-21 08:12:50 +00:00
/* explicitly free the old map if different
this guarantees that mod_known[0] is the
2012-07-21 12:09:45 +00:00
world map */
flushmap = Cvar_Get("flushmap", "0", 0);
2012-07-21 12:09:45 +00:00
if (strcmp(mod_known[0].name, fullname) || flushmap->value)
2010-10-21 08:12:50 +00:00
{
2012-07-21 12:09:45 +00:00
Mod_Free(&mod_known[0]);
2010-10-21 08:12:50 +00:00
}
2012-07-21 12:09:45 +00:00
r_worldmodel = Mod_ForName(fullname, true);
2010-10-21 08:12:50 +00:00
r_viewcluster = -1;
}
2010-10-21 08:12:50 +00:00
struct model_s *
2012-07-21 12:09:45 +00:00
R_RegisterModel(char *name)
{
2010-10-21 08:12:50 +00:00
model_t *mod;
int i;
2012-07-21 12:09:45 +00:00
dsprite_t *sprout;
dmdl_t *pheader;
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
mod = Mod_ForName(name, false);
2012-07-21 12:09:45 +00:00
if (mod)
{
mod->registration_sequence = registration_sequence;
2010-10-21 08:12:50 +00:00
/* register any images used by the models */
2012-07-21 12:09:45 +00:00
if (mod->type == mod_sprite)
{
2012-07-21 12:09:45 +00:00
sprout = (dsprite_t *)mod->extradata;
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
for (i = 0; i < sprout->numframes; i++)
2010-10-21 08:12:50 +00:00
{
2012-07-21 12:09:45 +00:00
mod->skins[i] = R_FindImage(sprout->frames[i].name, it_sprite);
2010-10-21 08:12:50 +00:00
}
}
2012-07-21 12:09:45 +00:00
else if (mod->type == mod_alias)
{
2012-07-21 12:09:45 +00:00
pheader = (dmdl_t *)mod->extradata;
2010-10-21 08:12:50 +00:00
2012-07-21 12:09:45 +00:00
for (i = 0; i < pheader->num_skins; i++)
2010-10-21 08:12:50 +00:00
{
2012-07-21 12:09:45 +00:00
mod->skins[i] = R_FindImage((char *)pheader + pheader->ofs_skins +
i * MAX_SKINNAME, it_skin);
2010-10-21 08:12:50 +00:00
}
mod->numframes = pheader->num_frames;
}
2012-07-21 12:09:45 +00:00
else if (mod->type == mod_brush)
{
2012-07-21 12:09:45 +00:00
for (i = 0; i < mod->numtexinfo; i++)
2010-10-21 08:12:50 +00:00
{
2012-07-21 12:09:45 +00:00
mod->texinfo[i].image->registration_sequence =
registration_sequence;
2010-10-21 08:12:50 +00:00
}
}
}
2012-07-21 12:09:45 +00:00
return mod;
2010-10-21 08:12:50 +00:00
}
2010-10-21 08:12:50 +00:00
void
2012-07-21 12:09:45 +00:00
R_EndRegistration(void)
{
2010-10-21 08:12:50 +00:00
int i;
model_t *mod;
2012-07-21 12:09:45 +00:00
for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++)
{
2012-07-21 12:09:45 +00:00
if (!mod->name[0])
2010-10-21 08:12:50 +00:00
{
continue;
2010-10-21 08:12:50 +00:00
}
2012-07-21 12:09:45 +00:00
if (mod->registration_sequence != registration_sequence)
2012-04-29 13:57:33 +00:00
{
2012-07-21 12:09:45 +00:00
/* don't need this model */
Mod_Free(mod);
}
}
R_FreeUnusedImages();
}
2012-07-21 12:09:45 +00:00