r_misc.c (14934B)
1 /* 2 Copyright (C) 1997-2001 Id Software, Inc. 3 4 This program is free software; you can redistribute it and/or 5 modify it under the terms of the GNU General Public License 6 as published by the Free Software Foundation; either version 2 7 of the License, or (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13 See the GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19 */ 20 // r_misc.c 21 22 #include "r_local.h" 23 24 #define NUM_MIPS 4 25 26 cvar_t *sw_mipcap; 27 cvar_t *sw_mipscale; 28 29 surfcache_t *d_initial_rover; 30 qboolean d_roverwrapped; 31 int d_minmip; 32 float d_scalemip[NUM_MIPS-1]; 33 34 static float basemip[NUM_MIPS-1] = {1.0, 0.5*0.8, 0.25*0.8}; 35 36 extern int d_aflatcolor; 37 38 int d_vrectx, d_vrecty, d_vrectright_particle, d_vrectbottom_particle; 39 40 int d_pix_min, d_pix_max, d_pix_shift; 41 42 int d_scantable[MAXHEIGHT]; 43 short *zspantable[MAXHEIGHT]; 44 45 /* 46 ================ 47 D_Patch 48 ================ 49 */ 50 void D_Patch (void) 51 { 52 #if id386 53 extern void D_Aff8Patch( void ); 54 static qboolean protectset8 = false; 55 extern void D_PolysetAff8Start( void ); 56 57 if (!protectset8) 58 { 59 Sys_MakeCodeWriteable ((int)D_PolysetAff8Start, 60 (int)D_Aff8Patch - (int)D_PolysetAff8Start); 61 Sys_MakeCodeWriteable ((long)R_Surf8Start, 62 (long)R_Surf8End - (long)R_Surf8Start); 63 protectset8 = true; 64 } 65 colormap = vid.colormap; 66 67 R_Surf8Patch (); 68 D_Aff8Patch(); 69 #endif 70 } 71 /* 72 ================ 73 D_ViewChanged 74 ================ 75 */ 76 unsigned char *alias_colormap; 77 78 void D_ViewChanged (void) 79 { 80 int i; 81 82 scale_for_mip = xscale; 83 if (yscale > xscale) 84 scale_for_mip = yscale; 85 86 d_zrowbytes = vid.width * 2; 87 d_zwidth = vid.width; 88 89 d_pix_min = r_refdef.vrect.width / 320; 90 if (d_pix_min < 1) 91 d_pix_min = 1; 92 93 d_pix_max = (int)((float)r_refdef.vrect.width / (320.0 / 4.0) + 0.5); 94 d_pix_shift = 8 - (int)((float)r_refdef.vrect.width / 320.0 + 0.5); 95 if (d_pix_max < 1) 96 d_pix_max = 1; 97 98 d_vrectx = r_refdef.vrect.x; 99 d_vrecty = r_refdef.vrect.y; 100 d_vrectright_particle = r_refdef.vrectright - d_pix_max; 101 d_vrectbottom_particle = 102 r_refdef.vrectbottom - d_pix_max; 103 104 for (i=0 ; i<vid.height; i++) 105 { 106 d_scantable[i] = i*r_screenwidth; 107 zspantable[i] = d_pzbuffer + i*d_zwidth; 108 } 109 110 /* 111 ** clear Z-buffer and color-buffers if we're doing the gallery 112 */ 113 if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) 114 { 115 memset( d_pzbuffer, 0xff, vid.width * vid.height * sizeof( d_pzbuffer[0] ) ); 116 Draw_Fill( r_newrefdef.x, r_newrefdef.y, r_newrefdef.width, r_newrefdef.height,( int ) sw_clearcolor->value & 0xff ); 117 } 118 119 alias_colormap = vid.colormap; 120 121 D_Patch (); 122 } 123 124 125 126 /* 127 ============= 128 R_PrintTimes 129 ============= 130 */ 131 void R_PrintTimes (void) 132 { 133 int r_time2; 134 int ms; 135 136 r_time2 = Sys_Milliseconds (); 137 138 ms = r_time2 - r_time1; 139 140 ri.Con_Printf (PRINT_ALL,"%5i ms %3i/%3i/%3i poly %3i surf\n", 141 ms, c_faceclip, r_polycount, r_drawnpolycount, c_surf); 142 c_surf = 0; 143 } 144 145 146 /* 147 ============= 148 R_PrintDSpeeds 149 ============= 150 */ 151 void R_PrintDSpeeds (void) 152 { 153 int ms, dp_time, r_time2, rw_time, db_time, se_time, de_time, da_time; 154 155 r_time2 = Sys_Milliseconds (); 156 157 da_time = (da_time2 - da_time1); 158 dp_time = (dp_time2 - dp_time1); 159 rw_time = (rw_time2 - rw_time1); 160 db_time = (db_time2 - db_time1); 161 se_time = (se_time2 - se_time1); 162 de_time = (de_time2 - de_time1); 163 ms = (r_time2 - r_time1); 164 165 ri.Con_Printf (PRINT_ALL,"%3i %2ip %2iw %2ib %2is %2ie %2ia\n", 166 ms, dp_time, rw_time, db_time, se_time, de_time, da_time); 167 } 168 169 170 /* 171 ============= 172 R_PrintAliasStats 173 ============= 174 */ 175 void R_PrintAliasStats (void) 176 { 177 ri.Con_Printf (PRINT_ALL,"%3i polygon model drawn\n", r_amodels_drawn); 178 } 179 180 181 182 /* 183 =================== 184 R_TransformFrustum 185 =================== 186 */ 187 void R_TransformFrustum (void) 188 { 189 int i; 190 vec3_t v, v2; 191 192 for (i=0 ; i<4 ; i++) 193 { 194 v[0] = screenedge[i].normal[2]; 195 v[1] = -screenedge[i].normal[0]; 196 v[2] = screenedge[i].normal[1]; 197 198 v2[0] = v[1]*vright[0] + v[2]*vup[0] + v[0]*vpn[0]; 199 v2[1] = v[1]*vright[1] + v[2]*vup[1] + v[0]*vpn[1]; 200 v2[2] = v[1]*vright[2] + v[2]*vup[2] + v[0]*vpn[2]; 201 202 VectorCopy (v2, view_clipplanes[i].normal); 203 204 view_clipplanes[i].dist = DotProduct (modelorg, v2); 205 } 206 } 207 208 209 #if !(defined __linux__ && defined __i386__) 210 #if !id386 211 212 /* 213 ================ 214 TransformVector 215 ================ 216 */ 217 void TransformVector (vec3_t in, vec3_t out) 218 { 219 out[0] = DotProduct(in,vright); 220 out[1] = DotProduct(in,vup); 221 out[2] = DotProduct(in,vpn); 222 } 223 224 #else 225 226 __declspec( naked ) void TransformVector( vec3_t vin, vec3_t vout ) 227 { 228 __asm mov eax, dword ptr [esp+4] 229 __asm mov edx, dword ptr [esp+8] 230 231 __asm fld dword ptr [eax+0] 232 __asm fmul dword ptr [vright+0] 233 __asm fld dword ptr [eax+0] 234 __asm fmul dword ptr [vup+0] 235 __asm fld dword ptr [eax+0] 236 __asm fmul dword ptr [vpn+0] 237 238 __asm fld dword ptr [eax+4] 239 __asm fmul dword ptr [vright+4] 240 __asm fld dword ptr [eax+4] 241 __asm fmul dword ptr [vup+4] 242 __asm fld dword ptr [eax+4] 243 __asm fmul dword ptr [vpn+4] 244 245 __asm fxch st(2) 246 247 __asm faddp st(5), st(0) 248 __asm faddp st(3), st(0) 249 __asm faddp st(1), st(0) 250 251 __asm fld dword ptr [eax+8] 252 __asm fmul dword ptr [vright+8] 253 __asm fld dword ptr [eax+8] 254 __asm fmul dword ptr [vup+8] 255 __asm fld dword ptr [eax+8] 256 __asm fmul dword ptr [vpn+8] 257 258 __asm fxch st(2) 259 260 __asm faddp st(5), st(0) 261 __asm faddp st(3), st(0) 262 __asm faddp st(1), st(0) 263 264 __asm fstp dword ptr [edx+8] 265 __asm fstp dword ptr [edx+4] 266 __asm fstp dword ptr [edx+0] 267 268 __asm ret 269 } 270 271 #endif 272 #endif 273 274 275 /* 276 ================ 277 R_TransformPlane 278 ================ 279 */ 280 void R_TransformPlane (mplane_t *p, float *normal, float *dist) 281 { 282 float d; 283 284 d = DotProduct (r_origin, p->normal); 285 *dist = p->dist - d; 286 // TODO: when we have rotating entities, this will need to use the view matrix 287 TransformVector (p->normal, normal); 288 } 289 290 291 /* 292 =============== 293 R_SetUpFrustumIndexes 294 =============== 295 */ 296 void R_SetUpFrustumIndexes (void) 297 { 298 int i, j, *pindex; 299 300 pindex = r_frustum_indexes; 301 302 for (i=0 ; i<4 ; i++) 303 { 304 for (j=0 ; j<3 ; j++) 305 { 306 if (view_clipplanes[i].normal[j] < 0) 307 { 308 pindex[j] = j; 309 pindex[j+3] = j+3; 310 } 311 else 312 { 313 pindex[j] = j+3; 314 pindex[j+3] = j; 315 } 316 } 317 318 // FIXME: do just once at start 319 pfrustum_indexes[i] = pindex; 320 pindex += 6; 321 } 322 } 323 324 /* 325 =============== 326 R_ViewChanged 327 328 Called every time the vid structure or r_refdef changes. 329 Guaranteed to be called before the first refresh 330 =============== 331 */ 332 void R_ViewChanged (vrect_t *vr) 333 { 334 int i; 335 336 r_refdef.vrect = *vr; 337 338 r_refdef.horizontalFieldOfView = 2*tan((float)r_newrefdef.fov_x/360*M_PI);; 339 verticalFieldOfView = 2*tan((float)r_newrefdef.fov_y/360*M_PI); 340 341 r_refdef.fvrectx = (float)r_refdef.vrect.x; 342 r_refdef.fvrectx_adj = (float)r_refdef.vrect.x - 0.5; 343 r_refdef.vrect_x_adj_shift20 = (r_refdef.vrect.x<<20) + (1<<19) - 1; 344 r_refdef.fvrecty = (float)r_refdef.vrect.y; 345 r_refdef.fvrecty_adj = (float)r_refdef.vrect.y - 0.5; 346 r_refdef.vrectright = r_refdef.vrect.x + r_refdef.vrect.width; 347 r_refdef.vrectright_adj_shift20 = (r_refdef.vrectright<<20) + (1<<19) - 1; 348 r_refdef.fvrectright = (float)r_refdef.vrectright; 349 r_refdef.fvrectright_adj = (float)r_refdef.vrectright - 0.5; 350 r_refdef.vrectrightedge = (float)r_refdef.vrectright - 0.99; 351 r_refdef.vrectbottom = r_refdef.vrect.y + r_refdef.vrect.height; 352 r_refdef.fvrectbottom = (float)r_refdef.vrectbottom; 353 r_refdef.fvrectbottom_adj = (float)r_refdef.vrectbottom - 0.5; 354 355 r_refdef.aliasvrect.x = (int)(r_refdef.vrect.x * r_aliasuvscale); 356 r_refdef.aliasvrect.y = (int)(r_refdef.vrect.y * r_aliasuvscale); 357 r_refdef.aliasvrect.width = (int)(r_refdef.vrect.width * r_aliasuvscale); 358 r_refdef.aliasvrect.height = (int)(r_refdef.vrect.height * r_aliasuvscale); 359 r_refdef.aliasvrectright = r_refdef.aliasvrect.x + 360 r_refdef.aliasvrect.width; 361 r_refdef.aliasvrectbottom = r_refdef.aliasvrect.y + 362 r_refdef.aliasvrect.height; 363 364 xOrigin = r_refdef.xOrigin; 365 yOrigin = r_refdef.yOrigin; 366 367 // values for perspective projection 368 // if math were exact, the values would range from 0.5 to to range+0.5 369 // hopefully they wll be in the 0.000001 to range+.999999 and truncate 370 // the polygon rasterization will never render in the first row or column 371 // but will definately render in the [range] row and column, so adjust the 372 // buffer origin to get an exact edge to edge fill 373 xcenter = ((float)r_refdef.vrect.width * XCENTERING) + 374 r_refdef.vrect.x - 0.5; 375 aliasxcenter = xcenter * r_aliasuvscale; 376 ycenter = ((float)r_refdef.vrect.height * YCENTERING) + 377 r_refdef.vrect.y - 0.5; 378 aliasycenter = ycenter * r_aliasuvscale; 379 380 xscale = r_refdef.vrect.width / r_refdef.horizontalFieldOfView; 381 aliasxscale = xscale * r_aliasuvscale; 382 xscaleinv = 1.0 / xscale; 383 384 yscale = xscale; 385 aliasyscale = yscale * r_aliasuvscale; 386 yscaleinv = 1.0 / yscale; 387 xscaleshrink = (r_refdef.vrect.width-6)/r_refdef.horizontalFieldOfView; 388 yscaleshrink = xscaleshrink; 389 390 // left side clip 391 screenedge[0].normal[0] = -1.0 / (xOrigin*r_refdef.horizontalFieldOfView); 392 screenedge[0].normal[1] = 0; 393 screenedge[0].normal[2] = 1; 394 screenedge[0].type = PLANE_ANYZ; 395 396 // right side clip 397 screenedge[1].normal[0] = 398 1.0 / ((1.0-xOrigin)*r_refdef.horizontalFieldOfView); 399 screenedge[1].normal[1] = 0; 400 screenedge[1].normal[2] = 1; 401 screenedge[1].type = PLANE_ANYZ; 402 403 // top side clip 404 screenedge[2].normal[0] = 0; 405 screenedge[2].normal[1] = -1.0 / (yOrigin*verticalFieldOfView); 406 screenedge[2].normal[2] = 1; 407 screenedge[2].type = PLANE_ANYZ; 408 409 // bottom side clip 410 screenedge[3].normal[0] = 0; 411 screenedge[3].normal[1] = 1.0 / ((1.0-yOrigin)*verticalFieldOfView); 412 screenedge[3].normal[2] = 1; 413 screenedge[3].type = PLANE_ANYZ; 414 415 for (i=0 ; i<4 ; i++) 416 VectorNormalize (screenedge[i].normal); 417 418 D_ViewChanged (); 419 } 420 421 422 /* 423 =============== 424 R_SetupFrame 425 =============== 426 */ 427 void R_SetupFrame (void) 428 { 429 int i; 430 vrect_t vrect; 431 432 if (r_fullbright->modified) 433 { 434 r_fullbright->modified = false; 435 D_FlushCaches (); // so all lighting changes 436 } 437 438 r_framecount++; 439 440 441 // build the transformation matrix for the given view angles 442 VectorCopy (r_refdef.vieworg, modelorg); 443 VectorCopy (r_refdef.vieworg, r_origin); 444 445 AngleVectors (r_refdef.viewangles, vpn, vright, vup); 446 447 // current viewleaf 448 if ( !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) ) 449 { 450 r_viewleaf = Mod_PointInLeaf (r_origin, r_worldmodel); 451 r_viewcluster = r_viewleaf->cluster; 452 } 453 454 if (sw_waterwarp->value && (r_newrefdef.rdflags & RDF_UNDERWATER) ) 455 r_dowarp = true; 456 else 457 r_dowarp = false; 458 459 if (r_dowarp) 460 { // warp into off screen buffer 461 vrect.x = 0; 462 vrect.y = 0; 463 vrect.width = r_newrefdef.width < WARP_WIDTH ? r_newrefdef.width : WARP_WIDTH; 464 vrect.height = r_newrefdef.height < WARP_HEIGHT ? r_newrefdef.height : WARP_HEIGHT; 465 466 d_viewbuffer = r_warpbuffer; 467 r_screenwidth = WARP_WIDTH; 468 } 469 else 470 { 471 vrect.x = r_newrefdef.x; 472 vrect.y = r_newrefdef.y; 473 vrect.width = r_newrefdef.width; 474 vrect.height = r_newrefdef.height; 475 476 d_viewbuffer = (void *)vid.buffer; 477 r_screenwidth = vid.rowbytes; 478 } 479 480 R_ViewChanged (&vrect); 481 482 // start off with just the four screen edge clip planes 483 R_TransformFrustum (); 484 R_SetUpFrustumIndexes (); 485 486 // save base values 487 VectorCopy (vpn, base_vpn); 488 VectorCopy (vright, base_vright); 489 VectorCopy (vup, base_vup); 490 491 // clear frame counts 492 c_faceclip = 0; 493 d_spanpixcount = 0; 494 r_polycount = 0; 495 r_drawnpolycount = 0; 496 r_wholepolycount = 0; 497 r_amodels_drawn = 0; 498 r_outofsurfaces = 0; 499 r_outofedges = 0; 500 501 // d_setup 502 d_roverwrapped = false; 503 d_initial_rover = sc_rover; 504 505 d_minmip = sw_mipcap->value; 506 if (d_minmip > 3) 507 d_minmip = 3; 508 else if (d_minmip < 0) 509 d_minmip = 0; 510 511 for (i=0 ; i<(NUM_MIPS-1) ; i++) 512 d_scalemip[i] = basemip[i] * sw_mipscale->value; 513 514 d_aflatcolor = 0; 515 } 516 517 518 #if !id386 519 520 /* 521 ================ 522 R_SurfacePatch 523 ================ 524 */ 525 void R_SurfacePatch (void) 526 { 527 // we only patch code on Intel 528 } 529 530 #endif // !id386 531 532 533 /* 534 ============================================================================== 535 536 SCREEN SHOTS 537 538 ============================================================================== 539 */ 540 541 542 /* 543 ============== 544 WritePCXfile 545 ============== 546 */ 547 void WritePCXfile (char *filename, byte *data, int width, int height, 548 int rowbytes, byte *palette) 549 { 550 int i, j, length; 551 pcx_t *pcx; 552 byte *pack; 553 FILE *f; 554 555 pcx = (pcx_t *)malloc (width*height*2+1000); 556 if (!pcx) 557 return; 558 559 pcx->manufacturer = 0x0a; // PCX id 560 pcx->version = 5; // 256 color 561 pcx->encoding = 1; // uncompressed 562 pcx->bits_per_pixel = 8; // 256 color 563 pcx->xmin = 0; 564 pcx->ymin = 0; 565 pcx->xmax = LittleShort((short)(width-1)); 566 pcx->ymax = LittleShort((short)(height-1)); 567 pcx->hres = LittleShort((short)width); 568 pcx->vres = LittleShort((short)height); 569 memset (pcx->palette,0,sizeof(pcx->palette)); 570 pcx->color_planes = 1; // chunky image 571 pcx->bytes_per_line = LittleShort((short)width); 572 pcx->palette_type = LittleShort(2); // not a grey scale 573 memset (pcx->filler,0,sizeof(pcx->filler)); 574 575 // pack the image 576 pack = &pcx->data; 577 578 for (i=0 ; i<height ; i++) 579 { 580 for (j=0 ; j<width ; j++) 581 { 582 if ( (*data & 0xc0) != 0xc0) 583 *pack++ = *data++; 584 else 585 { 586 *pack++ = 0xc1; 587 *pack++ = *data++; 588 } 589 } 590 591 data += rowbytes - width; 592 } 593 594 // write the palette 595 *pack++ = 0x0c; // palette ID byte 596 for (i=0 ; i<768 ; i++) 597 *pack++ = *palette++; 598 599 // write output file 600 length = pack - (byte *)pcx; 601 f = fopen (filename, "wb"); 602 if (!f) 603 ri.Con_Printf (PRINT_ALL, "Failed to open to %s\n", filename); 604 else 605 { 606 fwrite ((void *)pcx, 1, length, f); 607 fclose (f); 608 } 609 610 free (pcx); 611 } 612 613 614 615 /* 616 ================== 617 R_ScreenShot_f 618 ================== 619 */ 620 void R_ScreenShot_f (void) 621 { 622 int i; 623 char pcxname[80]; 624 char checkname[MAX_OSPATH]; 625 FILE *f; 626 byte palette[768]; 627 628 // create the scrnshots directory if it doesn't exist 629 Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot", ri.FS_Gamedir()); 630 Sys_Mkdir (checkname); 631 632 // 633 // find a file name to save it to 634 // 635 strcpy(pcxname,"quake00.pcx"); 636 637 for (i=0 ; i<=99 ; i++) 638 { 639 pcxname[5] = i/10 + '0'; 640 pcxname[6] = i%10 + '0'; 641 Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot/%s", ri.FS_Gamedir(), pcxname); 642 f = fopen (checkname, "r"); 643 if (!f) 644 break; // file doesn't exist 645 fclose (f); 646 } 647 if (i==100) 648 { 649 ri.Con_Printf (PRINT_ALL, "R_ScreenShot_f: Couldn't create a PCX"); 650 return; 651 } 652 653 // turn the current 32 bit palette into a 24 bit palette 654 for (i=0 ; i<256 ; i++) 655 { 656 palette[i*3+0] = sw_state.currentpalette[i*4+0]; 657 palette[i*3+1] = sw_state.currentpalette[i*4+1]; 658 palette[i*3+2] = sw_state.currentpalette[i*4+2]; 659 } 660 661 // 662 // save the pcx file 663 // 664 665 WritePCXfile (checkname, vid.buffer, vid.width, vid.height, vid.rowbytes, 666 palette); 667 668 ri.Con_Printf (PRINT_ALL, "Wrote %s\n", checkname); 669 } 670