1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 Copyright (C) 2006 Robert Beckebans <trebor_7@users.sourceforge.net>
5
6 This file is part of XreaL source code.
7
8 XreaL source code is free software; you can redistribute it
9 and/or modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the License,
11 or (at your option) any later version.
12
13 XreaL source code is distributed in the hope that it will be
14 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with XreaL source code; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 ===========================================================================
22 */
23 // tr_bsp.c
24 #include "tr_local.h"
25
26 /*
27
28 Loads and prepares a map file for scene rendering.
29
30 A single entry point:
31
32 void RE_LoadWorldMap( const char *name );
33
34 */
35
36 static world_t s_worldData;
37 static int s_lightCount;
38 static int s_interactionCount;
39 static int s_lightIndexes[SHADER_MAX_INDEXES];
40 static int s_numLightIndexes;
41 static int s_shadowIndexes[SHADER_MAX_INDEXES];
42 static int s_numShadowIndexes;
43 static byte *fileBase;
44
45 int c_culledFaceTriangles;
46 int c_culledTriTriangles;
47 int c_culledGridTriangles;
48 int c_gridVerts;
49
50 //===============================================================================
51
HSVtoRGB(float h,float s,float v,float rgb[3])52 static void HSVtoRGB(float h, float s, float v, float rgb[3])
53 {
54 int i;
55 float f;
56 float p, q, t;
57
58 h *= 5;
59
60 i = floor(h);
61 f = h - i;
62
63 p = v * (1 - s);
64 q = v * (1 - s * f);
65 t = v * (1 - s * (1 - f));
66
67 switch (i)
68 {
69 case 0:
70 rgb[0] = v;
71 rgb[1] = t;
72 rgb[2] = p;
73 break;
74 case 1:
75 rgb[0] = q;
76 rgb[1] = v;
77 rgb[2] = p;
78 break;
79 case 2:
80 rgb[0] = p;
81 rgb[1] = v;
82 rgb[2] = t;
83 break;
84 case 3:
85 rgb[0] = p;
86 rgb[1] = q;
87 rgb[2] = v;
88 break;
89 case 4:
90 rgb[0] = t;
91 rgb[1] = p;
92 rgb[2] = v;
93 break;
94 case 5:
95 rgb[0] = v;
96 rgb[1] = p;
97 rgb[2] = q;
98 break;
99 }
100 }
101
102 /*
103 ===============
104 R_ColorShiftLightingBytes
105 ===============
106 */
R_ColorShiftLightingBytes(byte in[4],byte out[4])107 static void R_ColorShiftLightingBytes(byte in[4], byte out[4])
108 {
109 int shift, r, g, b;
110
111 // shift the color data based on overbright range
112 shift = r_mapOverBrightBits->integer - tr.overbrightBits;
113
114 // shift the data based on overbright range
115 r = in[0] << shift;
116 g = in[1] << shift;
117 b = in[2] << shift;
118
119 // normalize by color instead of saturating to white
120 if((r | g | b) > 255)
121 {
122 int max;
123
124 max = r > g ? r : g;
125 max = max > b ? max : b;
126 r = r * 255 / max;
127 g = g * 255 / max;
128 b = b * 255 / max;
129 }
130
131 out[0] = r;
132 out[1] = g;
133 out[2] = b;
134 out[3] = in[3];
135 }
136
137 /*
138 ===============
139 R_NormalizeLightingBytes
140 ===============
141 */
R_NormalizeLightingBytes(byte in[4],byte out[4])142 static void R_NormalizeLightingBytes(byte in[4], byte out[4])
143 {
144 #if 0
145 vec3_t n;
146 vec_t length;
147 float inv127 = 1.0f / 127.0f;
148
149 n[0] = in[0] * inv127;
150 n[1] = in[1] * inv127;
151 n[2] = in[2] * inv127;
152
153 length = VectorLength(n);
154
155 if(length)
156 {
157 n[0] /= length;
158 n[1] /= length;
159 n[2] /= length;
160 }
161 else
162 {
163 VectorSet(n, 0.0, 0.0, 1.0);
164 }
165
166 out[0] = (byte) (128 + 127 * n[0]);
167 out[1] = (byte) (128 + 127 * n[1]);
168 out[2] = (byte) (128 + 127 * n[2]);
169 out[3] = in[3];
170 #else
171 out[0] = in[0];
172 out[1] = in[1];
173 out[2] = in[2];
174 out[3] = in[3];
175 #endif
176 }
177
178 /*
179 ===============
180 R_LoadLightmaps
181 ===============
182 */
183 #define LIGHTMAP_SIZE 128
R_LoadLightmaps(lump_t * l)184 static void R_LoadLightmaps(lump_t * l)
185 {
186 byte *buf, *buf_p;
187 int len;
188 static byte image[LIGHTMAP_SIZE * LIGHTMAP_SIZE * 4];
189 int i, j;
190 float maxIntensity = 0;
191 double sumIntensity = 0;
192
193 ri.Printf(PRINT_ALL, "...loading lightmaps\n");
194
195 len = l->filelen;
196 if(!len)
197 {
198 return;
199 }
200 buf = fileBase + l->fileofs;
201
202 // we are about to upload textures
203 R_SyncRenderThread();
204
205 // create all the lightmaps
206 tr.numLightmaps = len / (LIGHTMAP_SIZE * LIGHTMAP_SIZE * 3);
207 if(tr.numLightmaps == 1)
208 {
209 //FIXME: HACK: maps with only one lightmap turn up fullbright for some reason.
210 //this avoids this, but isn't the correct solution.
211 tr.numLightmaps++;
212 }
213
214 for(i = 0; i < tr.numLightmaps; i++)
215 {
216 // expand the 24 bit on-disk to 32 bit
217 buf_p = buf + i * LIGHTMAP_SIZE * LIGHTMAP_SIZE * 3;
218
219 if(tr.worldDeluxeMapping)
220 {
221 if(i % 2 == 0)
222 {
223 if(r_showLightMaps->integer == 2)
224 {
225 // color code by intensity as development tool (FIXME: check range)
226 for(j = 0; j < LIGHTMAP_SIZE * LIGHTMAP_SIZE; j++)
227 {
228 float r = buf_p[j * 3 + 0];
229 float g = buf_p[j * 3 + 1];
230 float b = buf_p[j * 3 + 2];
231 float intensity;
232 float out[3];
233
234 intensity = 0.33f * r + 0.685f * g + 0.063f * b;
235
236 if(intensity > 255)
237 intensity = 1.0f;
238 else
239 intensity /= 255.0f;
240
241 if(intensity > maxIntensity)
242 maxIntensity = intensity;
243
244 HSVtoRGB(intensity, 1.00, 0.50, out);
245
246 image[j * 4 + 0] = out[0] * 255;
247 image[j * 4 + 1] = out[1] * 255;
248 image[j * 4 + 2] = out[2] * 255;
249 image[j * 4 + 3] = 255;
250
251 sumIntensity += intensity;
252 }
253 }
254 else
255 {
256 for(j = 0; j < LIGHTMAP_SIZE * LIGHTMAP_SIZE; j++)
257 {
258 R_ColorShiftLightingBytes(&buf_p[j * 3], &image[j * 4]);
259 image[j * 4 + 3] = 255;
260 }
261 }
262 tr.lightmaps[i] =
263 R_CreateImage(va("_lightmap%d", i), image, LIGHTMAP_SIZE, LIGHTMAP_SIZE, IF_NONE, FT_DEFAULT, WT_CLAMP);
264 }
265 else
266 {
267 for(j = 0; j < LIGHTMAP_SIZE * LIGHTMAP_SIZE; j++)
268 {
269 R_NormalizeLightingBytes(&buf_p[j * 3], &image[j * 4]);
270 image[j * 4 + 3] = 255;
271 }
272 tr.lightmaps[i] =
273 R_CreateImage(va("_lightmap%d", i), image, LIGHTMAP_SIZE, LIGHTMAP_SIZE, IF_NORMALMAP, FT_DEFAULT, WT_CLAMP);
274 }
275 }
276 else
277 {
278 for(j = 0; j < LIGHTMAP_SIZE * LIGHTMAP_SIZE; j++)
279 {
280 R_ColorShiftLightingBytes(&buf_p[j * 3], &image[j * 4]);
281 image[j * 4 + 3] = 255;
282 }
283 tr.lightmaps[i] =
284 R_CreateImage(va("_lightmap%d", i), image, LIGHTMAP_SIZE, LIGHTMAP_SIZE, IF_NONE, FT_DEFAULT, WT_CLAMP);
285 }
286 }
287
288 if(r_showLightMaps->integer == 2)
289 {
290 ri.Printf(PRINT_ALL, "Brightest lightmap value: %d\n", (int)(maxIntensity * 255));
291 }
292 }
293
294 /*
295 =================
296 RE_SetWorldVisData
297
298 This is called by the clipmodel subsystem so we can share the 1.8 megs of
299 space in big maps...
300 =================
301 */
RE_SetWorldVisData(const byte * vis)302 void RE_SetWorldVisData(const byte * vis)
303 {
304 tr.externalVisData = vis;
305 }
306
307 /*
308 =================
309 R_LoadVisibility
310 =================
311 */
R_LoadVisibility(lump_t * l)312 static void R_LoadVisibility(lump_t * l)
313 {
314 int len;
315 byte *buf;
316
317 ri.Printf(PRINT_ALL, "...loading visibility\n");
318
319 len = (s_worldData.numClusters + 63) & ~63;
320 s_worldData.novis = ri.Hunk_Alloc(len, h_low);
321 Com_Memset(s_worldData.novis, 0xff, len);
322
323 len = l->filelen;
324 if(!len)
325 {
326 return;
327 }
328 buf = fileBase + l->fileofs;
329
330 s_worldData.numClusters = LittleLong(((int *)buf)[0]);
331 s_worldData.clusterBytes = LittleLong(((int *)buf)[1]);
332
333 // TODO: CM_Load should have given us the vis data to share, so
334 // we don't need to allocate another copy
335 if(tr.externalVisData)
336 {
337 s_worldData.vis = tr.externalVisData;
338 }
339 else
340 {
341 byte *dest;
342
343 dest = ri.Hunk_Alloc(len - 8, h_low);
344 Com_Memcpy(dest, buf + 8, len - 8);
345 s_worldData.vis = dest;
346 }
347 }
348
349 //===============================================================================
350
351
352 /*
353 ===============
354 ShaderForShaderNum
355 ===============
356 */
ShaderForShaderNum(int shaderNum,int lightmapNum)357 static shader_t *ShaderForShaderNum(int shaderNum, int lightmapNum)
358 {
359 shader_t *shader;
360 dshader_t *dsh;
361 shaderType_t shaderType;
362
363 shaderNum = LittleLong(shaderNum);
364 if(shaderNum < 0 || shaderNum >= s_worldData.numShaders)
365 {
366 ri.Error(ERR_DROP, "ShaderForShaderNum: bad num %i", shaderNum);
367 }
368 dsh = &s_worldData.shaders[shaderNum];
369
370 if(lightmapNum >= 0)
371 {
372 shaderType = SHADER_3D_LIGHTMAP;
373 }
374 else
375 {
376 shaderType = SHADER_3D_STATIC;
377 }
378
379 shader = R_FindShader(dsh->shader, shaderType, qtrue);
380
381 // if the shader had errors, just use default shader
382 if(shader->defaultShader)
383 {
384 return tr.defaultShader;
385 }
386
387 return shader;
388 }
389
390 /*
391 ===============
392 ParseFace
393 ===============
394 */
ParseFace(dsurface_t * ds,drawVert_t * verts,msurface_t * surf,int * indexes)395 static void ParseFace(dsurface_t * ds, drawVert_t * verts, msurface_t * surf, int *indexes)
396 {
397 int i, j;
398 srfSurfaceFace_t *cv;
399 srfTriangle_t *tri;
400 int numVerts, numTriangles;
401
402 // get lightmap
403 surf->lightmapNum = LittleLong(ds->lightmapNum);
404
405 // get fog volume
406 surf->fogIndex = LittleLong(ds->fogNum) + 1;
407
408 // get shader value
409 surf->shader = ShaderForShaderNum(ds->shaderNum, surf->lightmapNum);
410 if(r_singleShader->integer && !surf->shader->isSky)
411 {
412 surf->shader = tr.defaultShader;
413 }
414
415 numVerts = LittleLong(ds->numVerts);
416 if(numVerts > MAX_FACE_POINTS)
417 {
418 ri.Printf(PRINT_WARNING, "WARNING: MAX_FACE_POINTS exceeded: %i\n", numVerts);
419 numVerts = MAX_FACE_POINTS;
420 surf->shader = tr.defaultShader;
421 }
422 numTriangles = LittleLong(ds->numIndexes) / 3;
423
424 cv = ri.Hunk_Alloc(sizeof(*cv), h_low);
425 cv->surfaceType = SF_FACE;
426
427 cv->numTriangles = numTriangles;
428 cv->triangles = ri.Hunk_Alloc(numTriangles * sizeof(cv->triangles[0]), h_low);
429
430 cv->numVerts = numVerts;
431 cv->verts = ri.Hunk_Alloc(numVerts * sizeof(cv->verts[0]), h_low);
432
433 surf->data = (surfaceType_t *) cv;
434
435 // copy vertexes
436 ClearBounds(cv->bounds[0], cv->bounds[1]);
437 verts += LittleLong(ds->firstVert);
438 for(i = 0; i < numVerts; i++)
439 {
440 for(j = 0; j < 3; j++)
441 {
442 cv->verts[i].xyz[j] = LittleFloat(verts[i].xyz[j]);
443 cv->verts[i].normal[j] = LittleFloat(verts[i].normal[j]);
444 }
445 AddPointToBounds(cv->verts[i].xyz, cv->bounds[0], cv->bounds[1]);
446 for(j = 0; j < 2; j++)
447 {
448 cv->verts[i].st[j] = LittleFloat(verts[i].st[j]);
449 cv->verts[i].lightmap[j] = LittleFloat(verts[i].lightmap[j]);
450 }
451
452 R_ColorShiftLightingBytes(verts[i].color, cv->verts[i].color);
453 }
454
455 // copy triangles
456 indexes += LittleLong(ds->firstIndex);
457 for(i = 0, tri = cv->triangles; i < numTriangles; i++, tri++)
458 {
459 for(j = 0; j < 3; j++)
460 {
461 tri->indexes[j] = LittleLong(indexes[i * 3 + j]);
462
463 if(tri->indexes[j] < 0 || tri->indexes[j] >= numVerts)
464 {
465 ri.Error(ERR_DROP, "Bad index in face surface");
466 }
467 }
468 }
469
470 R_CalcSurfaceTriangleNeighbors(numTriangles, cv->triangles);
471 R_CalcSurfaceTrianglePlanes(numTriangles, cv->triangles, cv->verts);
472
473 // take the plane information from the lightmap vector
474 for(i = 0; i < 3; i++)
475 {
476 cv->plane.normal[i] = LittleFloat(ds->lightmapVecs[2][i]);
477 }
478 cv->plane.dist = DotProduct(cv->verts[0].xyz, cv->plane.normal);
479 SetPlaneSignbits(&cv->plane);
480 cv->plane.type = PlaneTypeForNormal(cv->plane.normal);
481
482 surf->data = (surfaceType_t *) cv;
483
484 // Tr3B - calc tangent spaces
485 {
486 float *v;
487 const float *v0, *v1, *v2;
488 const float *t0, *t1, *t2;
489 vec3_t tangent;
490 vec3_t binormal;
491 vec3_t normal;
492
493 for(i = 0; i < numVerts; i++)
494 {
495 VectorClear(cv->verts[i].tangent);
496 VectorClear(cv->verts[i].binormal);
497 VectorClear(cv->verts[i].normal);
498 }
499
500 for(i = 0, tri = cv->triangles; i < numTriangles; i++, tri++)
501 {
502 v0 = cv->verts[tri->indexes[0]].xyz;
503 v1 = cv->verts[tri->indexes[1]].xyz;
504 v2 = cv->verts[tri->indexes[2]].xyz;
505
506 t0 = cv->verts[tri->indexes[0]].st;
507 t1 = cv->verts[tri->indexes[1]].st;
508 t2 = cv->verts[tri->indexes[2]].st;
509
510 R_CalcTangentSpace(tangent, binormal, normal, v0, v1, v2, t0, t1, t2, cv->plane.normal);
511
512 for(j = 0; j < 3; j++)
513 {
514 v = cv->verts[tri->indexes[j]].tangent;
515 VectorAdd(v, tangent, v);
516 v = cv->verts[tri->indexes[j]].binormal;
517 VectorAdd(v, binormal, v);
518 v = cv->verts[tri->indexes[j]].normal;
519 VectorAdd(v, normal, v);
520 }
521 }
522
523 for(i = 0; i < numVerts; i++)
524 {
525 VectorNormalize(cv->verts[i].tangent);
526 VectorNormalize(cv->verts[i].binormal);
527 VectorNormalize(cv->verts[i].normal);
528 }
529 }
530
531 // create VBOs
532 if(glConfig2.vertexBufferObjectAvailable)
533 {
534 if(numTriangles)
535 {
536 byte *data;
537 int dataSize;
538 int dataOfs;
539
540 qglGenBuffersARB(1, &cv->indexesVBO);
541
542 dataSize = numTriangles * sizeof(cv->triangles[0].indexes);
543 data = ri.Hunk_AllocateTempMemory(dataSize);
544 dataOfs = 0;
545
546 for(i = 0, tri = cv->triangles; i < numTriangles; i++, tri++)
547 {
548 memcpy(data + dataOfs, tri->indexes, sizeof(tri->indexes));
549 dataOfs += sizeof(tri->indexes);
550 }
551
552 qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, cv->indexesVBO);
553 qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, dataSize, indexes, GL_STATIC_DRAW_ARB);
554
555 qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
556
557 ri.Hunk_FreeTempMemory(data);
558 }
559
560 if(cv->numVerts)
561 {
562 byte *data;
563 int dataSize;
564 int dataOfs;
565 vec4_t tmp;
566
567 qglGenBuffersARB(1, &cv->vertsVBO);
568
569 dataSize = cv->numVerts * (sizeof(vec4_t) * 6 + sizeof(color4ub_t));
570 data = ri.Hunk_AllocateTempMemory(dataSize);
571 dataOfs = 0;
572
573 // set up xyz array
574 cv->ofsXYZ = 0;
575 for(i = 0; i < cv->numVerts; i++)
576 {
577 for(j = 0; j < 3; j++)
578 {
579 tmp[j] = cv->verts[i].xyz[j];
580 }
581 tmp[3] = 1;
582
583 memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
584 dataOfs += sizeof(vec4_t);
585 }
586
587 // set up texcoords array
588 cv->ofsTexCoords = dataOfs;
589 for(i = 0; i < cv->numVerts; i++)
590 {
591 for(j = 0; j < 2; j++)
592 {
593 tmp[j] = cv->verts[i].st[j];
594 }
595 tmp[2] = 0;
596 tmp[3] = 1;
597
598 memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
599 dataOfs += sizeof(vec4_t);
600 }
601
602 // set up texcoords2 array
603 cv->ofsTexCoords2 = dataOfs;
604 for(i = 0; i < cv->numVerts; i++)
605 {
606 for(j = 0; j < 2; j++)
607 {
608 tmp[j] = cv->verts[i].lightmap[j];
609 }
610 tmp[2] = 0;
611 tmp[3] = 1;
612
613 memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
614 dataOfs += sizeof(vec4_t);
615 }
616
617 // set up tangents array
618 cv->ofsTangents = dataOfs;
619 for(i = 0; i < cv->numVerts; i++)
620 {
621 for(j = 0; j < 3; j++)
622 {
623 tmp[j] = cv->verts[i].tangent[j];
624 }
625 tmp[3] = 1;
626
627 memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
628 dataOfs += sizeof(vec4_t);
629 }
630
631 // set up binormals array
632 cv->ofsBinormals = dataOfs;
633 for(i = 0; i < cv->numVerts; i++)
634 {
635 for(j = 0; j < 3; j++)
636 {
637 tmp[j] = cv->verts[i].binormal[j];
638 }
639 tmp[3] = 1;
640
641 memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
642 dataOfs += sizeof(vec4_t);
643 }
644
645 // set up normals array
646 cv->ofsNormals = dataOfs;
647 for(i = 0; i < cv->numVerts; i++)
648 {
649 for(j = 0; j < 3; j++)
650 {
651 tmp[j] = cv->verts[i].normal[j];
652 }
653 tmp[3] = 1;
654
655 memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
656 dataOfs += sizeof(vec4_t);
657 }
658
659 // set up colors array
660 cv->ofsColors = dataOfs;
661 for(i = 0; i < cv->numVerts; i++)
662 {
663 memcpy(data + dataOfs, cv->verts[i].color, sizeof(color4ub_t));
664 dataOfs += sizeof(color4ub_t);
665 }
666
667 qglBindBufferARB(GL_ARRAY_BUFFER_ARB, cv->vertsVBO);
668 qglBufferDataARB(GL_ARRAY_BUFFER_ARB, dataSize, data, GL_STATIC_DRAW_ARB);
669
670 qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
671 ri.Hunk_FreeTempMemory(data);
672 }
673 }
674 }
675
676
677 /*
678 ===============
679 ParseMesh
680 ===============
681 */
ParseMesh(dsurface_t * ds,drawVert_t * verts,msurface_t * surf)682 static void ParseMesh(dsurface_t * ds, drawVert_t * verts, msurface_t * surf)
683 {
684 srfGridMesh_t *grid;
685 int i, j;
686 int width, height, numPoints;
687 static srfVert_t points[MAX_PATCH_SIZE * MAX_PATCH_SIZE];
688 vec3_t bounds[2];
689 vec3_t tmpVec;
690 static surfaceType_t skipData = SF_SKIP;
691
692 // get lightmap
693 surf->lightmapNum = LittleLong(ds->lightmapNum);
694
695 // get fog volume
696 surf->fogIndex = LittleLong(ds->fogNum) + 1;
697
698 // get shader value
699 surf->shader = ShaderForShaderNum(ds->shaderNum, surf->lightmapNum);
700 if(r_singleShader->integer && !surf->shader->isSky)
701 {
702 surf->shader = tr.defaultShader;
703 }
704
705 // we may have a nodraw surface, because they might still need to
706 // be around for movement clipping
707 if(s_worldData.shaders[LittleLong(ds->shaderNum)].surfaceFlags & SURF_NODRAW)
708 {
709 surf->data = &skipData;
710 return;
711 }
712
713 width = LittleLong(ds->patchWidth);
714 height = LittleLong(ds->patchHeight);
715
716 verts += LittleLong(ds->firstVert);
717 numPoints = width * height;
718 for(i = 0; i < numPoints; i++)
719 {
720 for(j = 0; j < 3; j++)
721 {
722 points[i].xyz[j] = LittleFloat(verts[i].xyz[j]);
723 points[i].normal[j] = LittleFloat(verts[i].normal[j]);
724 }
725 for(j = 0; j < 2; j++)
726 {
727 points[i].st[j] = LittleFloat(verts[i].st[j]);
728 points[i].lightmap[j] = LittleFloat(verts[i].lightmap[j]);
729 }
730 R_ColorShiftLightingBytes(verts[i].color, points[i].color);
731 }
732
733 // pre-tesseleate
734 grid = R_SubdividePatchToGrid(width, height, points);
735 surf->data = (surfaceType_t *) grid;
736
737 // copy the level of detail origin, which is the center
738 // of the group of all curves that must subdivide the same
739 // to avoid cracking
740 for(i = 0; i < 3; i++)
741 {
742 bounds[0][i] = LittleFloat(ds->lightmapVecs[0][i]);
743 bounds[1][i] = LittleFloat(ds->lightmapVecs[1][i]);
744 }
745 VectorAdd(bounds[0], bounds[1], bounds[1]);
746 VectorScale(bounds[1], 0.5f, grid->lodOrigin);
747 VectorSubtract(bounds[0], grid->lodOrigin, tmpVec);
748 grid->lodRadius = VectorLength(tmpVec);
749 }
750
751 /*
752 ===============
753 ParseTriSurf
754 ===============
755 */
ParseTriSurf(dsurface_t * ds,drawVert_t * verts,msurface_t * surf,int * indexes)756 static void ParseTriSurf(dsurface_t * ds, drawVert_t * verts, msurface_t * surf, int *indexes)
757 {
758 srfTriangles_t *cv;
759 srfTriangle_t *tri;
760 int i, j;
761 int numVerts, numTriangles;
762
763 // set lightmap
764 surf->lightmapNum = -1;
765
766 // get fog volume
767 surf->fogIndex = LittleLong(ds->fogNum) + 1;
768
769 // get shader
770 surf->shader = ShaderForShaderNum(ds->shaderNum, surf->lightmapNum);
771 if(r_singleShader->integer && !surf->shader->isSky)
772 {
773 surf->shader = tr.defaultShader;
774 }
775
776 numVerts = LittleLong(ds->numVerts);
777 numTriangles = LittleLong(ds->numIndexes) / 3;
778
779 cv = ri.Hunk_Alloc(sizeof(*cv), h_low);
780 cv->surfaceType = SF_TRIANGLES;
781
782 cv->numTriangles = numTriangles;
783 cv->triangles = ri.Hunk_Alloc(numTriangles * sizeof(cv->triangles[0]), h_low);
784
785 cv->numVerts = numVerts;
786 cv->verts = ri.Hunk_Alloc(numVerts * sizeof(cv->verts[0]), h_low);
787
788 surf->data = (surfaceType_t *) cv;
789
790 // copy vertexes
791 verts += LittleLong(ds->firstVert);
792 for(i = 0; i < numVerts; i++)
793 {
794 for(j = 0; j < 3; j++)
795 {
796 cv->verts[i].xyz[j] = LittleFloat(verts[i].xyz[j]);
797 cv->verts[i].normal[j] = LittleFloat(verts[i].normal[j]);
798 }
799
800 for(j = 0; j < 2; j++)
801 {
802 cv->verts[i].st[j] = LittleFloat(verts[i].st[j]);
803 cv->verts[i].lightmap[j] = LittleFloat(verts[i].lightmap[j]);
804 }
805
806 R_ColorShiftLightingBytes(verts[i].color, cv->verts[i].color);
807 }
808
809 // copy triangles
810 indexes += LittleLong(ds->firstIndex);
811 for(i = 0, tri = cv->triangles; i < numTriangles; i++, tri++)
812 {
813 for(j = 0; j < 3; j++)
814 {
815 tri->indexes[j] = LittleLong(indexes[i * 3 + j]);
816
817 if(tri->indexes[j] < 0 || tri->indexes[j] >= numVerts)
818 {
819 ri.Error(ERR_DROP, "Bad index in face surface");
820 }
821 }
822 }
823
824 // calc bounding box
825 // HACK: don't loop only through the vertices because they can contain bad data with .lwo models ...
826 ClearBounds(cv->bounds[0], cv->bounds[1]);
827 for(i = 0, tri = cv->triangles; i < numTriangles; i++, tri++)
828 {
829 AddPointToBounds(cv->verts[tri->indexes[0]].xyz, cv->bounds[0], cv->bounds[1]);
830 AddPointToBounds(cv->verts[tri->indexes[1]].xyz, cv->bounds[0], cv->bounds[1]);
831 AddPointToBounds(cv->verts[tri->indexes[2]].xyz, cv->bounds[0], cv->bounds[1]);
832 }
833
834 R_CalcSurfaceTriangleNeighbors(numTriangles, cv->triangles);
835 R_CalcSurfaceTrianglePlanes(numTriangles, cv->triangles, cv->verts);
836
837 // Tr3B - calc tangent spaces
838 {
839 vec3_t faceNormal;
840 float *v;
841 const float *v0, *v1, *v2;
842 const float *t0, *t1, *t2;
843 vec3_t tangent;
844 vec3_t binormal;
845 vec3_t normal;
846
847 for(i = 0; i < numVerts; i++)
848 {
849 VectorClear(cv->verts[i].tangent);
850 VectorClear(cv->verts[i].binormal);
851 VectorClear(cv->verts[i].normal);
852 }
853
854 for(i = 0, tri = cv->triangles; i < numTriangles; i++, tri++)
855 {
856 v0 = cv->verts[tri->indexes[0]].xyz;
857 v1 = cv->verts[tri->indexes[1]].xyz;
858 v2 = cv->verts[tri->indexes[2]].xyz;
859
860 t0 = cv->verts[tri->indexes[0]].st;
861 t1 = cv->verts[tri->indexes[1]].st;
862 t2 = cv->verts[tri->indexes[2]].st;
863
864 R_CalcNormalForTriangle(faceNormal, v0, v1, v2);
865 R_CalcTangentSpace(tangent, binormal, normal, v0, v1, v2, t0, t1, t2, faceNormal);
866
867 for(j = 0; j < 3; j++)
868 {
869 v = cv->verts[tri->indexes[j]].tangent;
870 VectorAdd(v, tangent, v);
871 v = cv->verts[tri->indexes[j]].binormal;
872 VectorAdd(v, binormal, v);
873 v = cv->verts[tri->indexes[j]].normal;
874 VectorAdd(v, normal, v);
875 }
876 }
877
878 for(i = 0; i < numVerts; i++)
879 {
880 VectorNormalize(cv->verts[i].tangent);
881 VectorNormalize(cv->verts[i].binormal);
882 VectorNormalize(cv->verts[i].normal);
883 }
884 }
885
886 // create VBOs
887 if(glConfig2.vertexBufferObjectAvailable)
888 {
889 if(numTriangles)
890 {
891 byte *data;
892 int dataSize;
893 int dataOfs;
894
895 qglGenBuffersARB(1, &cv->indexesVBO);
896
897 dataSize = numTriangles * sizeof(cv->triangles[0].indexes);
898 data = ri.Hunk_AllocateTempMemory(dataSize);
899 dataOfs = 0;
900
901 for(i = 0, tri = cv->triangles; i < numTriangles; i++, tri++)
902 {
903 memcpy(data + dataOfs, tri->indexes, sizeof(tri->indexes));
904 dataOfs += sizeof(tri->indexes);
905 }
906
907 qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, cv->indexesVBO);
908 qglBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, dataSize, indexes, GL_STATIC_DRAW_ARB);
909
910 qglBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
911
912 ri.Hunk_FreeTempMemory(data);
913 }
914
915 if(numVerts)
916 {
917 byte *data;
918 int dataSize;
919 int dataOfs;
920 vec4_t tmp;
921
922 qglGenBuffersARB(1, &cv->vertsVBO);
923
924 dataSize = numVerts * (sizeof(vec4_t) * 5 + sizeof(color4ub_t));
925 data = ri.Hunk_AllocateTempMemory(dataSize);
926 dataOfs = 0;
927
928 // set up xyz array
929 cv->ofsXYZ = 0;
930 for(i = 0; i < numVerts; i++)
931 {
932 for(j = 0; j < 3; j++)
933 {
934 tmp[j] = cv->verts[i].xyz[j];
935 }
936 tmp[3] = 1;
937
938 memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
939 dataOfs += sizeof(vec4_t);
940 }
941
942 // set up texcoords array
943 cv->ofsTexCoords = dataOfs;
944 for(i = 0; i < numVerts; i++)
945 {
946 for(j = 0; j < 2; j++)
947 {
948 tmp[j] = cv->verts[i].st[j];
949 }
950 tmp[2] = 0;
951 tmp[3] = 1;
952
953 memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
954 dataOfs += sizeof(vec4_t);
955 }
956
957 // set up tangents array
958 cv->ofsTangents = dataOfs;
959 for(i = 0; i < numVerts; i++)
960 {
961 for(j = 0; j < 3; j++)
962 {
963 tmp[j] = cv->verts[i].tangent[j];
964 }
965 tmp[3] = 1;
966
967 memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
968 dataOfs += sizeof(vec4_t);
969 }
970
971 // set up binormals array
972 cv->ofsBinormals = dataOfs;
973 for(i = 0; i < numVerts; i++)
974 {
975 for(j = 0; j < 3; j++)
976 {
977 tmp[j] = cv->verts[i].binormal[j];
978 }
979 tmp[3] = 1;
980
981 memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
982 dataOfs += sizeof(vec4_t);
983 }
984
985 // set up normals array
986 cv->ofsNormals = dataOfs;
987 for(i = 0; i < numVerts; i++)
988 {
989 for(j = 0; j < 3; j++)
990 {
991 tmp[j] = cv->verts[i].normal[j];
992 }
993 tmp[3] = 1;
994
995 memcpy(data + dataOfs, (vec_t *) tmp, sizeof(vec4_t));
996 dataOfs += sizeof(vec4_t);
997 }
998
999 // set up colors array
1000 cv->ofsColors = dataOfs;
1001 for(i = 0; i < numVerts; i++)
1002 {
1003 memcpy(data + dataOfs, cv->verts[i].color, sizeof(color4ub_t));
1004 dataOfs += sizeof(color4ub_t);
1005 }
1006
1007 qglBindBufferARB(GL_ARRAY_BUFFER_ARB, cv->vertsVBO);
1008 qglBufferDataARB(GL_ARRAY_BUFFER_ARB, dataSize, data, GL_STATIC_DRAW_ARB);
1009
1010 qglBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
1011 ri.Hunk_FreeTempMemory(data);
1012 }
1013 }
1014 }
1015
1016 /*
1017 ===============
1018 ParseFlare
1019 ===============
1020 */
ParseFlare(dsurface_t * ds,drawVert_t * verts,msurface_t * surf,int * indexes)1021 static void ParseFlare(dsurface_t * ds, drawVert_t * verts, msurface_t * surf, int *indexes)
1022 {
1023 srfFlare_t *flare;
1024 int i;
1025
1026 // set lightmap
1027 surf->lightmapNum = -1;
1028
1029 // get fog volume
1030 surf->fogIndex = LittleLong(ds->fogNum) + 1;
1031
1032 // get shader
1033 surf->shader = ShaderForShaderNum(ds->shaderNum, surf->lightmapNum);
1034 if(r_singleShader->integer && !surf->shader->isSky)
1035 {
1036 surf->shader = tr.defaultShader;
1037 }
1038
1039 flare = ri.Hunk_Alloc(sizeof(*flare), h_low);
1040 flare->surfaceType = SF_FLARE;
1041
1042 surf->data = (surfaceType_t *) flare;
1043
1044 for(i = 0; i < 3; i++)
1045 {
1046 flare->origin[i] = LittleFloat(ds->lightmapOrigin[i]);
1047 flare->color[i] = LittleFloat(ds->lightmapVecs[0][i]);
1048 flare->normal[i] = LittleFloat(ds->lightmapVecs[2][i]);
1049 }
1050 }
1051
1052
1053 /*
1054 =================
1055 R_MergedWidthPoints
1056
1057 returns true if there are grid points merged on a width edge
1058 =================
1059 */
R_MergedWidthPoints(srfGridMesh_t * grid,int offset)1060 int R_MergedWidthPoints(srfGridMesh_t * grid, int offset)
1061 {
1062 int i, j;
1063
1064 for(i = 1; i < grid->width - 1; i++)
1065 {
1066 for(j = i + 1; j < grid->width - 1; j++)
1067 {
1068 if(fabs(grid->verts[i + offset].xyz[0] - grid->verts[j + offset].xyz[0]) > .1)
1069 continue;
1070 if(fabs(grid->verts[i + offset].xyz[1] - grid->verts[j + offset].xyz[1]) > .1)
1071 continue;
1072 if(fabs(grid->verts[i + offset].xyz[2] - grid->verts[j + offset].xyz[2]) > .1)
1073 continue;
1074 return qtrue;
1075 }
1076 }
1077 return qfalse;
1078 }
1079
1080 /*
1081 =================
1082 R_MergedHeightPoints
1083
1084 returns true if there are grid points merged on a height edge
1085 =================
1086 */
R_MergedHeightPoints(srfGridMesh_t * grid,int offset)1087 int R_MergedHeightPoints(srfGridMesh_t * grid, int offset)
1088 {
1089 int i, j;
1090
1091 for(i = 1; i < grid->height - 1; i++)
1092 {
1093 for(j = i + 1; j < grid->height - 1; j++)
1094 {
1095 if(fabs(grid->verts[grid->width * i + offset].xyz[0] - grid->verts[grid->width * j + offset].xyz[0]) > .1)
1096 continue;
1097 if(fabs(grid->verts[grid->width * i + offset].xyz[1] - grid->verts[grid->width * j + offset].xyz[1]) > .1)
1098 continue;
1099 if(fabs(grid->verts[grid->width * i + offset].xyz[2] - grid->verts[grid->width * j + offset].xyz[2]) > .1)
1100 continue;
1101 return qtrue;
1102 }
1103 }
1104 return qfalse;
1105 }
1106
1107 /*
1108 =================
1109 R_FixSharedVertexLodError_r
1110
1111 NOTE: never sync LoD through grid edges with merged points!
1112
1113 FIXME: write generalized version that also avoids cracks between a patch and one that meets half way?
1114 =================
1115 */
R_FixSharedVertexLodError_r(int start,srfGridMesh_t * grid1)1116 void R_FixSharedVertexLodError_r(int start, srfGridMesh_t * grid1)
1117 {
1118 int j, k, l, m, n, offset1, offset2, touch;
1119 srfGridMesh_t *grid2;
1120
1121 for(j = start; j < s_worldData.numsurfaces; j++)
1122 {
1123 grid2 = (srfGridMesh_t *) s_worldData.surfaces[j].data;
1124 // if this surface is not a grid
1125 if(grid2->surfaceType != SF_GRID)
1126 continue;
1127 // if the LOD errors are already fixed for this patch
1128 if(grid2->lodFixed == 2)
1129 continue;
1130 // grids in the same LOD group should have the exact same lod radius
1131 if(grid1->lodRadius != grid2->lodRadius)
1132 continue;
1133 // grids in the same LOD group should have the exact same lod origin
1134 if(grid1->lodOrigin[0] != grid2->lodOrigin[0])
1135 continue;
1136 if(grid1->lodOrigin[1] != grid2->lodOrigin[1])
1137 continue;
1138 if(grid1->lodOrigin[2] != grid2->lodOrigin[2])
1139 continue;
1140
1141 touch = qfalse;
1142 for(n = 0; n < 2; n++)
1143 {
1144 if(n)
1145 offset1 = (grid1->height - 1) * grid1->width;
1146 else
1147 offset1 = 0;
1148 if(R_MergedWidthPoints(grid1, offset1))
1149 continue;
1150 for(k = 1; k < grid1->width - 1; k++)
1151 {
1152 for(m = 0; m < 2; m++)
1153 {
1154
1155 if(m)
1156 offset2 = (grid2->height - 1) * grid2->width;
1157 else
1158 offset2 = 0;
1159 if(R_MergedWidthPoints(grid2, offset2))
1160 continue;
1161 for(l = 1; l < grid2->width - 1; l++)
1162 {
1163 if(fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1)
1164 continue;
1165 if(fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1)
1166 continue;
1167 if(fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1)
1168 continue;
1169 // ok the points are equal and should have the same lod error
1170 grid2->widthLodError[l] = grid1->widthLodError[k];
1171 touch = qtrue;
1172 }
1173 }
1174 for(m = 0; m < 2; m++)
1175 {
1176
1177 if(m)
1178 offset2 = grid2->width - 1;
1179 else
1180 offset2 = 0;
1181 if(R_MergedHeightPoints(grid2, offset2))
1182 continue;
1183 for(l = 1; l < grid2->height - 1; l++)
1184 {
1185 if(fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1)
1186 continue;
1187 if(fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1)
1188 continue;
1189 if(fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1)
1190 continue;
1191 // ok the points are equal and should have the same lod error
1192 grid2->heightLodError[l] = grid1->widthLodError[k];
1193 touch = qtrue;
1194 }
1195 }
1196 }
1197 }
1198 for(n = 0; n < 2; n++)
1199 {
1200 if(n)
1201 offset1 = grid1->width - 1;
1202 else
1203 offset1 = 0;
1204 if(R_MergedHeightPoints(grid1, offset1))
1205 continue;
1206 for(k = 1; k < grid1->height - 1; k++)
1207 {
1208 for(m = 0; m < 2; m++)
1209 {
1210
1211 if(m)
1212 offset2 = (grid2->height - 1) * grid2->width;
1213 else
1214 offset2 = 0;
1215 if(R_MergedWidthPoints(grid2, offset2))
1216 continue;
1217 for(l = 1; l < grid2->width - 1; l++)
1218 {
1219 if(fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1)
1220 continue;
1221 if(fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1)
1222 continue;
1223 if(fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1)
1224 continue;
1225 // ok the points are equal and should have the same lod error
1226 grid2->widthLodError[l] = grid1->heightLodError[k];
1227 touch = qtrue;
1228 }
1229 }
1230 for(m = 0; m < 2; m++)
1231 {
1232 if(m)
1233 offset2 = grid2->width - 1;
1234 else
1235 offset2 = 0;
1236 if(R_MergedHeightPoints(grid2, offset2))
1237 continue;
1238 for(l = 1; l < grid2->height - 1; l++)
1239 {
1240 if(fabs
1241 (grid1->verts[grid1->width * k + offset1].xyz[0] -
1242 grid2->verts[grid2->width * l + offset2].xyz[0]) > .1)
1243 continue;
1244 if(fabs
1245 (grid1->verts[grid1->width * k + offset1].xyz[1] -
1246 grid2->verts[grid2->width * l + offset2].xyz[1]) > .1)
1247 continue;
1248 if(fabs
1249 (grid1->verts[grid1->width * k + offset1].xyz[2] -
1250 grid2->verts[grid2->width * l + offset2].xyz[2]) > .1)
1251 continue;
1252 // ok the points are equal and should have the same lod error
1253 grid2->heightLodError[l] = grid1->heightLodError[k];
1254 touch = qtrue;
1255 }
1256 }
1257 }
1258 }
1259 if(touch)
1260 {
1261 grid2->lodFixed = 2;
1262 R_FixSharedVertexLodError_r(start, grid2);
1263 //NOTE: this would be correct but makes things really slow
1264 //grid2->lodFixed = 1;
1265 }
1266 }
1267 }
1268
1269 /*
1270 =================
1271 R_FixSharedVertexLodError
1272
1273 This function assumes that all patches in one group are nicely stitched together for the highest LoD.
1274 If this is not the case this function will still do its job but won't fix the highest LoD cracks.
1275 =================
1276 */
R_FixSharedVertexLodError(void)1277 void R_FixSharedVertexLodError(void)
1278 {
1279 int i;
1280 srfGridMesh_t *grid1;
1281
1282 for(i = 0; i < s_worldData.numsurfaces; i++)
1283 {
1284 grid1 = (srfGridMesh_t *) s_worldData.surfaces[i].data;
1285 // if this surface is not a grid
1286 if(grid1->surfaceType != SF_GRID)
1287 continue;
1288 if(grid1->lodFixed)
1289 continue;
1290 grid1->lodFixed = 2;
1291 // recursively fix other patches in the same LOD group
1292 R_FixSharedVertexLodError_r(i + 1, grid1);
1293 }
1294 }
1295
1296
1297 /*
1298 ===============
1299 R_StitchPatches
1300 ===============
1301 */
R_StitchPatches(int grid1num,int grid2num)1302 int R_StitchPatches(int grid1num, int grid2num)
1303 {
1304 float *v1, *v2;
1305 srfGridMesh_t *grid1, *grid2;
1306 int k, l, m, n, offset1, offset2, row, column;
1307
1308 grid1 = (srfGridMesh_t *) s_worldData.surfaces[grid1num].data;
1309 grid2 = (srfGridMesh_t *) s_worldData.surfaces[grid2num].data;
1310 for(n = 0; n < 2; n++)
1311 {
1312 if(n)
1313 offset1 = (grid1->height - 1) * grid1->width;
1314 else
1315 offset1 = 0;
1316 if(R_MergedWidthPoints(grid1, offset1))
1317 continue;
1318 for(k = 0; k < grid1->width - 2; k += 2)
1319 {
1320 for(m = 0; m < 2; m++)
1321 {
1322 if(grid2->width >= MAX_GRID_SIZE)
1323 break;
1324 if(m)
1325 offset2 = (grid2->height - 1) * grid2->width;
1326 else
1327 offset2 = 0;
1328 for(l = 0; l < grid2->width - 1; l++)
1329 {
1330 v1 = grid1->verts[k + offset1].xyz;
1331 v2 = grid2->verts[l + offset2].xyz;
1332 if(fabs(v1[0] - v2[0]) > .1)
1333 continue;
1334 if(fabs(v1[1] - v2[1]) > .1)
1335 continue;
1336 if(fabs(v1[2] - v2[2]) > .1)
1337 continue;
1338
1339 v1 = grid1->verts[k + 2 + offset1].xyz;
1340 v2 = grid2->verts[l + 1 + offset2].xyz;
1341 if(fabs(v1[0] - v2[0]) > .1)
1342 continue;
1343 if(fabs(v1[1] - v2[1]) > .1)
1344 continue;
1345 if(fabs(v1[2] - v2[2]) > .1)
1346
1347 v1 = grid2->verts[l + offset2].xyz;
1348 v2 = grid2->verts[l + 1 + offset2].xyz;
1349 if(fabs(v1[0] - v2[0]) < .01 && fabs(v1[1] - v2[1]) < .01 && fabs(v1[2] - v2[2]) < .01)
1350 continue;
1351
1352 // insert column into grid2 right after after column l
1353 if(m)
1354 row = grid2->height - 1;
1355 else
1356 row = 0;
1357 grid2 = R_GridInsertColumn(grid2, l + 1, row, grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k + 1]);
1358 grid2->lodStitched = qfalse;
1359 s_worldData.surfaces[grid2num].data = (void *)grid2;
1360 return qtrue;
1361 }
1362 }
1363 for(m = 0; m < 2; m++)
1364 {
1365 if(grid2->height >= MAX_GRID_SIZE)
1366 break;
1367 if(m)
1368 offset2 = grid2->width - 1;
1369 else
1370 offset2 = 0;
1371 for(l = 0; l < grid2->height - 1; l++)
1372 {
1373
1374 v1 = grid1->verts[k + offset1].xyz;
1375 v2 = grid2->verts[grid2->width * l + offset2].xyz;
1376 if(fabs(v1[0] - v2[0]) > .1)
1377 continue;
1378 if(fabs(v1[1] - v2[1]) > .1)
1379 continue;
1380 if(fabs(v1[2] - v2[2]) > .1)
1381 continue;
1382
1383 v1 = grid1->verts[k + 2 + offset1].xyz;
1384 v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
1385 if(fabs(v1[0] - v2[0]) > .1)
1386 continue;
1387 if(fabs(v1[1] - v2[1]) > .1)
1388 continue;
1389 if(fabs(v1[2] - v2[2]) > .1)
1390 continue;
1391
1392 v1 = grid2->verts[grid2->width * l + offset2].xyz;
1393 v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
1394 if(fabs(v1[0] - v2[0]) < .01 && fabs(v1[1] - v2[1]) < .01 && fabs(v1[2] - v2[2]) < .01)
1395 continue;
1396
1397 // insert row into grid2 right after after row l
1398 if(m)
1399 column = grid2->width - 1;
1400 else
1401 column = 0;
1402 grid2 = R_GridInsertRow(grid2, l + 1, column, grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k + 1]);
1403 grid2->lodStitched = qfalse;
1404 s_worldData.surfaces[grid2num].data = (void *)grid2;
1405 return qtrue;
1406 }
1407 }
1408 }
1409 }
1410 for(n = 0; n < 2; n++)
1411 {
1412 if(n)
1413 offset1 = grid1->width - 1;
1414 else
1415 offset1 = 0;
1416 if(R_MergedHeightPoints(grid1, offset1))
1417 continue;
1418 for(k = 0; k < grid1->height - 2; k += 2)
1419 {
1420 for(m = 0; m < 2; m++)
1421 {
1422 if(grid2->width >= MAX_GRID_SIZE)
1423 break;
1424 if(m)
1425 offset2 = (grid2->height - 1) * grid2->width;
1426 else
1427 offset2 = 0;
1428 for(l = 0; l < grid2->width - 1; l++)
1429 {
1430 v1 = grid1->verts[grid1->width * k + offset1].xyz;
1431 v2 = grid2->verts[l + offset2].xyz;
1432 if(fabs(v1[0] - v2[0]) > .1)
1433 continue;
1434 if(fabs(v1[1] - v2[1]) > .1)
1435 continue;
1436 if(fabs(v1[2] - v2[2]) > .1)
1437 continue;
1438
1439 v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz;
1440 v2 = grid2->verts[l + 1 + offset2].xyz;
1441 if(fabs(v1[0] - v2[0]) > .1)
1442 continue;
1443 if(fabs(v1[1] - v2[1]) > .1)
1444 continue;
1445 if(fabs(v1[2] - v2[2]) > .1)
1446 continue;
1447 v1 = grid2->verts[l + offset2].xyz;
1448 v2 = grid2->verts[(l + 1) + offset2].xyz;
1449 if(fabs(v1[0] - v2[0]) < .01 && fabs(v1[1] - v2[1]) < .01 && fabs(v1[2] - v2[2]) < .01)
1450 continue;
1451
1452 // insert column into grid2 right after after column l
1453 if(m)
1454 row = grid2->height - 1;
1455 else
1456 row = 0;
1457 grid2 = R_GridInsertColumn(grid2, l + 1, row,
1458 grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k + 1]);
1459 grid2->lodStitched = qfalse;
1460 s_worldData.surfaces[grid2num].data = (void *)grid2;
1461 return qtrue;
1462 }
1463 }
1464 for(m = 0; m < 2; m++)
1465 {
1466 if(grid2->height >= MAX_GRID_SIZE)
1467 break;
1468 if(m)
1469 offset2 = grid2->width - 1;
1470 else
1471 offset2 = 0;
1472 for(l = 0; l < grid2->height - 1; l++)
1473 {
1474 v1 = grid1->verts[grid1->width * k + offset1].xyz;
1475 v2 = grid2->verts[grid2->width * l + offset2].xyz;
1476 if(fabs(v1[0] - v2[0]) > .1)
1477 continue;
1478 if(fabs(v1[1] - v2[1]) > .1)
1479 continue;
1480 if(fabs(v1[2] - v2[2]) > .1)
1481 continue;
1482
1483 v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz;
1484 v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
1485 if(fabs(v1[0] - v2[0]) > .1)
1486 continue;
1487 if(fabs(v1[1] - v2[1]) > .1)
1488 continue;
1489 if(fabs(v1[2] - v2[2]) > .1)
1490 continue;
1491
1492 v1 = grid2->verts[grid2->width * l + offset2].xyz;
1493 v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
1494 if(fabs(v1[0] - v2[0]) < .01 && fabs(v1[1] - v2[1]) < .01 && fabs(v1[2] - v2[2]) < .01)
1495 continue;
1496
1497 // insert row into grid2 right after after row l
1498 if(m)
1499 column = grid2->width - 1;
1500 else
1501 column = 0;
1502 grid2 = R_GridInsertRow(grid2, l + 1, column,
1503 grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k + 1]);
1504 grid2->lodStitched = qfalse;
1505 s_worldData.surfaces[grid2num].data = (void *)grid2;
1506 return qtrue;
1507 }
1508 }
1509 }
1510 }
1511 for(n = 0; n < 2; n++)
1512 {
1513 if(n)
1514 offset1 = (grid1->height - 1) * grid1->width;
1515 else
1516 offset1 = 0;
1517 if(R_MergedWidthPoints(grid1, offset1))
1518 continue;
1519 for(k = grid1->width - 1; k > 1; k -= 2)
1520 {
1521 for(m = 0; m < 2; m++)
1522 {
1523 if(grid2->width >= MAX_GRID_SIZE)
1524 break;
1525 if(m)
1526 offset2 = (grid2->height - 1) * grid2->width;
1527 else
1528 offset2 = 0;
1529 for(l = 0; l < grid2->width - 1; l++)
1530 {
1531 v1 = grid1->verts[k + offset1].xyz;
1532 v2 = grid2->verts[l + offset2].xyz;
1533 if(fabs(v1[0] - v2[0]) > .1)
1534 continue;
1535 if(fabs(v1[1] - v2[1]) > .1)
1536 continue;
1537 if(fabs(v1[2] - v2[2]) > .1)
1538 continue;
1539
1540 v1 = grid1->verts[k - 2 + offset1].xyz;
1541 v2 = grid2->verts[l + 1 + offset2].xyz;
1542 if(fabs(v1[0] - v2[0]) > .1)
1543 continue;
1544 if(fabs(v1[1] - v2[1]) > .1)
1545 continue;
1546 if(fabs(v1[2] - v2[2]) > .1)
1547 continue;
1548
1549 v1 = grid2->verts[l + offset2].xyz;
1550 v2 = grid2->verts[(l + 1) + offset2].xyz;
1551 if(fabs(v1[0] - v2[0]) < .01 && fabs(v1[1] - v2[1]) < .01 && fabs(v1[2] - v2[2]) < .01)
1552 continue;
1553
1554 // insert column into grid2 right after after column l
1555 if(m)
1556 row = grid2->height - 1;
1557 else
1558 row = 0;
1559 grid2 = R_GridInsertColumn(grid2, l + 1, row, grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k + 1]);
1560 grid2->lodStitched = qfalse;
1561 s_worldData.surfaces[grid2num].data = (void *)grid2;
1562 return qtrue;
1563 }
1564 }
1565 for(m = 0; m < 2; m++)
1566 {
1567 if(grid2->height >= MAX_GRID_SIZE)
1568 break;
1569 if(m)
1570 offset2 = grid2->width - 1;
1571 else
1572 offset2 = 0;
1573 for(l = 0; l < grid2->height - 1; l++)
1574 {
1575 v1 = grid1->verts[k + offset1].xyz;
1576 v2 = grid2->verts[grid2->width * l + offset2].xyz;
1577 if(fabs(v1[0] - v2[0]) > .1)
1578 continue;
1579 if(fabs(v1[1] - v2[1]) > .1)
1580 continue;
1581 if(fabs(v1[2] - v2[2]) > .1)
1582 continue;
1583
1584 v1 = grid1->verts[k - 2 + offset1].xyz;
1585 v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
1586 if(fabs(v1[0] - v2[0]) > .1)
1587 continue;
1588 if(fabs(v1[1] - v2[1]) > .1)
1589 continue;
1590 if(fabs(v1[2] - v2[2]) > .1)
1591 continue;
1592
1593 v1 = grid2->verts[grid2->width * l + offset2].xyz;
1594 v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
1595 if(fabs(v1[0] - v2[0]) < .01 && fabs(v1[1] - v2[1]) < .01 && fabs(v1[2] - v2[2]) < .01)
1596 continue;
1597
1598 // insert row into grid2 right after after row l
1599 if(m)
1600 column = grid2->width - 1;
1601 else
1602 column = 0;
1603 grid2 = R_GridInsertRow(grid2, l + 1, column, grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k + 1]);
1604 if(!grid2)
1605 break;
1606 grid2->lodStitched = qfalse;
1607 s_worldData.surfaces[grid2num].data = (void *)grid2;
1608 return qtrue;
1609 }
1610 }
1611 }
1612 }
1613 for(n = 0; n < 2; n++)
1614 {
1615 if(n)
1616 offset1 = grid1->width - 1;
1617 else
1618 offset1 = 0;
1619 if(R_MergedHeightPoints(grid1, offset1))
1620 continue;
1621 for(k = grid1->height - 1; k > 1; k -= 2)
1622 {
1623 for(m = 0; m < 2; m++)
1624 {
1625 if(grid2->width >= MAX_GRID_SIZE)
1626 break;
1627 if(m)
1628 offset2 = (grid2->height - 1) * grid2->width;
1629 else
1630 offset2 = 0;
1631 for(l = 0; l < grid2->width - 1; l++)
1632 {
1633 v1 = grid1->verts[grid1->width * k + offset1].xyz;
1634 v2 = grid2->verts[l + offset2].xyz;
1635 if(fabs(v1[0] - v2[0]) > .1)
1636 continue;
1637 if(fabs(v1[1] - v2[1]) > .1)
1638 continue;
1639 if(fabs(v1[2] - v2[2]) > .1)
1640 continue;
1641
1642 v1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz;
1643 v2 = grid2->verts[l + 1 + offset2].xyz;
1644 if(fabs(v1[0] - v2[0]) > .1)
1645 continue;
1646 if(fabs(v1[1] - v2[1]) > .1)
1647 continue;
1648 if(fabs(v1[2] - v2[2]) > .1)
1649 continue;
1650
1651 v1 = grid2->verts[l + offset2].xyz;
1652 v2 = grid2->verts[(l + 1) + offset2].xyz;
1653 if(fabs(v1[0] - v2[0]) < .01 && fabs(v1[1] - v2[1]) < .01 && fabs(v1[2] - v2[2]) < .01)
1654 continue;
1655
1656 // insert column into grid2 right after after column l
1657 if(m)
1658 row = grid2->height - 1;
1659 else
1660 row = 0;
1661 grid2 = R_GridInsertColumn(grid2, l + 1, row,
1662 grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k + 1]);
1663 grid2->lodStitched = qfalse;
1664 s_worldData.surfaces[grid2num].data = (void *)grid2;
1665 return qtrue;
1666 }
1667 }
1668 for(m = 0; m < 2; m++)
1669 {
1670 if(grid2->height >= MAX_GRID_SIZE)
1671 break;
1672 if(m)
1673 offset2 = grid2->width - 1;
1674 else
1675 offset2 = 0;
1676 for(l = 0; l < grid2->height - 1; l++)
1677 {
1678 v1 = grid1->verts[grid1->width * k + offset1].xyz;
1679 v2 = grid2->verts[grid2->width * l + offset2].xyz;
1680 if(fabs(v1[0] - v2[0]) > .1)
1681 continue;
1682 if(fabs(v1[1] - v2[1]) > .1)
1683 continue;
1684 if(fabs(v1[2] - v2[2]) > .1)
1685 continue;
1686
1687 v1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz;
1688 v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
1689 if(fabs(v1[0] - v2[0]) > .1)
1690 continue;
1691 if(fabs(v1[1] - v2[1]) > .1)
1692 continue;
1693 if(fabs(v1[2] - v2[2]) > .1)
1694 continue;
1695
1696 v1 = grid2->verts[grid2->width * l + offset2].xyz;
1697 v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
1698 if(fabs(v1[0] - v2[0]) < .01 && fabs(v1[1] - v2[1]) < .01 && fabs(v1[2] - v2[2]) < .01)
1699 continue;
1700
1701 // insert row into grid2 right after after row l
1702 if(m)
1703 column = grid2->width - 1;
1704 else
1705 column = 0;
1706 grid2 = R_GridInsertRow(grid2, l + 1, column,
1707 grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k + 1]);
1708 grid2->lodStitched = qfalse;
1709 s_worldData.surfaces[grid2num].data = (void *)grid2;
1710 return qtrue;
1711 }
1712 }
1713 }
1714 }
1715 return qfalse;
1716 }
1717
1718 /*
1719 ===============
1720 R_TryStitchPatch
1721
1722 This function will try to stitch patches in the same LoD group together for the highest LoD.
1723
1724 Only single missing vertice cracks will be fixed.
1725
1726 Vertices will be joined at the patch side a crack is first found, at the other side
1727 of the patch (on the same row or column) the vertices will not be joined and cracks
1728 might still appear at that side.
1729 ===============
1730 */
R_TryStitchingPatch(int grid1num)1731 int R_TryStitchingPatch(int grid1num)
1732 {
1733 int j, numstitches;
1734 srfGridMesh_t *grid1, *grid2;
1735
1736 numstitches = 0;
1737 grid1 = (srfGridMesh_t *) s_worldData.surfaces[grid1num].data;
1738 for(j = 0; j < s_worldData.numsurfaces; j++)
1739 {
1740 //
1741 grid2 = (srfGridMesh_t *) s_worldData.surfaces[j].data;
1742 // if this surface is not a grid
1743 if(grid2->surfaceType != SF_GRID)
1744 continue;
1745 // grids in the same LOD group should have the exact same lod radius
1746 if(grid1->lodRadius != grid2->lodRadius)
1747 continue;
1748 // grids in the same LOD group should have the exact same lod origin
1749 if(grid1->lodOrigin[0] != grid2->lodOrigin[0])
1750 continue;
1751 if(grid1->lodOrigin[1] != grid2->lodOrigin[1])
1752 continue;
1753 if(grid1->lodOrigin[2] != grid2->lodOrigin[2])
1754 continue;
1755 //
1756 while(R_StitchPatches(grid1num, j))
1757 {
1758 numstitches++;
1759 }
1760 }
1761 return numstitches;
1762 }
1763
1764 /*
1765 ===============
1766 R_StitchAllPatches
1767 ===============
1768 */
R_StitchAllPatches(void)1769 void R_StitchAllPatches(void)
1770 {
1771 int i, stitched, numstitches;
1772 srfGridMesh_t *grid1;
1773
1774 ri.Printf(PRINT_ALL, "...stitching LoD cracks\n");
1775
1776 numstitches = 0;
1777 do
1778 {
1779 stitched = qfalse;
1780 for(i = 0; i < s_worldData.numsurfaces; i++)
1781 {
1782 //
1783 grid1 = (srfGridMesh_t *) s_worldData.surfaces[i].data;
1784 // if this surface is not a grid
1785 if(grid1->surfaceType != SF_GRID)
1786 continue;
1787 //
1788 if(grid1->lodStitched)
1789 continue;
1790 //
1791 grid1->lodStitched = qtrue;
1792 stitched = qtrue;
1793 //
1794 numstitches += R_TryStitchingPatch(i);
1795 }
1796 } while(stitched);
1797 ri.Printf(PRINT_ALL, "stitched %d LoD cracks\n", numstitches);
1798 }
1799
1800 /*
1801 ===============
1802 R_MovePatchSurfacesToHunk
1803 ===============
1804 */
R_MovePatchSurfacesToHunk(void)1805 void R_MovePatchSurfacesToHunk(void)
1806 {
1807 int i, size;
1808 srfGridMesh_t *grid, *hunkgrid;
1809
1810 for(i = 0; i < s_worldData.numsurfaces; i++)
1811 {
1812 //
1813 grid = (srfGridMesh_t *) s_worldData.surfaces[i].data;
1814
1815 // if this surface is not a grid
1816 if(grid->surfaceType != SF_GRID)
1817 continue;
1818 //
1819 size = sizeof(*grid);
1820 hunkgrid = ri.Hunk_Alloc(size, h_low);
1821 Com_Memcpy(hunkgrid, grid, size);
1822
1823 hunkgrid->widthLodError = ri.Hunk_Alloc(grid->width * 4, h_low);
1824 Com_Memcpy(hunkgrid->widthLodError, grid->widthLodError, grid->width * 4);
1825
1826 hunkgrid->heightLodError = ri.Hunk_Alloc(grid->height * 4, h_low);
1827 Com_Memcpy(hunkgrid->heightLodError, grid->heightLodError, grid->height * 4);
1828
1829 hunkgrid->numTriangles = grid->numTriangles;
1830 hunkgrid->triangles = ri.Hunk_Alloc(grid->numTriangles * sizeof(srfTriangle_t), h_low);
1831 Com_Memcpy(hunkgrid->triangles, grid->triangles, grid->numTriangles * sizeof(srfTriangle_t));
1832
1833 hunkgrid->numVerts = grid->numVerts;
1834 hunkgrid->verts = ri.Hunk_Alloc(grid->numVerts * sizeof(srfVert_t), h_low);
1835 Com_Memcpy(hunkgrid->verts, grid->verts, grid->numVerts * sizeof(srfVert_t));
1836
1837 R_FreeSurfaceGridMesh(grid);
1838
1839 s_worldData.surfaces[i].data = (void *)hunkgrid;
1840 }
1841 }
1842
1843 /*
1844 ===============
1845 R_LoadSurfaces
1846 ===============
1847 */
R_LoadSurfaces(lump_t * surfs,lump_t * verts,lump_t * indexLump)1848 static void R_LoadSurfaces(lump_t * surfs, lump_t * verts, lump_t * indexLump)
1849 {
1850 dsurface_t *in;
1851 msurface_t *out;
1852 drawVert_t *dv;
1853 int *indexes;
1854 int count;
1855 int numFaces, numMeshes, numTriSurfs, numFlares;
1856 int i;
1857
1858 ri.Printf(PRINT_ALL, "...loading surfaces\n");
1859
1860 numFaces = 0;
1861 numMeshes = 0;
1862 numTriSurfs = 0;
1863 numFlares = 0;
1864
1865 in = (void *)(fileBase + surfs->fileofs);
1866 if(surfs->filelen % sizeof(*in))
1867 ri.Error(ERR_DROP, "LoadMap: funny lump size in %s", s_worldData.name);
1868 count = surfs->filelen / sizeof(*in);
1869
1870 dv = (void *)(fileBase + verts->fileofs);
1871 if(verts->filelen % sizeof(*dv))
1872 ri.Error(ERR_DROP, "LoadMap: funny lump size in %s", s_worldData.name);
1873
1874 indexes = (void *)(fileBase + indexLump->fileofs);
1875 if(indexLump->filelen % sizeof(*indexes))
1876 ri.Error(ERR_DROP, "LoadMap: funny lump size in %s", s_worldData.name);
1877
1878 out = ri.Hunk_Alloc(count * sizeof(*out), h_low);
1879
1880 s_worldData.surfaces = out;
1881 s_worldData.numsurfaces = count;
1882
1883 for(i = 0; i < count; i++, in++, out++)
1884 {
1885 switch (LittleLong(in->surfaceType))
1886 {
1887 case MST_PATCH:
1888 ParseMesh(in, dv, out);
1889 numMeshes++;
1890 break;
1891 case MST_TRIANGLE_SOUP:
1892 ParseTriSurf(in, dv, out, indexes);
1893 numTriSurfs++;
1894 break;
1895 case MST_PLANAR:
1896 ParseFace(in, dv, out, indexes);
1897 numFaces++;
1898 break;
1899 case MST_FLARE:
1900 ParseFlare(in, dv, out, indexes);
1901 numFlares++;
1902 break;
1903 default:
1904 ri.Error(ERR_DROP, "Bad surfaceType");
1905 }
1906 }
1907
1908 ri.Printf(PRINT_ALL, "...loaded %d faces, %i meshes, %i trisurfs, %i flares\n", numFaces, numMeshes, numTriSurfs, numFlares);
1909
1910 #ifdef PATCH_STITCHING
1911 R_StitchAllPatches();
1912 #endif
1913
1914 R_FixSharedVertexLodError();
1915
1916 #ifdef PATCH_STITCHING
1917 R_MovePatchSurfacesToHunk();
1918 #endif
1919 }
1920
1921
1922
1923 /*
1924 =================
1925 R_LoadSubmodels
1926 =================
1927 */
R_LoadSubmodels(lump_t * l)1928 static void R_LoadSubmodels(lump_t * l)
1929 {
1930 dmodel_t *in;
1931 bmodel_t *out;
1932 int i, j, count;
1933
1934 ri.Printf(PRINT_ALL, "...loading submodels\n");
1935
1936 in = (void *)(fileBase + l->fileofs);
1937 if(l->filelen % sizeof(*in))
1938 ri.Error(ERR_DROP, "LoadMap: funny lump size in %s", s_worldData.name);
1939 count = l->filelen / sizeof(*in);
1940
1941 s_worldData.bmodels = out = ri.Hunk_Alloc(count * sizeof(*out), h_low);
1942
1943 for(i = 0; i < count; i++, in++, out++)
1944 {
1945 model_t *model;
1946
1947 model = R_AllocModel();
1948
1949 assert(model != NULL); // this should never happen
1950
1951 model->type = MOD_BRUSH;
1952 model->bmodel = out;
1953 Com_sprintf(model->name, sizeof(model->name), "*%d", i);
1954
1955 for(j = 0; j < 3; j++)
1956 {
1957 out->bounds[0][j] = LittleFloat(in->mins[j]);
1958 out->bounds[1][j] = LittleFloat(in->maxs[j]);
1959 }
1960
1961 out->firstSurface = s_worldData.surfaces + LittleLong(in->firstSurface);
1962 out->numSurfaces = LittleLong(in->numSurfaces);
1963 }
1964 }
1965
1966
1967
1968 //==================================================================
1969
1970 /*
1971 =================
1972 R_SetParent
1973 =================
1974 */
R_SetParent(mnode_t * node,mnode_t * parent)1975 static void R_SetParent(mnode_t * node, mnode_t * parent)
1976 {
1977 node->parent = parent;
1978 if(node->contents != -1)
1979 return;
1980 R_SetParent(node->children[0], node);
1981 R_SetParent(node->children[1], node);
1982 }
1983
1984 /*
1985 =================
1986 R_LoadNodesAndLeafs
1987 =================
1988 */
R_LoadNodesAndLeafs(lump_t * nodeLump,lump_t * leafLump)1989 static void R_LoadNodesAndLeafs(lump_t * nodeLump, lump_t * leafLump)
1990 {
1991 int i, j, p;
1992 dnode_t *in;
1993 dleaf_t *inLeaf;
1994 mnode_t *out;
1995 int numNodes, numLeafs;
1996
1997 ri.Printf(PRINT_ALL, "...loading nodes and leaves\n");
1998
1999 in = (void *)(fileBase + nodeLump->fileofs);
2000 if(nodeLump->filelen % sizeof(dnode_t) || leafLump->filelen % sizeof(dleaf_t))
2001 {
2002 ri.Error(ERR_DROP, "LoadMap: funny lump size in %s", s_worldData.name);
2003 }
2004 numNodes = nodeLump->filelen / sizeof(dnode_t);
2005 numLeafs = leafLump->filelen / sizeof(dleaf_t);
2006
2007 out = ri.Hunk_Alloc((numNodes + numLeafs) * sizeof(*out), h_low);
2008
2009 s_worldData.nodes = out;
2010 s_worldData.numnodes = numNodes + numLeafs;
2011 s_worldData.numDecisionNodes = numNodes;
2012
2013 // load nodes
2014 for(i = 0; i < numNodes; i++, in++, out++)
2015 {
2016 for(j = 0; j < 3; j++)
2017 {
2018 out->mins[j] = LittleLong(in->mins[j]);
2019 out->maxs[j] = LittleLong(in->maxs[j]);
2020 }
2021
2022 p = LittleLong(in->planeNum);
2023 out->plane = s_worldData.planes + p;
2024
2025 out->contents = CONTENTS_NODE; // differentiate from leafs
2026
2027 for(j = 0; j < 2; j++)
2028 {
2029 p = LittleLong(in->children[j]);
2030 if(p >= 0)
2031 out->children[j] = s_worldData.nodes + p;
2032 else
2033 out->children[j] = s_worldData.nodes + numNodes + (-1 - p);
2034 }
2035 }
2036
2037 // load leafs
2038 inLeaf = (void *)(fileBase + leafLump->fileofs);
2039 for(i = 0; i < numLeafs; i++, inLeaf++, out++)
2040 {
2041 for(j = 0; j < 3; j++)
2042 {
2043 out->mins[j] = LittleLong(inLeaf->mins[j]);
2044 out->maxs[j] = LittleLong(inLeaf->maxs[j]);
2045 }
2046
2047 out->cluster = LittleLong(inLeaf->cluster);
2048 out->area = LittleLong(inLeaf->area);
2049
2050 if(out->cluster >= s_worldData.numClusters)
2051 {
2052 s_worldData.numClusters = out->cluster + 1;
2053 }
2054
2055 out->firstmarksurface = s_worldData.marksurfaces + LittleLong(inLeaf->firstLeafSurface);
2056 out->nummarksurfaces = LittleLong(inLeaf->numLeafSurfaces);
2057 }
2058
2059 // chain decendants
2060 R_SetParent(s_worldData.nodes, NULL);
2061 }
2062
2063 //=============================================================================
2064
2065 /*
2066 =================
2067 R_LoadShaders
2068 =================
2069 */
R_LoadShaders(lump_t * l)2070 static void R_LoadShaders(lump_t * l)
2071 {
2072 int i, count;
2073 dshader_t *in, *out;
2074
2075 ri.Printf(PRINT_ALL, "...loading shaders\n");
2076
2077 in = (void *)(fileBase + l->fileofs);
2078 if(l->filelen % sizeof(*in))
2079 ri.Error(ERR_DROP, "LoadMap: funny lump size in %s", s_worldData.name);
2080 count = l->filelen / sizeof(*in);
2081 out = ri.Hunk_Alloc(count * sizeof(*out), h_low);
2082
2083 s_worldData.shaders = out;
2084 s_worldData.numShaders = count;
2085
2086 Com_Memcpy(out, in, count * sizeof(*out));
2087
2088 for(i = 0; i < count; i++)
2089 {
2090 out[i].surfaceFlags = LittleLong(out[i].surfaceFlags);
2091 out[i].contentFlags = LittleLong(out[i].contentFlags);
2092 }
2093 }
2094
2095
2096 /*
2097 =================
2098 R_LoadMarksurfaces
2099 =================
2100 */
R_LoadMarksurfaces(lump_t * l)2101 static void R_LoadMarksurfaces(lump_t * l)
2102 {
2103 int i, j, count;
2104 int *in;
2105 msurface_t **out;
2106
2107 ri.Printf(PRINT_ALL, "...loading mark surfaces\n");
2108
2109 in = (void *)(fileBase + l->fileofs);
2110 if(l->filelen % sizeof(*in))
2111 ri.Error(ERR_DROP, "LoadMap: funny lump size in %s", s_worldData.name);
2112 count = l->filelen / sizeof(*in);
2113 out = ri.Hunk_Alloc(count * sizeof(*out), h_low);
2114
2115 s_worldData.marksurfaces = out;
2116 s_worldData.nummarksurfaces = count;
2117
2118 for(i = 0; i < count; i++)
2119 {
2120 j = LittleLong(in[i]);
2121 out[i] = s_worldData.surfaces + j;
2122 }
2123 }
2124
2125
2126 /*
2127 =================
2128 R_LoadPlanes
2129 =================
2130 */
R_LoadPlanes(lump_t * l)2131 static void R_LoadPlanes(lump_t * l)
2132 {
2133 int i, j;
2134 cplane_t *out;
2135 dplane_t *in;
2136 int count;
2137 int bits;
2138
2139 ri.Printf(PRINT_ALL, "...loading planes\n");
2140
2141 in = (void *)(fileBase + l->fileofs);
2142 if(l->filelen % sizeof(*in))
2143 ri.Error(ERR_DROP, "LoadMap: funny lump size in %s", s_worldData.name);
2144 count = l->filelen / sizeof(*in);
2145 out = ri.Hunk_Alloc(count * 2 * sizeof(*out), h_low);
2146
2147 s_worldData.planes = out;
2148 s_worldData.numplanes = count;
2149
2150 for(i = 0; i < count; i++, in++, out++)
2151 {
2152 bits = 0;
2153 for(j = 0; j < 3; j++)
2154 {
2155 out->normal[j] = LittleFloat(in->normal[j]);
2156 if(out->normal[j] < 0)
2157 {
2158 bits |= 1 << j;
2159 }
2160 }
2161
2162 out->dist = LittleFloat(in->dist);
2163 out->type = PlaneTypeForNormal(out->normal);
2164 out->signbits = bits;
2165 }
2166 }
2167
2168 /*
2169 =================
2170 R_LoadFogs
2171
2172 =================
2173 */
R_LoadFogs(lump_t * l,lump_t * brushesLump,lump_t * sidesLump)2174 static void R_LoadFogs(lump_t * l, lump_t * brushesLump, lump_t * sidesLump)
2175 {
2176 int i;
2177 fog_t *out;
2178 dfog_t *fogs;
2179 dbrush_t *brushes, *brush;
2180 dbrushside_t *sides;
2181 int count, brushesCount, sidesCount;
2182 int sideNum;
2183 int planeNum;
2184 shader_t *shader;
2185 float d;
2186 int firstSide;
2187
2188 ri.Printf(PRINT_ALL, "...loading fogs\n");
2189
2190 fogs = (void *)(fileBase + l->fileofs);
2191 if(l->filelen % sizeof(*fogs))
2192 {
2193 ri.Error(ERR_DROP, "LoadMap: funny lump size in %s", s_worldData.name);
2194 }
2195 count = l->filelen / sizeof(*fogs);
2196
2197 // create fog strucutres for them
2198 s_worldData.numfogs = count + 1;
2199 s_worldData.fogs = ri.Hunk_Alloc(s_worldData.numfogs * sizeof(*out), h_low);
2200 out = s_worldData.fogs + 1;
2201
2202 if(!count)
2203 {
2204 return;
2205 }
2206
2207 brushes = (void *)(fileBase + brushesLump->fileofs);
2208 if(brushesLump->filelen % sizeof(*brushes))
2209 {
2210 ri.Error(ERR_DROP, "LoadMap: funny lump size in %s", s_worldData.name);
2211 }
2212 brushesCount = brushesLump->filelen / sizeof(*brushes);
2213
2214 sides = (void *)(fileBase + sidesLump->fileofs);
2215 if(sidesLump->filelen % sizeof(*sides))
2216 {
2217 ri.Error(ERR_DROP, "LoadMap: funny lump size in %s", s_worldData.name);
2218 }
2219 sidesCount = sidesLump->filelen / sizeof(*sides);
2220
2221 for(i = 0; i < count; i++, fogs++)
2222 {
2223 out->originalBrushNumber = LittleLong(fogs->brushNum);
2224
2225 if((unsigned)out->originalBrushNumber >= brushesCount)
2226 {
2227 ri.Error(ERR_DROP, "fog brushNumber out of range");
2228 }
2229 brush = brushes + out->originalBrushNumber;
2230
2231 firstSide = LittleLong(brush->firstSide);
2232
2233 if((unsigned)firstSide > sidesCount - 6)
2234 {
2235 ri.Error(ERR_DROP, "fog brush sideNumber out of range");
2236 }
2237
2238 // brushes are always sorted with the axial sides first
2239 sideNum = firstSide + 0;
2240 planeNum = LittleLong(sides[sideNum].planeNum);
2241 out->bounds[0][0] = -s_worldData.planes[planeNum].dist;
2242
2243 sideNum = firstSide + 1;
2244 planeNum = LittleLong(sides[sideNum].planeNum);
2245 out->bounds[1][0] = s_worldData.planes[planeNum].dist;
2246
2247 sideNum = firstSide + 2;
2248 planeNum = LittleLong(sides[sideNum].planeNum);
2249 out->bounds[0][1] = -s_worldData.planes[planeNum].dist;
2250
2251 sideNum = firstSide + 3;
2252 planeNum = LittleLong(sides[sideNum].planeNum);
2253 out->bounds[1][1] = s_worldData.planes[planeNum].dist;
2254
2255 sideNum = firstSide + 4;
2256 planeNum = LittleLong(sides[sideNum].planeNum);
2257 out->bounds[0][2] = -s_worldData.planes[planeNum].dist;
2258
2259 sideNum = firstSide + 5;
2260 planeNum = LittleLong(sides[sideNum].planeNum);
2261 out->bounds[1][2] = s_worldData.planes[planeNum].dist;
2262
2263 // get information from the shader for fog parameters
2264 shader = R_FindShader(fogs->shader, SHADER_3D_DYNAMIC, qtrue);
2265
2266 out->parms = shader->fogParms;
2267
2268 out->colorInt = ColorBytes4(shader->fogParms.color[0] * tr.identityLight,
2269 shader->fogParms.color[1] * tr.identityLight,
2270 shader->fogParms.color[2] * tr.identityLight, 1.0);
2271
2272 d = shader->fogParms.depthForOpaque < 1 ? 1 : shader->fogParms.depthForOpaque;
2273 out->tcScale = 1.0f / (d * 8);
2274
2275 // set the gradient vector
2276 sideNum = LittleLong(fogs->visibleSide);
2277
2278 if(sideNum == -1)
2279 {
2280 out->hasSurface = qfalse;
2281 }
2282 else
2283 {
2284 out->hasSurface = qtrue;
2285 planeNum = LittleLong(sides[firstSide + sideNum].planeNum);
2286 VectorSubtract(vec3_origin, s_worldData.planes[planeNum].normal, out->surface);
2287 out->surface[3] = -s_worldData.planes[planeNum].dist;
2288 }
2289
2290 out++;
2291 }
2292
2293 }
2294
2295
2296 /*
2297 ================
2298 R_LoadLightGrid
2299
2300 ================
2301 */
R_LoadLightGrid(lump_t * l)2302 void R_LoadLightGrid(lump_t * l)
2303 {
2304 int i;
2305 vec3_t maxs;
2306 int numGridPoints;
2307 world_t *w;
2308 float *wMins, *wMaxs;
2309
2310 ri.Printf(PRINT_ALL, "...loading light grid\n");
2311
2312 w = &s_worldData;
2313
2314 w->lightGridInverseSize[0] = 1.0f / w->lightGridSize[0];
2315 w->lightGridInverseSize[1] = 1.0f / w->lightGridSize[1];
2316 w->lightGridInverseSize[2] = 1.0f / w->lightGridSize[2];
2317
2318 wMins = w->bmodels[0].bounds[0];
2319 wMaxs = w->bmodels[0].bounds[1];
2320
2321 for(i = 0; i < 3; i++)
2322 {
2323 w->lightGridOrigin[i] = w->lightGridSize[i] * ceil(wMins[i] / w->lightGridSize[i]);
2324 maxs[i] = w->lightGridSize[i] * floor(wMaxs[i] / w->lightGridSize[i]);
2325 w->lightGridBounds[i] = (maxs[i] - w->lightGridOrigin[i]) / w->lightGridSize[i] + 1;
2326 }
2327
2328 numGridPoints = w->lightGridBounds[0] * w->lightGridBounds[1] * w->lightGridBounds[2];
2329
2330 if(l->filelen != numGridPoints * 8)
2331 {
2332 ri.Printf(PRINT_WARNING, "WARNING: light grid mismatch\n");
2333 w->lightGridData = NULL;
2334 return;
2335 }
2336
2337 w->lightGridData = ri.Hunk_Alloc(l->filelen, h_low);
2338 Com_Memcpy(w->lightGridData, (void *)(fileBase + l->fileofs), l->filelen);
2339
2340 // deal with overbright bits
2341 for(i = 0; i < numGridPoints; i++)
2342 {
2343 R_ColorShiftLightingBytes(&w->lightGridData[i * 8], &w->lightGridData[i * 8]);
2344 R_ColorShiftLightingBytes(&w->lightGridData[i * 8 + 3], &w->lightGridData[i * 8 + 3]);
2345 }
2346 }
2347
2348 /*
2349 ================
2350 R_LoadEntities
2351 ================
2352 */
R_LoadEntities(lump_t * l)2353 void R_LoadEntities(lump_t * l)
2354 {
2355 int i;
2356 char *p, *pOld, *token, *s;
2357 char keyname[MAX_TOKEN_CHARS];
2358 char value[MAX_TOKEN_CHARS];
2359 world_t *w;
2360 qboolean isLight = qfalse;
2361 int numEntities = 0;
2362 int numLights = 0;
2363 int numOmniLights = 0;
2364 int numProjLights = 0;
2365 int numDirectLights = 0;
2366 trRefDlight_t *dl;
2367
2368 ri.Printf(PRINT_ALL, "...loading entities\n");
2369
2370 w = &s_worldData;
2371 w->lightGridSize[0] = 64;
2372 w->lightGridSize[1] = 64;
2373 w->lightGridSize[2] = 128;
2374
2375 // store for reference by the cgame
2376 w->entityString = ri.Hunk_Alloc(l->filelen + 1, h_low);
2377 strcpy(w->entityString, (char *)(fileBase + l->fileofs));
2378 w->entityParsePoint = w->entityString;
2379
2380 #if 1
2381 p = w->entityString;
2382 #else
2383 p = (char *)(fileBase + l->fileofs);
2384 #endif
2385
2386 // only parse the world spawn
2387 while(1)
2388 {
2389 // parse key
2390 token = Com_ParseExt(&p, qtrue);
2391
2392 if(!*token)
2393 {
2394 ri.Printf(PRINT_WARNING, "WARNING: unexpected end of entities string while parsing worldspawn\n", token);
2395 break;
2396 }
2397
2398 if(*token == '{')
2399 {
2400 continue;
2401 }
2402
2403 if(*token == '}')
2404 {
2405 break;
2406 }
2407
2408 Q_strncpyz(keyname, token, sizeof(keyname));
2409
2410 // parse value
2411 token = Com_ParseExt(&p, qfalse);
2412
2413 if(!*token)
2414 {
2415 continue;
2416 }
2417
2418 Q_strncpyz(value, token, sizeof(value));
2419
2420 // check for remapping of shaders for vertex lighting
2421 s = "vertexremapshader";
2422 if(!Q_strncmp(keyname, s, strlen(s)))
2423 {
2424 s = strchr(value, ';');
2425 if(!s)
2426 {
2427 ri.Printf(PRINT_WARNING, "WARNING: no semi colon in vertexshaderremap '%s'\n", value);
2428 break;
2429 }
2430 *s++ = 0;
2431 continue;
2432 }
2433
2434 // check for remapping of shaders
2435 s = "remapshader";
2436 if(!Q_strncmp(keyname, s, strlen(s)))
2437 {
2438 s = strchr(value, ';');
2439 if(!s)
2440 {
2441 ri.Printf(PRINT_WARNING, "WARNING: no semi colon in shaderremap '%s'\n", value);
2442 break;
2443 }
2444 *s++ = 0;
2445 R_RemapShader(value, s, "0");
2446 continue;
2447 }
2448
2449 // check for a different grid size
2450 if(!Q_stricmp(keyname, "gridsize"))
2451 {
2452 sscanf(value, "%f %f %f", &w->lightGridSize[0], &w->lightGridSize[1], &w->lightGridSize[2]);
2453 continue;
2454 }
2455
2456 // check for deluxe mapping support
2457 if((!Q_stricmp(keyname, "deluxeMapping") && !Q_stricmp(value, "1")) || (!Q_stricmp(keyname, "message") && !Q_stricmp(value, "camo-retro"))) // HACK: this map has it
2458 {
2459 tr.worldDeluxeMapping = qtrue;
2460 continue;
2461 }
2462
2463 if(!Q_stricmp(keyname, "classname") && Q_stricmp(value, "worldspawn"))
2464 {
2465 ri.Printf(PRINT_WARNING, "WARNING: expected worldspawn found '%s'\n", value);
2466 continue;
2467 }
2468 }
2469
2470 // ri.Printf(PRINT_ALL, "-----------\n%s\n----------\n", p);
2471
2472 #if 1
2473 pOld = p;
2474 numEntities = 1; // parsed worldspawn so far
2475
2476 // count lights
2477 while(1)
2478 {
2479 // parse {
2480 token = Com_ParseExt(&p, qtrue);
2481
2482 if(!*token)
2483 {
2484 // end of entities string
2485 break;
2486 }
2487
2488 if(*token != '{')
2489 {
2490 ri.Printf(PRINT_WARNING, "WARNING: expected { found '%s'\n", token);
2491 break;
2492 }
2493
2494 // new entity
2495 isLight = qfalse;
2496
2497 // parse epairs
2498 while(1)
2499 {
2500 // parse key
2501 token = Com_ParseExt(&p, qtrue);
2502
2503 if(*token == '}')
2504 {
2505 break;
2506 }
2507
2508 if(!*token)
2509 {
2510 ri.Printf(PRINT_WARNING, "WARNING: EOF without closing bracket\n");
2511 break;
2512 }
2513
2514 Q_strncpyz(keyname, token, sizeof(keyname));
2515
2516 // parse value
2517 token = Com_ParseExt(&p, qfalse);
2518
2519 if(!*token)
2520 {
2521 continue;
2522 }
2523
2524 Q_strncpyz(value, token, sizeof(value));
2525
2526 // check if this entity is a light
2527 if(!Q_stricmp(keyname, "classname") && !Q_stricmp(value, "light"))
2528 {
2529 isLight = qtrue;
2530 continue;
2531 }
2532 }
2533
2534 if(*token != '}')
2535 {
2536 ri.Printf(PRINT_WARNING, "WARNING: expected } found '%s'\n", token);
2537 break;
2538 }
2539
2540 if(isLight)
2541 {
2542 numLights++;
2543 }
2544
2545 numEntities++;
2546 }
2547
2548 ri.Printf(PRINT_ALL, "%i total entities counted\n", numEntities);
2549 ri.Printf(PRINT_ALL, "%i total lights counted\n", numLights);
2550
2551 s_worldData.numDlights = numLights;
2552 s_worldData.dlights = ri.Hunk_Alloc(s_worldData.numDlights * sizeof(trRefDlight_t), h_low);
2553
2554 // basic light setup
2555 for(i = 0, dl = s_worldData.dlights; i < s_worldData.numDlights; i++, dl++)
2556 {
2557 dl->l.color[0] = 1;
2558 dl->l.color[1] = 1;
2559 dl->l.color[2] = 1;
2560
2561 dl->l.radius[0] = 300;
2562 dl->l.radius[1] = 300;
2563 dl->l.radius[2] = 300;
2564
2565 AxisCopy(axisDefault, dl->l.axis);
2566
2567 dl->isStatic = qtrue;
2568 dl->additive = qtrue;
2569 }
2570 #endif
2571
2572 #if 1
2573 // parse lights
2574 p = pOld;
2575 numEntities = 1;
2576 dl = s_worldData.dlights;
2577
2578 while(1)
2579 {
2580 token = Com_ParseExt(&p, qtrue);
2581
2582 if(!*token)
2583 {
2584 // end of entities string
2585 break;
2586 }
2587
2588 if(*token != '{')
2589 {
2590 ri.Printf(PRINT_WARNING, "WARNING: expected { found '%s'\n", token);
2591 break;
2592 }
2593
2594 // new entity
2595 isLight = qfalse;
2596
2597 // parse epairs
2598 while(1)
2599 {
2600 // parse key
2601 token = Com_ParseExt(&p, qtrue);
2602
2603 if(*token == '}')
2604 {
2605 break;
2606 }
2607
2608 if(!*token)
2609 {
2610 ri.Printf(PRINT_WARNING, "WARNING: EOF without closing bracket\n");
2611 break;
2612 }
2613
2614 Q_strncpyz(keyname, token, sizeof(keyname));
2615
2616 // parse value
2617 token = Com_ParseExt(&p, qfalse);
2618
2619 if(!*token)
2620 {
2621 continue;
2622 }
2623
2624 Q_strncpyz(value, token, sizeof(value));
2625
2626 // check if this entity is a light
2627 if(!Q_stricmp(keyname, "classname") && !Q_stricmp(value, "light"))
2628 {
2629 isLight = qtrue;
2630 }
2631 // check for origin
2632 else if(!Q_stricmp(keyname, "origin") || !Q_stricmp(keyname, "light_origin"))
2633 {
2634 sscanf(value, "%f %f %f", &dl->l.origin[0], &dl->l.origin[1], &dl->l.origin[2]);
2635 }
2636 // check for center
2637 else if(!Q_stricmp(keyname, "light_center"))
2638 {
2639 sscanf(value, "%f %f %f", &dl->l.center[0], &dl->l.center[1], &dl->l.center[2]);
2640 }
2641 // check for color
2642 else if(!Q_stricmp(keyname, "_color"))
2643 {
2644 sscanf(value, "%f %f %f", &dl->l.color[0], &dl->l.color[1], &dl->l.color[2]);
2645 }
2646 // check for radius
2647 else if(!Q_stricmp(keyname, "light_radius"))
2648 {
2649 sscanf(value, "%f %f %f", &dl->l.radius[0], &dl->l.radius[1], &dl->l.radius[2]);
2650 }
2651 // check for target
2652 else if(!Q_stricmp(keyname, "light_target"))
2653 {
2654 sscanf(value, "%f %f %f", &dl->l.target[0], &dl->l.target[1], &dl->l.target[2]);
2655 dl->l.rlType = RL_PROJ;
2656 }
2657 // check for right
2658 else if(!Q_stricmp(keyname, "light_right"))
2659 {
2660 sscanf(value, "%f %f %f", &dl->l.right[0], &dl->l.right[1], &dl->l.right[2]);
2661 dl->l.rlType = RL_PROJ;
2662 }
2663 // check for up
2664 else if(!Q_stricmp(keyname, "light_up"))
2665 {
2666 sscanf(value, "%f %f %f", &dl->l.up[0], &dl->l.up[1], &dl->l.up[2]);
2667 dl->l.rlType = RL_PROJ;
2668 }
2669 // check for radius
2670 else if(!Q_stricmp(keyname, "light") || !Q_stricmp(keyname, "_light"))
2671 {
2672 vec_t value2;
2673
2674 value2 = atof(value);
2675 dl->l.radius[0] = value2;
2676 dl->l.radius[1] = value2;
2677 dl->l.radius[2] = value2;
2678 }
2679 // check for light shader
2680 else if(!Q_stricmp(keyname, "texture"))
2681 {
2682 //FIXME
2683 dl->l.attenuationShader = RE_RegisterShaderLightAttenuation(value);
2684 }
2685 // check for rotation
2686 else if(!Q_stricmp(keyname, "rotation") || !Q_stricmp(keyname, "light_rotation"))
2687 {
2688 matrix_t rotation;
2689
2690 sscanf(value, "%f %f %f %f %f %f %f %f %f", &rotation[0], &rotation[1], &rotation[2],
2691 &rotation[4], &rotation[5], &rotation[6], &rotation[8], &rotation[9], &rotation[10]);
2692 MatrixToVectorsFLU(rotation, dl->l.axis[0], dl->l.axis[1], dl->l.axis[2]);
2693 }
2694 // check if this light does not cast any shadows
2695 else if(!Q_stricmp(keyname, "noShadows") && !Q_stricmp(value, "1"))
2696 {
2697 dl->l.noShadows = qtrue;
2698 }
2699 }
2700
2701 if(*token != '}')
2702 {
2703 ri.Printf(PRINT_WARNING, "WARNING: expected } found '%s'\n", token);
2704 break;
2705 }
2706
2707 if(isLight)
2708 {
2709 if((numOmniLights + numProjLights + numDirectLights) < s_worldData.numDlights);
2710 {
2711 dl++;
2712
2713 switch (dl->l.rlType)
2714 {
2715 case RL_OMNI:
2716 numOmniLights++;
2717 break;
2718
2719 case RL_PROJ:
2720 numProjLights++;
2721 break;
2722
2723 case RL_DIRECT:
2724 numDirectLights++;
2725 break;
2726
2727 default:
2728 break;
2729 }
2730 }
2731 }
2732
2733 numEntities++;
2734 }
2735 #endif
2736
2737 ri.Printf(PRINT_ALL, "%i total entities parsed\n", numEntities);
2738 ri.Printf(PRINT_ALL, "%i total lights parsed\n", numOmniLights + numProjLights + numDirectLights);
2739 ri.Printf(PRINT_ALL, "%i omni-directional lights parsed\n", numOmniLights);
2740 ri.Printf(PRINT_ALL, "%i projective lights parsed\n", numProjLights);
2741 ri.Printf(PRINT_ALL, "%i directional lights parsed\n", numDirectLights);
2742 }
2743
2744
2745 /*
2746 =================
2747 R_GetEntityToken
2748 =================
2749 */
R_GetEntityToken(char * buffer,int size)2750 qboolean R_GetEntityToken(char *buffer, int size)
2751 {
2752 const char *s;
2753
2754 s = Com_Parse(&s_worldData.entityParsePoint);
2755 Q_strncpyz(buffer, s, size);
2756 if(!s_worldData.entityParsePoint || !s[0])
2757 {
2758 s_worldData.entityParsePoint = s_worldData.entityString;
2759 return qfalse;
2760 }
2761 else
2762 {
2763 return qtrue;
2764 }
2765 }
2766
2767
2768 /*
2769 =================
2770 R_PrecacheInteraction
2771 =================
2772 */
R_PrecacheInteraction(trRefDlight_t * light,msurface_t * surface)2773 static void R_PrecacheInteraction(trRefDlight_t * light, msurface_t * surface)
2774 {
2775 interactionCache_t *iaCache;
2776
2777 if(s_interactionCount >= s_worldData.numInteractions)
2778 {
2779 ri.Printf(PRINT_WARNING, "R_PrecacheInteraction: overflow, not enough interactions in pool\n");
2780 return;
2781 }
2782
2783 iaCache = &s_worldData.interactions[s_interactionCount];
2784 s_interactionCount++;
2785
2786 // connect to interaction grid
2787 if(!light->firstInteractionCache)
2788 {
2789 light->firstInteractionCache = iaCache;
2790 }
2791
2792 if(light->lastInteractionCache)
2793 {
2794 light->lastInteractionCache->next = iaCache;
2795 }
2796
2797 light->lastInteractionCache = iaCache;
2798
2799 iaCache->next = NULL;
2800 iaCache->surface = surface;
2801
2802 if(s_numLightIndexes >= 3)
2803 {
2804 iaCache->numLightIndexes = s_numLightIndexes;
2805 iaCache->lightIndexes = ri.Hunk_Alloc(s_numLightIndexes * sizeof(int), h_low);
2806 Com_Memcpy(iaCache->lightIndexes, s_lightIndexes, s_numLightIndexes * sizeof(int));
2807 }
2808 else
2809 {
2810 iaCache->numLightIndexes = 0;
2811 iaCache->lightIndexes = NULL;
2812 }
2813
2814 if(s_numShadowIndexes >= (6 + 2) * 3)
2815 {
2816 iaCache->numShadowIndexes = s_numShadowIndexes;
2817 iaCache->shadowIndexes = ri.Hunk_Alloc(s_numShadowIndexes * sizeof(int), h_low);
2818 Com_Memcpy(iaCache->shadowIndexes, s_shadowIndexes, s_numShadowIndexes * sizeof(int));
2819 }
2820 else
2821 {
2822 iaCache->numShadowIndexes = 0;
2823 iaCache->shadowIndexes = NULL;
2824 }
2825 }
2826
2827 /*
2828 Triangle-box collider by Alen Ladavac and Vedran Klanac.
2829 Ported to ODE by Oskari Nyman.
2830 Ported to Q3A by Robert Beckebans.
2831 */
2832
2833 // global collider data
2834 static vec3_t vBestNormal;
2835 static vec_t fBestDepth;
2836 static int iBestAxis = 0;
2837 static int iExitAxis = 0;
2838 static vec3_t vE0, vE1, vE2, vN;
2839
2840 // test normal of mesh face as separating axis for intersection
_cldTestNormal(vec_t fp0,vec_t fR,vec3_t vNormal,int iAxis)2841 static qboolean _cldTestNormal(vec_t fp0, vec_t fR, vec3_t vNormal, int iAxis)
2842 {
2843 // calculate overlapping interval of box and triangle
2844 vec_t fDepth = fR + fp0;
2845 vec_t fLength;
2846
2847 // if we do not overlap
2848 if(fDepth < 0)
2849 {
2850 // do nothing
2851 return qfalse;
2852 }
2853
2854 // calculate normal's length
2855 fLength = VectorLength(vNormal);
2856
2857 // if long enough
2858 if(fLength > 0.0f)
2859 {
2860
2861 vec_t fOneOverLength = 1.0f / fLength;
2862
2863 // normalize depth
2864 fDepth = fDepth * fOneOverLength;
2865
2866 // get minimum depth
2867 if(fDepth < fBestDepth)
2868 {
2869 vBestNormal[0] = -vNormal[0] * fOneOverLength;
2870 vBestNormal[1] = -vNormal[1] * fOneOverLength;
2871 vBestNormal[2] = -vNormal[2] * fOneOverLength;
2872 iBestAxis = iAxis;
2873 //dAASSERT(fDepth>=0);
2874 fBestDepth = fDepth;
2875 }
2876
2877 }
2878
2879 return qtrue;
2880 }
2881
2882 // test box axis as separating axis
_cldTestFace(vec_t fp0,vec_t fp1,vec_t fp2,vec_t fR,vec_t fD,vec3_t vNormal,int iAxis)2883 static qboolean _cldTestFace(vec_t fp0, vec_t fp1, vec_t fp2, vec_t fR, vec_t fD, vec3_t vNormal, int iAxis)
2884 {
2885 vec_t fMin, fMax;
2886 vec_t fDepthMin;
2887 vec_t fDepthMax;
2888 vec_t fDepth;
2889
2890 // find min of triangle interval
2891 if(fp0 < fp1)
2892 {
2893 if(fp0 < fp2)
2894 {
2895 fMin = fp0;
2896 }
2897 else
2898 {
2899 fMin = fp2;
2900 }
2901 }
2902 else
2903 {
2904 if(fp1 < fp2)
2905 {
2906 fMin = fp1;
2907 }
2908 else
2909 {
2910 fMin = fp2;
2911 }
2912 }
2913
2914 // find max of triangle interval
2915 if(fp0 > fp1)
2916 {
2917 if(fp0 > fp2)
2918 {
2919 fMax = fp0;
2920 }
2921 else
2922 {
2923 fMax = fp2;
2924 }
2925 }
2926 else
2927 {
2928 if(fp1 > fp2)
2929 {
2930 fMax = fp1;
2931 }
2932 else
2933 {
2934 fMax = fp2;
2935 }
2936 }
2937
2938 // calculate minimum and maximum depth
2939 fDepthMin = fR - fMin;
2940 fDepthMax = fMax + fR;
2941
2942 // if we dont't have overlapping interval
2943 if(fDepthMin < 0 || fDepthMax < 0)
2944 {
2945 // do nothing
2946 return qfalse;
2947 }
2948
2949 fDepth = 0;
2950
2951 // if greater depth is on negative side
2952 if(fDepthMin > fDepthMax)
2953 {
2954 // use smaller depth (one from positive side)
2955 fDepth = fDepthMax;
2956 // flip normal direction
2957 vNormal[0] = -vNormal[0];
2958 vNormal[1] = -vNormal[1];
2959 vNormal[2] = -vNormal[2];
2960 fD = -fD;
2961 // if greater depth is on positive side
2962 }
2963 else
2964 {
2965 // use smaller depth (one from negative side)
2966 fDepth = fDepthMin;
2967 }
2968
2969
2970 // if lower depth than best found so far
2971 if(fDepth < fBestDepth)
2972 {
2973 // remember current axis as best axis
2974 vBestNormal[0] = vNormal[0];
2975 vBestNormal[1] = vNormal[1];
2976 vBestNormal[2] = vNormal[2];
2977 iBestAxis = iAxis;
2978 //dAASSERT(fDepth>=0);
2979 fBestDepth = fDepth;
2980 }
2981
2982 return qtrue;
2983 }
2984
2985 // test cross products of box axis and triangle edges as separating axis
_cldTestEdge(vec_t fp0,vec_t fp1,vec_t fR,vec_t fD,vec3_t vNormal,int iAxis)2986 static qboolean _cldTestEdge(vec_t fp0, vec_t fp1, vec_t fR, vec_t fD, vec3_t vNormal, int iAxis)
2987 {
2988 vec_t fMin, fMax;
2989 vec_t fDepthMin;
2990 vec_t fDepthMax;
2991 vec_t fDepth;
2992 vec_t fLength;
2993
2994 // calculate min and max interval values
2995 if(fp0 < fp1)
2996 {
2997 fMin = fp0;
2998 fMax = fp1;
2999 }
3000 else
3001 {
3002 fMin = fp1;
3003 fMax = fp0;
3004 }
3005
3006 // check if we overlapp
3007 fDepthMin = fR - fMin;
3008 fDepthMax = fMax + fR;
3009
3010 // if we don't overlapp
3011 if(fDepthMin < 0 || fDepthMax < 0)
3012 {
3013 // do nothing
3014 return qfalse;
3015 }
3016
3017 // if greater depth is on negative side
3018 if(fDepthMin > fDepthMax)
3019 {
3020 // use smaller depth (one from positive side)
3021 fDepth = fDepthMax;
3022 // flip normal direction
3023 vNormal[0] = -vNormal[0];
3024 vNormal[1] = -vNormal[1];
3025 vNormal[2] = -vNormal[2];
3026 fD = -fD;
3027 // if greater depth is on positive side
3028 }
3029 else
3030 {
3031 // use smaller depth (one from negative side)
3032 fDepth = fDepthMin;
3033 }
3034
3035 // calculate normal's length
3036 fLength = VectorLength(vNormal);
3037
3038 // if long enough
3039 if(fLength > 0.0f)
3040 {
3041 // normalize depth
3042 vec_t fOneOverLength = 1.0f / fLength;
3043
3044 fDepth = fDepth * fOneOverLength;
3045 fD *= fOneOverLength;
3046
3047 // if lower depth than best found so far (favor face over edges)
3048 if(fDepth * 1.5f < fBestDepth)
3049 {
3050 // remember current axis as best axis
3051 vBestNormal[0] = vNormal[0] * fOneOverLength;
3052 vBestNormal[1] = vNormal[1] * fOneOverLength;
3053 vBestNormal[2] = vNormal[2] * fOneOverLength;
3054 iBestAxis = iAxis;
3055 //dAASSERT(fDepth>=0);
3056 fBestDepth = fDepth;
3057 }
3058 }
3059
3060 return qtrue;
3061 }
3062
_cldTestSeparatingAxes(trRefDlight_t * dl,const vec3_t v0,const vec3_t v1,const vec3_t v2)3063 static qboolean _cldTestSeparatingAxes(trRefDlight_t * dl, const vec3_t v0, const vec3_t v1, const vec3_t v2)
3064 {
3065 vec3_t vA0, vA1, vA2;
3066 vec_t fa0, fa1, fa2;
3067 vec3_t vD;
3068 vec_t fNLen;
3069 vec3_t vL;
3070 vec_t fp0, fp1, fp2, fR, fD;
3071
3072 // reset best axis
3073 iBestAxis = 0;
3074 iExitAxis = -1;
3075 fBestDepth = FLT_MAX;
3076
3077 // calculate edges
3078 VectorSubtract(v1, v0, vE0);
3079 VectorSubtract(v2, v0, vE1);
3080 VectorSubtract(vE1, vE0, vE2);
3081
3082 // calculate poly normal
3083 CrossProduct(vE0, vE1, vN);
3084
3085 // extract box axes as vectors
3086 VectorCopy(dl->l.axis[0], vA0);
3087 VectorCopy(dl->l.axis[1], vA1);
3088 VectorCopy(dl->l.axis[2], vA2);
3089
3090 // box halfsizes
3091 fa0 = dl->l.radius[0];
3092 fa1 = dl->l.radius[1];
3093 fa2 = dl->l.radius[2];
3094
3095 // calculate relative position between box and triangle
3096 VectorSubtract(v0, dl->l.origin, vD);
3097
3098 // calculate length of face normal
3099 fNLen = VectorLength(vN);
3100
3101 //
3102 // test separating axes for intersection
3103 //
3104
3105 // Axis 1 - Triangle Normal
3106 VectorCopy(vN, vL);
3107 fp0 = DotProduct(vL, vD);
3108 fp1 = fp0;
3109 fp2 = fp0;
3110 fR = fa0 * Q_fabs(DotProduct(vN, vA0)) + fa1 * Q_fabs(DotProduct(vN, vA1)) + fa2 * Q_fabs(DotProduct(vN, vA2));
3111
3112 if(!_cldTestNormal(fp0, fR, vL, 1))
3113 {
3114 iExitAxis = 1;
3115 return qfalse;
3116 }
3117
3118 //
3119 // test faces
3120 //
3121
3122 // Axis 2 - Box X-Axis
3123 VectorCopy(vA0, vL);
3124 fD = DotProduct(vL, vN) / fNLen;
3125 fp0 = DotProduct(vL, vD);
3126 fp1 = fp0 + DotProduct(vA0, vE0);
3127 fp2 = fp0 + DotProduct(vA0, vE1);
3128 fR = fa0;
3129
3130 if(!_cldTestFace(fp0, fp1, fp2, fR, fD, vL, 2))
3131 {
3132 iExitAxis = 2;
3133 return qfalse;
3134 }
3135
3136 // Axis 3 - Box Y-Axis
3137 VectorCopy(vA1, vL);
3138 fD = DotProduct(vL, vN) / fNLen;
3139 fp0 = DotProduct(vL, vD);
3140 fp1 = fp0 + DotProduct(vA1, vE0);
3141 fp2 = fp0 + DotProduct(vA1, vE1);
3142 fR = fa1;
3143
3144 if(!_cldTestFace(fp0, fp1, fp2, fR, fD, vL, 3))
3145 {
3146 iExitAxis = 3;
3147 return qfalse;
3148 }
3149
3150 // Axis 4 - Box Z-Axis
3151 VectorCopy(vA2, vL);
3152 fD = DotProduct(vL, vN) / fNLen;
3153 fp0 = DotProduct(vL, vD);
3154 fp1 = fp0 + DotProduct(vA2, vE0);
3155 fp2 = fp0 + DotProduct(vA2, vE1);
3156 fR = fa2;
3157
3158 if(!_cldTestFace(fp0, fp1, fp2, fR, fD, vL, 4))
3159 {
3160 iExitAxis = 4;
3161 return qfalse;
3162 }
3163
3164 //
3165 // test edges
3166 //
3167
3168 // Axis 5 - Box X-Axis cross Edge0
3169 CrossProduct(vA0, vE0, vL);
3170 fD = DotProduct(vL, vN) / fNLen;
3171 fp0 = DotProduct(vL, vD);
3172 fp1 = fp0;
3173 fp2 = fp0 + DotProduct(vA0, vN);
3174 fR = fa1 * Q_fabs(DotProduct(vA2, vE0)) + fa2 * Q_fabs(DotProduct(vA1, vE0));
3175
3176 if(!_cldTestEdge(fp1, fp2, fR, fD, vL, 5))
3177 {
3178 iExitAxis = 5;
3179 return qfalse;
3180 }
3181
3182 // Axis 6 - Box X-Axis cross Edge1
3183 CrossProduct(vA0, vE1, vL);
3184 fD = DotProduct(vL, vN) / fNLen;
3185 fp0 = DotProduct(vL, vD);
3186 fp1 = fp0 - DotProduct(vA0, vN);
3187 fp2 = fp0;
3188 fR = fa1 * Q_fabs(DotProduct(vA2, vE1)) + fa2 * Q_fabs(DotProduct(vA1, vE1));
3189
3190 if(!_cldTestEdge(fp0, fp1, fR, fD, vL, 6))
3191 {
3192 iExitAxis = 6;
3193 return qfalse;
3194 }
3195
3196 // Axis 7 - Box X-Axis cross Edge2
3197 CrossProduct(vA0, vE2, vL);
3198 fD = DotProduct(vL, vN) / fNLen;
3199 fp0 = DotProduct(vL, vD);
3200 fp1 = fp0 - DotProduct(vA0, vN);
3201 fp2 = fp0 - DotProduct(vA0, vN);
3202 fR = fa1 * Q_fabs(DotProduct(vA2, vE2)) + fa2 * Q_fabs(DotProduct(vA1, vE2));
3203
3204 if(!_cldTestEdge(fp0, fp1, fR, fD, vL, 7))
3205 {
3206 iExitAxis = 7;
3207 return qfalse;
3208 }
3209
3210 // Axis 8 - Box Y-Axis cross Edge0
3211 CrossProduct(vA1, vE0, vL);
3212 fD = DotProduct(vL, vN) / fNLen;
3213 fp0 = DotProduct(vL, vD);
3214 fp1 = fp0;
3215 fp2 = fp0 + DotProduct(vA1, vN);
3216 fR = fa0 * Q_fabs(DotProduct(vA2, vE0)) + fa2 * Q_fabs(DotProduct(vA0, vE0));
3217
3218 if(!_cldTestEdge(fp0, fp2, fR, fD, vL, 8))
3219 {
3220 iExitAxis = 8;
3221 return qfalse;
3222 }
3223
3224 // Axis 9 - Box Y-Axis cross Edge1
3225 CrossProduct(vA1, vE1, vL);
3226 fD = DotProduct(vL, vN) / fNLen;
3227 fp0 = DotProduct(vL, vD);
3228 fp1 = fp0 - DotProduct(vA1, vN);
3229 fp2 = fp0;
3230 fR = fa0 * Q_fabs(DotProduct(vA2, vE1)) + fa2 * Q_fabs(DotProduct(vA0, vE1));
3231
3232 if(!_cldTestEdge(fp0, fp1, fR, fD, vL, 9))
3233 {
3234 iExitAxis = 9;
3235 return qfalse;
3236 }
3237
3238 // Axis 10 - Box Y-Axis cross Edge2
3239 CrossProduct(vA1, vE2, vL);
3240 fD = DotProduct(vL, vN) / fNLen;
3241 fp0 = DotProduct(vL, vD);
3242 fp1 = fp0 - DotProduct(vA1, vN);
3243 fp2 = fp0 - DotProduct(vA1, vN);
3244 fR = fa0 * Q_fabs(DotProduct(vA2, vE2)) + fa2 * Q_fabs(DotProduct(vA0, vE2));
3245
3246 if(!_cldTestEdge(fp0, fp1, fR, fD, vL, 10))
3247 {
3248 iExitAxis = 10;
3249 return qfalse;
3250 }
3251
3252 // Axis 11 - Box Z-Axis cross Edge0
3253 CrossProduct(vA2, vE0, vL);
3254 fD = DotProduct(vL, vN) / fNLen;
3255 fp0 = DotProduct(vL, vD);
3256 fp1 = fp0;
3257 fp2 = fp0 + DotProduct(vA2, vN);
3258 fR = fa0 * Q_fabs(DotProduct(vA1, vE0)) + fa1 * Q_fabs(DotProduct(vA0, vE0));
3259
3260 if(!_cldTestEdge(fp0, fp2, fR, fD, vL, 11))
3261 {
3262 iExitAxis = 11;
3263 return qfalse;
3264 }
3265
3266 // Axis 12 - Box Z-Axis cross Edge1
3267 CrossProduct(vA2, vE1, vL);
3268 fD = DotProduct(vL, vN) / fNLen;
3269 fp0 = DotProduct(vL, vD);
3270 fp1 = fp0 - DotProduct(vA2, vN);
3271 fp2 = fp0;
3272 fR = fa0 * Q_fabs(DotProduct(vA1, vE1)) + fa1 * Q_fabs(DotProduct(vA0, vE1));
3273
3274 if(!_cldTestEdge(fp0, fp1, fR, fD, vL, 12))
3275 {
3276 iExitAxis = 12;
3277 return qfalse;
3278 }
3279
3280 // Axis 13 - Box Z-Axis cross Edge2
3281 CrossProduct(vA2, vE2, vL);
3282 fD = DotProduct(vL, vN) / fNLen;
3283 fp0 = DotProduct(vL, vD);
3284 fp1 = fp0 - DotProduct(vA2, vN);
3285 fp2 = fp0 - DotProduct(vA2, vN);
3286 fR = fa0 * Q_fabs(DotProduct(vA1, vE2)) + fa1 * Q_fabs(DotProduct(vA0, vE2));
3287
3288 if(!_cldTestEdge(fp0, fp1, fR, fD, vL, 13))
3289 {
3290 iExitAxis = 13;
3291 return qfalse;
3292 }
3293
3294 return qtrue;
3295 }
3296
3297 // test one mesh triangle on intersection with given box
_cldTestOneTriangle(trRefDlight_t * dl,const vec3_t v0,const vec3_t v1,const vec3_t v2)3298 static qboolean _cldTestOneTriangle(trRefDlight_t * dl, const vec3_t v0, const vec3_t v1, const vec3_t v2)
3299 {
3300 // do intersection test and find best separating axis
3301 if(!_cldTestSeparatingAxes(dl, v0, v1, v2))
3302 {
3303 // if not found do nothing
3304 return qfalse;
3305 }
3306
3307 return qtrue;
3308
3309 /*
3310 // if best separation axis is not found
3311 if ( iBestAxis == 0 ) {
3312 // this should not happen (we should already exit in that case)
3313 //dMessage (0, "best separation axis not found");
3314 // do nothing
3315 return;
3316 }
3317
3318 _cldClipping(v0, v1, v2);
3319 */
3320 }
3321
R_PrecacheFaceInteraction(srfSurfaceFace_t * cv,shader_t * shader,trRefDlight_t * dl)3322 static qboolean R_PrecacheFaceInteraction(srfSurfaceFace_t * cv, shader_t * shader, trRefDlight_t * dl)
3323 {
3324 int i;
3325 srfTriangle_t *tri;
3326 int numIndexes;
3327 int *indexes;
3328 float d;
3329
3330 // check if bounds intersect
3331 if(!BoundsIntersect(dl->worldBounds[0], dl->worldBounds[1], cv->bounds[0], cv->bounds[1]))
3332 {
3333 return qfalse;
3334 }
3335
3336 #if 1
3337 // check if light origin is behind surface
3338 d = DotProduct(cv->plane.normal, dl->origin);
3339
3340 // don't cull exactly on the plane, because there are levels of rounding
3341 // through the BSP, ICD, and hardware that may cause pixel gaps if an
3342 // epsilon isn't allowed here
3343 if(shader->cullType == CT_FRONT_SIDED)
3344 {
3345 if(d < cv->plane.dist - 8)
3346 {
3347 c_culledFaceTriangles += cv->numTriangles;
3348 return qfalse;
3349 }
3350 }
3351 else
3352 {
3353 if(d > cv->plane.dist + 8)
3354 {
3355 c_culledFaceTriangles += cv->numTriangles;
3356 return qfalse;
3357 }
3358 }
3359 #endif
3360
3361 // build a list of triangles that need light
3362 Com_Memset(sh.numEdges, 0, 4 * cv->numVerts);
3363
3364 numIndexes = 0;
3365 indexes = s_lightIndexes;
3366
3367 for(i = 0, tri = cv->triangles; i < cv->numTriangles; i++, tri++)
3368 {
3369 int i1, i2, i3;
3370 vec3_t verts[3];
3371
3372 //vec3_t d1, d2;
3373 vec4_t plane;
3374 float d;
3375
3376 sh.facing[i] = qtrue;
3377
3378 i1 = tri->indexes[0];
3379 i2 = tri->indexes[1];
3380 i3 = tri->indexes[2];
3381
3382 VectorCopy(cv->verts[i1].xyz, verts[0]);
3383 VectorCopy(cv->verts[i2].xyz, verts[1]);
3384 VectorCopy(cv->verts[i3].xyz, verts[2]);
3385
3386 /*
3387 VectorSubtract(verts[1], verts[0], d1);
3388 VectorSubtract(verts[2], verts[0], d2);
3389
3390 CrossProduct(d1, d2, plane);
3391 plane[3] = DotProduct(plane, verts[0]);
3392
3393 d = DotProduct(plane, dl->origin) - plane[3];
3394 if(d > 0)
3395 {
3396 sh.facing[i] = qtrue;
3397 }
3398 else
3399 {
3400 sh.facing[i] = qfalse;
3401 }
3402 */
3403
3404 if(PlaneFromPoints(plane, verts[0], verts[1], verts[2], qtrue))
3405 {
3406 #if 1
3407 // check if light origin is behind triangle
3408 d = DotProduct(plane, dl->origin) - plane[3];
3409
3410 if(shader->cullType == CT_FRONT_SIDED)
3411 {
3412 if(d < 0)
3413 {
3414 c_culledFaceTriangles++;
3415 sh.facing[i] = qfalse;
3416 }
3417 }
3418 else
3419 {
3420 if(d > 0)
3421 {
3422 c_culledFaceTriangles++;
3423 sh.facing[i] = qfalse;
3424 }
3425 }
3426 #endif
3427 }
3428
3429 #if 1
3430 // check with ODE's triangle<->OBB collider for an intersection
3431 if(!_cldTestOneTriangle(dl, verts[0], verts[1], verts[2]))
3432 {
3433 c_culledFaceTriangles++;
3434 sh.facing[i] = qfalse;
3435 }
3436 #endif
3437
3438 if(numIndexes >= SHADER_MAX_INDEXES)
3439 {
3440 ri.Error(ERR_DROP, "R_PrecacheFaceInteraction: indices > MAX (%d > %d)", numIndexes, SHADER_MAX_INDEXES);
3441 }
3442
3443 // create triangle indices
3444 if(sh.facing[i])
3445 {
3446 indexes[numIndexes + 0] = i1;
3447 indexes[numIndexes + 1] = i2;
3448 indexes[numIndexes + 2] = i3;
3449 numIndexes += 3;
3450
3451 sh.numFacing++;
3452 }
3453 }
3454
3455 #if 1
3456 if(numIndexes == 0)
3457 {
3458 return qfalse;
3459 }
3460 #endif
3461
3462 s_numLightIndexes = numIndexes;
3463
3464
3465 #if 1
3466 // calculate zfail shadow volume
3467 numIndexes = 0;
3468 indexes = s_shadowIndexes;
3469
3470 if((sh.numFacing * (6 + 2) * 3) >= SHADER_MAX_INDEXES)
3471 {
3472 return qtrue;
3473 }
3474
3475 // set up indices for silhouette edges
3476 for(i = 0, tri = cv->triangles; i < cv->numTriangles; i++, tri++)
3477 {
3478 if(!sh.facing[i])
3479 {
3480 continue;
3481 }
3482
3483 if((tri->neighbors[0] < 0) || (tri->neighbors[0] >= 0 && !sh.facing[tri->neighbors[0]]))
3484 {
3485 indexes[numIndexes + 0] = tri->indexes[1];
3486 indexes[numIndexes + 1] = tri->indexes[0];
3487 indexes[numIndexes + 2] = tri->indexes[0] + cv->numVerts;
3488
3489 indexes[numIndexes + 3] = tri->indexes[1];
3490 indexes[numIndexes + 4] = tri->indexes[0] + cv->numVerts;
3491 indexes[numIndexes + 5] = tri->indexes[1] + cv->numVerts;
3492
3493 numIndexes += 6;
3494 }
3495
3496 if((tri->neighbors[1] < 0) || (tri->neighbors[1] >= 0 && !sh.facing[tri->neighbors[1]]))
3497 {
3498 indexes[numIndexes + 0] = tri->indexes[2];
3499 indexes[numIndexes + 1] = tri->indexes[1];
3500 indexes[numIndexes + 2] = tri->indexes[1] + cv->numVerts;
3501
3502 indexes[numIndexes + 3] = tri->indexes[2];
3503 indexes[numIndexes + 4] = tri->indexes[1] + cv->numVerts;
3504 indexes[numIndexes + 5] = tri->indexes[2] + cv->numVerts;
3505
3506 numIndexes += 6;
3507 }
3508
3509 if((tri->neighbors[2] < 0) || (tri->neighbors[2] >= 0 && !sh.facing[tri->neighbors[2]]))
3510 {
3511 indexes[numIndexes + 0] = tri->indexes[0];
3512 indexes[numIndexes + 1] = tri->indexes[2];
3513 indexes[numIndexes + 2] = tri->indexes[2] + cv->numVerts;
3514
3515 indexes[numIndexes + 3] = tri->indexes[0];
3516 indexes[numIndexes + 4] = tri->indexes[2] + cv->numVerts;
3517 indexes[numIndexes + 5] = tri->indexes[0] + cv->numVerts;
3518
3519 numIndexes += 6;
3520 }
3521 }
3522
3523 // set up indices for light and dark caps
3524 for(i = 0, tri = cv->triangles; i < cv->numTriangles; i++, tri++)
3525 {
3526 if(!sh.facing[i])
3527 {
3528 continue;
3529 }
3530
3531 // light cap
3532 indexes[numIndexes + 0] = tri->indexes[0];
3533 indexes[numIndexes + 1] = tri->indexes[1];
3534 indexes[numIndexes + 2] = tri->indexes[2];
3535
3536 // dark cap
3537 indexes[numIndexes + 3] = tri->indexes[2] + cv->numVerts;
3538 indexes[numIndexes + 4] = tri->indexes[1] + cv->numVerts;
3539 indexes[numIndexes + 5] = tri->indexes[0] + cv->numVerts;
3540
3541 numIndexes += 6;
3542 }
3543
3544 s_numShadowIndexes = numIndexes;
3545 #endif
3546
3547 return qtrue;
3548 }
3549
3550
R_PrecacheGridInteraction(srfGridMesh_t * cv,shader_t * shader,trRefDlight_t * dl)3551 static int R_PrecacheGridInteraction(srfGridMesh_t * cv, shader_t * shader, trRefDlight_t * dl)
3552 {
3553 int i;
3554 srfTriangle_t *tri;
3555 int numIndexes;
3556 int *indexes;
3557
3558 // check if bounds intersect
3559 if(!BoundsIntersect(dl->worldBounds[0], dl->worldBounds[1], cv->meshBounds[0], cv->meshBounds[1]))
3560 {
3561 return qfalse;
3562 }
3563
3564 // build a list of triangles that need light
3565 Com_Memset(sh.numEdges, 0, 4 * cv->numVerts);
3566
3567 numIndexes = 0;
3568 indexes = s_lightIndexes;
3569
3570 for(i = 0, tri = cv->triangles; i < cv->numTriangles; i++, tri++)
3571 {
3572 int i1, i2, i3;
3573 vec3_t verts[3];
3574 vec4_t plane;
3575 float d;
3576
3577 sh.facing[i] = qtrue;
3578
3579 i1 = tri->indexes[0];
3580 i2 = tri->indexes[1];
3581 i3 = tri->indexes[2];
3582
3583 VectorCopy(cv->verts[i1].xyz, verts[0]);
3584 VectorCopy(cv->verts[i2].xyz, verts[1]);
3585 VectorCopy(cv->verts[i3].xyz, verts[2]);
3586
3587 if(PlaneFromPoints(plane, verts[0], verts[1], verts[2], qtrue))
3588 {
3589 #if 1
3590 // check if light origin is behind triangle
3591 d = DotProduct(plane, dl->origin) - plane[3];
3592
3593 if(shader->cullType == CT_FRONT_SIDED)
3594 {
3595 if(d < 0)
3596 {
3597 c_culledGridTriangles++;
3598 sh.facing[i] = qfalse;
3599 }
3600 }
3601 else
3602 {
3603 if(d > 0)
3604 {
3605 c_culledGridTriangles++;
3606 sh.facing[i] = qfalse;
3607 }
3608 }
3609 #endif
3610 }
3611
3612 #if 1
3613 // check with ODE's triangle<->OBB collider for an intersection
3614 if(!_cldTestOneTriangle(dl, verts[0], verts[1], verts[2]))
3615 {
3616 c_culledGridTriangles++;
3617 sh.facing[i] = qfalse;
3618 }
3619 #endif
3620
3621 if(numIndexes >= SHADER_MAX_INDEXES)
3622 {
3623 ri.Error(ERR_DROP, "R_PrecacheGridInteraction: indices > MAX (%d > %d)", numIndexes, SHADER_MAX_INDEXES);
3624 }
3625
3626 // create triangle indices
3627 if(sh.facing[i])
3628 {
3629 indexes[numIndexes + 0] = i1;
3630 indexes[numIndexes + 1] = i2;
3631 indexes[numIndexes + 2] = i3;
3632 numIndexes += 3;
3633
3634 sh.numFacing++;
3635 }
3636 }
3637
3638 #if 1
3639 if(numIndexes == 0)
3640 {
3641 return qfalse;
3642 }
3643 #endif
3644
3645 s_numLightIndexes = numIndexes;
3646
3647 #if 1
3648 // calculate zfail shadow volume
3649 numIndexes = 0;
3650 indexes = s_shadowIndexes;
3651
3652 if((sh.numFacing * (6 + 2) * 3) >= SHADER_MAX_INDEXES)
3653 {
3654 return qtrue;
3655 }
3656
3657 // set up indices for silhouette edges
3658 for(i = 0, tri = cv->triangles; i < cv->numTriangles; i++, tri++)
3659 {
3660 if(!sh.facing[i])
3661 {
3662 continue;
3663 }
3664
3665 if((tri->neighbors[0] < 0) || (tri->neighbors[0] >= 0 && !sh.facing[tri->neighbors[0]]))
3666 {
3667 indexes[numIndexes + 0] = tri->indexes[1];
3668 indexes[numIndexes + 1] = tri->indexes[0];
3669 indexes[numIndexes + 2] = tri->indexes[0] + cv->numVerts;
3670
3671 indexes[numIndexes + 3] = tri->indexes[1];
3672 indexes[numIndexes + 4] = tri->indexes[0] + cv->numVerts;
3673 indexes[numIndexes + 5] = tri->indexes[1] + cv->numVerts;
3674
3675 numIndexes += 6;
3676 }
3677
3678 if((tri->neighbors[1] < 0) || (tri->neighbors[1] >= 0 && !sh.facing[tri->neighbors[1]]))
3679 {
3680 indexes[numIndexes + 0] = tri->indexes[2];
3681 indexes[numIndexes + 1] = tri->indexes[1];
3682 indexes[numIndexes + 2] = tri->indexes[1] + cv->numVerts;
3683
3684 indexes[numIndexes + 3] = tri->indexes[2];
3685 indexes[numIndexes + 4] = tri->indexes[1] + cv->numVerts;
3686 indexes[numIndexes + 5] = tri->indexes[2] + cv->numVerts;
3687
3688 numIndexes += 6;
3689 }
3690
3691 if((tri->neighbors[2] < 0) || (tri->neighbors[2] >= 0 && !sh.facing[tri->neighbors[2]]))
3692 {
3693 indexes[numIndexes + 0] = tri->indexes[0];
3694 indexes[numIndexes + 1] = tri->indexes[2];
3695 indexes[numIndexes + 2] = tri->indexes[2] + cv->numVerts;
3696
3697 indexes[numIndexes + 3] = tri->indexes[0];
3698 indexes[numIndexes + 4] = tri->indexes[2] + cv->numVerts;
3699 indexes[numIndexes + 5] = tri->indexes[0] + cv->numVerts;
3700
3701 numIndexes += 6;
3702 }
3703 }
3704
3705 // set up indices for light and dark caps
3706 for(i = 0, tri = cv->triangles; i < cv->numTriangles; i++, tri++)
3707 {
3708 if(!sh.facing[i])
3709 {
3710 continue;
3711 }
3712
3713 // light cap
3714 indexes[numIndexes + 0] = tri->indexes[0];
3715 indexes[numIndexes + 1] = tri->indexes[1];
3716 indexes[numIndexes + 2] = tri->indexes[2];
3717
3718 // dark cap
3719 indexes[numIndexes + 3] = tri->indexes[2] + cv->numVerts;
3720 indexes[numIndexes + 4] = tri->indexes[1] + cv->numVerts;
3721 indexes[numIndexes + 5] = tri->indexes[0] + cv->numVerts;
3722
3723 numIndexes += 6;
3724 }
3725
3726 s_numShadowIndexes = numIndexes;
3727 #endif
3728
3729 return qtrue;
3730 }
3731
3732
R_PrecacheTrisurfInteraction(srfTriangles_t * cv,shader_t * shader,trRefDlight_t * dl)3733 static int R_PrecacheTrisurfInteraction(srfTriangles_t * cv, shader_t * shader, trRefDlight_t * dl)
3734 {
3735 int i;
3736 srfTriangle_t *tri;
3737 int numIndexes;
3738 int *indexes;
3739
3740 // check if bounds intersect
3741 if(!BoundsIntersect(dl->worldBounds[0], dl->worldBounds[1], cv->bounds[0], cv->bounds[1]))
3742 {
3743 return qfalse;
3744 }
3745
3746 // build a list of triangles that need light
3747 Com_Memset(sh.numEdges, 0, 4 * cv->numVerts);
3748
3749 numIndexes = 0;
3750 indexes = s_lightIndexes;
3751
3752 for(i = 0, tri = cv->triangles; i < cv->numTriangles; i++, tri++)
3753 {
3754 int i1, i2, i3;
3755 vec3_t verts[3];
3756 vec4_t plane;
3757 float d;
3758
3759 sh.facing[i] = qtrue;
3760
3761 i1 = tri->indexes[0];
3762 i2 = tri->indexes[1];
3763 i3 = tri->indexes[2];
3764
3765 VectorCopy(cv->verts[i1].xyz, verts[0]);
3766 VectorCopy(cv->verts[i2].xyz, verts[1]);
3767 VectorCopy(cv->verts[i3].xyz, verts[2]);
3768
3769 if(PlaneFromPoints(plane, verts[0], verts[1], verts[2], qtrue))
3770 {
3771 #if 1
3772 // check if light origin is behind triangle
3773 d = DotProduct(plane, dl->origin) - plane[3];
3774
3775 if(shader->cullType == CT_FRONT_SIDED)
3776 {
3777 if(d < 0)
3778 {
3779 c_culledTriTriangles++;
3780 sh.facing[i] = qfalse;
3781 }
3782 }
3783 else
3784 {
3785 if(d > 0)
3786 {
3787 c_culledTriTriangles++;
3788 sh.facing[i] = qfalse;
3789 }
3790 }
3791 #endif
3792
3793 #if 0
3794 // check if light bounds do not intersect with with triangle plane
3795 r = BoxOnPlaneSide2(dl->worldBounds[0], dl->worldBounds[1], plane);
3796 if(r != 3)
3797 {
3798 c_culledTriTriangles++;
3799 sh.facing[i] = false;
3800 }
3801 #endif
3802 }
3803
3804 #if 0
3805 // check if the triangle is inside light frustum
3806 switch (R_CullDlightTriangle(dl, verts))
3807 {
3808 case CULL_IN:
3809 case CULL_CLIP:
3810 break;
3811
3812 case CULL_OUT:
3813 default:
3814 c_culledTriTriangles++;
3815 sh.facing[i] = false;
3816 }
3817 #endif
3818
3819 #if 1
3820 // check with ODE's triangle<->OBB collider for an intersection
3821 if(!_cldTestOneTriangle(dl, verts[0], verts[1], verts[2]))
3822 {
3823 c_culledTriTriangles++;
3824 sh.facing[i] = qfalse;
3825 }
3826 #endif
3827
3828 if(numIndexes >= SHADER_MAX_INDEXES)
3829 {
3830 ri.Error(ERR_DROP, "R_PrecacheTrisurfInteraction: indices > MAX (%d > %d)", numIndexes, SHADER_MAX_INDEXES);
3831 }
3832
3833 // create triangle indices
3834 if(sh.facing[i])
3835 {
3836 indexes[numIndexes + 0] = i1;
3837 indexes[numIndexes + 1] = i2;
3838 indexes[numIndexes + 2] = i3;
3839 numIndexes += 3;
3840
3841 sh.numFacing++;
3842 }
3843 }
3844
3845 #if 1
3846 if(numIndexes == 0)
3847 {
3848 return qfalse;
3849 }
3850 #endif
3851
3852 s_numLightIndexes = numIndexes;
3853
3854 #if 1
3855 // calculate zfail shadow volume
3856 numIndexes = 0;
3857 indexes = s_shadowIndexes;
3858
3859 if((sh.numFacing * (6 + 2) * 3) >= SHADER_MAX_INDEXES)
3860 {
3861 return qtrue;
3862 }
3863
3864 // set up indices for silhouette edges
3865 for(i = 0, tri = cv->triangles; i < cv->numTriangles; i++, tri++)
3866 {
3867 if(!sh.facing[i])
3868 {
3869 continue;
3870 }
3871
3872 if((tri->neighbors[0] < 0) || (tri->neighbors[0] >= 0 && !sh.facing[tri->neighbors[0]]))
3873 {
3874 indexes[numIndexes + 0] = tri->indexes[1];
3875 indexes[numIndexes + 1] = tri->indexes[0];
3876 indexes[numIndexes + 2] = tri->indexes[0] + cv->numVerts;
3877
3878 indexes[numIndexes + 3] = tri->indexes[1];
3879 indexes[numIndexes + 4] = tri->indexes[0] + cv->numVerts;
3880 indexes[numIndexes + 5] = tri->indexes[1] + cv->numVerts;
3881
3882 numIndexes += 6;
3883 }
3884
3885 if((tri->neighbors[1] < 0) || (tri->neighbors[1] >= 0 && !sh.facing[tri->neighbors[1]]))
3886 {
3887 indexes[numIndexes + 0] = tri->indexes[2];
3888 indexes[numIndexes + 1] = tri->indexes[1];
3889 indexes[numIndexes + 2] = tri->indexes[1] + cv->numVerts;
3890
3891 indexes[numIndexes + 3] = tri->indexes[2];
3892 indexes[numIndexes + 4] = tri->indexes[1] + cv->numVerts;
3893 indexes[numIndexes + 5] = tri->indexes[2] + cv->numVerts;
3894
3895 numIndexes += 6;
3896 }
3897
3898 if((tri->neighbors[2] < 0) || (tri->neighbors[2] >= 0 && !sh.facing[tri->neighbors[2]]))
3899 {
3900 indexes[numIndexes + 0] = tri->indexes[0];
3901 indexes[numIndexes + 1] = tri->indexes[2];
3902 indexes[numIndexes + 2] = tri->indexes[2] + cv->numVerts;
3903
3904 indexes[numIndexes + 3] = tri->indexes[0];
3905 indexes[numIndexes + 4] = tri->indexes[2] + cv->numVerts;
3906 indexes[numIndexes + 5] = tri->indexes[0] + cv->numVerts;
3907
3908 numIndexes += 6;
3909 }
3910 }
3911
3912 // set up indices for light and dark caps
3913 for(i = 0, tri = cv->triangles; i < cv->numTriangles; i++, tri++)
3914 {
3915 if(!sh.facing[i])
3916 {
3917 continue;
3918 }
3919
3920 // light cap
3921 indexes[numIndexes + 0] = tri->indexes[0];
3922 indexes[numIndexes + 1] = tri->indexes[1];
3923 indexes[numIndexes + 2] = tri->indexes[2];
3924
3925 // dark cap
3926 indexes[numIndexes + 3] = tri->indexes[2] + cv->numVerts;
3927 indexes[numIndexes + 4] = tri->indexes[1] + cv->numVerts;
3928 indexes[numIndexes + 5] = tri->indexes[0] + cv->numVerts;
3929
3930 numIndexes += 6;
3931 }
3932
3933 s_numShadowIndexes = numIndexes;
3934 #endif
3935
3936 return qtrue;
3937 }
3938
3939
3940 /*
3941 ======================
3942 R_PrecacheInteractionSurface
3943 ======================
3944 */
R_PrecacheInteractionSurface(msurface_t * surf,trRefDlight_t * light)3945 static void R_PrecacheInteractionSurface(msurface_t * surf, trRefDlight_t * light)
3946 {
3947 qboolean intersects;
3948
3949 if(surf->lightCount == s_lightCount)
3950 {
3951 return; // already checked this surface
3952 }
3953 surf->lightCount = s_lightCount;
3954
3955 // skip all surfaces that don't matter for lighting only pass
3956 if(surf->shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY))
3957 return;
3958
3959 s_numLightIndexes = 0;
3960 s_numShadowIndexes = 0;
3961
3962 if(*surf->data == SF_FACE)
3963 {
3964 intersects = R_PrecacheFaceInteraction((srfSurfaceFace_t *) surf->data, surf->shader, light);
3965 }
3966 else if(*surf->data == SF_GRID)
3967 {
3968 intersects = R_PrecacheGridInteraction((srfGridMesh_t *) surf->data, surf->shader, light);
3969 }
3970 else if(*surf->data == SF_TRIANGLES)
3971 {
3972 intersects = R_PrecacheTrisurfInteraction((srfTriangles_t *) surf->data, surf->shader, light);
3973 }
3974 else
3975 {
3976 intersects = qfalse;
3977 }
3978
3979 if(intersects)
3980 {
3981 R_PrecacheInteraction(light, surf);
3982 }
3983 }
3984
3985 /*
3986 ================
3987 R_RecursivePrecacheInteractionNode
3988 ================
3989 */
R_RecursivePrecacheInteractionNode(mnode_t * node,trRefDlight_t * light)3990 static void R_RecursivePrecacheInteractionNode(mnode_t * node, trRefDlight_t * light)
3991 {
3992 int r;
3993
3994 // light already hit node
3995 if(node->lightCount == s_lightCount)
3996 {
3997 return;
3998 }
3999 node->lightCount = s_lightCount;
4000
4001 if(node->contents != -1)
4002 {
4003 // leaf node, so add mark surfaces
4004 int c;
4005 msurface_t *surf, **mark;
4006
4007 // add the individual surfaces
4008 mark = node->firstmarksurface;
4009 c = node->nummarksurfaces;
4010 while(c--)
4011 {
4012 // the surface may have already been added if it
4013 // spans multiple leafs
4014 surf = *mark;
4015 R_PrecacheInteractionSurface(surf, light);
4016 mark++;
4017 }
4018
4019 return;
4020 }
4021
4022 // node is just a decision point, so go down both sides
4023 // since we don't care about sort orders, just go positive to negative
4024 r = BoxOnPlaneSide(light->worldBounds[0], light->worldBounds[1], node->plane);
4025
4026 switch (r)
4027 {
4028 case 1:
4029 R_RecursivePrecacheInteractionNode(node->children[0], light);
4030 break;
4031
4032 case 2:
4033 R_RecursivePrecacheInteractionNode(node->children[1], light);
4034 break;
4035
4036 case 3:
4037 default:
4038 // recurse down the children, front side first
4039 R_RecursivePrecacheInteractionNode(node->children[0], light);
4040 R_RecursivePrecacheInteractionNode(node->children[1], light);
4041 break;
4042 }
4043 }
4044
4045 /*
4046 ================
4047 R_RecursiveAddInteractionNode
4048 ================
4049 */
R_RecursiveAddInteractionNode(mnode_t * node,trRefDlight_t * light,int * numLeafs,qboolean onlyCount)4050 static void R_RecursiveAddInteractionNode(mnode_t * node, trRefDlight_t * light, int *numLeafs, qboolean onlyCount)
4051 {
4052 int r;
4053
4054 // light already hit node
4055 if(node->lightCount == s_lightCount)
4056 {
4057 return;
4058 }
4059 node->lightCount = s_lightCount;
4060
4061 if(node->contents != -1)
4062 {
4063 if(!onlyCount)
4064 {
4065 // assign leave and increase leave counter
4066 light->leafs[*numLeafs] = node;
4067 }
4068
4069 *numLeafs = *numLeafs + 1;
4070 return;
4071 }
4072
4073 // node is just a decision point, so go down both sides
4074 // since we don't care about sort orders, just go positive to negative
4075 r = BoxOnPlaneSide(light->worldBounds[0], light->worldBounds[1], node->plane);
4076
4077 switch (r)
4078 {
4079 case 1:
4080 R_RecursiveAddInteractionNode(node->children[0], light, numLeafs, onlyCount);
4081 break;
4082
4083 case 2:
4084 R_RecursiveAddInteractionNode(node->children[1], light, numLeafs, onlyCount);
4085 break;
4086
4087 case 3:
4088 default:
4089 // recurse down the children, front side first
4090 R_RecursiveAddInteractionNode(node->children[0], light, numLeafs, onlyCount);
4091 R_RecursiveAddInteractionNode(node->children[1], light, numLeafs, onlyCount);
4092 break;
4093 }
4094 }
4095
4096 /*
4097 =============
4098 R_PrecacheInteractions
4099 =============
4100 */
R_PrecacheInteractions()4101 void R_PrecacheInteractions()
4102 {
4103 int i;
4104 trRefDlight_t *dl;
4105 int numLeafs;
4106
4107 s_lightCount = 0;
4108 s_interactionCount = 0;
4109
4110 c_culledFaceTriangles = 0;
4111 c_culledGridTriangles = 0;
4112 c_culledTriTriangles = 0;
4113
4114 // FIXME use dynamic list
4115 s_worldData.numInteractions = s_worldData.numsurfaces * 16;
4116 s_worldData.interactions = ri.Hunk_Alloc(s_worldData.numInteractions * sizeof(interactionCache_t), h_low);
4117
4118 ri.Printf(PRINT_ALL, "...precaching %i lights\n", s_worldData.numDlights);
4119
4120 for(i = 0; i < s_worldData.numDlights; i++)
4121 {
4122 dl = &s_worldData.dlights[i];
4123
4124 // set up light transform matrix
4125 MatrixSetupTransform(dl->transformMatrix, dl->l.axis[0], dl->l.axis[1], dl->l.axis[2], dl->l.origin);
4126
4127 // set up light origin for lighting and shadowing
4128 R_SetupDlightOrigin(dl);
4129
4130 // calc local bounds for culling
4131 R_SetupDlightLocalBounds(dl);
4132
4133 // setup world bounds for intersection tests
4134 R_SetupDlightWorldBounds(dl);
4135
4136 // setup frustum planes for intersection tests
4137 R_SetupDlightFrustum(dl);
4138
4139 // set up model to light view matrix
4140 MatrixAffineInverse(dl->transformMatrix, dl->viewMatrix);
4141
4142 // set up projection
4143 R_SetupDlightProjection(dl);
4144
4145 // setup interactions
4146 dl->firstInteractionCache = NULL;
4147 dl->lastInteractionCache = NULL;
4148
4149 switch (dl->l.rlType)
4150 {
4151 case RL_OMNI:
4152 break;
4153
4154 case RL_PROJ:
4155 // FIXME support these in the future
4156 continue;
4157
4158 case RL_DIRECT:
4159 break;
4160
4161 default:
4162 break;
4163 }
4164
4165 // perform frustum culling and add all the potentially visible surfaces
4166 s_lightCount++;
4167 R_RecursivePrecacheInteractionNode(s_worldData.nodes, dl);
4168
4169 s_lightCount++;
4170 numLeafs = 0;
4171 R_RecursiveAddInteractionNode(s_worldData.nodes, dl, &numLeafs, qtrue);
4172
4173 //ri.Printf(PRINT_ALL, "light %i touched %i leaves\n", i, numLeafs);
4174
4175 dl->leafs = (struct mnode_s **) ri.Hunk_Alloc(numLeafs * sizeof(*dl->leafs), h_low);
4176 dl->numLeafs = numLeafs;
4177
4178 s_lightCount++;
4179 numLeafs = 0;
4180 R_RecursiveAddInteractionNode(s_worldData.nodes, dl, &numLeafs, qfalse);
4181 }
4182
4183 ri.Printf(PRINT_ALL, "%i interactions precached\n", s_interactionCount);
4184 ri.Printf(PRINT_ALL, "%i planar surface triangles culled\n", c_culledFaceTriangles);
4185 ri.Printf(PRINT_ALL, "%i bezier surface triangles culled\n", c_culledGridTriangles);
4186 ri.Printf(PRINT_ALL, "%i abitrary surface triangles culled\n", c_culledTriTriangles);
4187 }
4188
4189
4190 /*
4191 =================
4192 RE_LoadWorldMap
4193
4194 Called directly from cgame
4195 =================
4196 */
RE_LoadWorldMap(const char * name)4197 void RE_LoadWorldMap(const char *name)
4198 {
4199 int i;
4200 dheader_t *header;
4201 byte *buffer;
4202 byte *startMarker;
4203
4204 if(tr.worldMapLoaded)
4205 {
4206 ri.Error(ERR_DROP, "ERROR: attempted to redundantly load world map\n");
4207 }
4208
4209 ri.Printf(PRINT_ALL, "----- RE_LoadWorldMap( %s ) -----\n", name);
4210
4211 // set default sun direction to be used if it isn't overridden by a shader
4212 tr.sunDirection[0] = 0.45f;
4213 tr.sunDirection[1] = 0.3f;
4214 tr.sunDirection[2] = 0.9f;
4215
4216 VectorNormalize(tr.sunDirection);
4217
4218 tr.worldMapLoaded = qtrue;
4219
4220 // load it
4221 ri.FS_ReadFile(name, (void **)&buffer);
4222 if(!buffer)
4223 {
4224 ri.Error(ERR_DROP, "RE_LoadWorldMap: %s not found", name);
4225 }
4226
4227 // clear tr.world so if the level fails to load, the next
4228 // try will not look at the partially loaded version
4229 tr.world = NULL;
4230
4231 Com_Memset(&s_worldData, 0, sizeof(s_worldData));
4232 Q_strncpyz(s_worldData.name, name, sizeof(s_worldData.name));
4233
4234 Q_strncpyz(s_worldData.baseName, Com_SkipPath(s_worldData.name), sizeof(s_worldData.name));
4235 Com_StripExtension(s_worldData.baseName, s_worldData.baseName, sizeof(s_worldData.baseName));
4236
4237 startMarker = ri.Hunk_Alloc(0, h_low);
4238 c_gridVerts = 0;
4239
4240 header = (dheader_t *) buffer;
4241 fileBase = (byte *) header;
4242
4243 i = LittleLong(header->version);
4244 if(i != BSP_VERSION)
4245 {
4246 ri.Error(ERR_DROP, "RE_LoadWorldMap: %s has wrong version number (%i should be %i)", name, i, BSP_VERSION);
4247 }
4248
4249 // swap all the lumps
4250 for(i = 0; i < sizeof(dheader_t) / 4; i++)
4251 {
4252 ((int *)header)[i] = LittleLong(((int *)header)[i]);
4253 }
4254
4255 // load into heap
4256 R_LoadEntities(&header->lumps[LUMP_ENTITIES]);
4257 R_LoadShaders(&header->lumps[LUMP_SHADERS]);
4258 R_LoadLightmaps(&header->lumps[LUMP_LIGHTMAPS]);
4259 R_LoadPlanes(&header->lumps[LUMP_PLANES]);
4260 R_LoadFogs(&header->lumps[LUMP_FOGS], &header->lumps[LUMP_BRUSHES], &header->lumps[LUMP_BRUSHSIDES]);
4261 R_LoadSurfaces(&header->lumps[LUMP_SURFACES], &header->lumps[LUMP_DRAWVERTS], &header->lumps[LUMP_DRAWINDEXES]);
4262 R_LoadMarksurfaces(&header->lumps[LUMP_LEAFSURFACES]);
4263 R_LoadNodesAndLeafs(&header->lumps[LUMP_NODES], &header->lumps[LUMP_LEAFS]);
4264 R_LoadSubmodels(&header->lumps[LUMP_MODELS]);
4265 R_LoadVisibility(&header->lumps[LUMP_VISIBILITY]);
4266 R_LoadLightGrid(&header->lumps[LUMP_LIGHTGRID]);
4267
4268 // we precache interactions between lights and surfaces to reduce the polygon count
4269 R_PrecacheInteractions();
4270
4271 s_worldData.dataSize = (byte *) ri.Hunk_Alloc(0, h_low) - startMarker;
4272
4273 // only set tr.world now that we know the entire level has loaded properly
4274 tr.world = &s_worldData;
4275
4276 ri.FS_FreeFile(buffer);
4277 }
4278