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