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