1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 Copyright (C) 2010 COR Entertainment, LLC.
4 
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 
14 See the GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 
20 */
21 // r_model.c -- model loading and caching
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include "r_local.h"
28 #include "r_iqm.h"
29 #include "r_ragdoll.h"
30 #include "client/sound.h"
31 
32 model_t	*loadmodel;
33 int		modfilelen;
34 
35 void Mod_LoadBrushModel (model_t *mod, void *buffer);
36 model_t *Mod_LoadModel (model_t *mod, qboolean crash);
37 
38 byte	mod_novis[MAX_MAP_LEAFS/8];
39 
40 #define	MAX_MOD_KNOWN	512
41 model_t	mod_known[MAX_MOD_KNOWN];
42 int		mod_numknown;
43 
44 // the inline * models from the current map are kept seperate
45 model_t	mod_inline[MAX_MOD_KNOWN];
46 
47 LightGroup_t LightGroups[MAX_LIGHTS];
48 int r_lightgroups;
49 
50 int		registration_sequence;
51 
52 #if defined WIN32_VARIANT
53 char map_music[MAX_PATH];
54 char map_music_sec[MAX_PATH];
55 #else
56 char map_music[MAX_OSPATH];
57 char map_music_sec[MAX_OSPATH];
58 #endif
59 
60 char		map_entitystring[MAX_MAP_ENTSTRING];
61 int			numentitychars;
62 byte	*mod_base;
63 
64 /*
65 =================
66 Mod_LoadEntityString
67 =================
68 */
Mod_LoadEntityStrn(lump_t * l)69 void Mod_LoadEntityStrn (lump_t *l)
70 {
71 	numentitychars = l->filelen;
72 	if (l->filelen > MAX_MAP_ENTSTRING)
73 		Sys_Error ("Map has too large entity lump");
74 
75 	memcpy (map_entitystring, mod_base + l->fileofs, l->filelen);
76 }
77 
78 extern char	*CM_EntityString (void);
79 
R_RegisterLightGroups(void)80 void R_RegisterLightGroups (void)
81 {
82 	int			i;
83 	vec3_t		dist, mins, maxs;
84 	trace_t		r_trace;
85 	int			lnum = 0;
86 	qboolean	doneShadowGroups = false;
87 	qboolean	lightWasGrouped = false;
88 
89 	VectorSet(mins, 0, 0, 0);
90 	VectorSet(maxs, 0, 0, 0);
91 
92 	for (i=0; i<r_numWorldLights; i++) {
93 		r_worldLights[i].grouped = false;
94 	}
95 
96 	r_lightgroups = 0;
97 
98 	while(!doneShadowGroups) {
99 
100 		lightWasGrouped = false;
101 		for (i=0; i<r_numWorldLights; i++) {
102 
103 			if(r_worldLights[i].grouped)
104 				continue;
105 
106 			if(!lnum && !r_worldLights[i].grouped) { //none in group yet, first light establishes the initial origin of the group
107 				VectorCopy(r_worldLights[i].origin, LightGroups[r_lightgroups].group_origin);
108 				VectorCopy(r_worldLights[i].origin, LightGroups[r_lightgroups].accum_origin);
109 				LightGroups[r_lightgroups].avg_intensity = r_worldLights[i].intensity;
110 				r_worldLights[i].grouped = true;
111 				lnum++;
112 				lightWasGrouped = true;
113 			}
114 
115 			VectorSubtract(LightGroups[r_lightgroups].group_origin, r_worldLights[i].origin, dist);
116 			r_trace = CM_BoxTrace(LightGroups[r_lightgroups].group_origin, r_worldLights[i].origin, mins, maxs, r_worldmodel->firstnode, MASK_OPAQUE);
117 
118 			if(!r_worldLights[i].grouped && (lnum < r_numWorldLights) && r_trace.fraction == 1.0f && (VectorLength(dist) < 256.0f)) {
119 				r_worldLights[i].grouped = true;
120 				VectorAdd(r_worldLights[i].origin, LightGroups[r_lightgroups].accum_origin, LightGroups[r_lightgroups].accum_origin);
121 				LightGroups[r_lightgroups].avg_intensity+=(r_worldLights[i].intensity);
122 				lnum++;
123 				//we grouped an light in this pass
124 				lightWasGrouped = true;
125 			}
126 		}
127 
128 		if(!lightWasGrouped)
129 			doneShadowGroups = true;
130 		else {
131 			//we've reach the end, start a new group
132 			if(lnum) {
133 				VectorScale(LightGroups[r_lightgroups].accum_origin, 1.0/(float)(lnum), LightGroups[r_lightgroups].accum_origin);
134 				LightGroups[r_lightgroups].avg_intensity /= (float)lnum;
135 			}
136 			VectorCopy(LightGroups[r_lightgroups].accum_origin, LightGroups[r_lightgroups].group_origin);
137 			r_lightgroups++;
138 			if(r_lightgroups > MAX_LIGHTS)
139 				doneShadowGroups = true;
140 
141 			lnum = 0;
142 		}
143 	}
144 	Com_Printf("Condensed ^2%i worldlights into ^2%i lightgroups\n", r_numWorldLights, r_lightgroups);
145 }
146 
147 /*
148 ================
149 R_ParseLightEntities
150 
151 parses light entity string
152 ================
153 */
154 
R_ParseLightEntities(void)155 static void R_ParseLightEntities (void)
156 {
157 
158 	int			i;
159 	char		*entString;
160 	char		*buf, *tok;
161 	char		block[2048], *bl;
162 	vec3_t		origin;
163 	float		intensity;
164 
165 	entString = map_entitystring;
166 
167 	buf = CM_EntityString();
168 	while (1){
169 		tok = Com_ParseExt(&buf, true);
170 		if (!tok[0])
171 			break;			// End of data
172 
173 		if (Q_strcasecmp(tok, "{"))
174 			continue;		// Should never happen!
175 
176 		// Parse the text inside brackets
177 		block[0] = 0;
178 		do {
179 			tok = Com_ParseExt(&buf, false);
180 			if (!Q_strcasecmp(tok, "}"))
181 				break;		// Done
182 
183 			if (!tok[0])	// Newline
184 				Q_strcat(block, "\n", sizeof(block));
185 			else {			// Token
186 				Q_strcat(block, " ", sizeof(block));
187 				Q_strcat(block, tok, sizeof(block));
188 			}
189 		} while (buf);
190 
191 		// Now look for "classname"
192 		tok = strstr(block, "classname");
193 		if (!tok)
194 			continue;		// Not found
195 
196 		// Skip over "classname" and whitespace
197 		tok += strlen("classname");
198 		while (*tok && *tok == ' ')
199 			tok++;
200 
201 		// Next token must be "light"
202 		if (Q_strnicmp(tok, "light", 5))
203 			continue;		// Not "light"
204 
205 		// Finally parse the light entity
206 		VectorClear(origin);
207 		intensity = 0;
208 
209 		bl = block;
210 		while (1){
211 			tok = Com_ParseExt(&bl, true);
212 			if (!tok[0])
213 				break;		// End of data
214 
215 			if (!Q_strcasecmp("origin", tok)){
216 				for (i = 0; i < 3; i++){
217 					tok = Com_ParseExt(&bl, false);
218 					origin[i] = atof(tok);
219 				}
220 			}
221 			else if (!Q_strcasecmp("light", tok) || !Q_strcasecmp("_light", tok)){
222 				tok = Com_ParseExt(&bl, false);
223 				intensity = atof(tok);
224 			}
225 			else
226 				Com_SkipRestOfLine(&bl);
227 		}
228 
229 		if (!intensity)
230 			intensity = 150;
231 
232 		// Add it to the list
233 		if (r_numWorldLights == MAX_LIGHTS)
234 			break;
235 
236 		VectorCopy(origin, r_worldLights[r_numWorldLights].origin);
237 		r_worldLights[r_numWorldLights].intensity = intensity/2;
238 		r_worldLights[r_numWorldLights].surf = NULL;
239 		r_numWorldLights++;
240 	}
241 }
242 
R_FindSunTarget(void)243 static void R_FindSunTarget (void)
244 {
245 
246 	int			i;
247 	char		*entString;
248 	char		*buf, *tok;
249 	char		block[2048], *bl;
250 
251 	entString = map_entitystring;
252 
253 	buf = CM_EntityString();
254 	while (1){
255 		tok = Com_ParseExt(&buf, true);
256 		if (!tok[0])
257 			break;			// End of data
258 
259 		if (Q_strcasecmp(tok, "{"))
260 			continue;		// Should never happen!
261 
262 		// Parse the text inside brackets
263 		block[0] = 0;
264 		do {
265 			tok = Com_ParseExt(&buf, false);
266 			if (!Q_strcasecmp(tok, "}"))
267 				break;		// Done
268 
269 			if (!tok[0])	// Newline
270 				Q_strcat(block, "\n", sizeof(block));
271 			else {			// Token
272 				Q_strcat(block, " ", sizeof(block));
273 				Q_strcat(block, tok, sizeof(block));
274 			}
275 		} while (buf);
276 
277 		// Now look for "targetname"
278 		tok = strstr(block, "targetname");
279 		if (!tok)
280 			continue;		// Not found
281 
282 		// Skip over "target" and whitespace
283 		tok += strlen("targetname");
284 		while (*tok && *tok == ' ')
285 			tok++;
286 
287 		// Next token must match the sun targetname
288 		if (Q_strnicmp(tok, "moonspot", 8) && Q_strnicmp(tok, "sunspot", 7))
289 			continue;
290 
291 		// Finally parse the sun target entity
292 		bl = block;
293 		while (1){
294 			tok = Com_ParseExt(&bl, true);
295 			if (!tok[0])
296 				break;		// End of data
297 
298 			if (!Q_strcasecmp("origin", tok)){
299 				for (i = 0; i < 3; i++){
300 					tok = Com_ParseExt(&bl, false);
301 					r_sunLight->target[i] = atof(tok);
302 				}
303 				//Com_Printf("Found sun target@ : %4.2f %4.2f %4.2f\n", r_sunLight->target[0], r_sunLight->target[1], r_sunLight->target[2]);
304 			}
305 			else
306 				Com_SkipRestOfLine(&bl);
307 		}
308 	}
309 }
310 
R_FindSunEntity(void)311 static void R_FindSunEntity (void)
312 {
313 
314 	int			i;
315 	char		*entString;
316 	char		*buf, *tok;
317 	char		block[2048], *bl;
318 
319 	if(r_sunLight)
320 		free(r_sunLight); //free at level load
321 
322 	r_sunLight = (sunLight_t*)malloc(sizeof(sunLight_t));
323 
324 	r_sunLight->has_Sun = false;
325 
326 	entString = map_entitystring;
327 
328 	buf = CM_EntityString();
329 	while (1){
330 		tok = Com_ParseExt(&buf, true);
331 		if (!tok[0])
332 			break;			// End of data
333 
334 		if (Q_strcasecmp(tok, "{"))
335 			continue;		// Should never happen!
336 
337 		// Parse the text inside brackets
338 		block[0] = 0;
339 		do {
340 			tok = Com_ParseExt(&buf, false);
341 			if (!Q_strcasecmp(tok, "}"))
342 				break;		// Done
343 
344 			if (!tok[0])	// Newline
345 				Q_strcat(block, "\n", sizeof(block));
346 			else {			// Token
347 				Q_strcat(block, " ", sizeof(block));
348 				Q_strcat(block, tok, sizeof(block));
349 			}
350 		} while (buf);
351 
352 		// Now look for "target"
353 		tok = strstr(block, "target");
354 		if (!tok)
355 			continue;		// Not found
356 
357 		// Skip over "target" and whitespace
358 		tok += strlen("target");
359 		while (*tok && *tok == ' ')
360 			tok++;
361 
362 		// Next token must be a valid sun name( to do - maybe read this from the map header if possible?)
363 		if (Q_strnicmp(tok, "moonspot", 8) && Q_strnicmp(tok, "sunspot", 7))
364 			continue;
365 
366 		strcpy(r_sunLight->targetname, tok);
367 
368 		// Finally parse the sun entity
369 		bl = block;
370 		while (1){
371 			tok = Com_ParseExt(&bl, true);
372 			if (!tok[0])
373 				break;		// End of data
374 
375 			if (!Q_strcasecmp("origin", tok)){
376 				for (i = 0; i < 3; i++){
377 					tok = Com_ParseExt(&bl, false);
378 					r_sunLight->origin[i] = atof(tok);
379 					r_sunLight->target[i] = 0; //default to this
380 				}
381 				r_sunLight->has_Sun = true;
382 				//Com_Printf("Found sun @ : %4.2f %4.2f %4.2f\n", r_sunLight->origin[0], r_sunLight->origin[1], r_sunLight->origin[2]);
383 			}
384 			else
385 				Com_SkipRestOfLine(&bl);
386 		}
387 	}
388 	if(r_sunLight->has_Sun)
389 		R_FindSunTarget(); //find target
390 }
391 
392 /*
393 ===============
394 Mod_PointInLeaf
395 ===============
396 */
Mod_PointInLeaf(vec3_t p,model_t * model)397 mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
398 {
399 	mnode_t		*node;
400 	float		d;
401 	cplane_t	*plane;
402 
403 	if (!model || !model->nodes)
404 		Com_Printf ("Mod_PointInLeaf: bad model");
405 
406 	node = model->nodes;
407 	while (1)
408 	{
409 		if (node->contents != -1)
410 			return (mleaf_t *)node;
411 		plane = node->plane;
412 		d = DotProduct (p,plane->normal) - plane->dist;
413 		if (d > 0)
414 			node = node->children[0];
415 		else
416 			node = node->children[1];
417 	}
418 
419 	return NULL;	// never reached
420 }
421 
422 
423 /*
424 ===================
425 Mod_DecompressVis
426 ===================
427 */
Mod_DecompressVis(byte * in,model_t * model)428 byte *Mod_DecompressVis (byte *in, model_t *model)
429 {
430 	static byte	decompressed[MAX_MAP_LEAFS/8];
431 	int		c;
432 	byte	*out;
433 	int		row;
434 
435 	row = (model->vis->numclusters+7)>>3;
436 	out = decompressed;
437 
438 	if (!in)
439 	{	// no vis info, so make all visible
440 		while (row)
441 		{
442 			*out++ = 0xff;
443 			row--;
444 		}
445 		return decompressed;
446 	}
447 
448 	do
449 	{
450 		if (*in)
451 		{
452 			*out++ = *in++;
453 			continue;
454 		}
455 
456 		c = in[1];
457 		in += 2;
458 		while (c)
459 		{
460 			*out++ = 0;
461 			c--;
462 		}
463 	} while (out - decompressed < row);
464 
465 	return decompressed;
466 }
467 
468 /*
469 ==============
470 Mod_ClusterPVS
471 ==============
472 */
Mod_ClusterPVS(int cluster,model_t * model)473 byte *Mod_ClusterPVS (int cluster, model_t *model)
474 {
475 	if (cluster == -1 || !model->vis)
476 		return mod_novis;
477 	return Mod_DecompressVis ( (byte *)model->vis + model->vis->bitofs[cluster][DVIS_PVS],
478 		model);
479 }
480 
481 
482 //===============================================================================
483 
484 /*
485 ================
486 Mod_Modellist_f
487 ================
488 */
Mod_Modellist_f(void)489 void Mod_Modellist_f (void)
490 {
491 	int		i;
492 	model_t	*mod;
493 	int		total;
494 
495 	total = 0;
496 	Com_Printf ("Loaded models:\n");
497 	for (i=0, mod=mod_known ; i < mod_numknown ; i++, mod++)
498 	{
499 		if (!mod->name[0])
500 			continue;
501 		Com_Printf ("%8i : %s\n",mod->extradatasize, mod->name);
502 		total += mod->extradatasize;
503 	}
504 	Com_Printf ("Total resident: %i\n", total);
505 }
506 
507 /*
508 ===============
509 Mod_Init
510 ===============
511 */
Mod_Init(void)512 void Mod_Init (void)
513 {
514 	memset (mod_novis, 0xff, sizeof(mod_novis));
515 }
516 
517 
518 
519 /*
520 ==================
521 Mod_ForName
522 
523 Loads in a model for the given name
524 ==================
525 */
Mod_ForName(char * name,qboolean crash)526 model_t *Mod_ForName (char *name, qboolean crash)
527 {
528 	model_t	*mod;
529 	unsigned *buf;
530 	int		i;
531 	char shortname[MAX_QPATH], nameShortname[MAX_QPATH];
532 	qboolean is_iqm = false;
533 
534 	if (!name[0])
535 		Com_Error (ERR_DROP, "Mod_ForName: NULL name");
536 
537 	//
538 	// inline models are grabbed only from worldmodel
539 	//
540 	if (name[0] == '*')
541 	{
542 		i = atoi(name+1);
543 		if (i < 1 || !r_worldmodel || i >= r_worldmodel->numsubmodels)
544 			Com_Error (ERR_DROP, "bad inline model number");
545 		return &mod_inline[i];
546 	}
547 
548 	//
549 	// search the currently loaded models
550 	//
551 	for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
552 	{
553 		if (!mod->name[0])
554 			continue;
555 
556 		COM_StripExtension(mod->name, shortname);
557 		COM_StripExtension(name, nameShortname);
558 
559 		if (!strcmp (shortname, nameShortname) )
560 		{
561 			if (mod->type == mod_alias || mod->type == mod_iqm)
562 			{
563 				// Make sure models scripts are definately reloaded between maps
564 				image_t *img;
565 				img=mod->skins[0];
566 
567 				if (img != NULL)
568 				{
569 					mod->script = mod->skins[0]->script;
570 					if (mod->script)
571 						RS_ReadyScript( mod->script );
572 				}
573 			}
574 
575 			return mod;
576 		}
577 	}
578 
579 	//
580 	// find a free model slot spot
581 	//
582 	for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
583 	{
584 		if (!mod->name[0])
585 			break;	// free spot
586 	}
587 	if (i == mod_numknown)
588 	{
589 		if (mod_numknown == MAX_MOD_KNOWN)
590 			Com_Error (ERR_DROP, "mod_numknown == MAX_MOD_KNOWN");
591 		mod_numknown++;
592 	}
593 	strcpy (mod->name, name);
594 
595 	R_SetSimpleTexnum (mod, name);
596 
597 	//
598 	// load the file
599 	//
600 	//if .md2, check for IQM version first
601 	COM_StripExtension(mod->name, shortname);
602 	strcat(shortname, ".iqm");
603 
604 	modfilelen = FS_LoadFile (shortname, (void*)&buf);
605 
606 	if(!buf) //could not find iqm
607 	{
608 		modfilelen = FS_LoadFile (mod->name, (void*)&buf);
609 		if (!buf)
610 		{
611 			if (crash)
612 				Com_Error (ERR_DROP, "Mod_NumForName: %s not found", mod->name);
613 			memset (mod->name, 0, sizeof(mod->name));
614 			return NULL;
615 		}
616 	}
617 	else
618 	{
619 		//we have an .iqm
620 		is_iqm = true;
621 		strcpy(mod->name, shortname);
622 	}
623 
624 	loadmodel = mod;
625 
626 	if ( developer && developer->integer == 2 )
627 	{ // tracing for model loading
628 		Com_DPrintf("Mod_ForName: load: %s\n", loadmodel->name );
629 	}
630 
631 	//
632 	// fill it in
633 	//
634 
635 	// call the apropriate loader
636 	//iqm - try interquake model first
637 	if(is_iqm)
638 	{
639 		if(!Mod_INTERQUAKEMODEL_Load(mod, buf))
640 			Com_Error (ERR_DROP,"Mod_NumForName: wrong fileid for %s", mod->name);
641 	}
642 	else
643 	{
644 		switch (LittleLong(*(unsigned *)buf))
645 		{
646 		case IDALIASHEADER:
647 			loadmodel->extradata = Hunk_Begin (0x300000);
648 			Mod_LoadMD2Model (mod, buf);
649 			break;
650 
651 		case IDBSPHEADER:
652 			loadmodel->extradata = Hunk_Begin (0x1500000);
653 			Mod_LoadBrushModel (mod, buf);
654 			break;
655 
656 		default:
657 			Com_Error (ERR_DROP,"Mod_NumForName: unknown fileid for %s", mod->name);
658 			break;
659 		}
660 	}
661 
662 	loadmodel->extradatasize = Hunk_End ();
663 
664 	FS_FreeFile (buf);
665 
666 	return mod;
667 }
668 
669 /*
670 ===============================================================================
671 
672 					BRUSHMODEL LOADING
673 
674 ===============================================================================
675 */
676 
677 byte	*mod_base;
678 
679 
680 /*
681 =================
682 Mod_LoadLighting
683 =================
684 */
Mod_LoadLighting(lump_t * l)685 void Mod_LoadLighting (lump_t *l)
686 {
687 	if (!l->filelen)
688 	{
689 		loadmodel->lightdata = NULL;
690 		return;
691 	}
692 	loadmodel->lightdata = Hunk_Alloc ( l->filelen);
693 	memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
694 }
695 
696 
697 /*
698 =================
699 Mod_LoadVisibility
700 =================
701 */
Mod_LoadVisibility(lump_t * l)702 void Mod_LoadVisibility (lump_t *l)
703 {
704 	int		i;
705 
706 	if (!l->filelen)
707 	{
708 		loadmodel->vis = NULL;
709 		return;
710 	}
711 	loadmodel->vis = Hunk_Alloc ( l->filelen);
712 	memcpy (loadmodel->vis, mod_base + l->fileofs, l->filelen);
713 
714 	loadmodel->vis->numclusters = LittleLong (loadmodel->vis->numclusters);
715 	for (i=0 ; i<loadmodel->vis->numclusters ; i++)
716 	{
717 		loadmodel->vis->bitofs[i][0] = LittleLong (loadmodel->vis->bitofs[i][0]);
718 		loadmodel->vis->bitofs[i][1] = LittleLong (loadmodel->vis->bitofs[i][1]);
719 	}
720 }
721 
722 
723 /*
724 =================
725 Mod_LoadVertexes
726 =================
727 */
Mod_LoadVertexes(lump_t * l)728 void Mod_LoadVertexes (lump_t *l)
729 {
730 	dvertex_t	*in;
731 	mvertex_t	*out;
732 	int			i, count;
733 
734 	in = (void *)(mod_base + l->fileofs);
735 	if (l->filelen % sizeof(*in))
736 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
737 	count = l->filelen / sizeof(*in);
738 	out = Hunk_Alloc ( count*sizeof(*out));
739 
740 	loadmodel->vertexes = out;
741 	loadmodel->numvertexes = count;
742 
743 	for ( i=0 ; i<count ; i++, in++, out++)
744 	{
745 		out->position[0] = LittleFloat (in->point[0]);
746 		out->position[1] = LittleFloat (in->point[1]);
747 		out->position[2] = LittleFloat (in->point[2]);
748 	}
749 }
750 
751 /*
752 =================
753 RadiusFromBounds
754 =================
755 */
RadiusFromBounds(vec3_t mins,vec3_t maxs)756 float RadiusFromBounds (vec3_t mins, vec3_t maxs)
757 {
758 	int		i;
759 	vec3_t	corner;
760 
761 	for (i=0 ; i<3 ; i++)
762 	{
763 		corner[i] = fabs(mins[i]) > fabs(maxs[i]) ? fabs(mins[i]) : fabs(maxs[i]);
764 	}
765 
766 	return VectorLength (corner);
767 }
768 
769 
770 /*
771 =================
772 Mod_LoadSubmodels
773 =================
774 */
Mod_LoadSubmodels(lump_t * l)775 void Mod_LoadSubmodels (lump_t *l)
776 {
777 	dmodel_t	*in;
778 	mmodel_t	*out;
779 	int			i, j, count;
780 
781 	in = (void *)(mod_base + l->fileofs);
782 	if (l->filelen % sizeof(*in))
783 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
784 	count = l->filelen / sizeof(*in);
785 	out = Hunk_Alloc ( count*sizeof(*out));
786 
787 	loadmodel->submodels = out;
788 	loadmodel->numsubmodels = count;
789 
790 	for ( i=0 ; i<count ; i++, in++, out++)
791 	{
792 		for (j=0 ; j<3 ; j++)
793 		{	// spread the mins / maxs by a pixel
794 			out->mins[j] = LittleFloat (in->mins[j]) - 1;
795 			out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
796 		}
797 		out->radius = RadiusFromBounds (out->mins, out->maxs);
798 		out->headnode = LittleLong (in->headnode);
799 		out->firstface = LittleLong (in->firstface);
800 		out->numfaces = LittleLong (in->numfaces);
801 	}
802 }
803 
804 /*
805 =================
806 Mod_LoadEdges
807 =================
808 */
Mod_LoadEdges(lump_t * l)809 void Mod_LoadEdges (lump_t *l)
810 {
811 	dedge_t *in;
812 	medge_t *out;
813 	int 	i, count;
814 
815 	in = (void *)(mod_base + l->fileofs);
816 	if (l->filelen % sizeof(*in))
817 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
818 	count = l->filelen / sizeof(*in);
819 	out = Hunk_Alloc ( (count + 1) * sizeof(*out));
820 
821 	loadmodel->edges = out;
822 	loadmodel->numedges = count;
823 
824 	for ( i=0 ; i<count ; i++, in++, out++)
825 	{
826 		out->v[0] = (unsigned short)LittleShort(in->v[0]);
827 		out->v[1] = (unsigned short)LittleShort(in->v[1]);
828 	}
829 }
830 
831 /*
832 =================
833 Mod_LoadTexinfo
834 =================
835 */
836 
compare_unique_texinfo(const void * _a,const void * _b)837 int compare_unique_texinfo (const void *_a, const void *_b)
838 {
839 	mtexinfo_t *a = *(mtexinfo_t **)_a, *b = *(mtexinfo_t **)_b;
840 	return a->image->texnum-b->image->texnum;
841 }
842 
Mod_LoadTexinfo(lump_t * l)843 void Mod_LoadTexinfo (lump_t *l)
844 {
845 	texinfo_t *in, *in_base;
846 	mtexinfo_t *out, *step, **unique_temp;
847 	int 	i, j, count, num_unique;
848 	char	name[MAX_QPATH];
849 	char	sv_name[MAX_QPATH];
850 	int		next;
851 
852 	in_base = in = (void *)(mod_base + l->fileofs);
853 	if (l->filelen % sizeof(*in))
854 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
855 	count = l->filelen / sizeof(*in);
856 	out = Hunk_Alloc ( count*sizeof(*out));
857 
858 	loadmodel->texinfo = out;
859 	loadmodel->numtexinfo = count;
860 
861 	for ( i=0 ; i<count ; i++, in++, out++)
862 	{
863 		for (j=0 ; j<4 ; j++)
864 		{
865 			/* note: treating as vecs[0][8] gives warning with gcc -O3 */
866 			out->vecs[0][j] = LittleFloat (in->vecs[0][j]);
867 			out->vecs[1][j] = LittleFloat (in->vecs[1][j]);
868 		}
869 		out->value = LittleLong (in->value);
870 		out->flags = LittleLong (in->flags);
871 		next = LittleLong (in->nexttexinfo);
872 		if (next > 0 && next < loadmodel->numtexinfo)
873 			out->next = loadmodel->texinfo + next;
874 		else
875 		    out->next = NULL;
876 
877 		out->equiv = out;
878 
879 		Com_sprintf (name, sizeof(name), "textures/%s.wal", in->texture);
880 		out->image = GL_FindImage (name, it_wall);
881 
882 		Com_sprintf (name, sizeof(name), "textures/%s", in->texture);
883 		out->image->script = RS_FindScript(name);
884 
885 		if (out->image->script)
886 			RS_ReadyScript(out->image->script);
887 
888 		//check for normal, height and specular maps
889 		strcpy(sv_name, name);
890 		if( ( strlen( name ) + 8 ) <= MAX_QPATH )
891 		{
892 			strcat( name, "_nm.tga" );
893 			out->normalMap = GL_FindImage( name, it_bump );
894 			if( out->normalMap == NULL )
895 			{
896 				out->has_normalmap = false;
897 				out->normalMap = out->image;
898 			}
899 			else
900 				out->has_normalmap = true;
901 		}
902 		else
903 		{
904 			out->has_normalmap = false;
905 			out->normalMap = out->image;
906 		}
907 
908 		strcpy(name, sv_name);
909 		if( ( strlen( name ) + 8 ) <= MAX_QPATH )
910 		{
911 			strcat( name, "_hm.tga" );
912 			out->heightMap = GL_FindImage( name, it_bump );
913 			if( out->heightMap == NULL )
914 			{
915 				out->has_heightmap = false;
916 				out->heightMap = out->image;
917 			}
918 			else
919 				out->has_heightmap = true;
920 		}
921 		else
922 		{
923 			out->has_heightmap = false;
924 			out->heightMap = out->image;
925 		}
926 	}
927 
928 	// count animation frames
929 	for (i=0 ; i<count ; i++)
930 	{
931 		out = &loadmodel->texinfo[i];
932 		out->numframes = 1;
933 		for (step = out->next ; step && step != out ; step=step->next)
934 			out->numframes++;
935 	}
936 
937 	//find equivalent texinfos
938 	num_unique = 0;
939 	unique_temp = Z_Malloc (sizeof(mtexinfo_t*)*count);
940 	for (i = 0; i < count; i++)
941 	{
942 		for (j = 0; j < i; j++)
943 		{
944 			if (in_base[i].flags == in_base[j].flags &&
945 				in_base[i].nexttexinfo == in_base[j].nexttexinfo &&
946 				!strcmp (in_base[i].texture, in_base[j].texture))
947 			{
948 				loadmodel->texinfo[i].equiv = loadmodel->texinfo[j].equiv;
949 				break;
950 			}
951 		}
952 		if (j == i)
953 		{
954 			unique_temp[num_unique++] = loadmodel->texinfo[i].equiv;
955 		}
956 	}
957 
958 	qsort (unique_temp, num_unique, sizeof(mtexinfo_t*), compare_unique_texinfo);
959 
960 	loadmodel->unique_texinfo = Hunk_Alloc (num_unique*sizeof(mtexinfo_t*));
961 	memcpy (loadmodel->unique_texinfo, unique_temp, num_unique*sizeof(mtexinfo_t*));
962 	Z_Free (unique_temp);
963 	loadmodel->num_unique_texinfos = num_unique;
964 
965 	Com_Printf ("Condensed ^2%i texinfos into ^2%i equivalent texinfos\n", count, num_unique);
966 }
967 
968 /*
969 ================
970 CalcSurfaceExtents
971 
972 Fills in s->texturemins[] and s->extents[]
973 ================
974 */
CalcSurfaceExtents(msurface_t * s,qboolean override,int * smax,int * tmax,float * xscale,float * yscale,int firstedge,int numedges)975 void CalcSurfaceExtents (msurface_t *s, qboolean override, int *smax, int *tmax, float *xscale, float *yscale, int firstedge, int numedges)
976 {
977 	float	mins[2], maxs[2], val;
978 	int		i,j, e, vnum;
979 	mvertex_t	*v;
980 	mtexinfo_t	*tex;
981 	int		bmins[2], bmaxs[2];
982 
983 	mins[0] = mins[1] = 999999;
984 	maxs[0] = maxs[1] = -99999;
985 
986 	tex = s->texinfo;
987 
988 	if (firstedge < 0 || firstedge+numedges-1 >= loadmodel->numsurfedges)
989 		Com_Error (ERR_DROP,
990 			"Map contains invalid value for s->firstedge!\n"
991 			"The file is likely corrupted, please obtain a fresh copy.");
992 	for (i=0 ; i<numedges ; i++)
993 	{
994 		e = loadmodel->surfedges[firstedge+i];
995 		if (abs(e) > loadmodel->numedges)
996 			Com_Error (ERR_DROP,
997 				"Map contains invalid edge offsets!\n"
998 				"The file is likely corrupted, please obtain a fresh copy.");
999 		if (e >= 0)
1000 			vnum = loadmodel->edges[e].v[0];
1001 		else
1002 			vnum = loadmodel->edges[-e].v[1];
1003 		if (vnum < 0 || vnum >= loadmodel->numvertexes)
1004 			Com_Error (ERR_DROP,
1005 				"Map contains invalid vertex offsets!\n"
1006 				"The file is likely corrupted, please obtain a fresh copy.");
1007 		v = &loadmodel->vertexes[vnum];
1008 
1009 		for (j=0 ; j<2 ; j++)
1010 		{
1011 			val = v->position[0] * tex->vecs[j][0] +
1012 				v->position[1] * tex->vecs[j][1] +
1013 				v->position[2] * tex->vecs[j][2] +
1014 				tex->vecs[j][3];
1015 			if (val < mins[j])
1016 				mins[j] = val;
1017 			if (val > maxs[j])
1018 				maxs[j] = val;
1019 		}
1020 	}
1021 
1022 	if (!override)
1023 	{
1024 #define DEFAULT_LIGHTMAP_SCALE 16 //each lightmap pixel represents 16x16 units
1025 	    *xscale = *yscale = DEFAULT_LIGHTMAP_SCALE;
1026 		for (i=0 ; i<2 ; i++)
1027 	    {
1028 		    bmins[i] = floor(mins[i]/DEFAULT_LIGHTMAP_SCALE);
1029 		    bmaxs[i] = ceil(maxs[i]/DEFAULT_LIGHTMAP_SCALE);
1030 
1031 		    s->texturemins[i] = bmins[i] * DEFAULT_LIGHTMAP_SCALE;
1032 		    s->extents[i] = (bmaxs[i] - bmins[i]) * DEFAULT_LIGHTMAP_SCALE;
1033 	    }
1034 	    *smax = (s->extents[0]/DEFAULT_LIGHTMAP_SCALE)+1;
1035         *tmax = (s->extents[1]/DEFAULT_LIGHTMAP_SCALE)+1;
1036     }
1037     else
1038     {
1039 	    bmins[0] = floor(mins[0]/(*xscale));
1040 	    bmaxs[0] = ceil(maxs[0]/(*xscale));
1041 	    s->texturemins[0] = bmins[0] * (*xscale);
1042 	    s->extents[0] = (bmaxs[0] - bmins[0]) * (*xscale);
1043 
1044 	    bmins[1] = floor(mins[1]/(*yscale));
1045 	    bmaxs[1] = ceil(maxs[1]/(*yscale));
1046 	    s->texturemins[1] = bmins[1] * (*yscale);
1047 	    s->extents[1] = (bmaxs[1] - bmins[1]) * (*yscale);
1048     }
1049 }
1050 
Mod_CalcSurfaceNormals(msurface_t * surf)1051 void Mod_CalcSurfaceNormals(msurface_t *surf)
1052 {
1053 
1054 	glpoly_t *p = surf->polys;
1055 	float	*v;
1056 	int		i;
1057 	float 	temp_tangentSpaceTransform[3][3];
1058 
1059 	for (; p; p = p->chain)
1060 	{
1061 		vec3_t	v01, v02, temp1, temp2, temp3;
1062 		vec3_t	normal, binormal, tangent;
1063 		float	s = 0;
1064 		float	*vec;
1065 
1066 		_VectorSubtract( p->verts[ 1 ], p->verts[0], v01 );
1067 		vec = p->verts[0];
1068 		_VectorCopy(surf->plane->normal, normal);
1069 
1070 		// FIXME: on some maps, this code doesn't always initialize v02,
1071 		// leading to Valgrind complaining about use of uninitialized memory.
1072 		// dm-infinity and dm-zorn2k11 are two such maps. Probably not a huge
1073 		// deal, doesn't seem to be causing any issues.
1074 		for (v = p->verts[0], i = 0 ; i < p->numverts; i++, v += VERTEXSIZE)
1075 		{
1076 
1077 			float currentLength;
1078 			vec3_t currentNormal;
1079 
1080 			//do calculations for normal, tangent and binormal
1081 			if( i > 1) {
1082 				_VectorSubtract( p->verts[ i ], p->verts[0], temp1 );
1083 
1084 				CrossProduct( temp1, v01, currentNormal );
1085 				currentLength = VectorLength( currentNormal );
1086 
1087 				if( currentLength > s )
1088 				{
1089 					s = currentLength;
1090 					_VectorCopy( currentNormal, normal );
1091 
1092 					vec = p->verts[i];
1093 					_VectorCopy( temp1, v02 );
1094 
1095 				}
1096 			}
1097 		}
1098 
1099 		VectorNormalize( normal ); //we have the largest normal
1100 
1101 		temp_tangentSpaceTransform[ 0 ][ 2 ] = normal[ 0 ];
1102 		temp_tangentSpaceTransform[ 1 ][ 2 ] = normal[ 1 ];
1103 		temp_tangentSpaceTransform[ 2 ][ 2 ] = normal[ 2 ];
1104 
1105 		//now get the tangent
1106 		s = ( p->verts[ 1 ][ 3 ] - p->verts[ 0 ][ 3 ] )
1107 			* ( vec[ 4 ] - p->verts[ 0 ][ 4 ] );
1108 		s -= ( vec[ 3 ] - p->verts[ 0 ][ 3 ] )
1109 			 * ( p->verts[ 1 ][ 4 ] - p->verts[ 0 ][ 4 ] );
1110 		s = 1.0f / s;
1111 
1112 		VectorScale( v01, vec[ 4 ] - p->verts[ 0 ][ 4 ], temp1 );
1113 		VectorScale( v02, p->verts[ 1 ][ 4 ] - p->verts[ 0 ][ 4 ], temp2 );
1114 		_VectorSubtract( temp1, temp2, temp3 );
1115 		VectorScale( temp3, s, tangent );
1116 		VectorNormalize( tangent );
1117 
1118 		temp_tangentSpaceTransform[ 0 ][ 0 ] = tangent[ 0 ];
1119 		temp_tangentSpaceTransform[ 1 ][ 0 ] = tangent[ 1 ];
1120 		temp_tangentSpaceTransform[ 2 ][ 0 ] = tangent[ 2 ];
1121 
1122 		//now get the binormal
1123 		VectorScale( v02, p->verts[ 1 ][ 3 ] - p->verts[ 0 ][ 3 ], temp1 );
1124 		VectorScale( v01, vec[ 3 ] - p->verts[ 0 ][ 3 ], temp2 );
1125 		_VectorSubtract( temp1, temp2, temp3 );
1126 		VectorScale( temp3, s, binormal );
1127 		VectorNormalize( binormal );
1128 
1129 		temp_tangentSpaceTransform[ 0 ][ 1 ] = binormal[ 0 ];
1130 		temp_tangentSpaceTransform[ 1 ][ 1 ] = binormal[ 1 ];
1131 		temp_tangentSpaceTransform[ 2 ][ 1 ] = binormal[ 2 ];
1132 
1133 		//Try to find this tangentSpaceTransform in the existing array or else
1134 		//add it. This is not a RAM-saving measure, it's to allow comparison
1135 		//of different tangentSpaceTransforms using the == operator, which is
1136 		//more efficient.
1137 		{
1138 			float *tst;
1139 			int i;
1140 			int j;
1141 			for (tst = loadmodel->tangentSpaceTransforms, i = 0; i < loadmodel->numTangentSpaceTransforms; i++, tst += 9)
1142 			{
1143 				qboolean match = true;
1144 				for (j = 0; j < 9; j++)
1145 				{
1146 					// If we reduce our precision to just 4 decimal places,
1147 					// we can cut the number of transforms by a factor of more
1148 					// than 5. Single-precision floating point is precise to
1149 					// just 6 places anyway, so we're not loosing too much.
1150 					// Subjectively, it still looks fine.
1151 					if (fabs (tst[j]-temp_tangentSpaceTransform[j/3][j%3]) > 0.0001)
1152 					{
1153 						match = false;
1154 						break;
1155 					}
1156 				}
1157 				if (match)
1158 					break;
1159 			}
1160 			surf->tangentSpaceTransform = tst;
1161 			if (i == loadmodel->numTangentSpaceTransforms)
1162 			{
1163 				for (i = 0; i < 3; i++)
1164 					for (j = 0; j < 3; j++)
1165 						*(tst++) = temp_tangentSpaceTransform[i][j];
1166 				loadmodel->numTangentSpaceTransforms++;
1167 			}
1168 		}
1169 	}
1170 }
1171 
1172 void BSP_BuildPolygonFromSurface(msurface_t *fa, float xscale, float yscale, int light_s, int light_t, int firstedge, int lnumverts);
1173 void BSP_CreateSurfaceLightmap (msurface_t *surf, int smax, int tmax, int *light_s, int *light_t);
1174 void BSP_EndBuildingLightmaps (void);
1175 void BSP_BeginBuildingLightmaps (model_t *m);
1176 
1177 
1178 // FOR REFINE: .lightmap high-detail lightmap override files
1179 
1180 ltmp_facelookup_t   lfacelookups[MAX_MAP_FACES];
1181 int					lightdatasize;
1182 byte				override_lightdata[MAX_OVERRIDE_LIGHTING];
1183 byte				*lightmap_header;
1184 
1185 // choose up to one override for each map face
Mod_LoadRefineFaceLookups(lump_t * l)1186 void Mod_LoadRefineFaceLookups (lump_t *l)
1187 {
1188 	int i, count;
1189 	ltmp_facelookup_t *in;
1190 	ltmp_facelookup_t *out;
1191 
1192 	if (!l->filelen)
1193 		return;
1194 	in = (void *)(lightmap_header+l->fileofs);
1195 	printf ("%d / %d\n", l->filelen, sizeof(*in));
1196 	if (l->filelen % sizeof (*in))
1197 		Com_Error (ERR_DROP, "Mod_LoadRefineFaceLookups: funny lump size");
1198 	count = l->filelen / sizeof (*in);
1199 
1200 	Com_Printf ("%f\n", in->xscale);
1201 	for (i = 0; i < count; i++, in++)
1202 	{
1203 		int facenum, format, offset, size, width, height;
1204 
1205 		// Silently skip over pixel formats we don't understand. We do this
1206 		// check first so that in the future it can be used to work around the
1207 		// following two for backward compatibility.
1208 		format = LittleLong(in->format);
1209 		if (format >= LTMP_NUM_SUPPORTED_PIXFMTS)
1210 			continue;
1211 
1212 		// make a federal case out of bad face offsets
1213 		facenum = LittleLong(in->facenum);
1214 		if (facenum >= MAX_MAP_FACES || facenum < 0)
1215 			Com_Error (ERR_DROP, "Mod_LoadRefineFaceeLookups: bad facenum");
1216 
1217 		// make a federal case out of bad pixel data offsets
1218 		offset = LittleLong(in->offset);
1219 		width = LittleLong(in->width);
1220 		height = LittleLong(in->height);
1221 		switch (format)
1222 		{
1223 			case LTMP_PIXFMT_RGB24:
1224 				size = 3*width*height;
1225 				break;
1226 		}
1227 		if (offset < 1 || offset+size > MAX_OVERRIDE_LIGHTING*4)
1228 			Com_Error (ERR_DROP, "Mod_LoadRefineFaceeLookups: bad offset");
1229 
1230 		out = &lfacelookups[facenum];
1231 		out->offset = offset;
1232 		out->format = format;
1233 		out->width = width;
1234 		out->height = height;
1235 		out->xscale = LittleFloat(in->xscale);
1236 		out->yscale = LittleFloat(in->yscale);
1237 	}
1238 }
1239 
1240 // load only the lightmap data that will actually be used; readjust the
1241 // pixel data offsets accordingly
Mod_LoadRefineLighting(lump_t * l)1242 void Mod_LoadRefineLighting (lump_t *l)
1243 {
1244 	int					i;
1245 	byte				*in_buffer;
1246 	qboolean			overflowed = false;
1247 
1248 	if (!l->filelen)
1249 		return;
1250 	if (l->filelen > MAX_OVERRIDE_LIGHTING*4)
1251 		Com_Error (ERR_DROP, "Mod_LoadRefineLighting: too much light data");
1252 
1253 	lightdatasize = 0;
1254 	in_buffer = lightmap_header + l->fileofs;
1255 	for (i = 0; i < loadmodel->numsurfaces; i++)
1256 	{
1257 		int in_offset = lfacelookups[i].offset;
1258 		if (in_offset)
1259 		{
1260 			int size = 0;
1261 			switch (lfacelookups[i].format)
1262 			{
1263 				case LTMP_PIXFMT_RGB24:
1264 					size = 3*lfacelookups[i].width*lfacelookups[i].height;
1265 					break;
1266 			}
1267 			if (lightdatasize + size >= MAX_OVERRIDE_LIGHTING)
1268 			{
1269 				overflowed = true;
1270 				break;
1271 			}
1272 			memcpy (override_lightdata+lightdatasize, in_buffer+in_offset-1, size);
1273 			lfacelookups[i].offset = lightdatasize+1;
1274 			lightdatasize += size;
1275 		}
1276 	}
1277 
1278 	if (overflowed)
1279 	{
1280 		Com_Printf ("Mod_LoadRefineLighting: MAX_OVERRIDE_LIGHTING overflow!\n");
1281 		Com_Printf ("Disabling HD lightmaps for this map.\n");
1282 		memset (lfacelookups, 0, sizeof(lfacelookups));
1283 	}
1284 }
1285 
Mod_LoadRefineLightmap(char * bsp_name)1286 void Mod_LoadRefineLightmap (char *bsp_name)
1287 {
1288 	byte 				*buf, *uncompressed_buf;
1289 	lightmapheader_t	header;
1290 	int					length;
1291 	char				name[MAX_OSPATH];
1292 	char				*extension;
1293 	int					lightmap_file_lump_order[LTMP_LUMPS] = {
1294 		LTMP_LUMP_FACELOOKUP, LTMP_LUMP_LIGHTING
1295 	};
1296 
1297 	sizebuf_t			in, out;
1298 
1299 #ifndef HAVE_ZLIB
1300 	Com_Printf ("Zlib support must be enabled to use HD lightmaps!\n");
1301 	Com_Printf ("Please recompile with Zlib support.\n");
1302 	return;
1303 #endif
1304 
1305 	strncpy (name, bsp_name, MAX_OSPATH-1-strlen(".lightmap")+strlen(".bsp"));
1306 	extension = strstr (name, ".bsp");
1307 	if (extension)
1308 		*extension = 0;
1309 	strcat (name, ".lightmap");
1310 
1311 	length = FS_LoadFile (name, (void **)&buf);
1312 	if (!buf)
1313 	{
1314 		Com_Printf ("Could not load %s\n", name);
1315 		return;
1316 	}
1317 	else
1318 		Com_Printf ("Loaded %s\n", name);
1319 
1320 	SZ_Init (&in, buf, length);
1321 	in.cursize = length;
1322 	uncompressed_buf = malloc (LTMP_MAX_UNCOMPRESSED_DATA);
1323 	if (!uncompressed_buf)
1324 	{
1325 		Com_Printf ("Mod_LoadRefineLightmap: unable to allocate %d bytes!\n", LTMP_MAX_UNCOMPRESSED_DATA);
1326 		return;
1327 	}
1328 	SZ_Init (&out, (byte *)uncompressed_buf, LTMP_MAX_UNCOMPRESSED_DATA);
1329 	qdecompress (&in, &out, compression_zlib_header);
1330 	FS_FreeFile (buf);
1331 
1332 	if (!out.cursize)
1333 	{
1334 		Com_Printf ("Mod_LoadRefineLightmap: unable to decompress data in %s!\n",name);
1335 		free (uncompressed_buf);
1336 		return;
1337 	}
1338 
1339 	lightmap_header = (byte *)uncompressed_buf;
1340 	header = *(lightmapheader_t *)uncompressed_buf;
1341 
1342 	if (header.ident != IDLIGHTMAPHEADER)
1343 	{
1344 		Com_Printf ("Mod_LoadRefineLightmap: invalid magic number in %s!\n"
1345 					"The file is likely corrupt, please obtain a fresh copy.\n", name);
1346 		free (uncompressed_buf);
1347 		return;
1348 	}
1349 	if (header.version != LTMPVERSION)
1350 	{
1351 		Com_Printf ("Mod_LoadRefineLightmap: invalid major version number in %s!\n"
1352 					"Version %d of the format is not supported. Current major version number is %d\n",
1353 					name, header.version, LTMPVERSION);
1354 		free (uncompressed_buf);
1355 		return;
1356 	}
1357 
1358 	if (checkLumps (header.lumps, sizeof(int)*3, lightmap_file_lump_order, uncompressed_buf, LTMP_LUMPS, out.cursize))
1359 	{
1360 		Com_Printf ("Mod_LoadRefineLightmap: lumps in %s don't add up right!\n"
1361 					"The file is likely corrupt, please obtain a fresh copy.\n",name);
1362 		free (uncompressed_buf);
1363 		return;
1364 	}
1365 
1366 	Mod_LoadRefineFaceLookups (&header.lumps[LTMP_LUMP_FACELOOKUP]);
1367 	Mod_LoadRefineLighting (&header.lumps[LTMP_LUMP_LIGHTING]);
1368 
1369 	free (uncompressed_buf);
1370 }
1371 
1372 /*
1373 =================
1374 Mod_LoadFaces
1375 =================
1376 */
1377 
1378 // We need access to the lighting lump so we can check the bounds of lightmap
1379 // offsets. Otherwise, crafted or corrupted BSPs could crash the client.
Mod_LoadFaces(lump_t * l,lump_t * lighting)1380 void Mod_LoadFaces (lump_t *l, lump_t *lighting)
1381 {
1382 	dface_t		*in;
1383 	msurface_t 	*out;
1384 	int			i, count, surfnum;
1385 	int			planenum, side;
1386 	int			ti;
1387 	int			smax, tmax;
1388 	int			light_s, light_t;
1389 	float		xscale, yscale;
1390 	rscript_t	*rs;
1391 	vec3_t		color;
1392 
1393 	in = (void *)(mod_base + l->fileofs);
1394 	if (l->filelen % sizeof(*in))
1395 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1396 	count = l->filelen / sizeof(*in);
1397 	out = Hunk_Alloc ( count*sizeof(*out));
1398 
1399 	loadmodel->surfaces = out;
1400 	loadmodel->numsurfaces = count;
1401 
1402 	//we are guaranteed not to need more than this
1403 	loadmodel->tangentSpaceTransforms = Hunk_Alloc (sizeof(float)*9*count);
1404 
1405 	currentmodel = loadmodel;
1406 
1407 	memset (lfacelookups, 0, sizeof(lfacelookups));
1408 	if (r_lightmapfiles->integer)
1409 		Mod_LoadRefineLightmap (loadmodel->name);
1410 
1411 	BSP_BeginBuildingLightmaps (loadmodel);
1412 
1413 	VB_VCInit();
1414 
1415 	for ( surfnum=0 ; surfnum<count ; surfnum++, in++, out++)
1416 	{
1417 		int firstedge = LittleLong(in->firstedge);
1418 		int numedges = LittleShort(in->numedges);
1419 		out->iflags = 0;
1420 		out->polys = NULL;
1421 
1422 		planenum = (unsigned short)LittleShort(in->planenum);
1423 		side = LittleShort(in->side);
1424 		if (side)
1425 			out->iflags |= ISURF_PLANEBACK;
1426 
1427 		if (planenum >= loadmodel->numplanes)
1428 			Com_Error (ERR_DROP,
1429 				"Map has invalid plane offsets!\n"
1430 				"The file is likely corrupted, please obtain a fresh copy.");
1431 		out->plane = loadmodel->planes + planenum;
1432 
1433 		ti = LittleShort (in->texinfo);
1434 		if (ti < 0 || ti >= loadmodel->numtexinfo)
1435 			Com_Error (ERR_DROP,
1436 				"Map has invalid texinfo offsets!\n"
1437 				"The file is likely corrupted, please obtain a fresh copy.");
1438 		out->texinfo = loadmodel->texinfo + ti;
1439 
1440 		if (lfacelookups[surfnum].offset)
1441 		{
1442 			smax=lfacelookups[surfnum].width;
1443 			tmax=lfacelookups[surfnum].height;
1444 			xscale=lfacelookups[surfnum].xscale;
1445 			yscale=lfacelookups[surfnum].yscale;
1446 			CalcSurfaceExtents (out, true, &smax, &tmax, &xscale, &yscale, firstedge, numedges);
1447 		}
1448 		else
1449 		{
1450 			CalcSurfaceExtents (out, false, &smax, &tmax, &xscale, &yscale, firstedge, numedges);
1451 		}
1452 
1453 	// lighting info
1454 
1455 		for (i=0 ; i<MAXLIGHTMAPS ; i++)
1456 			out->styles[i] = in->styles[i];
1457 		i = LittleLong(in->lightofs);
1458 
1459 		if (i < 0 || i >= lighting->filelen)
1460 			out->samples = NULL;
1461 		else if (lfacelookups[surfnum].offset > 0 && lfacelookups[surfnum].offset <= lightdatasize)
1462 			out->samples = override_lightdata + lfacelookups[surfnum].offset-1;
1463 		else
1464 			out->samples = loadmodel->lightdata + i;
1465 
1466 		// set the drawing flags
1467 		if (out->texinfo->flags & SURF_WARP)
1468 		{
1469 			out->iflags |= ISURF_DRAWTURB;
1470 			for (i=0 ; i<2 ; i++)
1471 			{
1472 				out->extents[i] = 16384;
1473 				out->texturemins[i] = -8192;
1474 			}
1475 			if(!(gl_state.glsl_shaders && gl_glsl_shaders->value) || !strcmp(out->texinfo->normalMap->name, out->texinfo->image->name))
1476 				R_SubdivideSurface (out, firstedge, numedges);	// cut up polygon for warps
1477 		}
1478 
1479 		// create lightmaps and polygons
1480 		light_s = light_t = 0;
1481 		if ( !SurfaceHasNoLightmap(out) )
1482 		{
1483 			BSP_CreateSurfaceLightmap (out, smax, tmax, &light_s, &light_t);
1484 		}
1485 
1486 		if ( (! (out->texinfo->flags & SURF_WARP)) || (gl_state.glsl_shaders && gl_glsl_shaders->value && strcmp(out->texinfo->normalMap->name, out->texinfo->image->name)))
1487 			BSP_BuildPolygonFromSurface(out, xscale, yscale, light_s, light_t, firstedge, numedges);
1488 
1489 		rs = (rscript_t *)out->texinfo->image->script;
1490 
1491 		if(rs)	{
1492 
1493 			rs_stage_t	*stage = rs->stage;
1494 			do {
1495 				if (stage->lensflare) {
1496 					if(r_lensflare->value)
1497 						Mod_AddFlareSurface(out, stage->flaretype);
1498 				}
1499 				if (stage->grass && stage->texture) {
1500 					if(stage->colormap.enabled) {
1501 						color[0] = stage->colormap.red;
1502 						color[1] = stage->colormap.green;
1503 						color[2] = stage->colormap.blue;
1504 					}
1505 					Mod_AddVegetationSurface(out, stage->texture->texnum, color, stage->scale.scaleX, stage->texture->bare_name, stage->grasstype);
1506 				}
1507 				if (stage->beam && stage->texture) {
1508 					if(stage->colormap.enabled) {
1509 						color[0] = stage->colormap.red;
1510 						color[1] = stage->colormap.green;
1511 						color[2] = stage->colormap.blue;
1512 					}
1513 					Mod_AddBeamSurface(out, stage->texture->texnum, color, stage->scale.scaleX, stage->texture->bare_name, stage->beamtype,
1514 						stage->xang, stage->yang, stage->rotating);
1515 				}
1516 				if (stage->cube)
1517 					out->texinfo->flags |= SURF_SHINY;
1518 			} while ( (stage = stage->next) );
1519 		}
1520 		Mod_CalcSurfaceNormals(out);
1521 
1522 		if(gl_state.vbo) {
1523 			VB_BuildVBOBufferSize(out);
1524 			out->has_vbo = false;
1525 		}
1526 	}
1527 	BSP_EndBuildingLightmaps ();
1528 }
1529 
1530 
1531 /*
1532 =================
1533 Mod_SetParent
1534 =================
1535 */
Mod_SetParent(mnode_t * node,mnode_t * parent)1536 void Mod_SetParent (mnode_t *node, mnode_t *parent)
1537 {
1538 	node->parent = parent;
1539 	if (node->contents != -1)
1540 		return;
1541 	Mod_SetParent (node->children[0], node);
1542 	Mod_SetParent (node->children[1], node);
1543 }
1544 
1545 /*
1546 =================
1547 Mod_LoadNodes
1548 =================
1549 */
Mod_LoadNodes(lump_t * l)1550 void Mod_LoadNodes (lump_t *l)
1551 {
1552 	int			i, j, count, p;
1553 	dnode_t		*in;
1554 	mnode_t 	*out;
1555 
1556 	in = (void *)(mod_base + l->fileofs);
1557 	if (l->filelen % sizeof(*in))
1558 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1559 	count = l->filelen / sizeof(*in);
1560 	out = Hunk_Alloc ( count*sizeof(*out));
1561 
1562 	loadmodel->nodes = out;
1563 	loadmodel->numnodes = count;
1564 
1565 	for ( i=0 ; i<count ; i++, in++, out++)
1566 	{
1567 		for (j=0 ; j<3 ; j++)
1568 		{
1569 			out->minmaxs[j] = LittleShort (in->mins[j]);
1570 			out->minmaxs[3+j] = LittleShort (in->maxs[j]);
1571 		}
1572 
1573 		p = LittleLong(in->planenum);
1574 		if (p < 0 || p >= loadmodel->numplanes)
1575 			Com_Error (ERR_DROP,
1576 				"Map has invalid plane offsets!\n"
1577 				"The file is likely corrupted, please obtain a fresh copy.");
1578 		out->plane = loadmodel->planes + p;
1579 
1580 		out->firstsurface = (unsigned short)LittleShort (in->firstface);
1581 		out->numsurfaces = (unsigned short)LittleShort (in->numfaces);
1582 		out->contents = -1;	// differentiate from leafs
1583 
1584 		for (j=0 ; j<2 ; j++)
1585 		{
1586 			p = LittleLong (in->children[j]);
1587 			if (p >= 0)
1588 			{
1589 				if (p >= loadmodel->numnodes)
1590 					Com_Error (ERR_DROP,
1591 						"Map file has invalid node offsets!\n"
1592 						"The file is likely corrupted, please obtain a fresh copy.");
1593 				out->children[j] = loadmodel->nodes + p;
1594 			}
1595 			else
1596 			{
1597 				if (-1-p >= loadmodel->numleafs)
1598 					Com_Error (ERR_DROP,
1599 						"Map file has invalid leaf offsets!\n"
1600 						"The file is likely corrupted, please obtain a fresh copy.");
1601 				out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
1602 			}
1603 		}
1604 
1605 	}
1606 
1607 	Mod_SetParent (loadmodel->nodes, NULL);	// sets nodes and leafs
1608 }
1609 
1610 /*
1611 =================
1612 Mod_LoadLeafs
1613 =================
1614 */
Mod_LoadLeafs(lump_t * l)1615 void Mod_LoadLeafs (lump_t *l)
1616 {
1617 	dleaf_t 	*in;
1618 	mleaf_t 	*out;
1619 	int			i, j, count, p;
1620 	int			to_subtract = 0; //for removing SURF_NODRAW surfaces
1621 
1622 	in = (void *)(mod_base + l->fileofs);
1623 	if (l->filelen % sizeof(*in))
1624 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1625 	count = l->filelen / sizeof(*in);
1626 	out = Hunk_Alloc ( count*sizeof(*out));
1627 
1628 	loadmodel->leafs = out;
1629 	loadmodel->numleafs = count;
1630 
1631 	for ( i=0 ; i<count ; i++, in++, out++)
1632 	{
1633 		for (j=0 ; j<3 ; j++)
1634 		{
1635 			out->minmaxs[j] = LittleShort (in->mins[j]);
1636 			out->minmaxs[3+j] = LittleShort (in->maxs[j]);
1637 		}
1638 
1639 		p = LittleLong(in->contents);
1640 		out->contents = p;
1641 
1642 		out->cluster = LittleShort(in->cluster);
1643 		out->area = LittleShort(in->area);
1644 
1645 		out->firstmarksurface = loadmodel->marksurfaces +
1646 			(unsigned short)(LittleShort(in->firstleafface));
1647 		out->nummarksurfaces = (unsigned short)LittleShort(in->numleaffaces);
1648 		if (out->firstmarksurface < loadmodel->marksurfaces ||
1649 			out->nummarksurfaces < 0 ||
1650 			(unsigned short)LittleShort(in->firstleafface) >
1651 			loadmodel->nummarksurfaces)
1652 			Com_Error (ERR_DROP,
1653 				"Map file has invalid leaf surface offsets!\n"
1654 				"The file is likely corrupted, please obtain a fresh copy.");
1655 
1656 		out->firstmarksurface -= to_subtract;
1657 
1658 		// Remove SURF_NODRAW surfaces. We do this here instead of in
1659 		// Mod_LoadMarkSurfaces so we can correct the offsets in each leaf.
1660 		for (j = 0; j < out->nummarksurfaces; j++)
1661 		{
1662 			msurface_t *s;
1663 			out->firstmarksurface[j] = out->firstmarksurface[j+to_subtract];
1664 			s = out->firstmarksurface[j];
1665 			if (s->texinfo->flags & SURF_NODRAW)
1666 			{
1667 				to_subtract++;
1668 				j--;
1669 				out->nummarksurfaces--;
1670 			}
1671 		}
1672 
1673 		// gl underwater warp
1674 		for (j=0 ; j<out->nummarksurfaces ; j++)
1675 		{
1676 			msurface_t *s = out->firstmarksurface[j];
1677 			if	(	(out->contents & MASK_WATER) ||
1678 					(s->texinfo->flags & SURF_UNDERWATER))
1679 			out->firstmarksurface[j]->iflags |= ISURF_UNDERWATER;
1680 		}
1681 	}
1682 
1683 	loadmodel->nummarksurfaces -= to_subtract;
1684 
1685 	Com_Printf ("Eliminated ^2%i invisible surfaces.\n", to_subtract);
1686 }
1687 
1688 /*
1689 =================
1690 Mod_LoadMarksurfaces
1691 =================
1692 */
Mod_LoadMarksurfaces(lump_t * l)1693 void Mod_LoadMarksurfaces (lump_t *l)
1694 {
1695 	int		i, j, count;
1696 	short		*in;
1697 	msurface_t **out;
1698 
1699 	in = (void *)(mod_base + l->fileofs);
1700 	if (l->filelen % sizeof(*in))
1701 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1702 	count = l->filelen / sizeof(*in);
1703 	out = Hunk_Alloc ( count*sizeof(*out));
1704 
1705 	loadmodel->marksurfaces = out;
1706 	loadmodel->nummarksurfaces = count;
1707 
1708 	for ( i=0 ; i<count ; i++)
1709 	{
1710 		j = LittleShort(in[i]);
1711 		if (j < 0 ||  j >= loadmodel->numsurfaces)
1712 			Com_Error (ERR_DROP, "Mod_ParseMarksurfaces: bad surface number");
1713 		out[i] = loadmodel->surfaces + j;
1714 	}
1715 }
1716 
1717 /*
1718 =================
1719 Mod_LoadSurfedges
1720 =================
1721 */
Mod_LoadSurfedges(lump_t * l)1722 void Mod_LoadSurfedges (lump_t *l)
1723 {
1724 	int		i, count;
1725 	int		*in, *out;
1726 
1727 
1728 	in = (void *)(mod_base + l->fileofs);
1729 	if (l->filelen % sizeof(*in))
1730 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1731 	count = l->filelen / sizeof(*in);
1732 	if (count < 1 || count >= MAX_MAP_SURFEDGES)
1733 		Com_Error (ERR_DROP, "MOD_LoadBmodel: bad surfedges count in %s: %i",
1734 		loadmodel->name, count);
1735 
1736 	out = Hunk_Alloc ( count*sizeof(*out));
1737 
1738 	loadmodel->surfedges = out;
1739 	loadmodel->numsurfedges = count;
1740 
1741 	for ( i=0 ; i<count ; i++)
1742 		out[i] = LittleLong (in[i]);
1743 }
1744 
1745 
1746 /*
1747 =================
1748 Mod_LoadPlanes
1749 =================
1750 */
Mod_LoadPlanes(lump_t * l)1751 void Mod_LoadPlanes (lump_t *l)
1752 {
1753 	int			i, j;
1754 	cplane_t	*out;
1755 	dplane_t 	*in;
1756 	int			count;
1757 	int			bits;
1758 
1759 	in = (void *)(mod_base + l->fileofs);
1760 	if (l->filelen % sizeof(*in))
1761 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1762 	count = l->filelen / sizeof(*in);
1763 	out = Hunk_Alloc ( count*sizeof(*out));
1764 
1765 	loadmodel->planes = out;
1766 	loadmodel->numplanes = count;
1767 
1768 	for ( i=0 ; i<count ; i++, in++, out++)
1769 	{
1770 		bits = 0;
1771 		for (j=0 ; j<3 ; j++)
1772 		{
1773 			out->normal[j] = LittleFloat (in->normal[j]);
1774 			if (out->normal[j] < 0)
1775 				bits |= 1<<j;
1776 		}
1777 
1778 		out->dist = LittleFloat (in->dist);
1779 		out->type = LittleLong (in->type);
1780 		out->signbits = bits;
1781 	}
1782 }
1783 
1784 /*
1785 =================
1786 Mod_SummarizePVS
1787 
1788 Gather some statistics from the PVS data which allows the renderer to take
1789 some shortcuts.
1790 =================
1791 */
Mod_SummarizePVS(void)1792 void Mod_SummarizePVS (void)
1793 {
1794 	byte		*vis;
1795 	mleaf_t		*leaf, *leaf2;
1796 	int			cluster;
1797 	int			i;
1798 
1799 	loadmodel->num_areas = 0;
1800 	for (i = 0; i < MAX_MAP_AREAS; i++)
1801 	{
1802 		loadmodel->area_min_leaf[i] = loadmodel->numleafs-1;
1803 		loadmodel->area_max_leaf[i] = 0;
1804 	}
1805 
1806 	for (i=0,leaf=loadmodel->leafs ; i<loadmodel->numleafs ; i++, leaf++)
1807 	{
1808 		cluster = leaf->cluster;
1809 		if (cluster == -1)
1810 			continue;
1811 
1812 		vis = Mod_ClusterPVS (cluster, loadmodel);
1813 
1814 		if (loadmodel->area_min_leaf[leaf->area] > i)
1815 			loadmodel->area_min_leaf[leaf->area] = i;
1816 		if (loadmodel->area_max_leaf[leaf->area] < i)
1817 			loadmodel->area_max_leaf[leaf->area] = i;
1818 		if (leaf->area > loadmodel->num_areas)
1819 			loadmodel->num_areas = leaf->area;
1820 
1821 		// Two separate loops, one for minPVSleaf and one for maxPVSleaf,
1822 		// each coming from opposite directions, for greater efficiency.
1823 
1824 		for (	leaf->minPVSleaf = 0, leaf2 = loadmodel->leafs;
1825 				leaf->minPVSleaf < loadmodel->numleafs;
1826 				leaf->minPVSleaf++, leaf2++
1827 			)
1828 		{
1829 			cluster = leaf2->cluster;
1830 			if ((leaf2->contents & CONTENTS_SOLID) || cluster == -1)
1831 				continue;
1832 			if (leaf2->nummarksurfaces == 0)
1833 				continue;
1834 
1835 			if (vis[cluster>>3] & (1<<(cluster&7)))
1836 				break;
1837 		}
1838 
1839 		for (	leaf->maxPVSleaf = loadmodel->numleafs-1, leaf2 = &loadmodel->leafs[leaf->maxPVSleaf];
1840 				leaf->maxPVSleaf >= leaf->minPVSleaf;
1841 				leaf->maxPVSleaf--, leaf2--
1842 			)
1843 		{
1844 			cluster = leaf2->cluster;
1845 			if ((leaf2->contents & CONTENTS_SOLID) || cluster == -1)
1846 				continue;
1847 			if (leaf2->nummarksurfaces == 0)
1848 				continue;
1849 
1850 			if (vis[cluster>>3] & (1<<(cluster&7)))
1851 				break;
1852 		}
1853 	}
1854 	loadmodel->num_areas++;
1855 }
1856 
1857 /*
1858 =================
1859 Mod_LoadBrushModel
1860 =================
1861 */
1862 extern cvar_t *scriptsloaded;
Mod_LoadBrushModel(model_t * mod,void * buffer)1863 void Mod_LoadBrushModel (model_t *mod, void *buffer)
1864 {
1865 	int			i;
1866 	dheader_t	*header;
1867 	mmodel_t 	*bm;
1868 	char		rs_name[MAX_OSPATH], tmp[MAX_QPATH];		// rscript - MrG
1869 
1870 	if(r_lensflare->value)
1871 		R_ClearFlares();
1872 	R_ClearGrasses();
1873 	R_ClearBeams();
1874 
1875 	RS_FreeUnmarked();
1876 	strcpy(tmp,loadmodel->name+5);
1877 	tmp[strlen(tmp)-4]=0;
1878 	Com_sprintf(rs_name,MAX_OSPATH,"scripts/maps/%s.rscript",tmp);
1879 	RS_ScanPathForScripts();		// load all found scripts
1880 	RS_LoadScript(rs_name);
1881 	RS_ReloadImageScriptLinks();
1882 	RS_LoadSpecialScripts();
1883 	Cvar_SetValue("scriptsloaded", 1);
1884 
1885 	//ODE - clear out any ragdolls;
1886 	R_ClearAllRagdolls();
1887 
1888 	//ODE - create new world(flush out old first)
1889 	RGD_DestroyWorldObject();
1890 	RGD_CreateWorldObject();
1891 
1892 	r_numWorldLights = 0;
1893 
1894 	loadmodel->type = mod_brush;
1895 	if (loadmodel != mod_known)
1896 		Com_Error (ERR_DROP, "Loaded a brush model after the world");
1897 
1898 	header = (dheader_t *)buffer;
1899 
1900 	i = LittleLong (header->version);
1901 	if (i != BSPVERSION)
1902 		Com_Error (ERR_DROP, "Mod_LoadBrushModel: %s has wrong version number (%i should be %i)", mod->name, i, BSPVERSION);
1903 
1904 	// swap all the lumps
1905 	mod_base = (byte *)header;
1906 
1907 	for (i=0 ; i<sizeof(dheader_t)/sizeof(int) ; i++)
1908 		((int *)header)[i] = LittleLong ( ((int *)header)[i]);
1909 
1910 	// load into heap
1911 	Mod_LoadEntityStrn (&header->lumps[LUMP_ENTITIES]);
1912 	Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
1913 	Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
1914 	Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
1915 	Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
1916 	Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
1917 	Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
1918 	Mod_LoadFaces (&header->lumps[LUMP_FACES], &header->lumps[LUMP_LIGHTING]);
1919 	Mod_LoadMarksurfaces (&header->lumps[LUMP_LEAFFACES]);
1920 	Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
1921 	Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
1922 	Mod_LoadNodes (&header->lumps[LUMP_NODES]);
1923 	Mod_SummarizePVS ();
1924 	Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
1925 	mod->num_frames = 2;		// regular and alternate animation
1926 
1927 	//
1928 	// set up the submodels
1929 	//
1930 	for (i=0 ; i<mod->numsubmodels ; i++)
1931 	{
1932 		model_t	*starmod;
1933 
1934 		bm = &mod->submodels[i];
1935 		starmod = &mod_inline[i];
1936 
1937 		*starmod = *loadmodel;
1938 
1939 		starmod->firstmodelsurface = bm->firstface;
1940 		starmod->nummodelsurfaces = bm->numfaces;
1941 		starmod->firstnode = bm->headnode;
1942 		if (starmod->firstnode >= loadmodel->numnodes)
1943 			Com_Error (ERR_DROP, "Inline model %i has bad firstnode", i);
1944 
1945 		VectorCopy (bm->maxs, starmod->maxs);
1946 		VectorCopy (bm->mins, starmod->mins);
1947 		starmod->radius = bm->radius;
1948 
1949 		if (i == 0)
1950 			*loadmodel = *starmod;
1951 
1952 		starmod->numleafs = bm->visleafs;
1953 	}
1954 
1955 	R_ParseLightEntities();
1956 	R_FindSunEntity();
1957 	R_FinalizeGrass(loadmodel);
1958 }
1959 
1960 //=============================================================================
1961 
1962 /*
1963 @@@@@@@@@@@@@@@@@@@@@
1964 R_BeginRegistration
1965 
1966 Specifies the model that will be used as the world
1967 @@@@@@@@@@@@@@@@@@@@@
1968 */
R_FindFile(char * filename,FILE ** file)1969 int R_FindFile (char *filename, FILE **file)
1970 {
1971 
1972 	*file = fopen (filename, "rb");
1973 	if (!*file) {
1974 		*file = NULL;
1975 		return -1;
1976 	}
1977 	else
1978 		return 1;
1979 
1980 }
1981 
1982 //code to precache all base player models and their w_weapons(note - these are specific to Alien Arena and can be changed for other games)
1983 PModelList_t BasePModels[] =
1984 {
1985 	{ "martianenforcer" },
1986 	{ "martiancyborg" },
1987 	{ "martianoverlord" },
1988 	{ "martianwarrior" },
1989     { "enforcer" },
1990 	{ "commander" },
1991 	{ "lauren" },
1992 	{ "slashbot" }
1993 
1994 };
1995 int PModelsCount = (int)(sizeof(BasePModels)/sizeof(BasePModels[0]));
1996 
1997 WModelList_t BaseWModels[] =
1998 {
1999 	{ "w_blaster.md2" },
2000 	{ "w_shotgun.md2" },
2001     { "w_sshotgun.md2" },
2002 	{ "w_machinegun.md2" },
2003 	{ "w_chaingun.md2" },
2004 	{ "w_glauncher.md2" },
2005 	{ "w_rlauncher.md2" },
2006     { "w_hyperblaster.md2" },
2007 	{ "w_railgun.md2" },
2008 	{ "w_bfg.md2" },
2009 	{ "w_violator.md2" },
2010 	{ "weapon.md2" }
2011 };
2012 int WModelsCount = (int)(sizeof(BaseWModels)/sizeof(BaseWModels[0]));
2013 
R_RegisterBasePlayerModels(void)2014 void R_RegisterBasePlayerModels( void )
2015 {
2016 	char	mod_filename[MAX_QPATH];
2017 	char	scratch[MAX_QPATH];
2018 	int i, j;
2019 	// int npms = 0; // unused
2020 	int nskins = 0;
2021 	char **skinnames;
2022 
2023 	if (is_localhost) {
2024 	    //then the client is also the server so we have this cvar available
2025 	    cvar_t *maxclients = Cvar_Get ("maxclients", 0, 0);
2026 	    if (!maxclients|| maxclients->integer <= 1)
2027 	        return; //don't bother
2028 	}
2029 
2030 	//precache all player and weapon models(base only, otherwise could take very long loading a map!)
2031 	for (i = 0; i < PModelsCount; i++)
2032 	{
2033 		Com_Printf("Registering models for: %s\n", BasePModels[i].name);
2034 		Com_sprintf( mod_filename, sizeof(mod_filename), "players/%s/tris.md2", BasePModels[i].name);
2035 		R_RegisterModel(mod_filename);
2036 		Com_sprintf( mod_filename, sizeof(mod_filename), "players/%s/lod1.md2", BasePModels[i].name);
2037 		R_RegisterModel(mod_filename);
2038 		Com_sprintf( mod_filename, sizeof(mod_filename), "players/%s/lod2.md2", BasePModels[i].name);
2039 		R_RegisterModel(mod_filename);
2040 
2041 		//register weapon models
2042 		for (j = 0; j < WModelsCount; j++)
2043 		{
2044 			Com_sprintf( mod_filename, sizeof(mod_filename), "players/%s/%s", BasePModels[i].name, BaseWModels[j]);
2045 			R_RegisterModel(mod_filename);
2046 		}
2047 
2048 		//register standard sounds
2049 		S_RegisterSoundsForPlayer (BasePModels[i].name);
2050 
2051 		//register all skins
2052 		Com_sprintf( scratch, sizeof(scratch), "players/%s/*.jpg", BasePModels[i].name);
2053 		skinnames = FS_ListFilesInFS( scratch, &nskins, 0,
2054 		    SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM );
2055 
2056 		if(!skinnames)
2057 			continue;
2058 
2059 		for(j = 0; j < nskins; j++)
2060 			R_RegisterSkin (skinnames[j]);
2061 
2062 		if(skinnames)
2063 			free(skinnames);
2064 	}
2065 }
2066 
R_RegisterCustomPlayerModels(void)2067 void R_RegisterCustomPlayerModels( void )
2068 {
2069 	char	mod_filename[MAX_QPATH];
2070 	char	scratch[MAX_QPATH];
2071 	int i, j;
2072 	int npms = 0;
2073 	int nskins = 0;
2074 	char **dirnames;
2075 	char **skinnames;
2076 
2077 	dirnames = FS_ListFilesInFS( "players/*.*", &npms, SFF_SUBDIR, 0 );
2078 
2079 	if ( !dirnames )
2080 		return;
2081 
2082 	if ( npms > 1024 )
2083 		npms = 1024;
2084 
2085 	for(i = 0; i < npms; i++)
2086 	{
2087 		if ( dirnames[i] == 0 )
2088 			continue;
2089 
2090 		Com_Printf("Registering custom player model: %s\n", dirnames[i]);
2091 		Com_sprintf( mod_filename, sizeof(mod_filename), "%s/tris.md2", dirnames[i]);
2092 		if(FS_FileExists(mod_filename))
2093 			R_RegisterModel(mod_filename);
2094 		else
2095 			continue; //invalid player model
2096 		Com_sprintf( mod_filename, sizeof(mod_filename), "%s/lod1.md2", dirnames[i]);
2097 		if(FS_FileExists(mod_filename))
2098 			R_RegisterModel(mod_filename);
2099 		Com_sprintf( mod_filename, sizeof(mod_filename), "%s/lod2.md2", dirnames[i]);
2100 		if(FS_FileExists(mod_filename))
2101 			R_RegisterModel(mod_filename);
2102 
2103 		//register weapon models
2104 		for (j = 0; j < WModelsCount; j++)
2105 		{
2106 			Com_sprintf( mod_filename, sizeof(mod_filename), "%s/%s", dirnames[i], BaseWModels[j]);
2107 			if(FS_FileExists(mod_filename))
2108 				R_RegisterModel(mod_filename);
2109 		}
2110 
2111 		//register standard sounds
2112 		S_RegisterSoundsForPlayer (dirnames[i]);
2113 
2114 		//register all skins
2115 		strcpy( scratch, dirnames[i] );
2116 		strcat( scratch, "/*.jpg" );
2117 		skinnames = FS_ListFilesInFS( scratch, &nskins, 0,
2118 		    SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM );
2119 
2120 		if(!skinnames) {
2121 			// check for .tga, though this is no longer used for current models
2122 			strcpy( scratch, dirnames[i] );
2123 			strcat( scratch, "/*.tga" );
2124 			skinnames = FS_ListFilesInFS( scratch, &nskins, 0,
2125 				SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM );
2126 		}
2127 
2128 		if(!skinnames)
2129 			continue;
2130 
2131 		for(j = 0; j < nskins; j++)
2132 			R_RegisterSkin (skinnames[j]);
2133 
2134 		if(skinnames)
2135 			free(skinnames);
2136 
2137 	}
2138 	if(dirnames)
2139 		free(dirnames);
2140 }
2141 
R_BeginRegistration(char * model)2142 void R_BeginRegistration (char *model)
2143 {
2144 	char	fullname[MAX_OSPATH];
2145  	char    *path;
2146 	cvar_t	*flushmap;
2147 	FILE	*file;
2148 	int		i;
2149 
2150 	registration_sequence++;
2151 	r_oldviewcluster = -1;		// force markleafs
2152 
2153 	r_weather = 0; //default is 0
2154 	r_nosun = 0;
2155 
2156 	// check for fog file, using file system search path
2157 	path = NULL;
2158 	map_fog = false;
2159 	r_weather = false;
2160 	r_nosun = false;
2161 	r_sunX = 0;
2162 	r_sunY = 0;
2163 	r_sunZ = 0;
2164 	for(;;)
2165 	{
2166 		path = FS_NextPath( path );
2167 		if( !path )
2168 		{
2169 			break;
2170 		}
2171 		Com_sprintf(fullname, sizeof(fullname), "%s/maps/scripts/%s.fog", path, model);
2172 		i = 0;
2173 		R_FindFile( fullname, &file ); //does a fog file exist?
2174 		if(file) {
2175 			//read the file, get fog information
2176 			fclose(file);
2177 			R_ReadFogScript(fullname);
2178 			break;
2179 		}
2180 	}
2181 
2182 	// check for background music file, , using file system search path
2183 	//defaults below
2184 	strcpy(map_music, "music/menumusic.ogg");
2185 	strcpy(map_music_sec, "music/adrenaline.ogg");
2186 	S_RegisterSound (map_music_sec);
2187 	path = NULL;
2188 	for(;;)
2189 	{
2190 		path = FS_NextPath( path );
2191 		if( !path )
2192 		{
2193 			break;
2194 		}
2195 		Com_sprintf(fullname, sizeof(fullname), "%s/maps/scripts/%s.mus", path, model);
2196 		i = 0;
2197 		R_FindFile( fullname, &file ); //does a music file exist?
2198 		if(file)
2199 		{
2200 			//read the file, get music information
2201 			fclose( file );
2202 			R_ReadMusicScript( fullname );
2203 			break;
2204 		}
2205 	}
2206 	//set ctf flags
2207 	r_gotFlag = false;
2208 	r_lostFlag = false;
2209 	Cvar_Set("rs_hasflag", "0");
2210 
2211 	Com_sprintf (fullname, sizeof(fullname), "maps/%s.bsp", model);
2212 
2213 	// explicitly free the old map if different
2214 	// this guarantees that mod_known[0] is the world map
2215 	flushmap = Cvar_Get ("flushmap", "0", 0);
2216 
2217 	if ( strcmp(mod_known[0].name, fullname) || flushmap->value)
2218 		Mod_Free (&mod_known[0]);
2219 	else
2220 		Mod_Free (&mod_known[0]);	//do it every time to fix shader bugs in AA
2221 
2222 	r_worldmodel = Mod_ForName(fullname, true);
2223 
2224 	r_viewcluster = -1;
2225 
2226 	r_teamColor = 0;
2227 
2228 	R_RegisterLightGroups();
2229 
2230 	//ODE
2231 	RGD_BuildWorldTrimesh ();
2232 
2233 	//VBO
2234 	if(gl_state.vbo)
2235 		VB_BuildWorldVBO();
2236 }
2237 
2238 /*
2239 @@@@@@@@@@@@@@@@@@@@@
2240 R_RegisterModel
2241 
2242 @@@@@@@@@@@@@@@@@@@@@
2243 */
2244 
R_RegisterModel(char * name)2245 struct model_s *R_RegisterModel (char *name)
2246 {
2247 	model_t	*mod;
2248 	int		i;
2249 	dmdl_t		*pheader;
2250 
2251 	mod = Mod_ForName (name, false);
2252 	if (mod)
2253 	{
2254 		mod->registration_sequence = registration_sequence;
2255 
2256 		// register any images used by the models
2257 		if (mod->type == mod_alias)
2258 		{
2259 			pheader = (dmdl_t *)mod->extradata;
2260 			for (i=0 ; i<pheader->num_skins ; i++)
2261 				mod->skins[i] = GL_FindImage ((char *)pheader + pheader->ofs_skins + i*MAX_SKINNAME, it_skin);
2262 //PGM
2263 			mod->num_frames = pheader->num_frames;
2264 //PGM
2265 		}
2266 		else if (mod->type == mod_iqm)
2267 		{
2268 			mod->skins[0] = GL_FindImage (mod->skinname, it_skin);
2269 		}
2270 		else if (mod->type == mod_brush)
2271 		{
2272 			for (i=0 ; i<mod->numtexinfo ; i++) {
2273 				mod->texinfo[i].image->registration_sequence = registration_sequence;
2274 				mod->texinfo[i].normalMap->registration_sequence = registration_sequence;
2275 			}
2276 		}
2277 	}
2278 	return mod;
2279 }
2280 
2281 
2282 /*
2283 @@@@@@@@@@@@@@@@@@@@@
2284 R_EndRegistration
2285 
2286 @@@@@@@@@@@@@@@@@@@@@
2287 */
R_EndRegistration(void)2288 void R_EndRegistration (void)
2289 {
2290 	int		i;
2291 	model_t	*mod;
2292 
2293 	for (i=0, mod=mod_known ; i<mod_numknown ; i++, mod++)
2294 	{
2295 		if (!mod->name[0])
2296 			continue;
2297 		if (mod->registration_sequence != registration_sequence)
2298 		{	// don't need this model
2299 			Mod_Free (mod);
2300 		}
2301 	}
2302 
2303 	GL_FreeUnusedImages ();
2304 }
2305 
2306 
2307 //=============================================================================
2308 
2309 
2310 /*
2311 ================
2312 Mod_Free
2313 ================
2314 */
Mod_Free(model_t * mod)2315 void Mod_Free (model_t *mod)
2316 {
2317 	Hunk_Free (mod->extradata);
2318 	memset (mod, 0, sizeof(*mod));
2319 }
2320 
2321 /*
2322 ================
2323 Mod_FreeAll
2324 ================
2325 */
Mod_FreeAll(void)2326 void Mod_FreeAll (void)
2327 {
2328 	int		i;
2329 
2330 	for (i=0 ; i<mod_numknown ; i++)
2331 	{
2332 		if (mod_known[i].extradatasize)
2333 			Mod_Free (&mod_known[i]);
2334 	}
2335 }
2336 
2337 
2338 
2339