1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 
5 This file is part of Quake III Arena source code.
6 
7 Quake III Arena source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11 
12 Quake III Arena source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Quake III Arena source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 ===========================================================================
21 */
22 // tr_map.c
23 
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	byte		*fileBase;
38 
39 int			c_subdivisions;
40 int			c_gridVerts;
41 
42 //===============================================================================
43 
HSVtoRGB(float h,float s,float v,float rgb[3])44 static void HSVtoRGB( float h, float s, float v, float rgb[3] )
45 {
46 	int i;
47 	float f;
48 	float p, q, t;
49 
50 	h *= 5;
51 
52 	i = floor( h );
53 	f = h - i;
54 
55 	p = v * ( 1 - s );
56 	q = v * ( 1 - s * f );
57 	t = v * ( 1 - s * ( 1 - f ) );
58 
59 	switch ( i )
60 	{
61 	case 0:
62 		rgb[0] = v;
63 		rgb[1] = t;
64 		rgb[2] = p;
65 		break;
66 	case 1:
67 		rgb[0] = q;
68 		rgb[1] = v;
69 		rgb[2] = p;
70 		break;
71 	case 2:
72 		rgb[0] = p;
73 		rgb[1] = v;
74 		rgb[2] = t;
75 		break;
76 	case 3:
77 		rgb[0] = p;
78 		rgb[1] = q;
79 		rgb[2] = v;
80 		break;
81 	case 4:
82 		rgb[0] = t;
83 		rgb[1] = p;
84 		rgb[2] = v;
85 		break;
86 	case 5:
87 		rgb[0] = v;
88 		rgb[1] = p;
89 		rgb[2] = q;
90 		break;
91 	}
92 }
93 
94 /*
95 ===============
96 R_ColorShiftLightingBytes
97 
98 ===============
99 */
R_ColorShiftLightingBytes(byte in[4],byte out[4])100 static	void R_ColorShiftLightingBytes( byte in[4], byte out[4] ) {
101 	int		shift, r, g, b;
102 
103 	// shift the color data based on overbright range
104 	shift = r_mapOverBrightBits->integer - tr.overbrightBits;
105 
106 	// shift the data based on overbright range
107 	r = in[0] << shift;
108 	g = in[1] << shift;
109 	b = in[2] << shift;
110 
111 	// normalize by color instead of saturating to white
112 	if ( ( r | g | b ) > 255 ) {
113 		int		max;
114 
115 		max = r > g ? r : g;
116 		max = max > b ? max : b;
117 		r = r * 255 / max;
118 		g = g * 255 / max;
119 		b = b * 255 / max;
120 	}
121 
122 	out[0] = r;
123 	out[1] = g;
124 	out[2] = b;
125 	out[3] = in[3];
126 }
127 
128 /*
129 ===============
130 R_LoadLightmaps
131 
132 ===============
133 */
134 #define	LIGHTMAP_SIZE	128
R_LoadLightmaps(lump_t * l)135 static	void R_LoadLightmaps( lump_t *l ) {
136 	byte		*buf, *buf_p;
137 	int			len;
138 	byte		image[LIGHTMAP_SIZE*LIGHTMAP_SIZE*4];
139 	int			i, j;
140 	float maxIntensity = 0;
141 	double sumIntensity = 0;
142 
143 	len = l->filelen;
144 	if ( !len ) {
145 		return;
146 	}
147 	buf = fileBase + l->fileofs;
148 
149 	// we are about to upload textures
150 	R_SyncRenderThread();
151 
152 	// create all the lightmaps
153 	tr.numLightmaps = len / (LIGHTMAP_SIZE * LIGHTMAP_SIZE * 3);
154 	if ( tr.numLightmaps == 1 ) {
155 		//FIXME: HACK: maps with only one lightmap turn up fullbright for some reason.
156 		//this avoids this, but isn't the correct solution.
157 		tr.numLightmaps++;
158 	} else if ( tr.numLightmaps >= MAX_LIGHTMAPS ) { // 20051020 misantropia
159 		ri.Printf( PRINT_WARNING, "WARNING: number of lightmaps > MAX_LIGHTMAPS\n" );
160 		tr.numLightmaps = MAX_LIGHTMAPS;
161 	}
162 
163 	// if we are in r_vertexLight mode, we don't need the lightmaps at all
164 	if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 ) {
165 		return;
166 	}
167 
168 	for ( i = 0 ; i < tr.numLightmaps ; i++ ) {
169 		// expand the 24 bit on-disk to 32 bit
170 		buf_p = buf + i * LIGHTMAP_SIZE*LIGHTMAP_SIZE * 3;
171 
172 		if ( r_lightmap->integer == 2 )
173 		{	// color code by intensity as development tool	(FIXME: check range)
174 			for ( j = 0; j < LIGHTMAP_SIZE * LIGHTMAP_SIZE; j++ )
175 			{
176 				float r = buf_p[j*3+0];
177 				float g = buf_p[j*3+1];
178 				float b = buf_p[j*3+2];
179 				float intensity;
180 				float out[3] = {0.0, 0.0, 0.0};
181 
182 				intensity = 0.33f * r + 0.685f * g + 0.063f * b;
183 
184 				if ( intensity > 255 )
185 					intensity = 1.0f;
186 				else
187 					intensity /= 255.0f;
188 
189 				if ( intensity > maxIntensity )
190 					maxIntensity = intensity;
191 
192 				HSVtoRGB( intensity, 1.00, 0.50, out );
193 
194 				image[j*4+0] = out[0] * 255;
195 				image[j*4+1] = out[1] * 255;
196 				image[j*4+2] = out[2] * 255;
197 				image[j*4+3] = 255;
198 
199 				sumIntensity += intensity;
200 			}
201 		} else {
202 			for ( j = 0 ; j < LIGHTMAP_SIZE * LIGHTMAP_SIZE; j++ ) {
203 				R_ColorShiftLightingBytes( &buf_p[j*3], &image[j*4] );
204 				image[j*4+3] = 255;
205 			}
206 		}
207 		tr.lightmaps[i] = R_CreateImage( va("*lightmap%d",i), image,
208 			LIGHTMAP_SIZE, LIGHTMAP_SIZE, qfalse, qfalse, GL_CLAMP_TO_EDGE );
209 	}
210 
211 	if ( r_lightmap->integer == 2 )	{
212 		ri.Printf( PRINT_ALL, "Brightest lightmap value: %d\n", ( int ) ( maxIntensity * 255 ) );
213 	}
214 }
215 
216 
217 /*
218 =================
219 RE_SetWorldVisData
220 
221 This is called by the clipmodel subsystem so we can share the 1.8 megs of
222 space in big maps...
223 =================
224 */
RE_SetWorldVisData(const byte * vis)225 void		RE_SetWorldVisData( const byte *vis ) {
226 	tr.externalVisData = vis;
227 }
228 
229 
230 /*
231 =================
232 R_LoadVisibility
233 =================
234 */
R_LoadVisibility(lump_t * l)235 static	void R_LoadVisibility( lump_t *l ) {
236 	int		len;
237 	byte	*buf;
238 
239 	len = ( s_worldData.numClusters + 63 ) & ~63;
240 	s_worldData.novis = ri.Hunk_Alloc( len, h_low );
241 	Com_Memset( s_worldData.novis, 0xff, len );
242 
243     len = l->filelen;
244 	if ( !len ) {
245 		return;
246 	}
247 	buf = fileBase + l->fileofs;
248 
249 	s_worldData.numClusters = LittleLong( ((int *)buf)[0] );
250 	s_worldData.clusterBytes = LittleLong( ((int *)buf)[1] );
251 
252 	// CM_Load should have given us the vis data to share, so
253 	// we don't need to allocate another copy
254 	if ( tr.externalVisData ) {
255 		s_worldData.vis = tr.externalVisData;
256 	} else {
257 		byte	*dest;
258 
259 		dest = ri.Hunk_Alloc( len - 8, h_low );
260 		Com_Memcpy( dest, buf + 8, len - 8 );
261 		s_worldData.vis = dest;
262 	}
263 }
264 
265 //===============================================================================
266 
267 
268 /*
269 ===============
270 ShaderForShaderNum
271 ===============
272 */
ShaderForShaderNum(int shaderNum,int lightmapNum)273 static shader_t *ShaderForShaderNum( int shaderNum, int lightmapNum ) {
274 	shader_t	*shader;
275 	dshader_t	*dsh;
276 
277 	shaderNum = LittleLong( shaderNum );
278 	if ( shaderNum < 0 || shaderNum >= s_worldData.numShaders ) {
279 		ri.Error( ERR_DROP, "ShaderForShaderNum: bad num %i", shaderNum );
280 	}
281 	dsh = &s_worldData.shaders[ shaderNum ];
282 
283 	if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 ) {
284 		lightmapNum = LIGHTMAP_BY_VERTEX;
285 	}
286 
287 	if ( r_fullbright->integer ) {
288 		lightmapNum = LIGHTMAP_WHITEIMAGE;
289 	}
290 
291 	shader = R_FindShader( dsh->shader, lightmapNum, qtrue );
292 
293 	// if the shader had errors, just use default shader
294 	if ( shader->defaultShader ) {
295 		return tr.defaultShader;
296 	}
297 
298 	return shader;
299 }
300 
301 /*
302 ===============
303 ParseFace
304 ===============
305 */
ParseFace(dsurface_t * ds,drawVert_t * verts,msurface_t * surf,int * indexes)306 static void ParseFace( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes  ) {
307 	int			i, j;
308 	srfSurfaceFace_t	*cv;
309 	int			numPoints, numIndexes;
310 	int			lightmapNum;
311 	int			sfaceSize, ofsIndexes;
312 
313 	lightmapNum = LittleLong( ds->lightmapNum );
314 
315 	// get fog volume
316 	surf->fogIndex = LittleLong( ds->fogNum ) + 1;
317 
318 	// get shader value
319 	surf->shader = ShaderForShaderNum( ds->shaderNum, lightmapNum );
320 	if ( r_singleShader->integer && !surf->shader->isSky ) {
321 		surf->shader = tr.defaultShader;
322 	}
323 
324 	numPoints = LittleLong( ds->numVerts );
325 	if (numPoints > MAX_FACE_POINTS) {
326 		ri.Printf( PRINT_WARNING, "WARNING: MAX_FACE_POINTS exceeded: %i\n", numPoints);
327     numPoints = MAX_FACE_POINTS;
328     surf->shader = tr.defaultShader;
329 	}
330 
331 	numIndexes = LittleLong( ds->numIndexes );
332 
333 	// create the srfSurfaceFace_t
334 	sfaceSize = ( size_t ) &((srfSurfaceFace_t *)0)->points[numPoints];
335 	ofsIndexes = sfaceSize;
336 	sfaceSize += sizeof( int ) * numIndexes;
337 
338 	cv = ri.Hunk_Alloc( sfaceSize, h_low );
339 	cv->surfaceType = SF_FACE;
340 	cv->numPoints = numPoints;
341 	cv->numIndices = numIndexes;
342 	cv->ofsIndices = ofsIndexes;
343 
344 	verts += LittleLong( ds->firstVert );
345 	for ( i = 0 ; i < numPoints ; i++ ) {
346 		for ( j = 0 ; j < 3 ; j++ ) {
347 			cv->points[i][j] = LittleFloat( verts[i].xyz[j] );
348 		}
349 		for ( j = 0 ; j < 2 ; j++ ) {
350 			cv->points[i][3+j] = LittleFloat( verts[i].st[j] );
351 			cv->points[i][5+j] = LittleFloat( verts[i].lightmap[j] );
352 		}
353 		R_ColorShiftLightingBytes( verts[i].color, (byte *)&cv->points[i][7] );
354 	}
355 
356 	indexes += LittleLong( ds->firstIndex );
357 	for ( i = 0 ; i < numIndexes ; i++ ) {
358 		((int *)((byte *)cv + cv->ofsIndices ))[i] = LittleLong( indexes[ i ] );
359 	}
360 
361 	// take the plane information from the lightmap vector
362 	for ( i = 0 ; i < 3 ; i++ ) {
363 		cv->plane.normal[i] = LittleFloat( ds->lightmapVecs[2][i] );
364 	}
365 	cv->plane.dist = DotProduct( cv->points[0], cv->plane.normal );
366 	SetPlaneSignbits( &cv->plane );
367 	cv->plane.type = PlaneTypeForNormal( cv->plane.normal );
368 
369 	surf->data = (surfaceType_t *)cv;
370 }
371 
372 
373 /*
374 ===============
375 ParseMesh
376 ===============
377 */
ParseMesh(dsurface_t * ds,drawVert_t * verts,msurface_t * surf)378 static void ParseMesh ( dsurface_t *ds, drawVert_t *verts, msurface_t *surf ) {
379 	srfGridMesh_t	*grid;
380 	int				i, j;
381 	int				width, height, numPoints;
382 	drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE];
383 	int				lightmapNum;
384 	vec3_t			bounds[2];
385 	vec3_t			tmpVec;
386 	static surfaceType_t	skipData = SF_SKIP;
387 
388 	lightmapNum = LittleLong( ds->lightmapNum );
389 
390 	// get fog volume
391 	surf->fogIndex = LittleLong( ds->fogNum ) + 1;
392 
393 	// get shader value
394 	surf->shader = ShaderForShaderNum( ds->shaderNum, lightmapNum );
395 	if ( r_singleShader->integer && !surf->shader->isSky ) {
396 		surf->shader = tr.defaultShader;
397 	}
398 
399 	// we may have a nodraw surface, because they might still need to
400 	// be around for movement clipping
401 	if ( s_worldData.shaders[ LittleLong( ds->shaderNum ) ].surfaceFlags & SURF_NODRAW ) {
402 		surf->data = &skipData;
403 		return;
404 	}
405 
406 	width = LittleLong( ds->patchWidth );
407 	height = LittleLong( ds->patchHeight );
408 
409 	verts += LittleLong( ds->firstVert );
410 	numPoints = width * height;
411 	for ( i = 0 ; i < numPoints ; i++ ) {
412 		for ( j = 0 ; j < 3 ; j++ ) {
413 			points[i].xyz[j] = LittleFloat( verts[i].xyz[j] );
414 			points[i].normal[j] = LittleFloat( verts[i].normal[j] );
415 		}
416 		for ( j = 0 ; j < 2 ; j++ ) {
417 			points[i].st[j] = LittleFloat( verts[i].st[j] );
418 			points[i].lightmap[j] = LittleFloat( verts[i].lightmap[j] );
419 		}
420 		R_ColorShiftLightingBytes( verts[i].color, points[i].color );
421 	}
422 
423 	// pre-tesseleate
424 	grid = R_SubdividePatchToGrid( width, height, points );
425 	surf->data = (surfaceType_t *)grid;
426 
427 	// copy the level of detail origin, which is the center
428 	// of the group of all curves that must subdivide the same
429 	// to avoid cracking
430 	for ( i = 0 ; i < 3 ; i++ ) {
431 		bounds[0][i] = LittleFloat( ds->lightmapVecs[0][i] );
432 		bounds[1][i] = LittleFloat( ds->lightmapVecs[1][i] );
433 	}
434 	VectorAdd( bounds[0], bounds[1], bounds[1] );
435 	VectorScale( bounds[1], 0.5f, grid->lodOrigin );
436 	VectorSubtract( bounds[0], grid->lodOrigin, tmpVec );
437 	grid->lodRadius = VectorLength( tmpVec );
438 }
439 
440 /*
441 ===============
442 ParseTriSurf
443 ===============
444 */
ParseTriSurf(dsurface_t * ds,drawVert_t * verts,msurface_t * surf,int * indexes)445 static void ParseTriSurf( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) {
446 	srfTriangles_t	*tri;
447 	int				i, j;
448 	int				numVerts, numIndexes;
449 
450 	// get fog volume
451 	surf->fogIndex = LittleLong( ds->fogNum ) + 1;
452 
453 	// get shader
454 	surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX );
455 	if ( r_singleShader->integer && !surf->shader->isSky ) {
456 		surf->shader = tr.defaultShader;
457 	}
458 
459 	numVerts = LittleLong( ds->numVerts );
460 	numIndexes = LittleLong( ds->numIndexes );
461 
462 	tri = ri.Hunk_Alloc( sizeof( *tri ) + numVerts * sizeof( tri->verts[0] )
463 		+ numIndexes * sizeof( tri->indexes[0] ), h_low );
464 	tri->surfaceType = SF_TRIANGLES;
465 	tri->numVerts = numVerts;
466 	tri->numIndexes = numIndexes;
467 	tri->verts = (drawVert_t *)(tri + 1);
468 	tri->indexes = (int *)(tri->verts + tri->numVerts );
469 
470 	surf->data = (surfaceType_t *)tri;
471 
472 	// copy vertexes
473 	ClearBounds( tri->bounds[0], tri->bounds[1] );
474 	verts += LittleLong( ds->firstVert );
475 	for ( i = 0 ; i < numVerts ; i++ ) {
476 		for ( j = 0 ; j < 3 ; j++ ) {
477 			tri->verts[i].xyz[j] = LittleFloat( verts[i].xyz[j] );
478 			tri->verts[i].normal[j] = LittleFloat( verts[i].normal[j] );
479 		}
480 		AddPointToBounds( tri->verts[i].xyz, tri->bounds[0], tri->bounds[1] );
481 		for ( j = 0 ; j < 2 ; j++ ) {
482 			tri->verts[i].st[j] = LittleFloat( verts[i].st[j] );
483 			tri->verts[i].lightmap[j] = LittleFloat( verts[i].lightmap[j] );
484 		}
485 
486 		R_ColorShiftLightingBytes( verts[i].color, tri->verts[i].color );
487 	}
488 
489 	// copy indexes
490 	indexes += LittleLong( ds->firstIndex );
491 	for ( i = 0 ; i < numIndexes ; i++ ) {
492 		tri->indexes[i] = LittleLong( indexes[i] );
493 		if ( tri->indexes[i] < 0 || tri->indexes[i] >= numVerts ) {
494 			ri.Error( ERR_DROP, "Bad index in triangle surface" );
495 		}
496 	}
497 }
498 
499 /*
500 ===============
501 ParseFlare
502 ===============
503 */
ParseFlare(dsurface_t * ds,drawVert_t * verts,msurface_t * surf,int * indexes)504 static void ParseFlare( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) {
505 	srfFlare_t		*flare;
506 	int				i;
507 
508 	// get fog volume
509 	surf->fogIndex = LittleLong( ds->fogNum ) + 1;
510 
511 	// get shader
512 	surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX );
513 	if ( r_singleShader->integer && !surf->shader->isSky ) {
514 		surf->shader = tr.defaultShader;
515 	}
516 
517 	flare = ri.Hunk_Alloc( sizeof( *flare ), h_low );
518 	flare->surfaceType = SF_FLARE;
519 
520 	surf->data = (surfaceType_t *)flare;
521 
522 	for ( i = 0 ; i < 3 ; i++ ) {
523 		flare->origin[i] = LittleFloat( ds->lightmapOrigin[i] );
524 		flare->color[i] = LittleFloat( ds->lightmapVecs[0][i] );
525 		flare->normal[i] = LittleFloat( ds->lightmapVecs[2][i] );
526 	}
527 }
528 
529 
530 /*
531 =================
532 R_MergedWidthPoints
533 
534 returns true if there are grid points merged on a width edge
535 =================
536 */
R_MergedWidthPoints(srfGridMesh_t * grid,int offset)537 int R_MergedWidthPoints(srfGridMesh_t *grid, int offset) {
538 	int i, j;
539 
540 	for (i = 1; i < grid->width-1; i++) {
541 		for (j = i + 1; j < grid->width-1; j++) {
542 			if ( fabs(grid->verts[i + offset].xyz[0] - grid->verts[j + offset].xyz[0]) > .1) continue;
543 			if ( fabs(grid->verts[i + offset].xyz[1] - grid->verts[j + offset].xyz[1]) > .1) continue;
544 			if ( fabs(grid->verts[i + offset].xyz[2] - grid->verts[j + offset].xyz[2]) > .1) continue;
545 			return qtrue;
546 		}
547 	}
548 	return qfalse;
549 }
550 
551 /*
552 =================
553 R_MergedHeightPoints
554 
555 returns true if there are grid points merged on a height edge
556 =================
557 */
R_MergedHeightPoints(srfGridMesh_t * grid,int offset)558 int R_MergedHeightPoints(srfGridMesh_t *grid, int offset) {
559 	int i, j;
560 
561 	for (i = 1; i < grid->height-1; i++) {
562 		for (j = i + 1; j < grid->height-1; j++) {
563 			if ( fabs(grid->verts[grid->width * i + offset].xyz[0] - grid->verts[grid->width * j + offset].xyz[0]) > .1) continue;
564 			if ( fabs(grid->verts[grid->width * i + offset].xyz[1] - grid->verts[grid->width * j + offset].xyz[1]) > .1) continue;
565 			if ( fabs(grid->verts[grid->width * i + offset].xyz[2] - grid->verts[grid->width * j + offset].xyz[2]) > .1) continue;
566 			return qtrue;
567 		}
568 	}
569 	return qfalse;
570 }
571 
572 /*
573 =================
574 R_FixSharedVertexLodError_r
575 
576 NOTE: never sync LoD through grid edges with merged points!
577 
578 FIXME: write generalized version that also avoids cracks between a patch and one that meets half way?
579 =================
580 */
R_FixSharedVertexLodError_r(int start,srfGridMesh_t * grid1)581 void R_FixSharedVertexLodError_r( int start, srfGridMesh_t *grid1 ) {
582 	int j, k, l, m, n, offset1, offset2, touch;
583 	srfGridMesh_t *grid2;
584 
585 	for ( j = start; j < s_worldData.numsurfaces; j++ ) {
586 		//
587 		grid2 = (srfGridMesh_t *) s_worldData.surfaces[j].data;
588 		// if this surface is not a grid
589 		if ( grid2->surfaceType != SF_GRID ) continue;
590 		// if the LOD errors are already fixed for this patch
591 		if ( grid2->lodFixed == 2 ) continue;
592 		// grids in the same LOD group should have the exact same lod radius
593 		if ( grid1->lodRadius != grid2->lodRadius ) continue;
594 		// grids in the same LOD group should have the exact same lod origin
595 		if ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue;
596 		if ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue;
597 		if ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue;
598 		//
599 		touch = qfalse;
600 		for (n = 0; n < 2; n++) {
601 			//
602 			if (n) offset1 = (grid1->height-1) * grid1->width;
603 			else offset1 = 0;
604 			if (R_MergedWidthPoints(grid1, offset1)) continue;
605 			for (k = 1; k < grid1->width-1; k++) {
606 				for (m = 0; m < 2; m++) {
607 
608 					if (m) offset2 = (grid2->height-1) * grid2->width;
609 					else offset2 = 0;
610 					if (R_MergedWidthPoints(grid2, offset2)) continue;
611 					for ( l = 1; l < grid2->width-1; l++) {
612 					//
613 						if ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue;
614 						if ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue;
615 						if ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue;
616 						// ok the points are equal and should have the same lod error
617 						grid2->widthLodError[l] = grid1->widthLodError[k];
618 						touch = qtrue;
619 					}
620 				}
621 				for (m = 0; m < 2; m++) {
622 
623 					if (m) offset2 = grid2->width-1;
624 					else offset2 = 0;
625 					if (R_MergedHeightPoints(grid2, offset2)) continue;
626 					for ( l = 1; l < grid2->height-1; l++) {
627 					//
628 						if ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue;
629 						if ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue;
630 						if ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue;
631 						// ok the points are equal and should have the same lod error
632 						grid2->heightLodError[l] = grid1->widthLodError[k];
633 						touch = qtrue;
634 					}
635 				}
636 			}
637 		}
638 		for (n = 0; n < 2; n++) {
639 			//
640 			if (n) offset1 = grid1->width-1;
641 			else offset1 = 0;
642 			if (R_MergedHeightPoints(grid1, offset1)) continue;
643 			for (k = 1; k < grid1->height-1; k++) {
644 				for (m = 0; m < 2; m++) {
645 
646 					if (m) offset2 = (grid2->height-1) * grid2->width;
647 					else offset2 = 0;
648 					if (R_MergedWidthPoints(grid2, offset2)) continue;
649 					for ( l = 1; l < grid2->width-1; l++) {
650 					//
651 						if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue;
652 						if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue;
653 						if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue;
654 						// ok the points are equal and should have the same lod error
655 						grid2->widthLodError[l] = grid1->heightLodError[k];
656 						touch = qtrue;
657 					}
658 				}
659 				for (m = 0; m < 2; m++) {
660 
661 					if (m) offset2 = grid2->width-1;
662 					else offset2 = 0;
663 					if (R_MergedHeightPoints(grid2, offset2)) continue;
664 					for ( l = 1; l < grid2->height-1; l++) {
665 					//
666 						if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue;
667 						if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue;
668 						if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue;
669 						// ok the points are equal and should have the same lod error
670 						grid2->heightLodError[l] = grid1->heightLodError[k];
671 						touch = qtrue;
672 					}
673 				}
674 			}
675 		}
676 		if (touch) {
677 			grid2->lodFixed = 2;
678 			R_FixSharedVertexLodError_r ( start, grid2 );
679 			//NOTE: this would be correct but makes things really slow
680 			//grid2->lodFixed = 1;
681 		}
682 	}
683 }
684 
685 /*
686 =================
687 R_FixSharedVertexLodError
688 
689 This function assumes that all patches in one group are nicely stitched together for the highest LoD.
690 If this is not the case this function will still do its job but won't fix the highest LoD cracks.
691 =================
692 */
R_FixSharedVertexLodError(void)693 void R_FixSharedVertexLodError( void ) {
694 	int i;
695 	srfGridMesh_t *grid1;
696 
697 	for ( i = 0; i < s_worldData.numsurfaces; i++ ) {
698 		//
699 		grid1 = (srfGridMesh_t *) s_worldData.surfaces[i].data;
700 		// if this surface is not a grid
701 		if ( grid1->surfaceType != SF_GRID )
702 			continue;
703 		//
704 		if ( grid1->lodFixed )
705 			continue;
706 		//
707 		grid1->lodFixed = 2;
708 		// recursively fix other patches in the same LOD group
709 		R_FixSharedVertexLodError_r( i + 1, grid1);
710 	}
711 }
712 
713 
714 /*
715 ===============
716 R_StitchPatches
717 ===============
718 */
R_StitchPatches(int grid1num,int grid2num)719 int R_StitchPatches( int grid1num, int grid2num ) {
720 	float *v1, *v2;
721 	srfGridMesh_t *grid1, *grid2;
722 	int k, l, m, n, offset1, offset2, row, column;
723 
724 	grid1 = (srfGridMesh_t *) s_worldData.surfaces[grid1num].data;
725 	grid2 = (srfGridMesh_t *) s_worldData.surfaces[grid2num].data;
726 	for (n = 0; n < 2; n++) {
727 		//
728 		if (n) offset1 = (grid1->height-1) * grid1->width;
729 		else offset1 = 0;
730 		if (R_MergedWidthPoints(grid1, offset1))
731 			continue;
732 		for (k = 0; k < grid1->width-2; k += 2) {
733 
734 			for (m = 0; m < 2; m++) {
735 
736 				if ( grid2->width >= MAX_GRID_SIZE )
737 					break;
738 				if (m) offset2 = (grid2->height-1) * grid2->width;
739 				else offset2 = 0;
740 				for ( l = 0; l < grid2->width-1; l++) {
741 				//
742 					v1 = grid1->verts[k + offset1].xyz;
743 					v2 = grid2->verts[l + offset2].xyz;
744 					if ( fabs(v1[0] - v2[0]) > .1)
745 						continue;
746 					if ( fabs(v1[1] - v2[1]) > .1)
747 						continue;
748 					if ( fabs(v1[2] - v2[2]) > .1)
749 						continue;
750 
751 					v1 = grid1->verts[k + 2 + offset1].xyz;
752 					v2 = grid2->verts[l + 1 + offset2].xyz;
753 					if ( fabs(v1[0] - v2[0]) > .1)
754 						continue;
755 					if ( fabs(v1[1] - v2[1]) > .1)
756 						continue;
757 					if ( fabs(v1[2] - v2[2]) > .1)
758 						continue;
759 					//
760 					v1 = grid2->verts[l + offset2].xyz;
761 					v2 = grid2->verts[l + 1 + offset2].xyz;
762 					if ( fabs(v1[0] - v2[0]) < .01 &&
763 							fabs(v1[1] - v2[1]) < .01 &&
764 							fabs(v1[2] - v2[2]) < .01)
765 						continue;
766 					//
767 					//ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
768 					// insert column into grid2 right after after column l
769 					if (m) row = grid2->height-1;
770 					else row = 0;
771 					grid2 = R_GridInsertColumn( grid2, l+1, row,
772 									grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]);
773 					grid2->lodStitched = qfalse;
774 					s_worldData.surfaces[grid2num].data = (void *) grid2;
775 					return qtrue;
776 				}
777 			}
778 			for (m = 0; m < 2; m++) {
779 
780 				if (grid2->height >= MAX_GRID_SIZE)
781 					break;
782 				if (m) offset2 = grid2->width-1;
783 				else offset2 = 0;
784 				for ( l = 0; l < grid2->height-1; l++) {
785 					//
786 					v1 = grid1->verts[k + offset1].xyz;
787 					v2 = grid2->verts[grid2->width * l + offset2].xyz;
788 					if ( fabs(v1[0] - v2[0]) > .1)
789 						continue;
790 					if ( fabs(v1[1] - v2[1]) > .1)
791 						continue;
792 					if ( fabs(v1[2] - v2[2]) > .1)
793 						continue;
794 
795 					v1 = grid1->verts[k + 2 + offset1].xyz;
796 					v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
797 					if ( fabs(v1[0] - v2[0]) > .1)
798 						continue;
799 					if ( fabs(v1[1] - v2[1]) > .1)
800 						continue;
801 					if ( fabs(v1[2] - v2[2]) > .1)
802 						continue;
803 					//
804 					v1 = grid2->verts[grid2->width * l + offset2].xyz;
805 					v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
806 					if ( fabs(v1[0] - v2[0]) < .01 &&
807 							fabs(v1[1] - v2[1]) < .01 &&
808 							fabs(v1[2] - v2[2]) < .01)
809 						continue;
810 					//
811 					//ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
812 					// insert row into grid2 right after after row l
813 					if (m) column = grid2->width-1;
814 					else column = 0;
815 					grid2 = R_GridInsertRow( grid2, l+1, column,
816 										grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]);
817 					grid2->lodStitched = qfalse;
818 					s_worldData.surfaces[grid2num].data = (void *) grid2;
819 					return qtrue;
820 				}
821 			}
822 		}
823 	}
824 	for (n = 0; n < 2; n++) {
825 		//
826 		if (n) offset1 = grid1->width-1;
827 		else offset1 = 0;
828 		if (R_MergedHeightPoints(grid1, offset1))
829 			continue;
830 		for (k = 0; k < grid1->height-2; k += 2) {
831 			for (m = 0; m < 2; m++) {
832 
833 				if ( grid2->width >= MAX_GRID_SIZE )
834 					break;
835 				if (m) offset2 = (grid2->height-1) * grid2->width;
836 				else offset2 = 0;
837 				for ( l = 0; l < grid2->width-1; l++) {
838 				//
839 					v1 = grid1->verts[grid1->width * k + offset1].xyz;
840 					v2 = grid2->verts[l + offset2].xyz;
841 					if ( fabs(v1[0] - v2[0]) > .1)
842 						continue;
843 					if ( fabs(v1[1] - v2[1]) > .1)
844 						continue;
845 					if ( fabs(v1[2] - v2[2]) > .1)
846 						continue;
847 
848 					v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz;
849 					v2 = grid2->verts[l + 1 + offset2].xyz;
850 					if ( fabs(v1[0] - v2[0]) > .1)
851 						continue;
852 					if ( fabs(v1[1] - v2[1]) > .1)
853 						continue;
854 					if ( fabs(v1[2] - v2[2]) > .1)
855 						continue;
856 					//
857 					v1 = grid2->verts[l + offset2].xyz;
858 					v2 = grid2->verts[(l + 1) + offset2].xyz;
859 					if ( fabs(v1[0] - v2[0]) < .01 &&
860 							fabs(v1[1] - v2[1]) < .01 &&
861 							fabs(v1[2] - v2[2]) < .01)
862 						continue;
863 					//
864 					//ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
865 					// insert column into grid2 right after after column l
866 					if (m) row = grid2->height-1;
867 					else row = 0;
868 					grid2 = R_GridInsertColumn( grid2, l+1, row,
869 									grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]);
870 					grid2->lodStitched = qfalse;
871 					s_worldData.surfaces[grid2num].data = (void *) grid2;
872 					return qtrue;
873 				}
874 			}
875 			for (m = 0; m < 2; m++) {
876 
877 				if (grid2->height >= MAX_GRID_SIZE)
878 					break;
879 				if (m) offset2 = grid2->width-1;
880 				else offset2 = 0;
881 				for ( l = 0; l < grid2->height-1; l++) {
882 				//
883 					v1 = grid1->verts[grid1->width * k + offset1].xyz;
884 					v2 = grid2->verts[grid2->width * l + offset2].xyz;
885 					if ( fabs(v1[0] - v2[0]) > .1)
886 						continue;
887 					if ( fabs(v1[1] - v2[1]) > .1)
888 						continue;
889 					if ( fabs(v1[2] - v2[2]) > .1)
890 						continue;
891 
892 					v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz;
893 					v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
894 					if ( fabs(v1[0] - v2[0]) > .1)
895 						continue;
896 					if ( fabs(v1[1] - v2[1]) > .1)
897 						continue;
898 					if ( fabs(v1[2] - v2[2]) > .1)
899 						continue;
900 					//
901 					v1 = grid2->verts[grid2->width * l + offset2].xyz;
902 					v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
903 					if ( fabs(v1[0] - v2[0]) < .01 &&
904 							fabs(v1[1] - v2[1]) < .01 &&
905 							fabs(v1[2] - v2[2]) < .01)
906 						continue;
907 					//
908 					//ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
909 					// insert row into grid2 right after after row l
910 					if (m) column = grid2->width-1;
911 					else column = 0;
912 					grid2 = R_GridInsertRow( grid2, l+1, column,
913 									grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]);
914 					grid2->lodStitched = qfalse;
915 					s_worldData.surfaces[grid2num].data = (void *) grid2;
916 					return qtrue;
917 				}
918 			}
919 		}
920 	}
921 	for (n = 0; n < 2; n++) {
922 		//
923 		if (n) offset1 = (grid1->height-1) * grid1->width;
924 		else offset1 = 0;
925 		if (R_MergedWidthPoints(grid1, offset1))
926 			continue;
927 		for (k = grid1->width-1; k > 1; k -= 2) {
928 
929 			for (m = 0; m < 2; m++) {
930 
931 				if ( grid2->width >= MAX_GRID_SIZE )
932 					break;
933 				if (m) offset2 = (grid2->height-1) * grid2->width;
934 				else offset2 = 0;
935 				for ( l = 0; l < grid2->width-1; l++) {
936 				//
937 					v1 = grid1->verts[k + offset1].xyz;
938 					v2 = grid2->verts[l + offset2].xyz;
939 					if ( fabs(v1[0] - v2[0]) > .1)
940 						continue;
941 					if ( fabs(v1[1] - v2[1]) > .1)
942 						continue;
943 					if ( fabs(v1[2] - v2[2]) > .1)
944 						continue;
945 
946 					v1 = grid1->verts[k - 2 + offset1].xyz;
947 					v2 = grid2->verts[l + 1 + offset2].xyz;
948 					if ( fabs(v1[0] - v2[0]) > .1)
949 						continue;
950 					if ( fabs(v1[1] - v2[1]) > .1)
951 						continue;
952 					if ( fabs(v1[2] - v2[2]) > .1)
953 						continue;
954 					//
955 					v1 = grid2->verts[l + offset2].xyz;
956 					v2 = grid2->verts[(l + 1) + offset2].xyz;
957 					if ( fabs(v1[0] - v2[0]) < .01 &&
958 							fabs(v1[1] - v2[1]) < .01 &&
959 							fabs(v1[2] - v2[2]) < .01)
960 						continue;
961 					//
962 					//ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
963 					// insert column into grid2 right after after column l
964 					if (m) row = grid2->height-1;
965 					else row = 0;
966 					grid2 = R_GridInsertColumn( grid2, l+1, row,
967 										grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]);
968 					grid2->lodStitched = qfalse;
969 					s_worldData.surfaces[grid2num].data = (void *) grid2;
970 					return qtrue;
971 				}
972 			}
973 			for (m = 0; m < 2; m++) {
974 
975 				if (grid2->height >= MAX_GRID_SIZE)
976 					break;
977 				if (m) offset2 = grid2->width-1;
978 				else offset2 = 0;
979 				for ( l = 0; l < grid2->height-1; l++) {
980 				//
981 					v1 = grid1->verts[k + offset1].xyz;
982 					v2 = grid2->verts[grid2->width * l + offset2].xyz;
983 					if ( fabs(v1[0] - v2[0]) > .1)
984 						continue;
985 					if ( fabs(v1[1] - v2[1]) > .1)
986 						continue;
987 					if ( fabs(v1[2] - v2[2]) > .1)
988 						continue;
989 
990 					v1 = grid1->verts[k - 2 + offset1].xyz;
991 					v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
992 					if ( fabs(v1[0] - v2[0]) > .1)
993 						continue;
994 					if ( fabs(v1[1] - v2[1]) > .1)
995 						continue;
996 					if ( fabs(v1[2] - v2[2]) > .1)
997 						continue;
998 					//
999 					v1 = grid2->verts[grid2->width * l + offset2].xyz;
1000 					v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
1001 					if ( fabs(v1[0] - v2[0]) < .01 &&
1002 							fabs(v1[1] - v2[1]) < .01 &&
1003 							fabs(v1[2] - v2[2]) < .01)
1004 						continue;
1005 					//
1006 					//ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
1007 					// insert row into grid2 right after after row l
1008 					if (m) column = grid2->width-1;
1009 					else column = 0;
1010 					grid2 = R_GridInsertRow( grid2, l+1, column,
1011 										grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]);
1012 					if (!grid2)
1013 						break;
1014 					grid2->lodStitched = qfalse;
1015 					s_worldData.surfaces[grid2num].data = (void *) grid2;
1016 					return qtrue;
1017 				}
1018 			}
1019 		}
1020 	}
1021 	for (n = 0; n < 2; n++) {
1022 		//
1023 		if (n) offset1 = grid1->width-1;
1024 		else offset1 = 0;
1025 		if (R_MergedHeightPoints(grid1, offset1))
1026 			continue;
1027 		for (k = grid1->height-1; k > 1; k -= 2) {
1028 			for (m = 0; m < 2; m++) {
1029 
1030 				if ( grid2->width >= MAX_GRID_SIZE )
1031 					break;
1032 				if (m) offset2 = (grid2->height-1) * grid2->width;
1033 				else offset2 = 0;
1034 				for ( l = 0; l < grid2->width-1; l++) {
1035 				//
1036 					v1 = grid1->verts[grid1->width * k + offset1].xyz;
1037 					v2 = grid2->verts[l + offset2].xyz;
1038 					if ( fabs(v1[0] - v2[0]) > .1)
1039 						continue;
1040 					if ( fabs(v1[1] - v2[1]) > .1)
1041 						continue;
1042 					if ( fabs(v1[2] - v2[2]) > .1)
1043 						continue;
1044 
1045 					v1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz;
1046 					v2 = grid2->verts[l + 1 + offset2].xyz;
1047 					if ( fabs(v1[0] - v2[0]) > .1)
1048 						continue;
1049 					if ( fabs(v1[1] - v2[1]) > .1)
1050 						continue;
1051 					if ( fabs(v1[2] - v2[2]) > .1)
1052 						continue;
1053 					//
1054 					v1 = grid2->verts[l + offset2].xyz;
1055 					v2 = grid2->verts[(l + 1) + offset2].xyz;
1056 					if ( fabs(v1[0] - v2[0]) < .01 &&
1057 							fabs(v1[1] - v2[1]) < .01 &&
1058 							fabs(v1[2] - v2[2]) < .01)
1059 						continue;
1060 					//
1061 					//ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
1062 					// insert column into grid2 right after after column l
1063 					if (m) row = grid2->height-1;
1064 					else row = 0;
1065 					grid2 = R_GridInsertColumn( grid2, l+1, row,
1066 										grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]);
1067 					grid2->lodStitched = qfalse;
1068 					s_worldData.surfaces[grid2num].data = (void *) grid2;
1069 					return qtrue;
1070 				}
1071 			}
1072 			for (m = 0; m < 2; m++) {
1073 
1074 				if (grid2->height >= MAX_GRID_SIZE)
1075 					break;
1076 				if (m) offset2 = grid2->width-1;
1077 				else offset2 = 0;
1078 				for ( l = 0; l < grid2->height-1; l++) {
1079 				//
1080 					v1 = grid1->verts[grid1->width * k + offset1].xyz;
1081 					v2 = grid2->verts[grid2->width * l + offset2].xyz;
1082 					if ( fabs(v1[0] - v2[0]) > .1)
1083 						continue;
1084 					if ( fabs(v1[1] - v2[1]) > .1)
1085 						continue;
1086 					if ( fabs(v1[2] - v2[2]) > .1)
1087 						continue;
1088 
1089 					v1 = grid1->verts[grid1->width * (k - 2) + offset1].xyz;
1090 					v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
1091 					if ( fabs(v1[0] - v2[0]) > .1)
1092 						continue;
1093 					if ( fabs(v1[1] - v2[1]) > .1)
1094 						continue;
1095 					if ( fabs(v1[2] - v2[2]) > .1)
1096 						continue;
1097 					//
1098 					v1 = grid2->verts[grid2->width * l + offset2].xyz;
1099 					v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
1100 					if ( fabs(v1[0] - v2[0]) < .01 &&
1101 							fabs(v1[1] - v2[1]) < .01 &&
1102 							fabs(v1[2] - v2[2]) < .01)
1103 						continue;
1104 					//
1105 					//ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
1106 					// insert row into grid2 right after after row l
1107 					if (m) column = grid2->width-1;
1108 					else column = 0;
1109 					grid2 = R_GridInsertRow( grid2, l+1, column,
1110 										grid1->verts[grid1->width * (k - 1) + offset1].xyz, grid1->heightLodError[k+1]);
1111 					grid2->lodStitched = qfalse;
1112 					s_worldData.surfaces[grid2num].data = (void *) grid2;
1113 					return qtrue;
1114 				}
1115 			}
1116 		}
1117 	}
1118 	return qfalse;
1119 }
1120 
1121 /*
1122 ===============
1123 R_TryStitchPatch
1124 
1125 This function will try to stitch patches in the same LoD group together for the highest LoD.
1126 
1127 Only single missing vertice cracks will be fixed.
1128 
1129 Vertices will be joined at the patch side a crack is first found, at the other side
1130 of the patch (on the same row or column) the vertices will not be joined and cracks
1131 might still appear at that side.
1132 ===============
1133 */
R_TryStitchingPatch(int grid1num)1134 int R_TryStitchingPatch( int grid1num ) {
1135 	int j, numstitches;
1136 	srfGridMesh_t *grid1, *grid2;
1137 
1138 	numstitches = 0;
1139 	grid1 = (srfGridMesh_t *) s_worldData.surfaces[grid1num].data;
1140 	for ( j = 0; j < s_worldData.numsurfaces; j++ ) {
1141 		//
1142 		grid2 = (srfGridMesh_t *) s_worldData.surfaces[j].data;
1143 		// if this surface is not a grid
1144 		if ( grid2->surfaceType != SF_GRID ) continue;
1145 		// grids in the same LOD group should have the exact same lod radius
1146 		if ( grid1->lodRadius != grid2->lodRadius ) continue;
1147 		// grids in the same LOD group should have the exact same lod origin
1148 		if ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue;
1149 		if ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue;
1150 		if ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue;
1151 		//
1152 		while (R_StitchPatches(grid1num, j))
1153 		{
1154 			numstitches++;
1155 		}
1156 	}
1157 	return numstitches;
1158 }
1159 
1160 /*
1161 ===============
1162 R_StitchAllPatches
1163 ===============
1164 */
R_StitchAllPatches(void)1165 void R_StitchAllPatches( void ) {
1166 	int i, stitched, numstitches;
1167 	srfGridMesh_t *grid1;
1168 
1169 	numstitches = 0;
1170 	do
1171 	{
1172 		stitched = qfalse;
1173 		for ( i = 0; i < s_worldData.numsurfaces; i++ ) {
1174 			//
1175 			grid1 = (srfGridMesh_t *) s_worldData.surfaces[i].data;
1176 			// if this surface is not a grid
1177 			if ( grid1->surfaceType != SF_GRID )
1178 				continue;
1179 			//
1180 			if ( grid1->lodStitched )
1181 				continue;
1182 			//
1183 			grid1->lodStitched = qtrue;
1184 			stitched = qtrue;
1185 			//
1186 			numstitches += R_TryStitchingPatch( i );
1187 		}
1188 	}
1189 	while (stitched);
1190 	ri.Printf( PRINT_ALL, "stitched %d LoD cracks\n", numstitches );
1191 }
1192 
1193 /*
1194 ===============
1195 R_MovePatchSurfacesToHunk
1196 ===============
1197 */
R_MovePatchSurfacesToHunk(void)1198 void R_MovePatchSurfacesToHunk(void) {
1199 	int i, size;
1200 	srfGridMesh_t *grid, *hunkgrid;
1201 
1202 	for ( i = 0; i < s_worldData.numsurfaces; i++ ) {
1203 		//
1204 		grid = (srfGridMesh_t *) s_worldData.surfaces[i].data;
1205 		// if this surface is not a grid
1206 		if ( grid->surfaceType != SF_GRID )
1207 			continue;
1208 		//
1209 		size = (grid->width * grid->height - 1) * sizeof( drawVert_t ) + sizeof( *grid );
1210 		hunkgrid = ri.Hunk_Alloc( size, h_low );
1211 		Com_Memcpy(hunkgrid, grid, size);
1212 
1213 		hunkgrid->widthLodError = ri.Hunk_Alloc( grid->width * 4, h_low );
1214 		Com_Memcpy( hunkgrid->widthLodError, grid->widthLodError, grid->width * 4 );
1215 
1216 		hunkgrid->heightLodError = ri.Hunk_Alloc( grid->height * 4, h_low );
1217 		Com_Memcpy( hunkgrid->heightLodError, grid->heightLodError, grid->height * 4 );
1218 
1219 		R_FreeSurfaceGridMesh( grid );
1220 
1221 		s_worldData.surfaces[i].data = (void *) hunkgrid;
1222 	}
1223 }
1224 
1225 /*
1226 ===============
1227 R_LoadSurfaces
1228 ===============
1229 */
R_LoadSurfaces(lump_t * surfs,lump_t * verts,lump_t * indexLump)1230 static	void R_LoadSurfaces( lump_t *surfs, lump_t *verts, lump_t *indexLump ) {
1231 	dsurface_t	*in;
1232 	msurface_t	*out;
1233 	drawVert_t	*dv;
1234 	int			*indexes;
1235 	int			count;
1236 	int			numFaces, numMeshes, numTriSurfs, numFlares;
1237 	int			i;
1238 
1239 	numFaces = 0;
1240 	numMeshes = 0;
1241 	numTriSurfs = 0;
1242 	numFlares = 0;
1243 
1244 	in = (void *)(fileBase + surfs->fileofs);
1245 	if (surfs->filelen % sizeof(*in))
1246 		ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
1247 	count = surfs->filelen / sizeof(*in);
1248 
1249 	dv = (void *)(fileBase + verts->fileofs);
1250 	if (verts->filelen % sizeof(*dv))
1251 		ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
1252 
1253 	indexes = (void *)(fileBase + indexLump->fileofs);
1254 	if ( indexLump->filelen % sizeof(*indexes))
1255 		ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
1256 
1257 	out = ri.Hunk_Alloc ( count * sizeof(*out), h_low );
1258 
1259 	s_worldData.surfaces = out;
1260 	s_worldData.numsurfaces = count;
1261 
1262 	for ( i = 0 ; i < count ; i++, in++, out++ ) {
1263 		switch ( LittleLong( in->surfaceType ) ) {
1264 		case MST_PATCH:
1265 			ParseMesh ( in, dv, out );
1266 			numMeshes++;
1267 			break;
1268 		case MST_TRIANGLE_SOUP:
1269 			ParseTriSurf( in, dv, out, indexes );
1270 			numTriSurfs++;
1271 			break;
1272 		case MST_PLANAR:
1273 			ParseFace( in, dv, out, indexes );
1274 			numFaces++;
1275 			break;
1276 		case MST_FLARE:
1277 			ParseFlare( in, dv, out, indexes );
1278 			numFlares++;
1279 			break;
1280 		default:
1281 			ri.Error( ERR_DROP, "Bad surfaceType" );
1282 		}
1283 	}
1284 
1285 #ifdef PATCH_STITCHING
1286 	R_StitchAllPatches();
1287 #endif
1288 
1289 	R_FixSharedVertexLodError();
1290 
1291 #ifdef PATCH_STITCHING
1292 	R_MovePatchSurfacesToHunk();
1293 #endif
1294 
1295 	ri.Printf( PRINT_ALL, "...loaded %d faces, %i meshes, %i trisurfs, %i flares\n",
1296 		numFaces, numMeshes, numTriSurfs, numFlares );
1297 }
1298 
1299 
1300 
1301 /*
1302 =================
1303 R_LoadSubmodels
1304 =================
1305 */
R_LoadSubmodels(lump_t * l)1306 static	void R_LoadSubmodels( lump_t *l ) {
1307 	dmodel_t	*in;
1308 	bmodel_t	*out;
1309 	int			i, j, count;
1310 
1311 	in = (void *)(fileBase + l->fileofs);
1312 	if (l->filelen % sizeof(*in))
1313 		ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
1314 	count = l->filelen / sizeof(*in);
1315 
1316 	s_worldData.bmodels = out = ri.Hunk_Alloc( count * sizeof(*out), h_low );
1317 
1318 	for ( i=0 ; i<count ; i++, in++, out++ ) {
1319 		model_t *model;
1320 
1321 		model = R_AllocModel();
1322 
1323 		assert( model != NULL );			// this should never happen
1324 		if ( model == NULL ) {
1325 			ri.Error(ERR_DROP, "R_LoadSubmodels: R_AllocModel() failed");
1326 		}
1327 
1328 		model->type = MOD_BRUSH;
1329 		model->bmodel = out;
1330 		Com_sprintf( model->name, sizeof( model->name ), "*%d", i );
1331 
1332 		for (j=0 ; j<3 ; j++) {
1333 			out->bounds[0][j] = LittleFloat (in->mins[j]);
1334 			out->bounds[1][j] = LittleFloat (in->maxs[j]);
1335 		}
1336 
1337 		out->firstSurface = s_worldData.surfaces + LittleLong( in->firstSurface );
1338 		out->numSurfaces = LittleLong( in->numSurfaces );
1339 	}
1340 }
1341 
1342 
1343 
1344 //==================================================================
1345 
1346 /*
1347 =================
1348 R_SetParent
1349 =================
1350 */
R_SetParent(mnode_t * node,mnode_t * parent)1351 static	void R_SetParent (mnode_t *node, mnode_t *parent)
1352 {
1353 	node->parent = parent;
1354 	if (node->contents != -1)
1355 		return;
1356 	R_SetParent (node->children[0], node);
1357 	R_SetParent (node->children[1], node);
1358 }
1359 
1360 /*
1361 =================
1362 R_LoadNodesAndLeafs
1363 =================
1364 */
R_LoadNodesAndLeafs(lump_t * nodeLump,lump_t * leafLump)1365 static	void R_LoadNodesAndLeafs (lump_t *nodeLump, lump_t *leafLump) {
1366 	int			i, j, p;
1367 	dnode_t		*in;
1368 	dleaf_t		*inLeaf;
1369 	mnode_t 	*out;
1370 	int			numNodes, numLeafs;
1371 
1372 	in = (void *)(fileBase + nodeLump->fileofs);
1373 	if (nodeLump->filelen % sizeof(dnode_t) ||
1374 		leafLump->filelen % sizeof(dleaf_t) ) {
1375 		ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
1376 	}
1377 	numNodes = nodeLump->filelen / sizeof(dnode_t);
1378 	numLeafs = leafLump->filelen / sizeof(dleaf_t);
1379 
1380 	out = ri.Hunk_Alloc ( (numNodes + numLeafs) * sizeof(*out), h_low);
1381 
1382 	s_worldData.nodes = out;
1383 	s_worldData.numnodes = numNodes + numLeafs;
1384 	s_worldData.numDecisionNodes = numNodes;
1385 
1386 	// load nodes
1387 	for ( i=0 ; i<numNodes; i++, in++, out++)
1388 	{
1389 		for (j=0 ; j<3 ; j++)
1390 		{
1391 			out->mins[j] = LittleLong (in->mins[j]);
1392 			out->maxs[j] = LittleLong (in->maxs[j]);
1393 		}
1394 
1395 		p = LittleLong(in->planeNum);
1396 		out->plane = s_worldData.planes + p;
1397 
1398 		out->contents = CONTENTS_NODE;	// differentiate from leafs
1399 
1400 		for (j=0 ; j<2 ; j++)
1401 		{
1402 			p = LittleLong (in->children[j]);
1403 			if (p >= 0)
1404 				out->children[j] = s_worldData.nodes + p;
1405 			else
1406 				out->children[j] = s_worldData.nodes + numNodes + (-1 - p);
1407 		}
1408 	}
1409 
1410 	// load leafs
1411 	inLeaf = (void *)(fileBase + leafLump->fileofs);
1412 	for ( i=0 ; i<numLeafs ; i++, inLeaf++, out++)
1413 	{
1414 		for (j=0 ; j<3 ; j++)
1415 		{
1416 			out->mins[j] = LittleLong (inLeaf->mins[j]);
1417 			out->maxs[j] = LittleLong (inLeaf->maxs[j]);
1418 		}
1419 
1420 		out->cluster = LittleLong(inLeaf->cluster);
1421 		out->area = LittleLong(inLeaf->area);
1422 
1423 		if ( out->cluster >= s_worldData.numClusters ) {
1424 			s_worldData.numClusters = out->cluster + 1;
1425 		}
1426 
1427 		out->firstmarksurface = s_worldData.marksurfaces +
1428 			LittleLong(inLeaf->firstLeafSurface);
1429 		out->nummarksurfaces = LittleLong(inLeaf->numLeafSurfaces);
1430 	}
1431 
1432 	// chain decendants
1433 	R_SetParent (s_worldData.nodes, NULL);
1434 }
1435 
1436 //=============================================================================
1437 
1438 /*
1439 =================
1440 R_LoadShaders
1441 =================
1442 */
R_LoadShaders(lump_t * l)1443 static	void R_LoadShaders( lump_t *l ) {
1444 	int		i, count;
1445 	dshader_t	*in, *out;
1446 
1447 	in = (void *)(fileBase + l->fileofs);
1448 	if (l->filelen % sizeof(*in))
1449 		ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
1450 	count = l->filelen / sizeof(*in);
1451 	out = ri.Hunk_Alloc ( count*sizeof(*out), h_low );
1452 
1453 	s_worldData.shaders = out;
1454 	s_worldData.numShaders = count;
1455 
1456 	Com_Memcpy( out, in, count*sizeof(*out) );
1457 
1458 	for ( i=0 ; i<count ; i++ ) {
1459 		out[i].surfaceFlags = LittleLong( out[i].surfaceFlags );
1460 		out[i].contentFlags = LittleLong( out[i].contentFlags );
1461 	}
1462 }
1463 
1464 
1465 /*
1466 =================
1467 R_LoadMarksurfaces
1468 =================
1469 */
R_LoadMarksurfaces(lump_t * l)1470 static	void R_LoadMarksurfaces (lump_t *l)
1471 {
1472 	int		i, j, count;
1473 	int		*in;
1474 	msurface_t **out;
1475 
1476 	in = (void *)(fileBase + l->fileofs);
1477 	if (l->filelen % sizeof(*in))
1478 		ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
1479 	count = l->filelen / sizeof(*in);
1480 	out = ri.Hunk_Alloc ( count*sizeof(*out), h_low);
1481 
1482 	s_worldData.marksurfaces = out;
1483 	s_worldData.nummarksurfaces = count;
1484 
1485 	for ( i=0 ; i<count ; i++)
1486 	{
1487 		j = LittleLong(in[i]);
1488 		out[i] = s_worldData.surfaces + j;
1489 	}
1490 }
1491 
1492 
1493 /*
1494 =================
1495 R_LoadPlanes
1496 =================
1497 */
R_LoadPlanes(lump_t * l)1498 static	void R_LoadPlanes( lump_t *l ) {
1499 	int			i, j;
1500 	cplane_t	*out;
1501 	dplane_t 	*in;
1502 	int			count;
1503 	int			bits;
1504 
1505 	in = (void *)(fileBase + l->fileofs);
1506 	if (l->filelen % sizeof(*in))
1507 		ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
1508 	count = l->filelen / sizeof(*in);
1509 	out = ri.Hunk_Alloc ( count*2*sizeof(*out), h_low);
1510 
1511 	s_worldData.planes = out;
1512 	s_worldData.numplanes = count;
1513 
1514 	for ( i=0 ; i<count ; i++, in++, out++) {
1515 		bits = 0;
1516 		for (j=0 ; j<3 ; j++) {
1517 			out->normal[j] = LittleFloat (in->normal[j]);
1518 			if (out->normal[j] < 0) {
1519 				bits |= 1<<j;
1520 			}
1521 		}
1522 
1523 		out->dist = LittleFloat (in->dist);
1524 		out->type = PlaneTypeForNormal( out->normal );
1525 		out->signbits = bits;
1526 	}
1527 }
1528 
1529 /*
1530 =================
1531 R_LoadFogs
1532 
1533 =================
1534 */
R_LoadFogs(lump_t * l,lump_t * brushesLump,lump_t * sidesLump)1535 static	void R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump ) {
1536 	int			i;
1537 	fog_t		*out;
1538 	dfog_t		*fogs;
1539 	dbrush_t 	*brushes, *brush;
1540 	dbrushside_t	*sides;
1541 	int			count, brushesCount, sidesCount;
1542 	int			sideNum;
1543 	int			planeNum;
1544 	shader_t	*shader;
1545 	float		d;
1546 	int			firstSide;
1547 
1548 	fogs = (void *)(fileBase + l->fileofs);
1549 	if (l->filelen % sizeof(*fogs)) {
1550 		ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
1551 	}
1552 	count = l->filelen / sizeof(*fogs);
1553 
1554 	// create fog strucutres for them
1555 	s_worldData.numfogs = count + 1;
1556 	s_worldData.fogs = ri.Hunk_Alloc ( s_worldData.numfogs*sizeof(*out), h_low);
1557 	out = s_worldData.fogs + 1;
1558 
1559 	if ( !count ) {
1560 		return;
1561 	}
1562 
1563 	brushes = (void *)(fileBase + brushesLump->fileofs);
1564 	if (brushesLump->filelen % sizeof(*brushes)) {
1565 		ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
1566 	}
1567 	brushesCount = brushesLump->filelen / sizeof(*brushes);
1568 
1569 	sides = (void *)(fileBase + sidesLump->fileofs);
1570 	if (sidesLump->filelen % sizeof(*sides)) {
1571 		ri.Error (ERR_DROP, "LoadMap: funny lump size in %s",s_worldData.name);
1572 	}
1573 	sidesCount = sidesLump->filelen / sizeof(*sides);
1574 
1575 	for ( i=0 ; i<count ; i++, fogs++) {
1576 		out->originalBrushNumber = LittleLong( fogs->brushNum );
1577 
1578 		if ( (unsigned)out->originalBrushNumber >= brushesCount ) {
1579 			ri.Error( ERR_DROP, "fog brushNumber out of range" );
1580 		}
1581 		brush = brushes + out->originalBrushNumber;
1582 
1583 		firstSide = LittleLong( brush->firstSide );
1584 
1585 			if ( (unsigned)firstSide > sidesCount - 6 ) {
1586 			ri.Error( ERR_DROP, "fog brush sideNumber out of range" );
1587 		}
1588 
1589 		// brushes are always sorted with the axial sides first
1590 		sideNum = firstSide + 0;
1591 		planeNum = LittleLong( sides[ sideNum ].planeNum );
1592 		out->bounds[0][0] = -s_worldData.planes[ planeNum ].dist;
1593 
1594 		sideNum = firstSide + 1;
1595 		planeNum = LittleLong( sides[ sideNum ].planeNum );
1596 		out->bounds[1][0] = s_worldData.planes[ planeNum ].dist;
1597 
1598 		sideNum = firstSide + 2;
1599 		planeNum = LittleLong( sides[ sideNum ].planeNum );
1600 		out->bounds[0][1] = -s_worldData.planes[ planeNum ].dist;
1601 
1602 		sideNum = firstSide + 3;
1603 		planeNum = LittleLong( sides[ sideNum ].planeNum );
1604 		out->bounds[1][1] = s_worldData.planes[ planeNum ].dist;
1605 
1606 		sideNum = firstSide + 4;
1607 		planeNum = LittleLong( sides[ sideNum ].planeNum );
1608 		out->bounds[0][2] = -s_worldData.planes[ planeNum ].dist;
1609 
1610 		sideNum = firstSide + 5;
1611 		planeNum = LittleLong( sides[ sideNum ].planeNum );
1612 		out->bounds[1][2] = s_worldData.planes[ planeNum ].dist;
1613 
1614 		// get information from the shader for fog parameters
1615 		shader = R_FindShader( fogs->shader, LIGHTMAP_NONE, qtrue );
1616 
1617 		out->parms = shader->fogParms;
1618 
1619 		out->colorInt = ColorBytes4 ( shader->fogParms.color[0] * tr.identityLight,
1620 			                          shader->fogParms.color[1] * tr.identityLight,
1621 			                          shader->fogParms.color[2] * tr.identityLight, 1.0 );
1622 
1623 		d = shader->fogParms.depthForOpaque < 1 ? 1 : shader->fogParms.depthForOpaque;
1624 		out->tcScale = 1.0f / ( d * 8 );
1625 
1626 		// set the gradient vector
1627 		sideNum = LittleLong( fogs->visibleSide );
1628 
1629 		if ( sideNum == -1 ) {
1630 			out->hasSurface = qfalse;
1631 		} else {
1632 			out->hasSurface = qtrue;
1633 			planeNum = LittleLong( sides[ firstSide + sideNum ].planeNum );
1634 			VectorSubtract( vec3_origin, s_worldData.planes[ planeNum ].normal, out->surface );
1635 			out->surface[3] = -s_worldData.planes[ planeNum ].dist;
1636 		}
1637 
1638 		out++;
1639 	}
1640 
1641 }
1642 
1643 
1644 /*
1645 ================
1646 R_LoadLightGrid
1647 
1648 ================
1649 */
R_LoadLightGrid(lump_t * l)1650 void R_LoadLightGrid( lump_t *l ) {
1651 	int		i;
1652 	vec3_t	maxs;
1653 	int		numGridPoints;
1654 	world_t	*w;
1655 	float	*wMins, *wMaxs;
1656 
1657 	w = &s_worldData;
1658 
1659 	w->lightGridInverseSize[0] = 1.0f / w->lightGridSize[0];
1660 	w->lightGridInverseSize[1] = 1.0f / w->lightGridSize[1];
1661 	w->lightGridInverseSize[2] = 1.0f / w->lightGridSize[2];
1662 
1663 	wMins = w->bmodels[0].bounds[0];
1664 	wMaxs = w->bmodels[0].bounds[1];
1665 
1666 	for ( i = 0 ; i < 3 ; i++ ) {
1667 		w->lightGridOrigin[i] = w->lightGridSize[i] * ceil( wMins[i] / w->lightGridSize[i] );
1668 		maxs[i] = w->lightGridSize[i] * floor( wMaxs[i] / w->lightGridSize[i] );
1669 		w->lightGridBounds[i] = (maxs[i] - w->lightGridOrigin[i])/w->lightGridSize[i] + 1;
1670 	}
1671 
1672 	numGridPoints = w->lightGridBounds[0] * w->lightGridBounds[1] * w->lightGridBounds[2];
1673 
1674 	if ( l->filelen != numGridPoints * 8 ) {
1675 		ri.Printf( PRINT_WARNING, "WARNING: light grid mismatch\n" );
1676 		w->lightGridData = NULL;
1677 		return;
1678 	}
1679 
1680 	w->lightGridData = ri.Hunk_Alloc( l->filelen, h_low );
1681 	Com_Memcpy( w->lightGridData, (void *)(fileBase + l->fileofs), l->filelen );
1682 
1683 	// deal with overbright bits
1684 	for ( i = 0 ; i < numGridPoints ; i++ ) {
1685 		R_ColorShiftLightingBytes( &w->lightGridData[i*8], &w->lightGridData[i*8] );
1686 		R_ColorShiftLightingBytes( &w->lightGridData[i*8+3], &w->lightGridData[i*8+3] );
1687 	}
1688 }
1689 
1690 /*
1691 ================
1692 R_LoadEntities
1693 ================
1694 */
R_LoadEntities(lump_t * l)1695 void R_LoadEntities( lump_t *l ) {
1696 	char *p, *token, *s;
1697 	char keyname[MAX_TOKEN_CHARS];
1698 	char value[MAX_TOKEN_CHARS];
1699 	world_t	*w;
1700 
1701 	w = &s_worldData;
1702 	w->lightGridSize[0] = 64;
1703 	w->lightGridSize[1] = 64;
1704 	w->lightGridSize[2] = 128;
1705 
1706 	p = (char *)(fileBase + l->fileofs);
1707 
1708 	// store for reference by the cgame
1709 	w->entityString = ri.Hunk_Alloc( l->filelen + 1, h_low );
1710 	strcpy( w->entityString, p );
1711 	w->entityParsePoint = w->entityString;
1712 
1713 	token = COM_ParseExt( &p, qtrue );
1714 	if (!*token || *token != '{') {
1715 		return;
1716 	}
1717 
1718 	// only parse the world spawn
1719 	while ( 1 ) {
1720 		// parse key
1721 		token = COM_ParseExt( &p, qtrue );
1722 
1723 		if ( !*token || *token == '}' ) {
1724 			break;
1725 		}
1726 		Q_strncpyz(keyname, token, sizeof(keyname));
1727 
1728 		// parse value
1729 		token = COM_ParseExt( &p, qtrue );
1730 
1731 		if ( !*token || *token == '}' ) {
1732 			break;
1733 		}
1734 		Q_strncpyz(value, token, sizeof(value));
1735 
1736 		// check for remapping of shaders for vertex lighting
1737 		s = "vertexremapshader";
1738 		if (!Q_strncmp(keyname, s, strlen(s)) ) {
1739 			s = strchr(value, ';');
1740 			if (!s) {
1741 				ri.Printf( PRINT_WARNING, "WARNING: no semi colon in vertexshaderremap '%s'\n", value );
1742 				break;
1743 			}
1744 			*s++ = 0;
1745 			if (r_vertexLight->integer) {
1746 				R_RemapShader(value, s, "0");
1747 			}
1748 			continue;
1749 		}
1750 		// check for remapping of shaders
1751 		s = "remapshader";
1752 		if (!Q_strncmp(keyname, s, strlen(s)) ) {
1753 			s = strchr(value, ';');
1754 			if (!s) {
1755 				ri.Printf( PRINT_WARNING, "WARNING: no semi colon in shaderremap '%s'\n", value );
1756 				break;
1757 			}
1758 			*s++ = 0;
1759 			R_RemapShader(value, s, "0");
1760 			continue;
1761 		}
1762 		// check for a different grid size
1763 		if (!Q_stricmp(keyname, "gridsize")) {
1764 			sscanf(value, "%f %f %f", &w->lightGridSize[0], &w->lightGridSize[1], &w->lightGridSize[2] );
1765 			continue;
1766 		}
1767 	}
1768 }
1769 
1770 /*
1771 =================
1772 R_GetEntityToken
1773 =================
1774 */
R_GetEntityToken(char * buffer,int size)1775 qboolean R_GetEntityToken( char *buffer, int size ) {
1776 	const char	*s;
1777 
1778 	s = COM_Parse( &s_worldData.entityParsePoint );
1779 	Q_strncpyz( buffer, s, size );
1780 	if ( !s_worldData.entityParsePoint || !s[0] ) {
1781 		s_worldData.entityParsePoint = s_worldData.entityString;
1782 		return qfalse;
1783 	} else {
1784 		return qtrue;
1785 	}
1786 }
1787 
1788 /*
1789 =================
1790 RE_LoadWorldMap
1791 
1792 Called directly from cgame
1793 =================
1794 */
RE_LoadWorldMap(const char * name)1795 void RE_LoadWorldMap( const char *name ) {
1796 	int			i;
1797 	dheader_t	*header;
1798 	union {
1799 		byte *b;
1800 		void *v;
1801 	} buffer;
1802 	byte		*startMarker;
1803 
1804 	if ( tr.worldMapLoaded ) {
1805 		ri.Error( ERR_DROP, "ERROR: attempted to redundantly load world map\n" );
1806 	}
1807 
1808 	// set default sun direction to be used if it isn't
1809 	// overridden by a shader
1810 	tr.sunDirection[0] = 0.45f;
1811 	tr.sunDirection[1] = 0.3f;
1812 	tr.sunDirection[2] = 0.9f;
1813 
1814 	VectorNormalize( tr.sunDirection );
1815 
1816 	tr.worldMapLoaded = qtrue;
1817 
1818 	// load it
1819     ri.FS_ReadFile( name, &buffer.v );
1820 	if ( !buffer.b ) {
1821 		ri.Error (ERR_DROP, "RE_LoadWorldMap: %s not found", name);
1822 	}
1823 
1824 	// clear tr.world so if the level fails to load, the next
1825 	// try will not look at the partially loaded version
1826 	tr.world = NULL;
1827 
1828 	Com_Memset( &s_worldData, 0, sizeof( s_worldData ) );
1829 	Q_strncpyz( s_worldData.name, name, sizeof( s_worldData.name ) );
1830 
1831 	Q_strncpyz( s_worldData.baseName, COM_SkipPath( s_worldData.name ), sizeof( s_worldData.name ) );
1832 	COM_StripExtension(s_worldData.baseName, s_worldData.baseName, sizeof(s_worldData.baseName));
1833 
1834 	startMarker = ri.Hunk_Alloc(0, h_low);
1835 	c_gridVerts = 0;
1836 
1837 	header = (dheader_t *)buffer.b;
1838 	fileBase = (byte *)header;
1839 
1840 	i = LittleLong (header->version);
1841 	if ( i != BSP_VERSION ) {
1842 		ri.Error (ERR_DROP, "RE_LoadWorldMap: %s has wrong version number (%i should be %i)",
1843 			name, i, BSP_VERSION);
1844 	}
1845 
1846 	// swap all the lumps
1847 	for (i=0 ; i<sizeof(dheader_t)/4 ; i++) {
1848 		((int *)header)[i] = LittleLong ( ((int *)header)[i]);
1849 	}
1850 
1851 	// load into heap
1852 	R_LoadShaders( &header->lumps[LUMP_SHADERS] );
1853 	R_LoadLightmaps( &header->lumps[LUMP_LIGHTMAPS] );
1854 	R_LoadPlanes (&header->lumps[LUMP_PLANES]);
1855 	R_LoadFogs( &header->lumps[LUMP_FOGS], &header->lumps[LUMP_BRUSHES], &header->lumps[LUMP_BRUSHSIDES] );
1856 	R_LoadSurfaces( &header->lumps[LUMP_SURFACES], &header->lumps[LUMP_DRAWVERTS], &header->lumps[LUMP_DRAWINDEXES] );
1857 	R_LoadMarksurfaces (&header->lumps[LUMP_LEAFSURFACES]);
1858 	R_LoadNodesAndLeafs (&header->lumps[LUMP_NODES], &header->lumps[LUMP_LEAFS]);
1859 	R_LoadSubmodels (&header->lumps[LUMP_MODELS]);
1860 	R_LoadVisibility( &header->lumps[LUMP_VISIBILITY] );
1861 	R_LoadEntities( &header->lumps[LUMP_ENTITIES] );
1862 	R_LoadLightGrid( &header->lumps[LUMP_LIGHTGRID] );
1863 
1864 	s_worldData.dataSize = (byte *)ri.Hunk_Alloc(0, h_low) - startMarker;
1865 
1866 	// only set tr.world now that we know the entire level has loaded properly
1867 	tr.world = &s_worldData;
1868 
1869     ri.FS_FreeFile( buffer.v );
1870 }
1871 
1872