Home | History | Annotate | Download | only in WinQuake
      1 /*
      2 Copyright (C) 1996-1997 Id Software, Inc.
      3 
      4 This program is free software; you can redistribute it and/or
      5 modify it under the terms of the GNU General Public License
      6 as published by the Free Software Foundation; either version 2
      7 of the License, or (at your option) any later version.
      8 
      9 This program is distributed in the hope that it will be useful,
     10 but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     12 
     13 See the GNU General Public License for more details.
     14 
     15 You should have received a copy of the GNU General Public License
     16 along with this program; if not, write to the Free Software
     17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     18 
     19 */
     20 // models.c -- model loading and caching
     21 
     22 // models are the only shared resource between a client and server running
     23 // on the same machine.
     24 
     25 #include "quakedef.h"
     26 #include "r_local.h"
     27 
     28 model_t	*loadmodel;
     29 char	loadname[32];	// for hunk tags
     30 
     31 void Mod_LoadSpriteModel (model_t *mod, void *buffer);
     32 void Mod_LoadBrushModel (model_t *mod, void *buffer);
     33 void Mod_LoadAliasModel (model_t *mod, void *buffer);
     34 model_t *Mod_LoadModel (model_t *mod, qboolean crash);
     35 
     36 byte	mod_novis[MAX_MAP_LEAFS/8];
     37 
     38 #define	MAX_MOD_KNOWN	256
     39 model_t	mod_known[MAX_MOD_KNOWN];
     40 int		mod_numknown;
     41 
     42 // values for model_t's needload
     43 #define NL_PRESENT		0
     44 #define NL_NEEDS_LOADED	1
     45 #define NL_UNREFERENCED	2
     46 
     47 /*
     48 ===============
     49 Mod_Init
     50 ===============
     51 */
     52 void Mod_Init (void)
     53 {
     54 	memset (mod_novis, 0xff, sizeof(mod_novis));
     55 }
     56 
     57 /*
     58 ===============
     59 Mod_Extradata
     60 
     61 Caches the data if needed
     62 ===============
     63 */
     64 void *Mod_Extradata (model_t *mod)
     65 {
     66 	void	*r;
     67 
     68 	r = Cache_Check (&mod->cache);
     69 	if (r)
     70 		return r;
     71 
     72 	Mod_LoadModel (mod, true);
     73 
     74 	if (!mod->cache.data)
     75 		Sys_Error ("Mod_Extradata: caching failed");
     76 	return mod->cache.data;
     77 }
     78 
     79 /*
     80 ===============
     81 Mod_PointInLeaf
     82 ===============
     83 */
     84 mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
     85 {
     86 	mnode_t		*node;
     87 	float		d;
     88 	mplane_t	*plane;
     89 
     90 	if (!model || !model->nodes)
     91 		Sys_Error ("Mod_PointInLeaf: bad model");
     92 
     93 	node = model->nodes;
     94 	while (1)
     95 	{
     96 		if (node->contents < 0)
     97 			return (mleaf_t *)node;
     98 		plane = node->plane;
     99 		d = DotProduct (p,plane->normal) - plane->dist;
    100 		if (d > 0)
    101 			node = node->children[0];
    102 		else
    103 			node = node->children[1];
    104 	}
    105 
    106 	return NULL;	// never reached
    107 }
    108 
    109 
    110 /*
    111 ===================
    112 Mod_DecompressVis
    113 ===================
    114 */
    115 byte *Mod_DecompressVis (byte *in, model_t *model)
    116 {
    117 	static byte	decompressed[MAX_MAP_LEAFS/8];
    118 	int		c;
    119 	byte	*out;
    120 	int		row;
    121 
    122 	row = (model->numleafs+7)>>3;
    123 	out = decompressed;
    124 
    125 	if (!in)
    126 	{	// no vis info, so make all visible
    127 		while (row)
    128 		{
    129 			*out++ = 0xff;
    130 			row--;
    131 		}
    132 		return decompressed;
    133 	}
    134 
    135 	do
    136 	{
    137 		if (*in)
    138 		{
    139 			*out++ = *in++;
    140 			continue;
    141 		}
    142 
    143 		c = in[1];
    144 		in += 2;
    145 		while (c)
    146 		{
    147 			*out++ = 0;
    148 			c--;
    149 		}
    150 	} while (out - decompressed < row);
    151 
    152 	return decompressed;
    153 }
    154 
    155 byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model)
    156 {
    157 	if (leaf == model->leafs)
    158 		return mod_novis;
    159 	return Mod_DecompressVis (leaf->compressed_vis, model);
    160 }
    161 
    162 /*
    163 ===================
    164 Mod_ClearAll
    165 ===================
    166 */
    167 void Mod_ClearAll (void)
    168 {
    169 	int		i;
    170 	model_t	*mod;
    171 
    172 
    173 	for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++) {
    174 		mod->needload = NL_UNREFERENCED;
    175 //FIX FOR CACHE_ALLOC ERRORS:
    176 		if (mod->type == mod_sprite) mod->cache.data = NULL;
    177 	}
    178 }
    179 
    180 /*
    181 ==================
    182 Mod_FindName
    183 
    184 ==================
    185 */
    186 model_t *Mod_FindName (char *name)
    187 {
    188 	int		i;
    189 	model_t	*mod;
    190 	model_t	*avail = NULL;
    191 
    192 	if (!name[0])
    193 		Sys_Error ("Mod_ForName: NULL name");
    194 
    195 //
    196 // search the currently loaded models
    197 //
    198 	for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
    199 	{
    200 		if (!strcmp (mod->name, name) )
    201 			break;
    202 		if (mod->needload == NL_UNREFERENCED)
    203 			if (!avail || mod->type != mod_alias)
    204 				avail = mod;
    205 	}
    206 
    207 	if (i == mod_numknown)
    208 	{
    209 		if (mod_numknown == MAX_MOD_KNOWN)
    210 		{
    211 			if (avail)
    212 			{
    213 				mod = avail;
    214 				if (mod->type == mod_alias)
    215 					if (Cache_Check (&mod->cache))
    216 						Cache_Free (&mod->cache);
    217 			}
    218 			else
    219 				Sys_Error ("mod_numknown == MAX_MOD_KNOWN");
    220 		}
    221 		else
    222 			mod_numknown++;
    223 		strcpy (mod->name, name);
    224 		mod->needload = NL_NEEDS_LOADED;
    225 	}
    226 
    227 	return mod;
    228 }
    229 
    230 /*
    231 ==================
    232 Mod_TouchModel
    233 
    234 ==================
    235 */
    236 void Mod_TouchModel (char *name)
    237 {
    238 	model_t	*mod;
    239 
    240 	mod = Mod_FindName (name);
    241 
    242 	if (mod->needload == NL_PRESENT)
    243 	{
    244 		if (mod->type == mod_alias)
    245 			Cache_Check (&mod->cache);
    246 	}
    247 }
    248 
    249 /*
    250 ==================
    251 Mod_LoadModel
    252 
    253 Loads a model into the cache
    254 ==================
    255 */
    256 model_t *Mod_LoadModel (model_t *mod, qboolean crash)
    257 {
    258 	unsigned *buf;
    259 	byte	stackbuf[1024];		// avoid dirtying the cache heap
    260 
    261 	if (mod->type == mod_alias)
    262 	{
    263 		if (Cache_Check (&mod->cache))
    264 		{
    265 			mod->needload = NL_PRESENT;
    266 			return mod;
    267 		}
    268 	}
    269 	else
    270 	{
    271 		if (mod->needload == NL_PRESENT)
    272 			return mod;
    273 	}
    274 
    275 //
    276 // because the world is so huge, load it one piece at a time
    277 //
    278 
    279 //
    280 // load the file
    281 //
    282 	buf = (unsigned *)COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf));
    283 	if (!buf)
    284 	{
    285 		if (crash)
    286 			Sys_Error ("Mod_NumForName: %s not found", mod->name);
    287 		return NULL;
    288 	}
    289 
    290 //
    291 // allocate a new model
    292 //
    293 	COM_FileBase (mod->name, loadname, sizeof(loadname));
    294 
    295 	loadmodel = mod;
    296 
    297 //
    298 // fill it in
    299 //
    300 
    301 // call the apropriate loader
    302 	mod->needload = NL_PRESENT;
    303 
    304 	switch (LittleLong(*(unsigned *)buf))
    305 	{
    306 	case IDPOLYHEADER:
    307 		Mod_LoadAliasModel (mod, buf);
    308 		break;
    309 
    310 	case IDSPRITEHEADER:
    311 		Mod_LoadSpriteModel (mod, buf);
    312 		break;
    313 
    314 	default:
    315 		Mod_LoadBrushModel (mod, buf);
    316 		break;
    317 	}
    318 
    319 	return mod;
    320 }
    321 
    322 /*
    323 ==================
    324 Mod_ForName
    325 
    326 Loads in a model for the given name
    327 ==================
    328 */
    329 model_t *Mod_ForName (char *name, qboolean crash)
    330 {
    331 	model_t	*mod;
    332 
    333 	mod = Mod_FindName (name);
    334 
    335 	return Mod_LoadModel (mod, crash);
    336 }
    337 
    338 
    339 /*
    340 ===============================================================================
    341 
    342 					BRUSHMODEL LOADING
    343 
    344 ===============================================================================
    345 */
    346 
    347 byte	*mod_base;
    348 
    349 
    350 /*
    351 =================
    352 Mod_LoadTextures
    353 =================
    354 */
    355 void Mod_LoadTextures (lump_t *l)
    356 {
    357 	int		i, j, pixels, num, max, altmax;
    358 	miptex_t	*mt;
    359 	texture_t	*tx, *tx2;
    360 	texture_t	*anims[10];
    361 	texture_t	*altanims[10];
    362 	dmiptexlump_t *m;
    363 
    364 	if (!l->filelen)
    365 	{
    366 		loadmodel->textures = NULL;
    367 		return;
    368 	}
    369 	m = (dmiptexlump_t *)(mod_base + l->fileofs);
    370 
    371 	m->nummiptex = LittleLong (m->nummiptex);
    372 
    373 	loadmodel->numtextures = m->nummiptex;
    374 	loadmodel->textures = Hunk_AllocName (m->nummiptex * sizeof(*loadmodel->textures) , loadname);
    375 
    376 	for (i=0 ; i<m->nummiptex ; i++)
    377 	{
    378 		m->dataofs[i] = LittleLong(m->dataofs[i]);
    379 		if (m->dataofs[i] == -1)
    380 			continue;
    381 		mt = (miptex_t *)((byte *)m + m->dataofs[i]);
    382 		mt->width = LittleLong (mt->width);
    383 		mt->height = LittleLong (mt->height);
    384 		for (j=0 ; j<MIPLEVELS ; j++)
    385 			mt->offsets[j] = LittleLong (mt->offsets[j]);
    386 
    387 		if ( (mt->width & 15) || (mt->height & 15) )
    388 			Sys_Error ("Texture %s is not 16 aligned", mt->name);
    389 		pixels = mt->width*mt->height/64*85;
    390 		tx = Hunk_AllocName (sizeof(texture_t) +pixels, loadname );
    391 		loadmodel->textures[i] = tx;
    392 
    393 		memcpy (tx->name, mt->name, sizeof(tx->name));
    394 		tx->width = mt->width;
    395 		tx->height = mt->height;
    396 		for (j=0 ; j<MIPLEVELS ; j++)
    397 			tx->offsets[j] = mt->offsets[j] + sizeof(texture_t) - sizeof(miptex_t);
    398 		// the pixels immediately follow the structures
    399 		memcpy ( tx+1, mt+1, pixels);
    400 
    401 		if (!Q_strncmp(mt->name,"sky",3))
    402 			R_InitSky (tx);
    403 	}
    404 
    405 //
    406 // sequence the animations
    407 //
    408 	for (i=0 ; i<m->nummiptex ; i++)
    409 	{
    410 		tx = loadmodel->textures[i];
    411 		if (!tx || tx->name[0] != '+')
    412 			continue;
    413 		if (tx->anim_next)
    414 			continue;	// allready sequenced
    415 
    416 	// find the number of frames in the animation
    417 		memset (anims, 0, sizeof(anims));
    418 		memset (altanims, 0, sizeof(altanims));
    419 
    420 		max = tx->name[1];
    421 		altmax = 0;
    422 		if (max >= 'a' && max <= 'z')
    423 			max -= 'a' - 'A';
    424 		if (max >= '0' && max <= '9')
    425 		{
    426 			max -= '0';
    427 			altmax = 0;
    428 			anims[max] = tx;
    429 			max++;
    430 		}
    431 		else if (max >= 'A' && max <= 'J')
    432 		{
    433 			altmax = max - 'A';
    434 			max = 0;
    435 			altanims[altmax] = tx;
    436 			altmax++;
    437 		}
    438 		else
    439 			Sys_Error ("Bad animating texture %s", tx->name);
    440 
    441 		for (j=i+1 ; j<m->nummiptex ; j++)
    442 		{
    443 			tx2 = loadmodel->textures[j];
    444 			if (!tx2 || tx2->name[0] != '+')
    445 				continue;
    446 			if (strcmp (tx2->name+2, tx->name+2))
    447 				continue;
    448 
    449 			num = tx2->name[1];
    450 			if (num >= 'a' && num <= 'z')
    451 				num -= 'a' - 'A';
    452 			if (num >= '0' && num <= '9')
    453 			{
    454 				num -= '0';
    455 				anims[num] = tx2;
    456 				if (num+1 > max)
    457 					max = num + 1;
    458 			}
    459 			else if (num >= 'A' && num <= 'J')
    460 			{
    461 				num = num - 'A';
    462 				altanims[num] = tx2;
    463 				if (num+1 > altmax)
    464 					altmax = num+1;
    465 			}
    466 			else
    467 				Sys_Error ("Bad animating texture %s", tx->name);
    468 		}
    469 
    470 #define	ANIM_CYCLE	2
    471 	// link them all together
    472 		for (j=0 ; j<max ; j++)
    473 		{
    474 			tx2 = anims[j];
    475 			if (!tx2)
    476 				Sys_Error ("Missing frame %i of %s",j, tx->name);
    477 			tx2->anim_total = max * ANIM_CYCLE;
    478 			tx2->anim_min = j * ANIM_CYCLE;
    479 			tx2->anim_max = (j+1) * ANIM_CYCLE;
    480 			tx2->anim_next = anims[ (j+1)%max ];
    481 			if (altmax)
    482 				tx2->alternate_anims = altanims[0];
    483 		}
    484 		for (j=0 ; j<altmax ; j++)
    485 		{
    486 			tx2 = altanims[j];
    487 			if (!tx2)
    488 				Sys_Error ("Missing frame %i of %s",j, tx->name);
    489 			tx2->anim_total = altmax * ANIM_CYCLE;
    490 			tx2->anim_min = j * ANIM_CYCLE;
    491 			tx2->anim_max = (j+1) * ANIM_CYCLE;
    492 			tx2->anim_next = altanims[ (j+1)%altmax ];
    493 			if (max)
    494 				tx2->alternate_anims = anims[0];
    495 		}
    496 	}
    497 }
    498 
    499 /*
    500 =================
    501 Mod_LoadLighting
    502 =================
    503 */
    504 void Mod_LoadLighting (lump_t *l)
    505 {
    506 	if (!l->filelen)
    507 	{
    508 		loadmodel->lightdata = NULL;
    509 		return;
    510 	}
    511 	loadmodel->lightdata = Hunk_AllocName ( l->filelen, loadname);
    512 	memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
    513 }
    514 
    515 
    516 /*
    517 =================
    518 Mod_LoadVisibility
    519 =================
    520 */
    521 void Mod_LoadVisibility (lump_t *l)
    522 {
    523 	if (!l->filelen)
    524 	{
    525 		loadmodel->visdata = NULL;
    526 		return;
    527 	}
    528 	loadmodel->visdata = Hunk_AllocName ( l->filelen, loadname);
    529 	memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
    530 }
    531 
    532 
    533 /*
    534 =================
    535 Mod_LoadEntities
    536 =================
    537 */
    538 void Mod_LoadEntities (lump_t *l)
    539 {
    540 	if (!l->filelen)
    541 	{
    542 		loadmodel->entities = NULL;
    543 		return;
    544 	}
    545 	loadmodel->entities = Hunk_AllocName ( l->filelen, loadname);
    546 	memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
    547 }
    548 
    549 
    550 /*
    551 =================
    552 Mod_LoadVertexes
    553 =================
    554 */
    555 void Mod_LoadVertexes (lump_t *l)
    556 {
    557 	dvertex_t	*in;
    558 	mvertex_t	*out;
    559 	int			i, count;
    560 
    561 	in = (void *)(mod_base + l->fileofs);
    562 	if (l->filelen % sizeof(*in))
    563 		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
    564 	count = l->filelen / sizeof(*in);
    565 	out = Hunk_AllocName ( count*sizeof(*out), loadname);
    566 
    567 	loadmodel->vertexes = out;
    568 	loadmodel->numvertexes = count;
    569 
    570 	for ( i=0 ; i<count ; i++, in++, out++)
    571 	{
    572 		out->position[0] = LittleFloat (in->point[0]);
    573 		out->position[1] = LittleFloat (in->point[1]);
    574 		out->position[2] = LittleFloat (in->point[2]);
    575 	}
    576 }
    577 
    578 /*
    579 =================
    580 Mod_LoadSubmodels
    581 =================
    582 */
    583 void Mod_LoadSubmodels (lump_t *l)
    584 {
    585 	dmodel_t	*in;
    586 	dmodel_t	*out;
    587 	int			i, j, count;
    588 
    589 	in = (void *)(mod_base + l->fileofs);
    590 	if (l->filelen % sizeof(*in))
    591 		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
    592 	count = l->filelen / sizeof(*in);
    593 	out = Hunk_AllocName ( count*sizeof(*out), loadname);
    594 
    595 	loadmodel->submodels = out;
    596 	loadmodel->numsubmodels = count;
    597 
    598 	for ( i=0 ; i<count ; i++, in++, out++)
    599 	{
    600 		for (j=0 ; j<3 ; j++)
    601 		{	// spread the mins / maxs by a pixel
    602 			out->mins[j] = LittleFloat (in->mins[j]) - 1;
    603 			out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
    604 			out->origin[j] = LittleFloat (in->origin[j]);
    605 		}
    606 		for (j=0 ; j<MAX_MAP_HULLS ; j++)
    607 			out->headnode[j] = LittleLong (in->headnode[j]);
    608 		out->visleafs = LittleLong (in->visleafs);
    609 		out->firstface = LittleLong (in->firstface);
    610 		out->numfaces = LittleLong (in->numfaces);
    611 	}
    612 }
    613 
    614 /*
    615 =================
    616 Mod_LoadEdges
    617 =================
    618 */
    619 void Mod_LoadEdges (lump_t *l)
    620 {
    621 	dedge_t *in;
    622 	medge_t *out;
    623 	int 	i, count;
    624 
    625 	in = (void *)(mod_base + l->fileofs);
    626 	if (l->filelen % sizeof(*in))
    627 		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
    628 	count = l->filelen / sizeof(*in);
    629 	out = Hunk_AllocName ( (count + 1) * sizeof(*out), loadname);
    630 
    631 	loadmodel->edges = out;
    632 	loadmodel->numedges = count;
    633 
    634 	for ( i=0 ; i<count ; i++, in++, out++)
    635 	{
    636 		out->v[0] = (unsigned short)LittleShort(in->v[0]);
    637 		out->v[1] = (unsigned short)LittleShort(in->v[1]);
    638 	}
    639 }
    640 
    641 /*
    642 =================
    643 Mod_LoadTexinfo
    644 =================
    645 */
    646 void Mod_LoadTexinfo (lump_t *l)
    647 {
    648 	texinfo_t *in;
    649 	mtexinfo_t *out;
    650 	int 	i, j, count;
    651 	int		miptex;
    652 	float	len1, len2;
    653 
    654 	in = (void *)(mod_base + l->fileofs);
    655 	if (l->filelen % sizeof(*in))
    656 		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
    657 	count = l->filelen / sizeof(*in);
    658 	out = Hunk_AllocName ( count*sizeof(*out), loadname);
    659 
    660 	loadmodel->texinfo = out;
    661 	loadmodel->numtexinfo = count;
    662 
    663 	for ( i=0 ; i<count ; i++, in++, out++)
    664 	{
    665 		for (j=0 ; j<8 ; j++)
    666 			out->vecs[0][j] = LittleFloat (in->vecs[0][j]);
    667 		len1 = Length (out->vecs[0]);
    668 		len2 = Length (out->vecs[1]);
    669 		len1 = (len1 + len2)/2;
    670 		if (len1 < 0.32)
    671 			out->mipadjust = 4;
    672 		else if (len1 < 0.49)
    673 			out->mipadjust = 3;
    674 		else if (len1 < 0.99)
    675 			out->mipadjust = 2;
    676 		else
    677 			out->mipadjust = 1;
    678 #if 0
    679 		if (len1 + len2 < 0.001)
    680 			out->mipadjust = 1;		// don't crash
    681 		else
    682 			out->mipadjust = 1 / floor( (len1+len2)/2 + 0.1 );
    683 #endif
    684 
    685 		miptex = LittleLong (in->miptex);
    686 		out->flags = LittleLong (in->flags);
    687 
    688 		if (!loadmodel->textures)
    689 		{
    690 			out->texture = r_notexture_mip;	// checkerboard texture
    691 			out->flags = 0;
    692 		}
    693 		else
    694 		{
    695 			if (miptex >= loadmodel->numtextures)
    696 				Sys_Error ("miptex >= loadmodel->numtextures");
    697 			out->texture = loadmodel->textures[miptex];
    698 			if (!out->texture)
    699 			{
    700 				out->texture = r_notexture_mip; // texture not found
    701 				out->flags = 0;
    702 			}
    703 		}
    704 	}
    705 }
    706 
    707 /*
    708 ================
    709 CalcSurfaceExtents
    710 
    711 Fills in s->texturemins[] and s->extents[]
    712 ================
    713 */
    714 void CalcSurfaceExtents (msurface_t *s)
    715 {
    716 	float	mins[2], maxs[2], val;
    717 	int		i,j, e;
    718 	mvertex_t	*v;
    719 	mtexinfo_t	*tex;
    720 	int		bmins[2], bmaxs[2];
    721 
    722 	mins[0] = mins[1] = 999999;
    723 	maxs[0] = maxs[1] = -99999;
    724 
    725 	tex = s->texinfo;
    726 
    727 	for (i=0 ; i<s->numedges ; i++)
    728 	{
    729 		e = loadmodel->surfedges[s->firstedge+i];
    730 		if (e >= 0)
    731 			v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
    732 		else
    733 			v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
    734 
    735 		for (j=0 ; j<2 ; j++)
    736 		{
    737 			val = v->position[0] * tex->vecs[j][0] +
    738 				v->position[1] * tex->vecs[j][1] +
    739 				v->position[2] * tex->vecs[j][2] +
    740 				tex->vecs[j][3];
    741 			if (val < mins[j])
    742 				mins[j] = val;
    743 			if (val > maxs[j])
    744 				maxs[j] = val;
    745 		}
    746 	}
    747 
    748 	for (i=0 ; i<2 ; i++)
    749 	{
    750 		bmins[i] = floor(mins[i]/16);
    751 		bmaxs[i] = ceil(maxs[i]/16);
    752 
    753 		s->texturemins[i] = bmins[i] * 16;
    754 		s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
    755 		if ( !(tex->flags & TEX_SPECIAL) && s->extents[i] > 256)
    756 			Sys_Error ("Bad surface extents");
    757 	}
    758 }
    759 
    760 
    761 /*
    762 =================
    763 Mod_LoadFaces
    764 =================
    765 */
    766 void Mod_LoadFaces (lump_t *l)
    767 {
    768 	dface_t		*in;
    769 	msurface_t 	*out;
    770 	int			i, count, surfnum;
    771 	int			planenum, side;
    772 
    773 	in = (void *)(mod_base + l->fileofs);
    774 	if (l->filelen % sizeof(*in))
    775 		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
    776 	count = l->filelen / sizeof(*in);
    777 	out = Hunk_AllocName ( count*sizeof(*out), loadname);
    778 
    779 	loadmodel->surfaces = out;
    780 	loadmodel->numsurfaces = count;
    781 
    782 	for ( surfnum=0 ; surfnum<count ; surfnum++, in++, out++)
    783 	{
    784 		out->firstedge = LittleLong(in->firstedge);
    785 		out->numedges = LittleShort(in->numedges);
    786 		out->flags = 0;
    787 
    788 		planenum = LittleShort(in->planenum);
    789 		side = LittleShort(in->side);
    790 		if (side)
    791 			out->flags |= SURF_PLANEBACK;
    792 
    793 		out->plane = loadmodel->planes + planenum;
    794 
    795 		out->texinfo = loadmodel->texinfo + LittleShort (in->texinfo);
    796 
    797 		CalcSurfaceExtents (out);
    798 
    799 	// lighting info
    800 
    801 		for (i=0 ; i<MAXLIGHTMAPS ; i++)
    802 			out->styles[i] = in->styles[i];
    803 		i = LittleLong(in->lightofs);
    804 		if (i == -1)
    805 			out->samples = NULL;
    806 		else
    807 			out->samples = loadmodel->lightdata + i;
    808 
    809 	// set the drawing flags flag
    810 
    811 		if (!Q_strncmp(out->texinfo->texture->name,"sky",3))	// sky
    812 		{
    813 			out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED);
    814 			continue;
    815 		}
    816 
    817 		if (!Q_strncmp(out->texinfo->texture->name,"*",1))		// turbulent
    818 		{
    819 			out->flags |= (SURF_DRAWTURB | SURF_DRAWTILED);
    820 			for (i=0 ; i<2 ; i++)
    821 			{
    822 				out->extents[i] = 16384;
    823 				out->texturemins[i] = -8192;
    824 			}
    825 			continue;
    826 		}
    827 	}
    828 }
    829 
    830 
    831 /*
    832 =================
    833 Mod_SetParent
    834 =================
    835 */
    836 void Mod_SetParent (mnode_t *node, mnode_t *parent)
    837 {
    838 	node->parent = parent;
    839 	if (node->contents < 0)
    840 		return;
    841 	Mod_SetParent (node->children[0], node);
    842 	Mod_SetParent (node->children[1], node);
    843 }
    844 
    845 /*
    846 =================
    847 Mod_LoadNodes
    848 =================
    849 */
    850 void Mod_LoadNodes (lump_t *l)
    851 {
    852 	int			i, j, count, p;
    853 	dnode_t		*in;
    854 	mnode_t 	*out;
    855 
    856 	in = (void *)(mod_base + l->fileofs);
    857 	if (l->filelen % sizeof(*in))
    858 		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
    859 	count = l->filelen / sizeof(*in);
    860 	out = Hunk_AllocName ( count*sizeof(*out), loadname);
    861 
    862 	loadmodel->nodes = out;
    863 	loadmodel->numnodes = count;
    864 
    865 	for ( i=0 ; i<count ; i++, in++, out++)
    866 	{
    867 		for (j=0 ; j<3 ; j++)
    868 		{
    869 			out->minmaxs[j] = LittleShort (in->mins[j]);
    870 			out->minmaxs[3+j] = LittleShort (in->maxs[j]);
    871 		}
    872 
    873 		p = LittleLong(in->planenum);
    874 		out->plane = loadmodel->planes + p;
    875 
    876 		out->firstsurface = LittleShort (in->firstface);
    877 		out->numsurfaces = LittleShort (in->numfaces);
    878 
    879 		for (j=0 ; j<2 ; j++)
    880 		{
    881 			p = LittleShort (in->children[j]);
    882 			if (p >= 0)
    883 				out->children[j] = loadmodel->nodes + p;
    884 			else
    885 				out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
    886 		}
    887 	}
    888 
    889 	Mod_SetParent (loadmodel->nodes, NULL);	// sets nodes and leafs
    890 }
    891 
    892 /*
    893 =================
    894 Mod_LoadLeafs
    895 =================
    896 */
    897 void Mod_LoadLeafs (lump_t *l)
    898 {
    899 	dleaf_t 	*in;
    900 	mleaf_t 	*out;
    901 	int			i, j, count, p;
    902 
    903 	in = (void *)(mod_base + l->fileofs);
    904 	if (l->filelen % sizeof(*in))
    905 		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
    906 	count = l->filelen / sizeof(*in);
    907 	out = Hunk_AllocName ( count*sizeof(*out), loadname);
    908 
    909 	loadmodel->leafs = out;
    910 	loadmodel->numleafs = count;
    911 
    912 	for ( i=0 ; i<count ; i++, in++, out++)
    913 	{
    914 		for (j=0 ; j<3 ; j++)
    915 		{
    916 			out->minmaxs[j] = LittleShort (in->mins[j]);
    917 			out->minmaxs[3+j] = LittleShort (in->maxs[j]);
    918 		}
    919 
    920 		p = LittleLong(in->contents);
    921 		out->contents = p;
    922 
    923 		out->firstmarksurface = loadmodel->marksurfaces +
    924 			LittleShort(in->firstmarksurface);
    925 		out->nummarksurfaces = LittleShort(in->nummarksurfaces);
    926 
    927 		p = LittleLong(in->visofs);
    928 		if (p == -1)
    929 			out->compressed_vis = NULL;
    930 		else
    931 			out->compressed_vis = loadmodel->visdata + p;
    932 		out->efrags = NULL;
    933 
    934 		for (j=0 ; j<4 ; j++)
    935 			out->ambient_sound_level[j] = in->ambient_level[j];
    936 	}
    937 }
    938 
    939 /*
    940 =================
    941 Mod_LoadClipnodes
    942 =================
    943 */
    944 void Mod_LoadClipnodes (lump_t *l)
    945 {
    946 	dclipnode_t *in, *out;
    947 	int			i, count;
    948 	hull_t		*hull;
    949 
    950 	in = (void *)(mod_base + l->fileofs);
    951 	if (l->filelen % sizeof(*in))
    952 		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
    953 	count = l->filelen / sizeof(*in);
    954 	out = Hunk_AllocName ( count*sizeof(*out), loadname);
    955 
    956 	loadmodel->clipnodes = out;
    957 	loadmodel->numclipnodes = count;
    958 
    959 	hull = &loadmodel->hulls[1];
    960 	hull->clipnodes = out;
    961 	hull->firstclipnode = 0;
    962 	hull->lastclipnode = count-1;
    963 	hull->planes = loadmodel->planes;
    964 	hull->clip_mins[0] = -16;
    965 	hull->clip_mins[1] = -16;
    966 	hull->clip_mins[2] = -24;
    967 	hull->clip_maxs[0] = 16;
    968 	hull->clip_maxs[1] = 16;
    969 	hull->clip_maxs[2] = 32;
    970 
    971 	hull = &loadmodel->hulls[2];
    972 	hull->clipnodes = out;
    973 	hull->firstclipnode = 0;
    974 	hull->lastclipnode = count-1;
    975 	hull->planes = loadmodel->planes;
    976 	hull->clip_mins[0] = -32;
    977 	hull->clip_mins[1] = -32;
    978 	hull->clip_mins[2] = -24;
    979 	hull->clip_maxs[0] = 32;
    980 	hull->clip_maxs[1] = 32;
    981 	hull->clip_maxs[2] = 64;
    982 
    983 	for (i=0 ; i<count ; i++, out++, in++)
    984 	{
    985 		out->planenum = LittleLong(in->planenum);
    986 		out->children[0] = LittleShort(in->children[0]);
    987 		out->children[1] = LittleShort(in->children[1]);
    988 	}
    989 }
    990 
    991 /*
    992 =================
    993 Mod_MakeHull0
    994 
    995 Deplicate the drawing hull structure as a clipping hull
    996 =================
    997 */
    998 void Mod_MakeHull0 (void)
    999 {
   1000 	mnode_t		*in, *child;
   1001 	dclipnode_t *out;
   1002 	int			i, j, count;
   1003 	hull_t		*hull;
   1004 
   1005 	hull = &loadmodel->hulls[0];
   1006 
   1007 	in = loadmodel->nodes;
   1008 	count = loadmodel->numnodes;
   1009 	out = Hunk_AllocName ( count*sizeof(*out), loadname);
   1010 
   1011 	hull->clipnodes = out;
   1012 	hull->firstclipnode = 0;
   1013 	hull->lastclipnode = count-1;
   1014 	hull->planes = loadmodel->planes;
   1015 
   1016 	for (i=0 ; i<count ; i++, out++, in++)
   1017 	{
   1018 		out->planenum = in->plane - loadmodel->planes;
   1019 		for (j=0 ; j<2 ; j++)
   1020 		{
   1021 			child = in->children[j];
   1022 			if (child->contents < 0)
   1023 				out->children[j] = child->contents;
   1024 			else
   1025 				out->children[j] = child - loadmodel->nodes;
   1026 		}
   1027 	}
   1028 }
   1029 
   1030 /*
   1031 =================
   1032 Mod_LoadMarksurfaces
   1033 =================
   1034 */
   1035 void Mod_LoadMarksurfaces (lump_t *l)
   1036 {
   1037 	int		i, j, count;
   1038 	short		*in;
   1039 	msurface_t **out;
   1040 
   1041 	in = (void *)(mod_base + l->fileofs);
   1042 	if (l->filelen % sizeof(*in))
   1043 		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
   1044 	count = l->filelen / sizeof(*in);
   1045 	out = Hunk_AllocName ( count*sizeof(*out), loadname);
   1046 
   1047 	loadmodel->marksurfaces = out;
   1048 	loadmodel->nummarksurfaces = count;
   1049 
   1050 	for ( i=0 ; i<count ; i++)
   1051 	{
   1052 		j = LittleShort(in[i]);
   1053 		if (j >= loadmodel->numsurfaces)
   1054 			Sys_Error ("Mod_ParseMarksurfaces: bad surface number");
   1055 		out[i] = loadmodel->surfaces + j;
   1056 	}
   1057 }
   1058 
   1059 /*
   1060 =================
   1061 Mod_LoadSurfedges
   1062 =================
   1063 */
   1064 void Mod_LoadSurfedges (lump_t *l)
   1065 {
   1066 	int		i, count;
   1067 	int		*in, *out;
   1068 
   1069 	in = (void *)(mod_base + l->fileofs);
   1070 	if (l->filelen % sizeof(*in))
   1071 		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
   1072 	count = l->filelen / sizeof(*in);
   1073 	out = Hunk_AllocName ( count*sizeof(*out), loadname);
   1074 
   1075 	loadmodel->surfedges = out;
   1076 	loadmodel->numsurfedges = count;
   1077 
   1078 	for ( i=0 ; i<count ; i++)
   1079 		out[i] = LittleLong (in[i]);
   1080 }
   1081 
   1082 /*
   1083 =================
   1084 Mod_LoadPlanes
   1085 =================
   1086 */
   1087 void Mod_LoadPlanes (lump_t *l)
   1088 {
   1089 	int			i, j;
   1090 	mplane_t	*out;
   1091 	dplane_t 	*in;
   1092 	int			count;
   1093 	int			bits;
   1094 
   1095 	in = (void *)(mod_base + l->fileofs);
   1096 	if (l->filelen % sizeof(*in))
   1097 		Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
   1098 	count = l->filelen / sizeof(*in);
   1099 	out = Hunk_AllocName ( count*2*sizeof(*out), loadname);
   1100 
   1101 	loadmodel->planes = out;
   1102 	loadmodel->numplanes = count;
   1103 
   1104 	for ( i=0 ; i<count ; i++, in++, out++)
   1105 	{
   1106 		bits = 0;
   1107 		for (j=0 ; j<3 ; j++)
   1108 		{
   1109 			out->normal[j] = LittleFloat (in->normal[j]);
   1110 			if (out->normal[j] < 0)
   1111 				bits |= 1<<j;
   1112 		}
   1113 
   1114 		out->dist = LittleFloat (in->dist);
   1115 		out->type = LittleLong (in->type);
   1116 		out->signbits = bits;
   1117 	}
   1118 }
   1119 
   1120 /*
   1121 =================
   1122 RadiusFromBounds
   1123 =================
   1124 */
   1125 float RadiusFromBounds (vec3_t mins, vec3_t maxs)
   1126 {
   1127 	int		i;
   1128 	vec3_t	corner;
   1129 
   1130 	for (i=0 ; i<3 ; i++)
   1131 	{
   1132 		corner[i] = fabs(mins[i]) > fabs(maxs[i]) ? fabs(mins[i]) : fabs(maxs[i]);
   1133 	}
   1134 
   1135 	return Length (corner);
   1136 }
   1137 
   1138 /*
   1139 =================
   1140 Mod_LoadBrushModel
   1141 =================
   1142 */
   1143 void Mod_LoadBrushModel (model_t *mod, void *buffer)
   1144 {
   1145 	int			i, j;
   1146 	dheader_t	*header;
   1147 	dmodel_t 	*bm;
   1148 
   1149 	loadmodel->type = mod_brush;
   1150 
   1151 	header = (dheader_t *)buffer;
   1152 
   1153 	i = LittleLong (header->version);
   1154 	if (i != BSPVERSION)
   1155 		Sys_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i)", mod->name, i, BSPVERSION);
   1156 
   1157 // swap all the lumps
   1158 	mod_base = (byte *)header;
   1159 
   1160 	for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
   1161 		((int *)header)[i] = LittleLong ( ((int *)header)[i]);
   1162 
   1163 // load into heap
   1164 
   1165 	Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
   1166 	Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
   1167 	Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
   1168 	Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
   1169 	Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
   1170 	Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
   1171 	Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
   1172 	Mod_LoadFaces (&header->lumps[LUMP_FACES]);
   1173 	Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
   1174 	Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
   1175 	Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
   1176 	Mod_LoadNodes (&header->lumps[LUMP_NODES]);
   1177 	Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
   1178 	Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
   1179 	Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
   1180 
   1181 	Mod_MakeHull0 ();
   1182 
   1183 	mod->numframes = 2;		// regular and alternate animation
   1184 	mod->flags = 0;
   1185 
   1186 //
   1187 // set up the submodels (FIXME: this is confusing)
   1188 //
   1189 	for (i=0 ; i<mod->numsubmodels ; i++)
   1190 	{
   1191 		bm = &mod->submodels[i];
   1192 
   1193 		mod->hulls[0].firstclipnode = bm->headnode[0];
   1194 		for (j=1 ; j<MAX_MAP_HULLS ; j++)
   1195 		{
   1196 			mod->hulls[j].firstclipnode = bm->headnode[j];
   1197 			mod->hulls[j].lastclipnode = mod->numclipnodes-1;
   1198 		}
   1199 
   1200 		mod->firstmodelsurface = bm->firstface;
   1201 		mod->nummodelsurfaces = bm->numfaces;
   1202 
   1203 		VectorCopy (bm->maxs, mod->maxs);
   1204 		VectorCopy (bm->mins, mod->mins);
   1205 		mod->radius = RadiusFromBounds (mod->mins, mod->maxs);
   1206 
   1207 		mod->numleafs = bm->visleafs;
   1208 
   1209 		if (i < mod->numsubmodels-1)
   1210 		{	// duplicate the basic information
   1211 			char	name[10];
   1212 
   1213 			sprintf (name, "*%i", i+1);
   1214 			loadmodel = Mod_FindName (name);
   1215 			*loadmodel = *mod;
   1216 			strcpy (loadmodel->name, name);
   1217 			mod = loadmodel;
   1218 		}
   1219 	}
   1220 }
   1221 
   1222 /*
   1223 ==============================================================================
   1224 
   1225 ALIAS MODELS
   1226 
   1227 ==============================================================================
   1228 */
   1229 
   1230 /*
   1231 =================
   1232 Mod_LoadAliasFrame
   1233 =================
   1234 */
   1235 void * Mod_LoadAliasFrame (void * pin, int *pframeindex, int numv,
   1236 	trivertx_t *pbboxmin, trivertx_t *pbboxmax, aliashdr_t *pheader, char *name)
   1237 {
   1238 	trivertx_t		*pframe, *pinframe;
   1239 	int				i, j;
   1240 	daliasframe_t	*pdaliasframe;
   1241 
   1242 	pdaliasframe = (daliasframe_t *)pin;
   1243 
   1244 	strcpy (name, pdaliasframe->name);
   1245 
   1246 	for (i=0 ; i<3 ; i++)
   1247 	{
   1248 	// these are byte values, so we don't have to worry about
   1249 	// endianness
   1250 		pbboxmin->v[i] = pdaliasframe->bboxmin.v[i];
   1251 		pbboxmax->v[i] = pdaliasframe->bboxmax.v[i];
   1252 	}
   1253 
   1254 	pinframe = (trivertx_t *)(pdaliasframe + 1);
   1255 	pframe = Hunk_AllocName (numv * sizeof(*pframe), loadname);
   1256 
   1257 	*pframeindex = (byte *)pframe - (byte *)pheader;
   1258 
   1259 	for (j=0 ; j<numv ; j++)
   1260 	{
   1261 		int		k;
   1262 
   1263 	// these are all byte values, so no need to deal with endianness
   1264 		pframe[j].lightnormalindex = pinframe[j].lightnormalindex;
   1265 
   1266 		for (k=0 ; k<3 ; k++)
   1267 		{
   1268 			pframe[j].v[k] = pinframe[j].v[k];
   1269 		}
   1270 	}
   1271 
   1272 	pinframe += numv;
   1273 
   1274 	return (void *)pinframe;
   1275 }
   1276 
   1277 
   1278 /*
   1279 =================
   1280 Mod_LoadAliasGroup
   1281 =================
   1282 */
   1283 void * Mod_LoadAliasGroup (void * pin, int *pframeindex, int numv,
   1284 	trivertx_t *pbboxmin, trivertx_t *pbboxmax, aliashdr_t *pheader, char *name)
   1285 {
   1286 	daliasgroup_t		*pingroup;
   1287 	maliasgroup_t		*paliasgroup;
   1288 	int					i, numframes;
   1289 	daliasinterval_t	*pin_intervals;
   1290 	float				*poutintervals;
   1291 	void				*ptemp;
   1292 
   1293 	pingroup = (daliasgroup_t *)pin;
   1294 
   1295 	numframes = LittleLong (pingroup->numframes);
   1296 
   1297 	paliasgroup = Hunk_AllocName (sizeof (maliasgroup_t) +
   1298 			(numframes - 1) * sizeof (paliasgroup->frames[0]), loadname);
   1299 
   1300 	paliasgroup->numframes = numframes;
   1301 
   1302 	for (i=0 ; i<3 ; i++)
   1303 	{
   1304 	// these are byte values, so we don't have to worry about endianness
   1305 		pbboxmin->v[i] = pingroup->bboxmin.v[i];
   1306 		pbboxmax->v[i] = pingroup->bboxmax.v[i];
   1307 	}
   1308 
   1309 	*pframeindex = (byte *)paliasgroup - (byte *)pheader;
   1310 
   1311 	pin_intervals = (daliasinterval_t *)(pingroup + 1);
   1312 
   1313 	poutintervals = Hunk_AllocName (numframes * sizeof (float), loadname);
   1314 
   1315 	paliasgroup->intervals = (byte *)poutintervals - (byte *)pheader;
   1316 
   1317 	for (i=0 ; i<numframes ; i++)
   1318 	{
   1319 		*poutintervals = LittleFloat (pin_intervals->interval);
   1320 		if (*poutintervals <= 0.0)
   1321 			Sys_Error ("Mod_LoadAliasGroup: interval<=0");
   1322 
   1323 		poutintervals++;
   1324 		pin_intervals++;
   1325 	}
   1326 
   1327 	ptemp = (void *)pin_intervals;
   1328 
   1329 	for (i=0 ; i<numframes ; i++)
   1330 	{
   1331 		ptemp = Mod_LoadAliasFrame (ptemp,
   1332 									&paliasgroup->frames[i].frame,
   1333 									numv,
   1334 									&paliasgroup->frames[i].bboxmin,
   1335 									&paliasgroup->frames[i].bboxmax,
   1336 									pheader, name);
   1337 	}
   1338 
   1339 	return ptemp;
   1340 }
   1341 
   1342 
   1343 /*
   1344 =================
   1345 Mod_LoadAliasSkin
   1346 =================
   1347 */
   1348 void * Mod_LoadAliasSkin (void * pin, int *pskinindex, int skinsize,
   1349 	aliashdr_t *pheader)
   1350 {
   1351 	int		i;
   1352 	byte	*pskin, *pinskin;
   1353 	unsigned short	*pusskin;
   1354 
   1355 	pskin = Hunk_AllocName (skinsize * r_pixbytes, loadname);
   1356 	pinskin = (byte *)pin;
   1357 	*pskinindex = (byte *)pskin - (byte *)pheader;
   1358 
   1359 	if (r_pixbytes == 1)
   1360 	{
   1361 		Q_memcpy (pskin, pinskin, skinsize);
   1362 	}
   1363 	else if (r_pixbytes == 2)
   1364 	{
   1365 		pusskin = (unsigned short *)pskin;
   1366 
   1367 		for (i=0 ; i<skinsize ; i++)
   1368 			pusskin[i] = d_8to16table[pinskin[i]];
   1369 	}
   1370 	else
   1371 	{
   1372 		Sys_Error ("Mod_LoadAliasSkin: driver set invalid r_pixbytes: %d\n",
   1373 				 r_pixbytes);
   1374 	}
   1375 
   1376 	pinskin += skinsize;
   1377 
   1378 	return ((void *)pinskin);
   1379 }
   1380 
   1381 
   1382 /*
   1383 =================
   1384 Mod_LoadAliasSkinGroup
   1385 =================
   1386 */
   1387 void * Mod_LoadAliasSkinGroup (void * pin, int *pskinindex, int skinsize,
   1388 	aliashdr_t *pheader)
   1389 {
   1390 	daliasskingroup_t		*pinskingroup;
   1391 	maliasskingroup_t		*paliasskingroup;
   1392 	int						i, numskins;
   1393 	daliasskininterval_t	*pinskinintervals;
   1394 	float					*poutskinintervals;
   1395 	void					*ptemp;
   1396 
   1397 	pinskingroup = (daliasskingroup_t *)pin;
   1398 
   1399 	numskins = LittleLong (pinskingroup->numskins);
   1400 
   1401 	paliasskingroup = Hunk_AllocName (sizeof (maliasskingroup_t) +
   1402 			(numskins - 1) * sizeof (paliasskingroup->skindescs[0]),
   1403 			loadname);
   1404 
   1405 	paliasskingroup->numskins = numskins;
   1406 
   1407 	*pskinindex = (byte *)paliasskingroup - (byte *)pheader;
   1408 
   1409 	pinskinintervals = (daliasskininterval_t *)(pinskingroup + 1);
   1410 
   1411 	poutskinintervals = Hunk_AllocName (numskins * sizeof (float),loadname);
   1412 
   1413 	paliasskingroup->intervals = (byte *)poutskinintervals - (byte *)pheader;
   1414 
   1415 	for (i=0 ; i<numskins ; i++)
   1416 	{
   1417 		*poutskinintervals = LittleFloat (pinskinintervals->interval);
   1418 		if (*poutskinintervals <= 0)
   1419 			Sys_Error ("Mod_LoadAliasSkinGroup: interval<=0");
   1420 
   1421 		poutskinintervals++;
   1422 		pinskinintervals++;
   1423 	}
   1424 
   1425 	ptemp = (void *)pinskinintervals;
   1426 
   1427 	for (i=0 ; i<numskins ; i++)
   1428 	{
   1429 		ptemp = Mod_LoadAliasSkin (ptemp,
   1430 				&paliasskingroup->skindescs[i].skin, skinsize, pheader);
   1431 	}
   1432 
   1433 	return ptemp;
   1434 }
   1435 
   1436 
   1437 /*
   1438 =================
   1439 Mod_LoadAliasModel
   1440 =================
   1441 */
   1442 void Mod_LoadAliasModel (model_t *mod, void *buffer)
   1443 {
   1444 	int					i;
   1445 	mdl_t				*pmodel, *pinmodel;
   1446 	stvert_t			*pstverts, *pinstverts;
   1447 	aliashdr_t			*pheader;
   1448 	mtriangle_t			*ptri;
   1449 	dtriangle_t			*pintriangles;
   1450 	int					version, numframes, numskins;
   1451 	int					size;
   1452 	daliasframetype_t	*pframetype;
   1453 	daliasskintype_t	*pskintype;
   1454 	maliasskindesc_t	*pskindesc;
   1455 	int					skinsize;
   1456 	int					start, end, total;
   1457 
   1458 	start = Hunk_LowMark ();
   1459 
   1460 	pinmodel = (mdl_t *)buffer;
   1461 
   1462 	version = LittleLong (pinmodel->version);
   1463 	if (version != ALIAS_VERSION)
   1464 		Sys_Error ("%s has wrong version number (%i should be %i)",
   1465 				 mod->name, version, ALIAS_VERSION);
   1466 
   1467 //
   1468 // allocate space for a working header, plus all the data except the frames,
   1469 // skin and group info
   1470 //
   1471 	size = 	sizeof (aliashdr_t) + (LittleLong (pinmodel->numframes) - 1) *
   1472 			 sizeof (pheader->frames[0]) +
   1473 			sizeof (mdl_t) +
   1474 			LittleLong (pinmodel->numverts) * sizeof (stvert_t) +
   1475 			LittleLong (pinmodel->numtris) * sizeof (mtriangle_t);
   1476 
   1477 	pheader = Hunk_AllocName (size, loadname);
   1478 	pmodel = (mdl_t *) ((byte *)&pheader[1] +
   1479 			(LittleLong (pinmodel->numframes) - 1) *
   1480 			 sizeof (pheader->frames[0]));
   1481 
   1482 //	mod->cache.data = pheader;
   1483 	mod->flags = LittleLong (pinmodel->flags);
   1484 
   1485 //
   1486 // endian-adjust and copy the data, starting with the alias model header
   1487 //
   1488 	pmodel->boundingradius = LittleFloat (pinmodel->boundingradius);
   1489 	pmodel->numskins = LittleLong (pinmodel->numskins);
   1490 	pmodel->skinwidth = LittleLong (pinmodel->skinwidth);
   1491 	pmodel->skinheight = LittleLong (pinmodel->skinheight);
   1492 
   1493 	if (pmodel->skinheight > MAX_LBM_HEIGHT)
   1494 		Sys_Error ("model %s has a skin taller than %d", mod->name,
   1495 				   MAX_LBM_HEIGHT);
   1496 
   1497 	pmodel->numverts = LittleLong (pinmodel->numverts);
   1498 
   1499 	if (pmodel->numverts <= 0)
   1500 		Sys_Error ("model %s has no vertices", mod->name);
   1501 
   1502 	if (pmodel->numverts > MAXALIASVERTS)
   1503 		Sys_Error ("model %s has too many vertices", mod->name);
   1504 
   1505 	pmodel->numtris = LittleLong (pinmodel->numtris);
   1506 
   1507 	if (pmodel->numtris <= 0)
   1508 		Sys_Error ("model %s has no triangles", mod->name);
   1509 
   1510 	pmodel->numframes = LittleLong (pinmodel->numframes);
   1511 	pmodel->size = LittleFloat (pinmodel->size) * ALIAS_BASE_SIZE_RATIO;
   1512 	mod->synctype = LittleLong (pinmodel->synctype);
   1513 	mod->numframes = pmodel->numframes;
   1514 
   1515 	for (i=0 ; i<3 ; i++)
   1516 	{
   1517 		pmodel->scale[i] = LittleFloat (pinmodel->scale[i]);
   1518 		pmodel->scale_origin[i] = LittleFloat (pinmodel->scale_origin[i]);
   1519 		pmodel->eyeposition[i] = LittleFloat (pinmodel->eyeposition[i]);
   1520 	}
   1521 
   1522 	numskins = pmodel->numskins;
   1523 	numframes = pmodel->numframes;
   1524 
   1525 	if (pmodel->skinwidth & 0x03)
   1526 		Sys_Error ("Mod_LoadAliasModel: skinwidth not multiple of 4");
   1527 
   1528 	pheader->model = (byte *)pmodel - (byte *)pheader;
   1529 
   1530 //
   1531 // load the skins
   1532 //
   1533 	skinsize = pmodel->skinheight * pmodel->skinwidth;
   1534 
   1535 	if (numskins < 1)
   1536 		Sys_Error ("Mod_LoadAliasModel: Invalid # of skins: %d\n", numskins);
   1537 
   1538 	pskintype = (daliasskintype_t *)&pinmodel[1];
   1539 
   1540 	pskindesc = Hunk_AllocName (numskins * sizeof (maliasskindesc_t),
   1541 								loadname);
   1542 
   1543 	pheader->skindesc = (byte *)pskindesc - (byte *)pheader;
   1544 
   1545 	for (i=0 ; i<numskins ; i++)
   1546 	{
   1547 		aliasskintype_t	skintype;
   1548 
   1549 		skintype = LittleLong (pskintype->type);
   1550 		pskindesc[i].type = skintype;
   1551 
   1552 		if (skintype == ALIAS_SKIN_SINGLE)
   1553 		{
   1554 			pskintype = (daliasskintype_t *)
   1555 					Mod_LoadAliasSkin (pskintype + 1,
   1556 									   &pskindesc[i].skin,
   1557 									   skinsize, pheader);
   1558 		}
   1559 		else
   1560 		{
   1561 			pskintype = (daliasskintype_t *)
   1562 					Mod_LoadAliasSkinGroup (pskintype + 1,
   1563 											&pskindesc[i].skin,
   1564 											skinsize, pheader);
   1565 		}
   1566 	}
   1567 
   1568 //
   1569 // set base s and t vertices
   1570 //
   1571 	pstverts = (stvert_t *)&pmodel[1];
   1572 	pinstverts = (stvert_t *)pskintype;
   1573 
   1574 	pheader->stverts = (byte *)pstverts - (byte *)pheader;
   1575 
   1576 	for (i=0 ; i<pmodel->numverts ; i++)
   1577 	{
   1578 		pstverts[i].onseam = LittleLong (pinstverts[i].onseam);
   1579 	// put s and t in 16.16 format
   1580 		pstverts[i].s = LittleLong (pinstverts[i].s) << 16;
   1581 		pstverts[i].t = LittleLong (pinstverts[i].t) << 16;
   1582 	}
   1583 
   1584 //
   1585 // set up the triangles
   1586 //
   1587 	ptri = (mtriangle_t *)&pstverts[pmodel->numverts];
   1588 	pintriangles = (dtriangle_t *)&pinstverts[pmodel->numverts];
   1589 
   1590 	pheader->triangles = (byte *)ptri - (byte *)pheader;
   1591 
   1592 	for (i=0 ; i<pmodel->numtris ; i++)
   1593 	{
   1594 		int		j;
   1595 
   1596 		ptri[i].facesfront = LittleLong (pintriangles[i].facesfront);
   1597 
   1598 		for (j=0 ; j<3 ; j++)
   1599 		{
   1600 			ptri[i].vertindex[j] =
   1601 					LittleLong (pintriangles[i].vertindex[j]);
   1602 		}
   1603 	}
   1604 
   1605 //
   1606 // load the frames
   1607 //
   1608 	if (numframes < 1)
   1609 		Sys_Error ("Mod_LoadAliasModel: Invalid # of frames: %d\n", numframes);
   1610 
   1611 	pframetype = (daliasframetype_t *)&pintriangles[pmodel->numtris];
   1612 
   1613 	for (i=0 ; i<numframes ; i++)
   1614 	{
   1615 		aliasframetype_t	frametype;
   1616 
   1617 		frametype = LittleLong (pframetype->type);
   1618 		pheader->frames[i].type = frametype;
   1619 
   1620 		if (frametype == ALIAS_SINGLE)
   1621 		{
   1622 			pframetype = (daliasframetype_t *)
   1623 					Mod_LoadAliasFrame (pframetype + 1,
   1624 										&pheader->frames[i].frame,
   1625 										pmodel->numverts,
   1626 										&pheader->frames[i].bboxmin,
   1627 										&pheader->frames[i].bboxmax,
   1628 										pheader, pheader->frames[i].name);
   1629 		}
   1630 		else
   1631 		{
   1632 			pframetype = (daliasframetype_t *)
   1633 					Mod_LoadAliasGroup (pframetype + 1,
   1634 										&pheader->frames[i].frame,
   1635 										pmodel->numverts,
   1636 										&pheader->frames[i].bboxmin,
   1637 										&pheader->frames[i].bboxmax,
   1638 										pheader, pheader->frames[i].name);
   1639 		}
   1640 	}
   1641 
   1642 	mod->type = mod_alias;
   1643 
   1644 // FIXME: do this right
   1645 	mod->mins[0] = mod->mins[1] = mod->mins[2] = -16;
   1646 	mod->maxs[0] = mod->maxs[1] = mod->maxs[2] = 16;
   1647 
   1648 //
   1649 // move the complete, relocatable alias model to the cache
   1650 //
   1651 	end = Hunk_LowMark ();
   1652 	total = end - start;
   1653 
   1654 	Cache_Alloc (&mod->cache, total, loadname);
   1655 	if (!mod->cache.data)
   1656 		return;
   1657 	memcpy (mod->cache.data, pheader, total);
   1658 
   1659 	Hunk_FreeToLowMark (start);
   1660 }
   1661 
   1662 //=============================================================================
   1663 
   1664 /*
   1665 =================
   1666 Mod_LoadSpriteFrame
   1667 =================
   1668 */
   1669 void * Mod_LoadSpriteFrame (void * pin, mspriteframe_t **ppframe)
   1670 {
   1671 	dspriteframe_t		*pinframe;
   1672 	mspriteframe_t		*pspriteframe;
   1673 	int					i, width, height, size, origin[2];
   1674 	unsigned short		*ppixout;
   1675 	byte				*ppixin;
   1676 
   1677 	pinframe = (dspriteframe_t *)pin;
   1678 
   1679 	width = LittleLong (pinframe->width);
   1680 	height = LittleLong (pinframe->height);
   1681 	size = width * height;
   1682 
   1683 	pspriteframe = Hunk_AllocName (sizeof (mspriteframe_t) + size*r_pixbytes,
   1684 								   loadname);
   1685 
   1686 	Q_memset (pspriteframe, 0, sizeof (mspriteframe_t) + size);
   1687 	*ppframe = pspriteframe;
   1688 
   1689 	pspriteframe->width = width;
   1690 	pspriteframe->height = height;
   1691 	origin[0] = LittleLong (pinframe->origin[0]);
   1692 	origin[1] = LittleLong (pinframe->origin[1]);
   1693 
   1694 	pspriteframe->up = origin[1];
   1695 	pspriteframe->down = origin[1] - height;
   1696 	pspriteframe->left = origin[0];
   1697 	pspriteframe->right = width + origin[0];
   1698 
   1699 	if (r_pixbytes == 1)
   1700 	{
   1701 		Q_memcpy (&pspriteframe->pixels[0], (byte *)(pinframe + 1), size);
   1702 	}
   1703 	else if (r_pixbytes == 2)
   1704 	{
   1705 		ppixin = (byte *)(pinframe + 1);
   1706 		ppixout = (unsigned short *)&pspriteframe->pixels[0];
   1707 
   1708 		for (i=0 ; i<size ; i++)
   1709 			ppixout[i] = d_8to16table[ppixin[i]];
   1710 	}
   1711 	else
   1712 	{
   1713 		Sys_Error ("Mod_LoadSpriteFrame: driver set invalid r_pixbytes: %d\n",
   1714 				 r_pixbytes);
   1715 	}
   1716 
   1717 	return (void *)((byte *)pinframe + sizeof (dspriteframe_t) + size);
   1718 }
   1719 
   1720 
   1721 /*
   1722 =================
   1723 Mod_LoadSpriteGroup
   1724 =================
   1725 */
   1726 void * Mod_LoadSpriteGroup (void * pin, mspriteframe_t **ppframe)
   1727 {
   1728 	dspritegroup_t		*pingroup;
   1729 	mspritegroup_t		*pspritegroup;
   1730 	int					i, numframes;
   1731 	dspriteinterval_t	*pin_intervals;
   1732 	float				*poutintervals;
   1733 	void				*ptemp;
   1734 
   1735 	pingroup = (dspritegroup_t *)pin;
   1736 
   1737 	numframes = LittleLong (pingroup->numframes);
   1738 
   1739 	pspritegroup = Hunk_AllocName (sizeof (mspritegroup_t) +
   1740 				(numframes - 1) * sizeof (pspritegroup->frames[0]), loadname);
   1741 
   1742 	pspritegroup->numframes = numframes;
   1743 
   1744 	*ppframe = (mspriteframe_t *)pspritegroup;
   1745 
   1746 	pin_intervals = (dspriteinterval_t *)(pingroup + 1);
   1747 
   1748 	poutintervals = Hunk_AllocName (numframes * sizeof (float), loadname);
   1749 
   1750 	pspritegroup->intervals = poutintervals;
   1751 
   1752 	for (i=0 ; i<numframes ; i++)
   1753 	{
   1754 		*poutintervals = LittleFloat (pin_intervals->interval);
   1755 		if (*poutintervals <= 0.0)
   1756 			Sys_Error ("Mod_LoadSpriteGroup: interval<=0");
   1757 
   1758 		poutintervals++;
   1759 		pin_intervals++;
   1760 	}
   1761 
   1762 	ptemp = (void *)pin_intervals;
   1763 
   1764 	for (i=0 ; i<numframes ; i++)
   1765 	{
   1766 		ptemp = Mod_LoadSpriteFrame (ptemp, &pspritegroup->frames[i]);
   1767 	}
   1768 
   1769 	return ptemp;
   1770 }
   1771 
   1772 
   1773 /*
   1774 =================
   1775 Mod_LoadSpriteModel
   1776 =================
   1777 */
   1778 void Mod_LoadSpriteModel (model_t *mod, void *buffer)
   1779 {
   1780 	int					i;
   1781 	int					version;
   1782 	dsprite_t			*pin;
   1783 	msprite_t			*psprite;
   1784 	int					numframes;
   1785 	int					size;
   1786 	dspriteframetype_t	*pframetype;
   1787 
   1788 	pin = (dsprite_t *)buffer;
   1789 
   1790 	version = LittleLong (pin->version);
   1791 	if (version != SPRITE_VERSION)
   1792 		Sys_Error ("%s has wrong version number "
   1793 				 "(%i should be %i)", mod->name, version, SPRITE_VERSION);
   1794 
   1795 	numframes = LittleLong (pin->numframes);
   1796 
   1797 	size = sizeof (msprite_t) +	(numframes - 1) * sizeof (psprite->frames);
   1798 
   1799 	psprite = Hunk_AllocName (size, loadname);
   1800 
   1801 	mod->cache.data = psprite;
   1802 
   1803 	psprite->type = LittleLong (pin->type);
   1804 	psprite->maxwidth = LittleLong (pin->width);
   1805 	psprite->maxheight = LittleLong (pin->height);
   1806 	psprite->beamlength = LittleFloat (pin->beamlength);
   1807 	mod->synctype = LittleLong (pin->synctype);
   1808 	psprite->numframes = numframes;
   1809 
   1810 	mod->mins[0] = mod->mins[1] = -psprite->maxwidth/2;
   1811 	mod->maxs[0] = mod->maxs[1] = psprite->maxwidth/2;
   1812 	mod->mins[2] = -psprite->maxheight/2;
   1813 	mod->maxs[2] = psprite->maxheight/2;
   1814 
   1815 //
   1816 // load the frames
   1817 //
   1818 	if (numframes < 1)
   1819 		Sys_Error ("Mod_LoadSpriteModel: Invalid # of frames: %d\n", numframes);
   1820 
   1821 	mod->numframes = numframes;
   1822 	mod->flags = 0;
   1823 
   1824 	pframetype = (dspriteframetype_t *)(pin + 1);
   1825 
   1826 	for (i=0 ; i<numframes ; i++)
   1827 	{
   1828 		spriteframetype_t	frametype;
   1829 
   1830 		frametype = LittleLong (pframetype->type);
   1831 		psprite->frames[i].type = frametype;
   1832 
   1833 		if (frametype == SPR_SINGLE)
   1834 		{
   1835 			pframetype = (dspriteframetype_t *)
   1836 					Mod_LoadSpriteFrame (pframetype + 1,
   1837 										 &psprite->frames[i].frameptr);
   1838 		}
   1839 		else
   1840 		{
   1841 			pframetype = (dspriteframetype_t *)
   1842 					Mod_LoadSpriteGroup (pframetype + 1,
   1843 										 &psprite->frames[i].frameptr);
   1844 		}
   1845 	}
   1846 
   1847 	mod->type = mod_sprite;
   1848 }
   1849 
   1850 //=============================================================================
   1851 
   1852 /*
   1853 ================
   1854 Mod_Print
   1855 ================
   1856 */
   1857 void Mod_Print (void)
   1858 {
   1859 	int		i;
   1860 	model_t	*mod;
   1861 
   1862 	Con_Printf ("Cached models:\n");
   1863 	for (i=0, mod=mod_known ; i < mod_numknown ; i++, mod++)
   1864 	{
   1865 		Con_Printf ("%8p : %s",mod->cache.data, mod->name);
   1866 		if (mod->needload & NL_UNREFERENCED)
   1867 			Con_Printf (" (!R)");
   1868 		if (mod->needload & NL_NEEDS_LOADED)
   1869 			Con_Printf (" (!P)");
   1870 		Con_Printf ("\n");
   1871 	}
   1872 }
   1873 
   1874 
   1875