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