r_main.c (29507B)
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_main.c 21 22 #include "r_local.h" 23 24 viddef_t vid; 25 refimport_t ri; 26 27 unsigned d_8to24table[256]; 28 29 entity_t r_worldentity; 30 31 char skyname[MAX_QPATH]; 32 float skyrotate; 33 vec3_t skyaxis; 34 image_t *sky_images[6]; 35 36 refdef_t r_newrefdef; 37 model_t *currentmodel; 38 39 model_t *r_worldmodel; 40 41 byte r_warpbuffer[WARP_WIDTH * WARP_HEIGHT]; 42 43 swstate_t sw_state; 44 45 void *colormap; 46 vec3_t viewlightvec; 47 alight_t r_viewlighting = {128, 192, viewlightvec}; 48 float r_time1; 49 int r_numallocatededges; 50 float r_aliasuvscale = 1.0; 51 int r_outofsurfaces; 52 int r_outofedges; 53 54 qboolean r_dowarp; 55 56 mvertex_t *r_pcurrentvertbase; 57 58 int c_surf; 59 int r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs; 60 qboolean r_surfsonstack; 61 int r_clipflags; 62 63 // 64 // view origin 65 // 66 vec3_t vup, base_vup; 67 vec3_t vpn, base_vpn; 68 vec3_t vright, base_vright; 69 vec3_t r_origin; 70 71 // 72 // screen size info 73 // 74 oldrefdef_t r_refdef; 75 float xcenter, ycenter; 76 float xscale, yscale; 77 float xscaleinv, yscaleinv; 78 float xscaleshrink, yscaleshrink; 79 float aliasxscale, aliasyscale, aliasxcenter, aliasycenter; 80 81 int r_screenwidth; 82 83 float verticalFieldOfView; 84 float xOrigin, yOrigin; 85 86 mplane_t screenedge[4]; 87 88 // 89 // refresh flags 90 // 91 int r_framecount = 1; // so frame counts initialized to 0 don't match 92 int r_visframecount; 93 int d_spanpixcount; 94 int r_polycount; 95 int r_drawnpolycount; 96 int r_wholepolycount; 97 98 int *pfrustum_indexes[4]; 99 int r_frustum_indexes[4*6]; 100 101 mleaf_t *r_viewleaf; 102 int r_viewcluster, r_oldviewcluster; 103 104 image_t *r_notexture_mip; 105 106 float da_time1, da_time2, dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2; 107 float se_time1, se_time2, de_time1, de_time2; 108 109 void R_MarkLeaves (void); 110 111 cvar_t *r_lefthand; 112 cvar_t *sw_aliasstats; 113 cvar_t *sw_allow_modex; 114 cvar_t *sw_clearcolor; 115 cvar_t *sw_drawflat; 116 cvar_t *sw_draworder; 117 cvar_t *sw_maxedges; 118 cvar_t *sw_maxsurfs; 119 cvar_t *sw_mode; 120 cvar_t *sw_reportedgeout; 121 cvar_t *sw_reportsurfout; 122 cvar_t *sw_stipplealpha; 123 cvar_t *sw_surfcacheoverride; 124 cvar_t *sw_waterwarp; 125 126 cvar_t *r_drawworld; 127 cvar_t *r_drawentities; 128 cvar_t *r_dspeeds; 129 cvar_t *r_fullbright; 130 cvar_t *r_lerpmodels; 131 cvar_t *r_novis; 132 133 cvar_t *r_speeds; 134 cvar_t *r_lightlevel; //FIXME HACK 135 136 cvar_t *vid_fullscreen; 137 cvar_t *vid_gamma; 138 139 //PGM 140 cvar_t *sw_lockpvs; 141 //PGM 142 143 #define STRINGER(x) "x" 144 145 146 #if !id386 147 148 // r_vars.c 149 150 // all global and static refresh variables are collected in a contiguous block 151 // to avoid cache conflicts. 152 153 //------------------------------------------------------- 154 // global refresh variables 155 //------------------------------------------------------- 156 157 // FIXME: make into one big structure, like cl or sv 158 // FIXME: do separately for refresh engine and driver 159 160 161 // d_vars.c 162 163 // all global and static refresh variables are collected in a contiguous block 164 // to avoid cache conflicts. 165 166 //------------------------------------------------------- 167 // global refresh variables 168 //------------------------------------------------------- 169 170 // FIXME: make into one big structure, like cl or sv 171 // FIXME: do separately for refresh engine and driver 172 173 float d_sdivzstepu, d_tdivzstepu, d_zistepu; 174 float d_sdivzstepv, d_tdivzstepv, d_zistepv; 175 float d_sdivzorigin, d_tdivzorigin, d_ziorigin; 176 177 fixed16_t sadjust, tadjust, bbextents, bbextentt; 178 179 pixel_t *cacheblock; 180 int cachewidth; 181 pixel_t *d_viewbuffer; 182 short *d_pzbuffer; 183 unsigned int d_zrowbytes; 184 unsigned int d_zwidth; 185 186 187 #endif // !id386 188 189 byte r_notexture_buffer[1024]; 190 191 /* 192 ================== 193 R_InitTextures 194 ================== 195 */ 196 void R_InitTextures (void) 197 { 198 int x,y, m; 199 byte *dest; 200 201 // create a simple checkerboard texture for the default 202 r_notexture_mip = (image_t *)&r_notexture_buffer; 203 204 r_notexture_mip->width = r_notexture_mip->height = 16; 205 r_notexture_mip->pixels[0] = &r_notexture_buffer[sizeof(image_t)]; 206 r_notexture_mip->pixels[1] = r_notexture_mip->pixels[0] + 16*16; 207 r_notexture_mip->pixels[2] = r_notexture_mip->pixels[1] + 8*8; 208 r_notexture_mip->pixels[3] = r_notexture_mip->pixels[2] + 4*4; 209 210 for (m=0 ; m<4 ; m++) 211 { 212 dest = r_notexture_mip->pixels[m]; 213 for (y=0 ; y< (16>>m) ; y++) 214 for (x=0 ; x< (16>>m) ; x++) 215 { 216 if ( (y< (8>>m) ) ^ (x< (8>>m) ) ) 217 218 *dest++ = 0; 219 else 220 *dest++ = 0xff; 221 } 222 } 223 } 224 225 226 /* 227 ================ 228 R_InitTurb 229 ================ 230 */ 231 void R_InitTurb (void) 232 { 233 int i; 234 235 for (i=0 ; i<1280 ; i++) 236 { 237 sintable[i] = AMP + sin(i*3.14159*2/CYCLE)*AMP; 238 intsintable[i] = AMP2 + sin(i*3.14159*2/CYCLE)*AMP2; // AMP2, not 20 239 blanktable[i] = 0; //PGM 240 } 241 } 242 243 void R_ImageList_f( void ); 244 245 void R_Register (void) 246 { 247 sw_aliasstats = ri.Cvar_Get ("sw_polymodelstats", "0", 0); 248 sw_allow_modex = ri.Cvar_Get( "sw_allow_modex", "1", CVAR_ARCHIVE ); 249 sw_clearcolor = ri.Cvar_Get ("sw_clearcolor", "2", 0); 250 sw_drawflat = ri.Cvar_Get ("sw_drawflat", "0", 0); 251 sw_draworder = ri.Cvar_Get ("sw_draworder", "0", 0); 252 sw_maxedges = ri.Cvar_Get ("sw_maxedges", STRINGER(MAXSTACKSURFACES), 0); 253 sw_maxsurfs = ri.Cvar_Get ("sw_maxsurfs", "0", 0); 254 sw_mipcap = ri.Cvar_Get ("sw_mipcap", "0", 0); 255 sw_mipscale = ri.Cvar_Get ("sw_mipscale", "1", 0); 256 sw_reportedgeout = ri.Cvar_Get ("sw_reportedgeout", "0", 0); 257 sw_reportsurfout = ri.Cvar_Get ("sw_reportsurfout", "0", 0); 258 sw_stipplealpha = ri.Cvar_Get( "sw_stipplealpha", "0", CVAR_ARCHIVE ); 259 sw_surfcacheoverride = ri.Cvar_Get ("sw_surfcacheoverride", "0", 0); 260 sw_waterwarp = ri.Cvar_Get ("sw_waterwarp", "1", 0); 261 sw_mode = ri.Cvar_Get( "sw_mode", "0", CVAR_ARCHIVE ); 262 263 r_lefthand = ri.Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE ); 264 r_speeds = ri.Cvar_Get ("r_speeds", "0", 0); 265 r_fullbright = ri.Cvar_Get ("r_fullbright", "0", 0); 266 r_drawentities = ri.Cvar_Get ("r_drawentities", "1", 0); 267 r_drawworld = ri.Cvar_Get ("r_drawworld", "1", 0); 268 r_dspeeds = ri.Cvar_Get ("r_dspeeds", "0", 0); 269 r_lightlevel = ri.Cvar_Get ("r_lightlevel", "0", 0); 270 r_lerpmodels = ri.Cvar_Get( "r_lerpmodels", "1", 0 ); 271 r_novis = ri.Cvar_Get( "r_novis", "0", 0 ); 272 273 vid_fullscreen = ri.Cvar_Get( "vid_fullscreen", "0", CVAR_ARCHIVE ); 274 vid_gamma = ri.Cvar_Get( "vid_gamma", "1.0", CVAR_ARCHIVE ); 275 276 ri.Cmd_AddCommand ("modellist", Mod_Modellist_f); 277 ri.Cmd_AddCommand( "screenshot", R_ScreenShot_f ); 278 ri.Cmd_AddCommand( "imagelist", R_ImageList_f ); 279 280 sw_mode->modified = true; // force us to do mode specific stuff later 281 vid_gamma->modified = true; // force us to rebuild the gamma table later 282 283 //PGM 284 sw_lockpvs = ri.Cvar_Get ("sw_lockpvs", "0", 0); 285 //PGM 286 } 287 288 void R_UnRegister (void) 289 { 290 ri.Cmd_RemoveCommand( "screenshot" ); 291 ri.Cmd_RemoveCommand ("modellist"); 292 ri.Cmd_RemoveCommand( "imagelist" ); 293 } 294 295 /* 296 =============== 297 R_Init 298 =============== 299 */ 300 qboolean R_Init( void *hInstance, void *wndProc ) 301 { 302 R_InitImages (); 303 Mod_Init (); 304 Draw_InitLocal (); 305 R_InitTextures (); 306 307 R_InitTurb (); 308 309 view_clipplanes[0].leftedge = true; 310 view_clipplanes[1].rightedge = true; 311 view_clipplanes[1].leftedge = view_clipplanes[2].leftedge = 312 view_clipplanes[3].leftedge = false; 313 view_clipplanes[0].rightedge = view_clipplanes[2].rightedge = 314 view_clipplanes[3].rightedge = false; 315 316 r_refdef.xOrigin = XCENTERING; 317 r_refdef.yOrigin = YCENTERING; 318 319 // TODO: collect 386-specific code in one place 320 #if id386 321 Sys_MakeCodeWriteable ((long)R_EdgeCodeStart, 322 (long)R_EdgeCodeEnd - (long)R_EdgeCodeStart); 323 Sys_SetFPCW (); // get bit masks for FPCW (FIXME: is this id386?) 324 #endif // id386 325 326 r_aliasuvscale = 1.0; 327 328 R_Register (); 329 Draw_GetPalette (); 330 SWimp_Init( hInstance, wndProc ); 331 332 // create the window 333 R_BeginFrame( 0 ); 334 335 ri.Con_Printf (PRINT_ALL, "ref_soft version: "REF_VERSION"\n"); 336 337 return true; 338 } 339 340 /* 341 =============== 342 R_Shutdown 343 =============== 344 */ 345 void R_Shutdown (void) 346 { 347 // free z buffer 348 if (d_pzbuffer) 349 { 350 free (d_pzbuffer); 351 d_pzbuffer = NULL; 352 } 353 // free surface cache 354 if (sc_base) 355 { 356 D_FlushCaches (); 357 free (sc_base); 358 sc_base = NULL; 359 } 360 361 // free colormap 362 if (vid.colormap) 363 { 364 free (vid.colormap); 365 vid.colormap = NULL; 366 } 367 R_UnRegister (); 368 Mod_FreeAll (); 369 R_ShutdownImages (); 370 371 SWimp_Shutdown(); 372 } 373 374 /* 375 =============== 376 R_NewMap 377 =============== 378 */ 379 void R_NewMap (void) 380 { 381 r_viewcluster = -1; 382 383 r_cnumsurfs = sw_maxsurfs->value; 384 385 if (r_cnumsurfs <= MINSURFACES) 386 r_cnumsurfs = MINSURFACES; 387 388 if (r_cnumsurfs > NUMSTACKSURFACES) 389 { 390 surfaces = malloc (r_cnumsurfs * sizeof(surf_t)); 391 surface_p = surfaces; 392 surf_max = &surfaces[r_cnumsurfs]; 393 r_surfsonstack = false; 394 // surface 0 doesn't really exist; it's just a dummy because index 0 395 // is used to indicate no edge attached to surface 396 surfaces--; 397 R_SurfacePatch (); 398 } 399 else 400 { 401 r_surfsonstack = true; 402 } 403 404 r_maxedgesseen = 0; 405 r_maxsurfsseen = 0; 406 407 r_numallocatededges = sw_maxedges->value; 408 409 if (r_numallocatededges < MINEDGES) 410 r_numallocatededges = MINEDGES; 411 412 if (r_numallocatededges <= NUMSTACKEDGES) 413 { 414 auxedges = NULL; 415 } 416 else 417 { 418 auxedges = malloc (r_numallocatededges * sizeof(edge_t)); 419 } 420 } 421 422 423 /* 424 =============== 425 R_MarkLeaves 426 427 Mark the leaves and nodes that are in the PVS for the current 428 cluster 429 =============== 430 */ 431 void R_MarkLeaves (void) 432 { 433 byte *vis; 434 mnode_t *node; 435 int i; 436 mleaf_t *leaf; 437 int cluster; 438 439 if (r_oldviewcluster == r_viewcluster && !r_novis->value && r_viewcluster != -1) 440 return; 441 442 // development aid to let you run around and see exactly where 443 // the pvs ends 444 if (sw_lockpvs->value) 445 return; 446 447 r_visframecount++; 448 r_oldviewcluster = r_viewcluster; 449 450 if (r_novis->value || r_viewcluster == -1 || !r_worldmodel->vis) 451 { 452 // mark everything 453 for (i=0 ; i<r_worldmodel->numleafs ; i++) 454 r_worldmodel->leafs[i].visframe = r_visframecount; 455 for (i=0 ; i<r_worldmodel->numnodes ; i++) 456 r_worldmodel->nodes[i].visframe = r_visframecount; 457 return; 458 } 459 460 vis = Mod_ClusterPVS (r_viewcluster, r_worldmodel); 461 462 for (i=0,leaf=r_worldmodel->leafs ; i<r_worldmodel->numleafs ; i++, leaf++) 463 { 464 cluster = leaf->cluster; 465 if (cluster == -1) 466 continue; 467 if (vis[cluster>>3] & (1<<(cluster&7))) 468 { 469 node = (mnode_t *)leaf; 470 do 471 { 472 if (node->visframe == r_visframecount) 473 break; 474 node->visframe = r_visframecount; 475 node = node->parent; 476 } while (node); 477 } 478 } 479 480 #if 0 481 for (i=0 ; i<r_worldmodel->vis->numclusters ; i++) 482 { 483 if (vis[i>>3] & (1<<(i&7))) 484 { 485 node = (mnode_t *)&r_worldmodel->leafs[i]; // FIXME: cluster 486 do 487 { 488 if (node->visframe == r_visframecount) 489 break; 490 node->visframe = r_visframecount; 491 node = node->parent; 492 } while (node); 493 } 494 } 495 #endif 496 } 497 498 /* 499 ** R_DrawNullModel 500 ** 501 ** IMPLEMENT THIS! 502 */ 503 void R_DrawNullModel( void ) 504 { 505 } 506 507 /* 508 ============= 509 R_DrawEntitiesOnList 510 ============= 511 */ 512 void R_DrawEntitiesOnList (void) 513 { 514 int i; 515 qboolean translucent_entities = false; 516 517 if (!r_drawentities->value) 518 return; 519 520 // all bmodels have already been drawn by the edge list 521 for (i=0 ; i<r_newrefdef.num_entities ; i++) 522 { 523 currententity = &r_newrefdef.entities[i]; 524 525 if ( currententity->flags & RF_TRANSLUCENT ) 526 { 527 translucent_entities = true; 528 continue; 529 } 530 531 if ( currententity->flags & RF_BEAM ) 532 { 533 modelorg[0] = -r_origin[0]; 534 modelorg[1] = -r_origin[1]; 535 modelorg[2] = -r_origin[2]; 536 VectorCopy( vec3_origin, r_entorigin ); 537 R_DrawBeam( currententity ); 538 } 539 else 540 { 541 currentmodel = currententity->model; 542 if (!currentmodel) 543 { 544 R_DrawNullModel(); 545 continue; 546 } 547 VectorCopy (currententity->origin, r_entorigin); 548 VectorSubtract (r_origin, r_entorigin, modelorg); 549 550 switch (currentmodel->type) 551 { 552 case mod_sprite: 553 R_DrawSprite (); 554 break; 555 556 case mod_alias: 557 R_AliasDrawModel (); 558 break; 559 560 default: 561 break; 562 } 563 } 564 } 565 566 if ( !translucent_entities ) 567 return; 568 569 for (i=0 ; i<r_newrefdef.num_entities ; i++) 570 { 571 currententity = &r_newrefdef.entities[i]; 572 573 if ( !( currententity->flags & RF_TRANSLUCENT ) ) 574 continue; 575 576 if ( currententity->flags & RF_BEAM ) 577 { 578 modelorg[0] = -r_origin[0]; 579 modelorg[1] = -r_origin[1]; 580 modelorg[2] = -r_origin[2]; 581 VectorCopy( vec3_origin, r_entorigin ); 582 R_DrawBeam( currententity ); 583 } 584 else 585 { 586 currentmodel = currententity->model; 587 if (!currentmodel) 588 { 589 R_DrawNullModel(); 590 continue; 591 } 592 VectorCopy (currententity->origin, r_entorigin); 593 VectorSubtract (r_origin, r_entorigin, modelorg); 594 595 switch (currentmodel->type) 596 { 597 case mod_sprite: 598 R_DrawSprite (); 599 break; 600 601 case mod_alias: 602 R_AliasDrawModel (); 603 break; 604 605 default: 606 break; 607 } 608 } 609 } 610 } 611 612 613 /* 614 ============= 615 R_BmodelCheckBBox 616 ============= 617 */ 618 int R_BmodelCheckBBox (float *minmaxs) 619 { 620 int i, *pindex, clipflags; 621 vec3_t acceptpt, rejectpt; 622 float d; 623 624 clipflags = 0; 625 626 for (i=0 ; i<4 ; i++) 627 { 628 // generate accept and reject points 629 // FIXME: do with fast look-ups or integer tests based on the sign bit 630 // of the floating point values 631 632 pindex = pfrustum_indexes[i]; 633 634 rejectpt[0] = minmaxs[pindex[0]]; 635 rejectpt[1] = minmaxs[pindex[1]]; 636 rejectpt[2] = minmaxs[pindex[2]]; 637 638 d = DotProduct (rejectpt, view_clipplanes[i].normal); 639 d -= view_clipplanes[i].dist; 640 641 if (d <= 0) 642 return BMODEL_FULLY_CLIPPED; 643 644 acceptpt[0] = minmaxs[pindex[3+0]]; 645 acceptpt[1] = minmaxs[pindex[3+1]]; 646 acceptpt[2] = minmaxs[pindex[3+2]]; 647 648 d = DotProduct (acceptpt, view_clipplanes[i].normal); 649 d -= view_clipplanes[i].dist; 650 651 if (d <= 0) 652 clipflags |= (1<<i); 653 } 654 655 return clipflags; 656 } 657 658 659 /* 660 =================== 661 R_FindTopnode 662 663 Find the first node that splits the given box 664 =================== 665 */ 666 mnode_t *R_FindTopnode (vec3_t mins, vec3_t maxs) 667 { 668 mplane_t *splitplane; 669 int sides; 670 mnode_t *node; 671 672 node = r_worldmodel->nodes; 673 674 while (1) 675 { 676 if (node->visframe != r_visframecount) 677 return NULL; // not visible at all 678 679 if (node->contents != CONTENTS_NODE) 680 { 681 if (node->contents != CONTENTS_SOLID) 682 return node; // we've reached a non-solid leaf, so it's 683 // visible and not BSP clipped 684 return NULL; // in solid, so not visible 685 } 686 687 splitplane = node->plane; 688 sides = BOX_ON_PLANE_SIDE(mins, maxs, (cplane_t *)splitplane); 689 690 if (sides == 3) 691 return node; // this is the splitter 692 693 // not split yet; recurse down the contacted side 694 if (sides & 1) 695 node = node->children[0]; 696 else 697 node = node->children[1]; 698 } 699 } 700 701 702 /* 703 ============= 704 RotatedBBox 705 706 Returns an axially aligned box that contains the input box at the given rotation 707 ============= 708 */ 709 void RotatedBBox (vec3_t mins, vec3_t maxs, vec3_t angles, vec3_t tmins, vec3_t tmaxs) 710 { 711 vec3_t tmp, v; 712 int i, j; 713 vec3_t forward, right, up; 714 715 if (!angles[0] && !angles[1] && !angles[2]) 716 { 717 VectorCopy (mins, tmins); 718 VectorCopy (maxs, tmaxs); 719 return; 720 } 721 722 for (i=0 ; i<3 ; i++) 723 { 724 tmins[i] = 99999; 725 tmaxs[i] = -99999; 726 } 727 728 AngleVectors (angles, forward, right, up); 729 730 for ( i = 0; i < 8; i++ ) 731 { 732 if ( i & 1 ) 733 tmp[0] = mins[0]; 734 else 735 tmp[0] = maxs[0]; 736 737 if ( i & 2 ) 738 tmp[1] = mins[1]; 739 else 740 tmp[1] = maxs[1]; 741 742 if ( i & 4 ) 743 tmp[2] = mins[2]; 744 else 745 tmp[2] = maxs[2]; 746 747 748 VectorScale (forward, tmp[0], v); 749 VectorMA (v, -tmp[1], right, v); 750 VectorMA (v, tmp[2], up, v); 751 752 for (j=0 ; j<3 ; j++) 753 { 754 if (v[j] < tmins[j]) 755 tmins[j] = v[j]; 756 if (v[j] > tmaxs[j]) 757 tmaxs[j] = v[j]; 758 } 759 } 760 } 761 762 /* 763 ============= 764 R_DrawBEntitiesOnList 765 ============= 766 */ 767 void R_DrawBEntitiesOnList (void) 768 { 769 int i, clipflags; 770 vec3_t oldorigin; 771 vec3_t mins, maxs; 772 float minmaxs[6]; 773 mnode_t *topnode; 774 775 if (!r_drawentities->value) 776 return; 777 778 VectorCopy (modelorg, oldorigin); 779 insubmodel = true; 780 r_dlightframecount = r_framecount; 781 782 for (i=0 ; i<r_newrefdef.num_entities ; i++) 783 { 784 currententity = &r_newrefdef.entities[i]; 785 currentmodel = currententity->model; 786 if (!currentmodel) 787 continue; 788 if (currentmodel->nummodelsurfaces == 0) 789 continue; // clip brush only 790 if ( currententity->flags & RF_BEAM ) 791 continue; 792 if (currentmodel->type != mod_brush) 793 continue; 794 // see if the bounding box lets us trivially reject, also sets 795 // trivial accept status 796 RotatedBBox (currentmodel->mins, currentmodel->maxs, 797 currententity->angles, mins, maxs); 798 VectorAdd (mins, currententity->origin, minmaxs); 799 VectorAdd (maxs, currententity->origin, (minmaxs+3)); 800 801 clipflags = R_BmodelCheckBBox (minmaxs); 802 if (clipflags == BMODEL_FULLY_CLIPPED) 803 continue; // off the edge of the screen 804 805 topnode = R_FindTopnode (minmaxs, minmaxs+3); 806 if (!topnode) 807 continue; // no part in a visible leaf 808 809 VectorCopy (currententity->origin, r_entorigin); 810 VectorSubtract (r_origin, r_entorigin, modelorg); 811 812 r_pcurrentvertbase = currentmodel->vertexes; 813 814 // FIXME: stop transforming twice 815 R_RotateBmodel (); 816 817 // calculate dynamic lighting for bmodel 818 R_PushDlights (currentmodel); 819 820 if (topnode->contents == CONTENTS_NODE) 821 { 822 // not a leaf; has to be clipped to the world BSP 823 r_clipflags = clipflags; 824 R_DrawSolidClippedSubmodelPolygons (currentmodel, topnode); 825 } 826 else 827 { 828 // falls entirely in one leaf, so we just put all the 829 // edges in the edge list and let 1/z sorting handle 830 // drawing order 831 R_DrawSubmodelPolygons (currentmodel, clipflags, topnode); 832 } 833 834 // put back world rotation and frustum clipping 835 // FIXME: R_RotateBmodel should just work off base_vxx 836 VectorCopy (base_vpn, vpn); 837 VectorCopy (base_vup, vup); 838 VectorCopy (base_vright, vright); 839 VectorCopy (oldorigin, modelorg); 840 R_TransformFrustum (); 841 } 842 843 insubmodel = false; 844 } 845 846 847 /* 848 ================ 849 R_EdgeDrawing 850 ================ 851 */ 852 void R_EdgeDrawing (void) 853 { 854 edge_t ledges[NUMSTACKEDGES + 855 ((CACHE_SIZE - 1) / sizeof(edge_t)) + 1]; 856 surf_t lsurfs[NUMSTACKSURFACES + 857 ((CACHE_SIZE - 1) / sizeof(surf_t)) + 1]; 858 859 if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) 860 return; 861 862 if (auxedges) 863 { 864 r_edges = auxedges; 865 } 866 else 867 { 868 r_edges = (edge_t *) 869 (((long)&ledges[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); 870 } 871 872 if (r_surfsonstack) 873 { 874 surfaces = (surf_t *) 875 (((long)&lsurfs[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); 876 surf_max = &surfaces[r_cnumsurfs]; 877 // surface 0 doesn't really exist; it's just a dummy because index 0 878 // is used to indicate no edge attached to surface 879 surfaces--; 880 R_SurfacePatch (); 881 } 882 883 R_BeginEdgeFrame (); 884 885 if (r_dspeeds->value) 886 { 887 rw_time1 = Sys_Milliseconds (); 888 } 889 890 R_RenderWorld (); 891 892 if (r_dspeeds->value) 893 { 894 rw_time2 = Sys_Milliseconds (); 895 db_time1 = rw_time2; 896 } 897 898 R_DrawBEntitiesOnList (); 899 900 if (r_dspeeds->value) 901 { 902 db_time2 = Sys_Milliseconds (); 903 se_time1 = db_time2; 904 } 905 906 R_ScanEdges (); 907 } 908 909 //======================================================================= 910 911 912 /* 913 ============= 914 R_CalcPalette 915 916 ============= 917 */ 918 void R_CalcPalette (void) 919 { 920 static qboolean modified; 921 byte palette[256][4], *in, *out; 922 int i, j; 923 float alpha, one_minus_alpha; 924 vec3_t premult; 925 int v; 926 927 alpha = r_newrefdef.blend[3]; 928 if (alpha <= 0) 929 { 930 if (modified) 931 { // set back to default 932 modified = false; 933 R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table ); 934 return; 935 } 936 return; 937 } 938 939 modified = true; 940 if (alpha > 1) 941 alpha = 1; 942 943 premult[0] = r_newrefdef.blend[0]*alpha*255; 944 premult[1] = r_newrefdef.blend[1]*alpha*255; 945 premult[2] = r_newrefdef.blend[2]*alpha*255; 946 947 one_minus_alpha = (1.0 - alpha); 948 949 in = (byte *)d_8to24table; 950 out = palette[0]; 951 for (i=0 ; i<256 ; i++, in+=4, out+=4) 952 { 953 for (j=0 ; j<3 ; j++) 954 { 955 v = premult[j] + one_minus_alpha * in[j]; 956 if (v > 255) 957 v = 255; 958 out[j] = v; 959 } 960 out[3] = 255; 961 } 962 963 R_GammaCorrectAndSetPalette( ( const unsigned char * ) palette[0] ); 964 // SWimp_SetPalette( palette[0] ); 965 } 966 967 //======================================================================= 968 969 void R_SetLightLevel (void) 970 { 971 vec3_t light; 972 973 if ((r_newrefdef.rdflags & RDF_NOWORLDMODEL) || (!r_drawentities->value) || (!currententity)) 974 { 975 r_lightlevel->value = 150.0; 976 return; 977 } 978 979 // save off light value for server to look at (BIG HACK!) 980 R_LightPoint (r_newrefdef.vieworg, light); 981 r_lightlevel->value = 150.0 * light[0]; 982 } 983 984 985 /* 986 @@@@@@@@@@@@@@@@ 987 R_RenderFrame 988 989 @@@@@@@@@@@@@@@@ 990 */ 991 void R_RenderFrame (refdef_t *fd) 992 { 993 r_newrefdef = *fd; 994 995 if (!r_worldmodel && !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) ) 996 ri.Sys_Error (ERR_FATAL,"R_RenderView: NULL worldmodel"); 997 998 VectorCopy (fd->vieworg, r_refdef.vieworg); 999 VectorCopy (fd->viewangles, r_refdef.viewangles); 1000 1001 if (r_speeds->value || r_dspeeds->value) 1002 r_time1 = Sys_Milliseconds (); 1003 1004 R_SetupFrame (); 1005 1006 R_MarkLeaves (); // done here so we know if we're in water 1007 1008 R_PushDlights (r_worldmodel); 1009 1010 R_EdgeDrawing (); 1011 1012 if (r_dspeeds->value) 1013 { 1014 se_time2 = Sys_Milliseconds (); 1015 de_time1 = se_time2; 1016 } 1017 1018 R_DrawEntitiesOnList (); 1019 1020 if (r_dspeeds->value) 1021 { 1022 de_time2 = Sys_Milliseconds (); 1023 dp_time1 = Sys_Milliseconds (); 1024 } 1025 1026 R_DrawParticles (); 1027 1028 if (r_dspeeds->value) 1029 dp_time2 = Sys_Milliseconds (); 1030 1031 R_DrawAlphaSurfaces(); 1032 1033 R_SetLightLevel (); 1034 1035 if (r_dowarp) 1036 D_WarpScreen (); 1037 1038 if (r_dspeeds->value) 1039 da_time1 = Sys_Milliseconds (); 1040 1041 if (r_dspeeds->value) 1042 da_time2 = Sys_Milliseconds (); 1043 1044 R_CalcPalette (); 1045 1046 if (sw_aliasstats->value) 1047 R_PrintAliasStats (); 1048 1049 if (r_speeds->value) 1050 R_PrintTimes (); 1051 1052 if (r_dspeeds->value) 1053 R_PrintDSpeeds (); 1054 1055 if (sw_reportsurfout->value && r_outofsurfaces) 1056 ri.Con_Printf (PRINT_ALL,"Short %d surfaces\n", r_outofsurfaces); 1057 1058 if (sw_reportedgeout->value && r_outofedges) 1059 ri.Con_Printf (PRINT_ALL,"Short roughly %d edges\n", r_outofedges * 2 / 3); 1060 } 1061 1062 /* 1063 ** R_InitGraphics 1064 */ 1065 void R_InitGraphics( int width, int height ) 1066 { 1067 vid.width = width; 1068 vid.height = height; 1069 1070 // free z buffer 1071 if ( d_pzbuffer ) 1072 { 1073 free( d_pzbuffer ); 1074 d_pzbuffer = NULL; 1075 } 1076 1077 // free surface cache 1078 if ( sc_base ) 1079 { 1080 D_FlushCaches (); 1081 free( sc_base ); 1082 sc_base = NULL; 1083 } 1084 1085 d_pzbuffer = malloc(vid.width*vid.height*2); 1086 1087 R_InitCaches (); 1088 1089 R_GammaCorrectAndSetPalette( ( const unsigned char *) d_8to24table ); 1090 } 1091 1092 /* 1093 ** R_BeginFrame 1094 */ 1095 void R_BeginFrame( float camera_separation ) 1096 { 1097 extern void Draw_BuildGammaTable( void ); 1098 1099 /* 1100 ** rebuild the gamma correction palette if necessary 1101 */ 1102 if ( vid_gamma->modified ) 1103 { 1104 Draw_BuildGammaTable(); 1105 R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table ); 1106 1107 vid_gamma->modified = false; 1108 } 1109 1110 while ( sw_mode->modified || vid_fullscreen->modified ) 1111 { 1112 rserr_t err; 1113 1114 /* 1115 ** if this returns rserr_invalid_fullscreen then it set the mode but not as a 1116 ** fullscreen mode, e.g. 320x200 on a system that doesn't support that res 1117 */ 1118 if ( ( err = SWimp_SetMode( &vid.width, &vid.height, sw_mode->value, vid_fullscreen->value ) ) == rserr_ok ) 1119 { 1120 R_InitGraphics( vid.width, vid.height ); 1121 1122 sw_state.prev_mode = sw_mode->value; 1123 vid_fullscreen->modified = false; 1124 sw_mode->modified = false; 1125 } 1126 else 1127 { 1128 if ( err == rserr_invalid_mode ) 1129 { 1130 ri.Cvar_SetValue( "sw_mode", sw_state.prev_mode ); 1131 ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - could not set mode\n" ); 1132 } 1133 else if ( err == rserr_invalid_fullscreen ) 1134 { 1135 R_InitGraphics( vid.width, vid.height ); 1136 1137 ri.Cvar_SetValue( "vid_fullscreen", 0); 1138 ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - fullscreen unavailable in this mode\n" ); 1139 sw_state.prev_mode = sw_mode->value; 1140 // vid_fullscreen->modified = false; 1141 // sw_mode->modified = false; 1142 } 1143 else 1144 { 1145 ri.Sys_Error( ERR_FATAL, "ref_soft::R_BeginFrame() - catastrophic mode change failure\n" ); 1146 } 1147 } 1148 } 1149 } 1150 1151 /* 1152 ** R_GammaCorrectAndSetPalette 1153 */ 1154 void R_GammaCorrectAndSetPalette( const unsigned char *palette ) 1155 { 1156 int i; 1157 1158 for ( i = 0; i < 256; i++ ) 1159 { 1160 sw_state.currentpalette[i*4+0] = sw_state.gammatable[palette[i*4+0]]; 1161 sw_state.currentpalette[i*4+1] = sw_state.gammatable[palette[i*4+1]]; 1162 sw_state.currentpalette[i*4+2] = sw_state.gammatable[palette[i*4+2]]; 1163 } 1164 1165 SWimp_SetPalette( sw_state.currentpalette ); 1166 } 1167 1168 /* 1169 ** R_CinematicSetPalette 1170 */ 1171 void R_CinematicSetPalette( const unsigned char *palette ) 1172 { 1173 byte palette32[1024]; 1174 int i, j, w; 1175 int *d; 1176 1177 // clear screen to black to avoid any palette flash 1178 w = abs(vid.rowbytes)>>2; // stupid negative pitch win32 stuff... 1179 for (i=0 ; i<vid.height ; i++, d+=w) 1180 { 1181 d = (int *)(vid.buffer + i*vid.rowbytes); 1182 for (j=0 ; j<w ; j++) 1183 d[j] = 0; 1184 } 1185 // flush it to the screen 1186 SWimp_EndFrame (); 1187 1188 if ( palette ) 1189 { 1190 for ( i = 0; i < 256; i++ ) 1191 { 1192 palette32[i*4+0] = palette[i*3+0]; 1193 palette32[i*4+1] = palette[i*3+1]; 1194 palette32[i*4+2] = palette[i*3+2]; 1195 palette32[i*4+3] = 0xFF; 1196 } 1197 1198 R_GammaCorrectAndSetPalette( palette32 ); 1199 } 1200 else 1201 { 1202 R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table ); 1203 } 1204 } 1205 1206 /* 1207 ================ 1208 Draw_BuildGammaTable 1209 ================ 1210 */ 1211 void Draw_BuildGammaTable (void) 1212 { 1213 int i, inf; 1214 float g; 1215 1216 g = vid_gamma->value; 1217 1218 if (g == 1.0) 1219 { 1220 for (i=0 ; i<256 ; i++) 1221 sw_state.gammatable[i] = i; 1222 return; 1223 } 1224 1225 for (i=0 ; i<256 ; i++) 1226 { 1227 inf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5; 1228 if (inf < 0) 1229 inf = 0; 1230 if (inf > 255) 1231 inf = 255; 1232 sw_state.gammatable[i] = inf; 1233 } 1234 } 1235 1236 /* 1237 ** R_DrawBeam 1238 */ 1239 void R_DrawBeam( entity_t *e ) 1240 { 1241 #define NUM_BEAM_SEGS 6 1242 1243 int i; 1244 1245 vec3_t perpvec; 1246 vec3_t direction, normalized_direction; 1247 vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS]; 1248 vec3_t oldorigin, origin; 1249 1250 oldorigin[0] = e->oldorigin[0]; 1251 oldorigin[1] = e->oldorigin[1]; 1252 oldorigin[2] = e->oldorigin[2]; 1253 1254 origin[0] = e->origin[0]; 1255 origin[1] = e->origin[1]; 1256 origin[2] = e->origin[2]; 1257 1258 normalized_direction[0] = direction[0] = oldorigin[0] - origin[0]; 1259 normalized_direction[1] = direction[1] = oldorigin[1] - origin[1]; 1260 normalized_direction[2] = direction[2] = oldorigin[2] - origin[2]; 1261 1262 if ( VectorNormalize( normalized_direction ) == 0 ) 1263 return; 1264 1265 PerpendicularVector( perpvec, normalized_direction ); 1266 VectorScale( perpvec, e->frame / 2, perpvec ); 1267 1268 for ( i = 0; i < NUM_BEAM_SEGS; i++ ) 1269 { 1270 RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i ); 1271 VectorAdd( start_points[i], origin, start_points[i] ); 1272 VectorAdd( start_points[i], direction, end_points[i] ); 1273 } 1274 1275 for ( i = 0; i < NUM_BEAM_SEGS; i++ ) 1276 { 1277 R_IMFlatShadedQuad( start_points[i], 1278 end_points[i], 1279 end_points[(i+1)%NUM_BEAM_SEGS], 1280 start_points[(i+1)%NUM_BEAM_SEGS], 1281 e->skinnum & 0xFF, 1282 e->alpha ); 1283 } 1284 } 1285 1286 1287 //=================================================================== 1288 1289 /* 1290 ============ 1291 R_SetSky 1292 ============ 1293 */ 1294 // 3dstudio environment map names 1295 char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"}; 1296 int r_skysideimage[6] = {5, 2, 4, 1, 0, 3}; 1297 extern mtexinfo_t r_skytexinfo[6]; 1298 void R_SetSky (char *name, float rotate, vec3_t axis) 1299 { 1300 int i; 1301 char pathname[MAX_QPATH]; 1302 1303 strncpy (skyname, name, sizeof(skyname)-1); 1304 skyrotate = rotate; 1305 VectorCopy (axis, skyaxis); 1306 1307 for (i=0 ; i<6 ; i++) 1308 { 1309 Com_sprintf (pathname, sizeof(pathname), "env/%s%s.pcx", skyname, suf[r_skysideimage[i]]); 1310 r_skytexinfo[i].image = R_FindImage (pathname, it_sky); 1311 } 1312 } 1313 1314 1315 /* 1316 =============== 1317 Draw_GetPalette 1318 =============== 1319 */ 1320 void Draw_GetPalette (void) 1321 { 1322 byte *pal, *out; 1323 int i; 1324 int r, g, b; 1325 1326 // get the palette and colormap 1327 LoadPCX ("pics/colormap.pcx", &vid.colormap, &pal, NULL, NULL); 1328 if (!vid.colormap) 1329 ri.Sys_Error (ERR_FATAL, "Couldn't load pics/colormap.pcx"); 1330 vid.alphamap = vid.colormap + 64*256; 1331 1332 out = (byte *)d_8to24table; 1333 for (i=0 ; i<256 ; i++, out+=4) 1334 { 1335 r = pal[i*3+0]; 1336 g = pal[i*3+1]; 1337 b = pal[i*3+2]; 1338 1339 out[0] = r; 1340 out[1] = g; 1341 out[2] = b; 1342 } 1343 1344 free (pal); 1345 } 1346 1347 struct image_s *R_RegisterSkin (char *name); 1348 1349 /* 1350 @@@@@@@@@@@@@@@@@@@@@ 1351 GetRefAPI 1352 1353 @@@@@@@@@@@@@@@@@@@@@ 1354 */ 1355 refexport_t GetRefAPI (refimport_t rimp) 1356 { 1357 refexport_t re; 1358 1359 ri = rimp; 1360 1361 re.api_version = API_VERSION; 1362 1363 re.BeginRegistration = R_BeginRegistration; 1364 re.RegisterModel = R_RegisterModel; 1365 re.RegisterSkin = R_RegisterSkin; 1366 re.RegisterPic = Draw_FindPic; 1367 re.SetSky = R_SetSky; 1368 re.EndRegistration = R_EndRegistration; 1369 1370 re.RenderFrame = R_RenderFrame; 1371 1372 re.DrawGetPicSize = Draw_GetPicSize; 1373 re.DrawPic = Draw_Pic; 1374 re.DrawStretchPic = Draw_StretchPic; 1375 re.DrawChar = Draw_Char; 1376 re.DrawTileClear = Draw_TileClear; 1377 re.DrawFill = Draw_Fill; 1378 re.DrawFadeScreen= Draw_FadeScreen; 1379 1380 re.DrawStretchRaw = Draw_StretchRaw; 1381 1382 re.Init = R_Init; 1383 re.Shutdown = R_Shutdown; 1384 1385 re.CinematicSetPalette = R_CinematicSetPalette; 1386 re.BeginFrame = R_BeginFrame; 1387 re.EndFrame = SWimp_EndFrame; 1388 1389 re.AppActivate = SWimp_AppActivate; 1390 1391 Swap_Init (); 1392 1393 return re; 1394 } 1395 1396 #ifndef REF_HARD_LINKED 1397 // this is only here so the functions in q_shared.c and q_shwin.c can link 1398 void Sys_Error (char *error, ...) 1399 { 1400 va_list argptr; 1401 char text[1024]; 1402 1403 va_start (argptr, error); 1404 vsprintf (text, error, argptr); 1405 va_end (argptr); 1406 1407 ri.Sys_Error (ERR_FATAL, "%s", text); 1408 } 1409 1410 void Com_Printf (char *fmt, ...) 1411 { 1412 va_list argptr; 1413 char text[1024]; 1414 1415 va_start (argptr, fmt); 1416 vsprintf (text, fmt, argptr); 1417 va_end (argptr); 1418 1419 ri.Con_Printf (PRINT_ALL, "%s", text); 1420 } 1421 1422 #endif