1 /*
2 ===========================================================================
3 
4 Return to Castle Wolfenstein single player GPL Source Code
5 Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Return to Castle Wolfenstein single player GPL Source Code (“RTCW SP Source Code”).
8 
9 RTCW SP Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 RTCW SP Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with RTCW SP Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the RTCW SP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW SP Source Code.  If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 
30 #include "tr_local.h"
31 
32 /*
33 
34 This file does all of the processing necessary to turn a raw grid of points
35 read from the map file into a srfBspSurface_t ready for rendering.
36 
37 The level of detail solution is direction independent, based only on subdivided
38 distance from the true curve.
39 
40 Only a single entry point:
41 
42 srfBspSurface_t *R_SubdividePatchToGrid( int width, int height,
43 								srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) {
44 
45 */
46 
47 
48 /*
49 ============
50 LerpDrawVert
51 ============
52 */
LerpDrawVert(srfVert_t * a,srfVert_t * b,srfVert_t * out)53 static void LerpDrawVert( srfVert_t *a, srfVert_t *b, srfVert_t *out ) {
54 	out->xyz[0] = 0.5f * ( a->xyz[0] + b->xyz[0] );
55 	out->xyz[1] = 0.5f * ( a->xyz[1] + b->xyz[1] );
56 	out->xyz[2] = 0.5f * ( a->xyz[2] + b->xyz[2] );
57 
58 	out->st[0] = 0.5f * ( a->st[0] + b->st[0] );
59 	out->st[1] = 0.5f * ( a->st[1] + b->st[1] );
60 
61 	out->lightmap[0] = 0.5f * ( a->lightmap[0] + b->lightmap[0] );
62 	out->lightmap[1] = 0.5f * ( a->lightmap[1] + b->lightmap[1] );
63 
64 	out->color[0] = ((int)a->color[0] + (int)b->color[0]) >> 1;
65 	out->color[1] = ((int)a->color[1] + (int)b->color[1]) >> 1;
66 	out->color[2] = ((int)a->color[2] + (int)b->color[2]) >> 1;
67 	out->color[3] = ((int)a->color[3] + (int)b->color[3]) >> 1;
68 }
69 
70 /*
71 ============
72 Transpose
73 ============
74 */
Transpose(int width,int height,srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE])75 static void Transpose( int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
76 	int i, j;
77 	srfVert_t	temp;
78 
79 	if ( width > height ) {
80 		for ( i = 0 ; i < height ; i++ ) {
81 			for ( j = i + 1 ; j < width ; j++ ) {
82 				if ( j < height ) {
83 					// swap the value
84 					temp = ctrl[j][i];
85 					ctrl[j][i] = ctrl[i][j];
86 					ctrl[i][j] = temp;
87 				} else {
88 					// just copy
89 					ctrl[j][i] = ctrl[i][j];
90 				}
91 			}
92 		}
93 	} else {
94 		for ( i = 0 ; i < width ; i++ ) {
95 			for ( j = i + 1 ; j < height ; j++ ) {
96 				if ( j < width ) {
97 					// swap the value
98 					temp = ctrl[i][j];
99 					ctrl[i][j] = ctrl[j][i];
100 					ctrl[j][i] = temp;
101 				} else {
102 					// just copy
103 					ctrl[i][j] = ctrl[j][i];
104 				}
105 			}
106 		}
107 	}
108 
109 }
110 
111 
112 /*
113 =================
114 MakeMeshNormals
115 
116 Handles all the complicated wrapping and degenerate cases
117 =================
118 */
MakeMeshNormals(int width,int height,srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE])119 static void MakeMeshNormals( int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
120 	int i, j, k, dist;
121 	vec3_t normal;
122 	vec3_t sum;
123 	int count = 0;
124 	vec3_t base;
125 	vec3_t delta;
126 	int x, y;
127 	srfVert_t	*dv;
128 	vec3_t around[8], temp;
129 	qboolean good[8];
130 	qboolean wrapWidth, wrapHeight;
131 	float len;
132 	static int neighbors[8][2] = {
133 		{0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1}
134 	};
135 
136 	wrapWidth = qfalse;
137 	for ( i = 0 ; i < height ; i++ ) {
138 		VectorSubtract( ctrl[i][0].xyz, ctrl[i][width - 1].xyz, delta );
139 		len = VectorLengthSquared( delta );
140 		if ( len > 1.0 ) {
141 			break;
142 		}
143 	}
144 	if ( i == height ) {
145 		wrapWidth = qtrue;
146 	}
147 
148 	wrapHeight = qfalse;
149 	for ( i = 0 ; i < width ; i++ ) {
150 		VectorSubtract( ctrl[0][i].xyz, ctrl[height - 1][i].xyz, delta );
151 		len = VectorLengthSquared( delta );
152 		if ( len > 1.0 ) {
153 			break;
154 		}
155 	}
156 	if ( i == width ) {
157 		wrapHeight = qtrue;
158 	}
159 
160 
161 	for ( i = 0 ; i < width ; i++ ) {
162 		for ( j = 0 ; j < height ; j++ ) {
163 			count = 0;
164 			dv = &ctrl[j][i];
165 			VectorCopy( dv->xyz, base );
166 			for ( k = 0 ; k < 8 ; k++ ) {
167 				VectorClear( around[k] );
168 				good[k] = qfalse;
169 
170 				for ( dist = 1 ; dist <= 3 ; dist++ ) {
171 					x = i + neighbors[k][0] * dist;
172 					y = j + neighbors[k][1] * dist;
173 					if ( wrapWidth ) {
174 						if ( x < 0 ) {
175 							x = width - 1 + x;
176 						} else if ( x >= width ) {
177 							x = 1 + x - width;
178 						}
179 					}
180 					if ( wrapHeight ) {
181 						if ( y < 0 ) {
182 							y = height - 1 + y;
183 						} else if ( y >= height ) {
184 							y = 1 + y - height;
185 						}
186 					}
187 
188 					if ( x < 0 || x >= width || y < 0 || y >= height ) {
189 						break;                  // edge of patch
190 					}
191 					VectorSubtract( ctrl[y][x].xyz, base, temp );
192 					if ( VectorNormalize2( temp, temp ) == 0 ) {
193 						continue;               // degenerate edge, get more dist
194 					} else {
195 						good[k] = qtrue;
196 						VectorCopy( temp, around[k] );
197 						break;                  // good edge
198 					}
199 				}
200 			}
201 
202 			VectorClear( sum );
203 			for ( k = 0 ; k < 8 ; k++ ) {
204 				if ( !good[k] || !good[( k + 1 ) & 7] ) {
205 					continue;   // didn't get two points
206 				}
207 				CrossProduct( around[( k + 1 ) & 7], around[k], normal );
208 				if ( VectorNormalize2( normal, normal ) == 0 ) {
209 					continue;
210 				}
211 				VectorAdd( normal, sum, sum );
212 				count++;
213 			}
214 			//if ( count == 0 ) {
215 			//printf("bad normal\n");
216 			//}
217 			{
218 				vec3_t fNormal;
219 				VectorNormalize2(sum, fNormal);
220 				R_VaoPackNormal(dv->normal, fNormal);
221 			}
222 		}
223 	}
224 }
225 
MakeMeshTangentVectors(int width,int height,srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE],int numIndexes,glIndex_t indexes[(MAX_GRID_SIZE-1)* (MAX_GRID_SIZE-1)* 2* 3])226 static void MakeMeshTangentVectors(int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], int numIndexes,
227 								   glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3])
228 {
229 	int             i, j;
230 	srfVert_t      *dv[3];
231 	static srfVert_t       ctrl2[MAX_GRID_SIZE * MAX_GRID_SIZE];
232 	glIndex_t  *tri;
233 
234 	// FIXME: use more elegant way
235 	for(i = 0; i < width; i++)
236 	{
237 		for(j = 0; j < height; j++)
238 		{
239 			dv[0] = &ctrl2[j * width + i];
240 			*dv[0] = ctrl[j][i];
241 		}
242 	}
243 
244 	for(i = 0, tri = indexes; i < numIndexes; i += 3, tri += 3)
245 	{
246 		dv[0] = &ctrl2[tri[0]];
247 		dv[1] = &ctrl2[tri[1]];
248 		dv[2] = &ctrl2[tri[2]];
249 
250 		R_CalcTangentVectors(dv);
251 	}
252 
253 	for(i = 0; i < width; i++)
254 	{
255 		for(j = 0; j < height; j++)
256 		{
257 			dv[0] = &ctrl2[j * width + i];
258 			dv[1] = &ctrl[j][i];
259 
260 			VectorCopy4(dv[0]->tangent, dv[1]->tangent);
261 		}
262 	}
263 }
264 
265 
MakeMeshIndexes(int width,int height,glIndex_t indexes[(MAX_GRID_SIZE-1)* (MAX_GRID_SIZE-1)* 2* 3])266 static int MakeMeshIndexes(int width, int height, glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3])
267 {
268 	int             i, j;
269 	int             numIndexes;
270 	int             w, h;
271 
272 	h = height - 1;
273 	w = width - 1;
274 	numIndexes = 0;
275 	for(i = 0; i < h; i++)
276 	{
277 		for(j = 0; j < w; j++)
278 		{
279 			int             v1, v2, v3, v4;
280 
281 			// vertex order to be reckognized as tristrips
282 			v1 = i * width + j + 1;
283 			v2 = v1 - 1;
284 			v3 = v2 + width;
285 			v4 = v3 + 1;
286 
287 			indexes[numIndexes++] = v2;
288 			indexes[numIndexes++] = v3;
289 			indexes[numIndexes++] = v1;
290 
291 			indexes[numIndexes++] = v1;
292 			indexes[numIndexes++] = v3;
293 			indexes[numIndexes++] = v4;
294 		}
295 	}
296 
297 	return numIndexes;
298 }
299 
300 /*
301 ============
302 InvertCtrl
303 ============
304 */
InvertCtrl(int width,int height,srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE])305 static void InvertCtrl( int width, int height, srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE] ) {
306 	int i, j;
307 	srfVert_t	temp;
308 
309 	for ( i = 0 ; i < height ; i++ ) {
310 		for ( j = 0 ; j < width / 2 ; j++ ) {
311 			temp = ctrl[i][j];
312 			ctrl[i][j] = ctrl[i][width - 1 - j];
313 			ctrl[i][width - 1 - j] = temp;
314 		}
315 	}
316 }
317 
318 
319 /*
320 =================
321 InvertErrorTable
322 =================
323 */
InvertErrorTable(float errorTable[2][MAX_GRID_SIZE],int width,int height)324 static void InvertErrorTable( float errorTable[2][MAX_GRID_SIZE], int width, int height ) {
325 	int i;
326 	float copy[2][MAX_GRID_SIZE];
327 
328 	memcpy( copy, errorTable, sizeof( copy ) );
329 
330 	for ( i = 0 ; i < width ; i++ ) {
331 		errorTable[1][i] = copy[0][i];  //[width-1-i];
332 	}
333 
334 	for ( i = 0 ; i < height ; i++ ) {
335 		errorTable[0][i] = copy[1][height - 1 - i];
336 	}
337 
338 }
339 
340 /*
341 ==================
342 PutPointsOnCurve
343 ==================
344 */
PutPointsOnCurve(srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE],int width,int height)345 static void PutPointsOnCurve( srfVert_t	ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE],
346 							  int width, int height ) {
347 	int i, j;
348 	srfVert_t	prev, next;
349 
350 	for ( i = 0 ; i < width ; i++ ) {
351 		for ( j = 1 ; j < height ; j += 2 ) {
352 			LerpDrawVert( &ctrl[j][i], &ctrl[j + 1][i], &prev );
353 			LerpDrawVert( &ctrl[j][i], &ctrl[j - 1][i], &next );
354 			LerpDrawVert( &prev, &next, &ctrl[j][i] );
355 		}
356 	}
357 
358 
359 	for ( j = 0 ; j < height ; j++ ) {
360 		for ( i = 1 ; i < width ; i += 2 ) {
361 			LerpDrawVert( &ctrl[j][i], &ctrl[j][i + 1], &prev );
362 			LerpDrawVert( &ctrl[j][i], &ctrl[j][i - 1], &next );
363 			LerpDrawVert( &prev, &next, &ctrl[j][i] );
364 		}
365 	}
366 }
367 
368 
369 /*
370 =================
371 R_CreateSurfaceGridMesh
372 =================
373 */
R_CreateSurfaceGridMesh(srfBspSurface_t * grid,int width,int height,srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE],float errorTable[2][MAX_GRID_SIZE],int numIndexes,glIndex_t indexes[(MAX_GRID_SIZE-1)* (MAX_GRID_SIZE-1)* 2* 3])374 void R_CreateSurfaceGridMesh(srfBspSurface_t *grid, int width, int height,
375 								srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE], float errorTable[2][MAX_GRID_SIZE],
376 								int numIndexes, glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3]) {
377 	int i, j;
378 	srfVert_t	*vert;
379 	vec3_t tmpVec;
380 
381 	// copy the results out to a grid
382 	Com_Memset(grid, 0, sizeof(*grid));
383 
384 #ifdef PATCH_STITCHING
385 	grid->widthLodError = malloc( width * 4 );
386 	memcpy( grid->widthLodError, errorTable[0], width * 4 );
387 
388 	grid->heightLodError = malloc( height * 4 );
389 	memcpy( grid->heightLodError, errorTable[1], height * 4 );
390 
391 	grid->numIndexes = numIndexes;
392 	grid->indexes = ri.Z_Malloc(grid->numIndexes * sizeof(glIndex_t));
393 	Com_Memcpy(grid->indexes, indexes, numIndexes * sizeof(glIndex_t));
394 
395 	grid->numVerts = (width * height);
396 	grid->verts = ri.Z_Malloc(grid->numVerts * sizeof(srfVert_t));
397 #else
398 	grid->widthLodError = ri.Hunk_Alloc( width * 4, h_low );
399 	memcpy( grid->widthLodError, errorTable[0], width * 4 );
400 
401 	grid->heightLodError = ri.Hunk_Alloc( height * 4, h_low );
402 	memcpy( grid->heightLodError, errorTable[1], height * 4 );
403 
404 	grid->numIndexes = numIndexes;
405 	grid->indexes = ri.Hunk_Alloc(grid->numIndexes * sizeof(glIndex_t), h_low);
406 	Com_Memcpy(grid->indexes, indexes, numIndexes * sizeof(glIndex_t));
407 
408 	grid->numVerts = (width * height);
409 	grid->verts = ri.Hunk_Alloc(grid->numVerts * sizeof(srfVert_t), h_low);
410 #endif
411 
412 	grid->width = width;
413 	grid->height = height;
414 	grid->surfaceType = SF_GRID;
415 	ClearBounds( grid->cullBounds[0], grid->cullBounds[1] );
416 	for ( i = 0 ; i < width ; i++ ) {
417 		for ( j = 0 ; j < height ; j++ ) {
418 			vert = &grid->verts[j * width + i];
419 			*vert = ctrl[j][i];
420 			AddPointToBounds( vert->xyz, grid->cullBounds[0], grid->cullBounds[1] );
421 		}
422 	}
423 
424 	// compute local origin and bounds
425 	VectorAdd( grid->cullBounds[0], grid->cullBounds[1], grid->cullOrigin );
426 	VectorScale( grid->cullOrigin, 0.5f, grid->cullOrigin );
427 	VectorSubtract( grid->cullBounds[0], grid->cullOrigin, tmpVec );
428 	grid->cullRadius = VectorLength( tmpVec );
429 
430 	VectorCopy( grid->cullOrigin, grid->lodOrigin );
431 	grid->lodRadius = grid->cullRadius;
432 	//
433 }
434 
435 /*
436 =================
437 R_FreeSurfaceGridMeshData
438 =================
439 */
R_FreeSurfaceGridMeshData(srfBspSurface_t * grid)440 static void R_FreeSurfaceGridMeshData( srfBspSurface_t *grid ) {
441 	ri.Free( grid->widthLodError );
442 	ri.Free( grid->heightLodError );
443 	ri.Free( grid->indexes );
444 	ri.Free( grid->verts );
445 }
446 
447 /*
448 =================
449 R_SubdividePatchToGrid
450 =================
451 */
R_SubdividePatchToGrid(srfBspSurface_t * grid,int width,int height,srfVert_t points[MAX_PATCH_SIZE * MAX_PATCH_SIZE])452 void R_SubdividePatchToGrid( srfBspSurface_t *grid, int width, int height,
453 								srfVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE] ) {
454 	int i, j, k, l;
455 	srfVert_t_cleared( prev );
456 	srfVert_t_cleared( next );
457 	srfVert_t_cleared( mid );
458 	float len, maxLen;
459 	int dir;
460 	int t;
461 	srfVert_t	ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
462 	float errorTable[2][MAX_GRID_SIZE];
463 	int			numIndexes;
464 	static glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3];
465 	int consecutiveComplete;
466 
467 	for ( i = 0 ; i < width ; i++ ) {
468 		for ( j = 0 ; j < height ; j++ ) {
469 			ctrl[j][i] = points[j * width + i];
470 		}
471 	}
472 
473 	for ( dir = 0 ; dir < 2 ; dir++ ) {
474 
475 		for ( j = 0 ; j < MAX_GRID_SIZE ; j++ ) {
476 			errorTable[dir][j] = 0;
477 		}
478 
479 		consecutiveComplete = 0;
480 
481 		// horizontal subdivisions
482 		for ( j = 0 ; ; j = (j + 2) % (width - 1) ) {
483 			// check subdivided midpoints against control points
484 
485 			// FIXME: also check midpoints of adjacent patches against the control points
486 			// this would basically stitch all patches in the same LOD group together.
487 
488 			maxLen = 0;
489 			for ( i = 0 ; i < height ; i++ ) {
490 				vec3_t midxyz;
491 				vec3_t dir;
492 				vec3_t projected;
493 				float d;
494 
495 				// calculate the point on the curve
496 				for ( l = 0 ; l < 3 ; l++ ) {
497 					midxyz[l] = ( ctrl[i][j].xyz[l] + ctrl[i][j + 1].xyz[l] * 2
498 								  + ctrl[i][j + 2].xyz[l] ) * 0.25f;
499 				}
500 
501 				// see how far off the line it is
502 				// using dist-from-line will not account for internal
503 				// texture warping, but it gives a lot less polygons than
504 				// dist-from-midpoint
505 				VectorSubtract( midxyz, ctrl[i][j].xyz, midxyz );
506 				VectorSubtract( ctrl[i][j + 2].xyz, ctrl[i][j].xyz, dir );
507 				VectorNormalize( dir );
508 
509 				d = DotProduct( midxyz, dir );
510 				VectorScale( dir, d, projected );
511 				VectorSubtract( midxyz, projected, midxyz );
512 				len = VectorLengthSquared( midxyz );            // we will do the sqrt later
513 
514 				if ( len > maxLen ) {
515 					maxLen = len;
516 				}
517 			}
518 
519 			maxLen = sqrt( maxLen );
520 			// if all the points are on the lines, remove the entire columns
521 			if ( maxLen < 0.1f ) {
522 				errorTable[dir][j + 1] = 999;
523 				// if we go over the whole grid twice without adding any columns, stop
524 				if (++consecutiveComplete >= width)
525 					break;
526 				continue;
527 			}
528 
529 			// see if we want to insert subdivided columns
530 			if ( width + 2 > MAX_GRID_SIZE ) {
531 				errorTable[dir][j + 1] = 1.0f / maxLen;
532 				break;   // can't subdivide any more
533 			}
534 
535 			if ( maxLen <= r_subdivisions->value ) {
536 				errorTable[dir][j + 1] = 1.0f / maxLen;
537 				// if we go over the whole grid twice without adding any columns, stop
538 				if (++consecutiveComplete >= width)
539 					break;
540 				continue;   // didn't need subdivision
541 			}
542 
543 			errorTable[dir][j + 2] = 1.0f / maxLen;
544 
545 			consecutiveComplete = 0;
546 
547 			// insert two columns and replace the peak
548 			width += 2;
549 			for ( i = 0 ; i < height ; i++ ) {
550 				LerpDrawVert( &ctrl[i][j], &ctrl[i][j + 1], &prev );
551 				LerpDrawVert( &ctrl[i][j + 1], &ctrl[i][j + 2], &next );
552 				LerpDrawVert( &prev, &next, &mid );
553 
554 				for ( k = width - 1 ; k > j + 3 ; k-- ) {
555 					ctrl[i][k] = ctrl[i][k - 2];
556 				}
557 				ctrl[i][j + 1] = prev;
558 				ctrl[i][j + 2] = mid;
559 				ctrl[i][j + 3] = next;
560 			}
561 
562 			// skip the new one, we'll get it on the next pass
563 			j += 2;
564 		}
565 
566 		Transpose( width, height, ctrl );
567 		t = width;
568 		width = height;
569 		height = t;
570 	}
571 
572 
573 	// put all the aproximating points on the curve
574 	PutPointsOnCurve( ctrl, width, height );
575 
576 	// cull out any rows or columns that are colinear
577 	for ( i = 1 ; i < width - 1 ; i++ ) {
578 		if ( errorTable[0][i] != 999 ) {
579 			continue;
580 		}
581 		for ( j = i + 1 ; j < width ; j++ ) {
582 			for ( k = 0 ; k < height ; k++ ) {
583 				ctrl[k][j - 1] = ctrl[k][j];
584 			}
585 			errorTable[0][j - 1] = errorTable[0][j];
586 		}
587 		width--;
588 	}
589 
590 	for ( i = 1 ; i < height - 1 ; i++ ) {
591 		if ( errorTable[1][i] != 999 ) {
592 			continue;
593 		}
594 		for ( j = i + 1 ; j < height ; j++ ) {
595 			for ( k = 0 ; k < width ; k++ ) {
596 				ctrl[j - 1][k] = ctrl[j][k];
597 			}
598 			errorTable[1][j - 1] = errorTable[1][j];
599 		}
600 		height--;
601 	}
602 
603 #if 1
604 	// flip for longest tristrips as an optimization
605 	// the results should be visually identical with or
606 	// without this step
607 	if ( height > width ) {
608 		Transpose( width, height, ctrl );
609 		InvertErrorTable( errorTable, width, height );
610 		t = width;
611 		width = height;
612 		height = t;
613 		InvertCtrl( width, height, ctrl );
614 	}
615 #endif
616 
617 	// calculate indexes
618 	numIndexes = MakeMeshIndexes(width, height, indexes);
619 
620 	// calculate normals
621 	MakeMeshNormals( width, height, ctrl );
622 	MakeMeshTangentVectors(width, height, ctrl, numIndexes, indexes);
623 
624 	R_CreateSurfaceGridMesh(grid, width, height, ctrl, errorTable, numIndexes, indexes);
625 }
626 
627 /*
628 ===============
629 R_GridInsertColumn
630 ===============
631 */
R_GridInsertColumn(srfBspSurface_t * grid,int column,int row,vec3_t point,float loderror)632 void R_GridInsertColumn( srfBspSurface_t *grid, int column, int row, vec3_t point, float loderror ) {
633 	int i, j;
634 	int width, height, oldwidth;
635 	srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
636 	float errorTable[2][MAX_GRID_SIZE];
637 	float lodRadius;
638 	vec3_t lodOrigin;
639 	int    numIndexes;
640 	static glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3];
641 
642 	oldwidth = 0;
643 	width = grid->width + 1;
644 	if ( width > MAX_GRID_SIZE ) {
645 		return;
646 	}
647 	height = grid->height;
648 	for ( i = 0; i < width; i++ ) {
649 		if ( i == column ) {
650 			//insert new column
651 			for ( j = 0; j < grid->height; j++ ) {
652 				LerpDrawVert( &grid->verts[j * grid->width + i - 1], &grid->verts[j * grid->width + i], &ctrl[j][i] );
653 				if ( j == row ) {
654 					VectorCopy( point, ctrl[j][i].xyz );
655 				}
656 			}
657 			errorTable[0][i] = loderror;
658 			continue;
659 		}
660 		errorTable[0][i] = grid->widthLodError[oldwidth];
661 		for ( j = 0; j < grid->height; j++ ) {
662 			ctrl[j][i] = grid->verts[j * grid->width + oldwidth];
663 		}
664 		oldwidth++;
665 	}
666 	for ( j = 0; j < grid->height; j++ ) {
667 		errorTable[1][j] = grid->heightLodError[j];
668 	}
669 	// put all the aproximating points on the curve
670 	//PutPointsOnCurve( ctrl, width, height );
671 
672 	// calculate indexes
673 	numIndexes = MakeMeshIndexes(width, height, indexes);
674 
675 	// calculate normals
676 	MakeMeshNormals( width, height, ctrl );
677 	MakeMeshTangentVectors(width, height, ctrl, numIndexes, indexes);
678 
679 	VectorCopy( grid->lodOrigin, lodOrigin );
680 	lodRadius = grid->lodRadius;
681 	// free the old grid
682 	R_FreeSurfaceGridMeshData(grid);
683 	// create a new grid
684 	R_CreateSurfaceGridMesh(grid, width, height, ctrl, errorTable, numIndexes, indexes);
685 	grid->lodRadius = lodRadius;
686 	VectorCopy( lodOrigin, grid->lodOrigin );
687 }
688 
689 /*
690 ===============
691 R_GridInsertRow
692 ===============
693 */
R_GridInsertRow(srfBspSurface_t * grid,int row,int column,vec3_t point,float loderror)694 void R_GridInsertRow( srfBspSurface_t *grid, int row, int column, vec3_t point, float loderror ) {
695 	int i, j;
696 	int width, height, oldheight;
697 	srfVert_t ctrl[MAX_GRID_SIZE][MAX_GRID_SIZE];
698 	float errorTable[2][MAX_GRID_SIZE];
699 	float lodRadius;
700 	vec3_t lodOrigin;
701 	int             numIndexes;
702 	static glIndex_t indexes[(MAX_GRID_SIZE-1)*(MAX_GRID_SIZE-1)*2*3];
703 
704 	oldheight = 0;
705 	width = grid->width;
706 	height = grid->height + 1;
707 	if ( height > MAX_GRID_SIZE ) {
708 		return;
709 	}
710 	for ( i = 0; i < height; i++ ) {
711 		if ( i == row ) {
712 			//insert new row
713 			for ( j = 0; j < grid->width; j++ ) {
714 				LerpDrawVert( &grid->verts[( i - 1 ) * grid->width + j], &grid->verts[i * grid->width + j], &ctrl[i][j] );
715 				if ( j == column ) {
716 					VectorCopy( point, ctrl[i][j].xyz );
717 				}
718 			}
719 			errorTable[1][i] = loderror;
720 			continue;
721 		}
722 		errorTable[1][i] = grid->heightLodError[oldheight];
723 		for ( j = 0; j < grid->width; j++ ) {
724 			ctrl[i][j] = grid->verts[oldheight * grid->width + j];
725 		}
726 		oldheight++;
727 	}
728 	for ( j = 0; j < grid->width; j++ ) {
729 		errorTable[0][j] = grid->widthLodError[j];
730 	}
731 	// put all the aproximating points on the curve
732 	//PutPointsOnCurve( ctrl, width, height );
733 
734 	// calculate indexes
735 	numIndexes = MakeMeshIndexes(width, height, indexes);
736 
737 	// calculate normals
738 	MakeMeshNormals( width, height, ctrl );
739 	MakeMeshTangentVectors(width, height, ctrl, numIndexes, indexes);
740 
741 	VectorCopy( grid->lodOrigin, lodOrigin );
742 	lodRadius = grid->lodRadius;
743 	// free the old grid
744 	R_FreeSurfaceGridMeshData(grid);
745 	// create a new grid
746 	R_CreateSurfaceGridMesh(grid, width, height, ctrl, errorTable, numIndexes, indexes);
747 	grid->lodRadius = lodRadius;
748 	VectorCopy( lodOrigin, grid->lodOrigin );
749 }
750 
751