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