/* ================== V_RenderView The player's clipping box goes from (-16 -16 -24) to (16 16 32) from the entity origin, so any view position inside that will be valid ================== */ void V_RenderView (void) { if (con_forcedup) return; // don't allow cheats in multiplayer if (cl.maxclients > 1) { Cvar_Set ("scr_ofsx", "0"); Cvar_Set ("scr_ofsy", "0"); Cvar_Set ("scr_ofsz", "0"); } if (cl.intermission) { // intermission / finale rendering V_CalcIntermissionRefdef (); } else { if (!cl.paused /* && (sv.maxclients > 1 || key_dest == key_game) */ ) V_CalcRefdef (); } R_PushDlights (); if (lcd_x.value) { // // render two interleaved views // int i; vid.rowbytes <<= 1; vid.aspect *= 0.5f; r_refdef.viewangles[YAW] -= lcd_yaw.value; for (i=0 ; i<3 ; i++) r_refdef.vieworg[i] -= right[i]*lcd_x.value; R_RenderView (); vid.buffer += vid.rowbytes>>1; R_PushDlights (); r_refdef.viewangles[YAW] += lcd_yaw.value*2; for (i=0 ; i<3 ; i++) r_refdef.vieworg[i] += 2*right[i]*lcd_x.value; R_RenderView (); vid.buffer -= vid.rowbytes>>1; r_refdef.vrect.height <<= 1; vid.rowbytes >>= 1; vid.aspect *= 2; }
/* ================= R_XrayRender ================= */ void R_XrayRender( drawSurf_t *surf, textureStage_t *stage, idScreenRect scissor ) { viewDef_t *parms; // remote views can be reused in a single frame if( stage->dynamicFrameCount == tr.frameCount ) { return; } // issue a new view command parms = R_XrayViewBySurface( surf ); if( !parms ) { return; } tr.CropRenderSize( stage->width, stage->height, true ); parms->renderView.x = 0; parms->renderView.y = 0; parms->renderView.width = SCREEN_WIDTH; parms->renderView.height = SCREEN_HEIGHT; tr.RenderViewToViewport( &parms->renderView, &parms->viewport ); parms->scissor.x1 = 0; parms->scissor.y1 = 0; parms->scissor.x2 = parms->viewport.x2 - parms->viewport.x1; parms->scissor.y2 = parms->viewport.y2 - parms->viewport.y1; parms->superView = tr.viewDef; parms->subviewSurface = surf; // triangle culling order changes with mirroring parms->isMirror = ( ( ( int )parms->isMirror ^ ( int )tr.viewDef->isMirror ) != 0 ); // generate render commands for it R_RenderView( parms ); // copy this rendering to the image stage->dynamicFrameCount = tr.frameCount; stage->image = globalImages->scratchImage2; tr.CaptureRenderToImage( stage->image->imgName ); tr.UnCrop(); }
/* ==================== R_TimeRefresh_f For program optimization ==================== */ void R_TimeRefresh_f (void) { int i; float start, stop, time; int startangle; vrect_t vr; startangle = r_refdef.viewangles[1]; start = Sys_FloatTime (); for (i=0 ; i<128 ; i++) { r_refdef.viewangles[1] = i/128.0*360.0; VID_LockBuffer (); R_RenderView (); VID_UnlockBuffer (); vr.x = r_refdef.vrect.x; vr.y = r_refdef.vrect.y; vr.width = r_refdef.vrect.width; vr.height = r_refdef.vrect.height; vr.pnext = NULL; VID_Update (&vr); } stop = Sys_FloatTime (); time = stop-start; Con_Printf ("%f seconds (%f fps)\n", time, 128/time); r_refdef.viewangles[1] = startangle; }
/* ================== V_RenderView The player's clipping box goes from (-16 -16 -24) to (16 16 32) from the entity origin, so any view position inside that will be valid ================== */ void V_RenderView(void) { if (con_forcedup) return; // don't allow cheats in multiplayer if (cl.maxclients > 1) { Cvar_Set("scr_ofsx", "0"); Cvar_Set("scr_ofsy", "0"); Cvar_Set("scr_ofsz", "0"); } if (cl.intermission) { // intermission / finale rendering V_CalcIntermissionRefdef(); } else { if (!cl.paused /* && (sv.maxclients > 1 || key_dest == key_game) */ ) V_CalcRefdef(); } R_PushDlights(); R_RenderView(); #ifndef GLQUAKE if (crosshair.value) Draw_Crosshair(); #endif }
/* =============== R_RemoteRender =============== */ static void R_RemoteRender( drawSurf_t *surf, textureStage_t *stage ) { viewDef_t *parms; // remote views can be reused in a single frame if ( stage->dynamicFrameCount == tr.frameCount ) { return; } // if the entity doesn't have a remoteRenderView, do nothing if ( !surf->space->entityDef->parms.remoteRenderView ) { return; } // copy the viewport size from the original parms = (viewDef_t *)R_FrameAlloc( sizeof( *parms ) ); *parms = *tr.viewDef; parms->isSubview = true; parms->isMirror = false; parms->renderView = *surf->space->entityDef->parms.remoteRenderView; parms->renderView.viewID = 0; // clear to allow player bodies to show up, and suppress view weapons parms->initialViewAreaOrigin = parms->renderView.vieworg; tr.CropRenderSize( stage->width, stage->height, true ); parms->renderView.x = 0; parms->renderView.y = 0; parms->renderView.width = SCREEN_WIDTH; parms->renderView.height = SCREEN_HEIGHT; tr.RenderViewToViewport( &parms->renderView, &parms->viewport ); parms->scissor.x1 = 0; parms->scissor.y1 = 0; parms->scissor.x2 = parms->viewport.x2 - parms->viewport.x1; parms->scissor.y2 = parms->viewport.y2 - parms->viewport.y1; parms->superView = tr.viewDef; parms->subviewSurface = surf; // generate render commands for it R_RenderView(parms); // copy this rendering to the image stage->dynamicFrameCount = tr.frameCount; if (!stage->image) { stage->image = globalImages->scratchImage; } tr.CaptureRenderToImage( stage->image->imgName ); tr.UnCrop(); }
/* Grab six views for environment mapping tests */ void R_Envmap_f(void) { uint8_t buffer[256*256*4]; glDrawBuffer(GL_FRONT); glReadBuffer(GL_FRONT); r_refdef.bEnvironmentMap = true; r_refdef.vrect.x = r_refdef.vrect.y = 0; r_refdef.vrect.width = r_refdef.vrect.height = 256; Math_VectorClear(r_refdef.viewangles); GL_BeginRendering (&glx, &gly, &glwidth, &glheight); R_RenderView (); glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer); FileSystem_WriteFile ("env0.rgb", buffer, sizeof(buffer)); r_refdef.viewangles[1] = 90; GL_BeginRendering (&glx, &gly, &glwidth, &glheight); R_RenderView (); glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer); FileSystem_WriteFile ("env1.rgb", buffer, sizeof(buffer)); r_refdef.viewangles[1] = 180; GL_BeginRendering (&glx, &gly, &glwidth, &glheight); R_RenderView (); glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer); FileSystem_WriteFile ("env2.rgb", buffer, sizeof(buffer)); r_refdef.viewangles[1] = 270; GL_BeginRendering (&glx, &gly, &glwidth, &glheight); R_RenderView (); glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer); FileSystem_WriteFile ("env3.rgb", buffer, sizeof(buffer)); r_refdef.viewangles[0] = -90.0f; r_refdef.viewangles[1] = 0; GL_BeginRendering (&glx, &gly, &glwidth, &glheight); R_RenderView (); glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer); FileSystem_WriteFile("env4.rgb", buffer, sizeof(buffer)); r_refdef.viewangles[0] = 90; r_refdef.viewangles[1] = 0; GL_BeginRendering (&glx, &gly, &glwidth, &glheight); R_RenderView (); glReadPixels (0, 0, 256, 256, GL_RGBA, GL_UNSIGNED_BYTE, buffer); FileSystem_WriteFile("env5.rgb",buffer,sizeof(buffer)); r_refdef.bEnvironmentMap = false; glDrawBuffer(GL_BACK); glReadBuffer(GL_BACK); GL_EndRendering(); }
qboolean R_MirrorViewBySurface (drawSurf_t *drawSurf, int entityNum) { vec4_t clipDest[128]; viewParms_t newParms; viewParms_t oldParms; orientation_t surface, camera; // don't recursively mirror if (tr.viewParms.isPortal) { ri.Printf( PRINT_DEVELOPER, "WARNING: recursive mirror/portal found\n" ); return qfalse; } if ( r_noportals->integer || r_fastsky->integer ) { return qfalse; } // trivially reject portal/mirror if ( SurfIsOffscreen( drawSurf, clipDest ) ) { return qfalse; } // save old viewParms so we can return to it after the mirror view oldParms = tr.viewParms; newParms = tr.viewParms; newParms.isPortal = qtrue; if ( !R_GetPortalOrientations( drawSurf, entityNum, &surface, &camera, newParms.pvsOrigin, &newParms.isMirror ) ) { return qfalse; // bad portal, no portalentity } R_MirrorPoint (oldParms.or.origin, &surface, &camera, newParms.or.origin ); VectorSubtract( vec3_origin, camera.axis[0], newParms.portalPlane.normal ); newParms.portalPlane.dist = DotProduct( camera.origin, newParms.portalPlane.normal ); R_MirrorVector (oldParms.or.axis[0], &surface, &camera, newParms.or.axis[0]); R_MirrorVector (oldParms.or.axis[1], &surface, &camera, newParms.or.axis[1]); R_MirrorVector (oldParms.or.axis[2], &surface, &camera, newParms.or.axis[2]); // OPTIMIZE: restrict the viewport on the mirrored view // render the mirror view R_RenderView (&newParms); tr.viewParms = oldParms; return qtrue; }
void V_RenderView (void) { int i; translation_info_t translations[MAX_CLIENTS]; // if (cl.simangles[ROLL]) // Sys_Error ("cl.simangles[ROLL]"); // DEBUG cl.simangles[ROLL] = 0; // FIXME @@@ if (cls.state != ca_active) return; if (cl.validsequence) view_message = cl.frames[cl.validsequence & UPDATE_MASK].playerstate[Cam_PlayerNum()]; DropPunchAngle (); if (cl.intermission) { // intermission / finale rendering V_CalcIntermissionRefdef (); } else { V_CalcRefdef (); } r_refdef2.time = cl.time; // r_refdef2.allowCheats = false; r_refdef2.viewplayernum = Cam_PlayerNum(); r_refdef2.watervis = (atoi(Info_ValueForKey(cl.serverinfo, "watervis")) != 0); r_refdef2.lightstyles = cl_lightstyle; r_refdef2.numDlights = cl_numvisdlights; r_refdef2.dlights = cl_visdlights; r_refdef2.numParticles = 0; //cl_numvisparticles; r_refdef2.particles = NULL;//cl_visparticles; for (i = 0; i < MAX_CLIENTS; i++) { translations[i].topcolor = cl.players[i].topcolor; translations[i].bottomcolor = cl.players[i].bottomcolor; strlcpy (translations[i].skinname, cl.players[i].skin, sizeof(translations[0].skinname)); } r_refdef2.translations = translations; strlcpy (r_refdef2.baseskin, baseskin.string, sizeof(r_refdef2.baseskin)); R_RenderView (); }
void V_RenderView (void) { if (con_forcedup) return; if (cl.intermission) V_CalcIntermissionRefdef (); else if (!cl.paused /* && (cl.maxclients > 1 || key_dest == key_game) */) V_CalcRefdef (); //johnfitz -- removed lcd code R_RenderView (); V_PolyBlend (); //johnfitz -- moved here from R_Renderview (); }
void V_RenderView (void) { char *p; cl.simangles[ROLL] = 0; // FIXME @@@ if (cls.state != ca_active) { V_CalcBlend (); return; } view_frame = &cl.frames[cl.validsequence & UPDATE_MASK]; if (!cls.nqdemoplayback) view_message = view_frame->playerstate[cl.viewplayernum]; DropPunchAngle (); if (cl.intermission) // intermission / finale rendering V_CalcIntermissionRefdef (); else V_CalcRefdef (); R_PushDlights (); r_refdef2.time = cl.time; // restrictions r_refdef2.allow_cheats = (Info_ValueForKey(cl.serverinfo, "*cheats")[0] && com_serveractive) || cls.demoplayback; if (cls.demoplayback || cl.spectator) { r_refdef2.allow_lumas = true; r_refdef2.max_fbskins = 1; r_refdef2.max_watervis = 1; } else { r_refdef2.allow_lumas = !strcmp(Info_ValueForKey(cl.serverinfo, "24bit_fbs"), "0") ? false : true; r_refdef2.max_fbskins = *(p = Info_ValueForKey(cl.serverinfo, "fbskins")) ? bound(0, Q_atof(p), 1) : cl.teamfortress ? 0 : 1; r_refdef2.max_watervis = *(p = Info_ValueForKey(cl.serverinfo, "watervis")) ? bound(0, Q_atof(p), 1) : 0; } // r_refdef2.viewplayernum = Cam_PlayerNum(); // r_refdef2.lightstyles = cl_lightstyle; R_RenderView (); }
/* ================= R_XrayRender ================= */ void R_XrayRender( const drawSurf_t* surf, textureStage_t* stage, idScreenRect scissor ) { // remote views can be reused in a single frame if( stage->dynamicFrameCount == tr.frameCount ) { return; } // issue a new view command viewDef_t* parms = R_XrayViewBySurface( surf ); if( parms == NULL ) { return; } int stageWidth = stage->width; int stageHeight = stage->height; tr.CropRenderSize( stageWidth, stageHeight ); tr.GetCroppedViewport( &parms->viewport ); parms->scissor.x1 = 0; parms->scissor.y1 = 0; parms->scissor.x2 = parms->viewport.x2 - parms->viewport.x1; parms->scissor.y2 = parms->viewport.y2 - parms->viewport.y1; parms->superView = tr.viewDef; parms->subviewSurface = surf; // triangle culling order changes with mirroring parms->isMirror = ( ( ( int )parms->isMirror ^ ( int )tr.viewDef->isMirror ) != 0 ); // generate render commands for it R_RenderView( parms ); // copy this rendering to the image stage->dynamicFrameCount = tr.frameCount; stage->image = globalImages->scratchImage2; tr.CaptureRenderToImage( stage->image->GetName(), true ); tr.UnCrop(); }
/* For program optimization */ void R_TimeRefresh_f (void) { int i; float start, stop, time; glDrawBuffer (GL_FRONT); glFinish (); start = System_DoubleTime (); for (i=0 ; i<128 ; i++) { r_refdef.viewangles[1] = i/128.0f*360.0f; R_RenderView (); } glFinish (); stop = System_DoubleTime (); time = stop-start; Con_Printf("%f seconds (%f fps)\n",time,128/time); glDrawBuffer (GL_BACK); GL_EndRendering (); }
/* ==================== R_TimeRefresh_f For program optimization ==================== */ void R_TimeRefresh_f (void) { int i; double start, stop, time; int startangle; vrect_t vr; #ifdef PSP_SOFTWARE_VIDEO startangle = r_refdef.viewangles[1]; start = Sys_FloatTime (); for (i=0 ; i<128 ; i++) { r_refdef.viewangles[1] = i/128.0*360.0; VID_LockBuffer (); R_RenderView (); VID_UnlockBuffer (); vr.x = r_refdef.vrect.x; vr.y = r_refdef.vrect.y; vr.width = r_refdef.vrect.width; vr.height = r_refdef.vrect.height; vr.pnext = NULL; VID_Update (&vr); } stop = Sys_FloatTime (); time = stop-start; Con_Printf ("%f seconds (%f fps)\n", time, 128/time); r_refdef.viewangles[1] = startangle; #else Con_Printf ("Sorry: 'timerefresh' command disabled\n"); #endif }
/* * R_DrawPortalSurface * * Renders the portal view and captures the results from framebuffer if * we need to do a $portalmap stage. Note that for $portalmaps we must * use a different viewport. */ static void R_DrawPortalSurface( portalSurface_t *portalSurface ) { unsigned int i; int x, y, w, h; float dist, d, best_d; vec3_t viewerOrigin; vec3_t origin; mat3_t axis; entity_t *ent, *best; cplane_t *portal_plane = &portalSurface->plane, *untransformed_plane = &portalSurface->untransformed_plane; const shader_t *shader = portalSurface->shader; vec_t *portal_centre = portalSurface->centre; bool mirror, refraction = false; image_t *captureTexture; int captureTextureId = -1; int prevRenderFlags = 0; bool prevFlipped; bool doReflection, doRefraction; image_t *portalTexures[2] = { NULL, NULL }; doReflection = doRefraction = true; if( shader->flags & SHADER_PORTAL_CAPTURE ) { shaderpass_t *pass; captureTexture = NULL; captureTextureId = 0; for( i = 0, pass = shader->passes; i < shader->numpasses; i++, pass++ ) { if( pass->program_type == GLSL_PROGRAM_TYPE_DISTORTION ) { if( ( pass->alphagen.type == ALPHA_GEN_CONST && pass->alphagen.args[0] == 1 ) ) { doRefraction = false; } else if( ( pass->alphagen.type == ALPHA_GEN_CONST && pass->alphagen.args[0] == 0 ) ) { doReflection = false; } break; } } } else { captureTexture = NULL; captureTextureId = -1; } x = y = 0; w = rn.refdef.width; h = rn.refdef.height; dist = PlaneDiff( rn.viewOrigin, portal_plane ); if( dist <= BACKFACE_EPSILON || !doReflection ) { if( !( shader->flags & SHADER_PORTAL_CAPTURE2 ) || !doRefraction ) { return; } // even if we're behind the portal, we still need to capture // the second portal image for refraction refraction = true; captureTexture = NULL; captureTextureId = 1; if( dist < 0 ) { VectorInverse( portal_plane->normal ); portal_plane->dist = -portal_plane->dist; } } mirror = true; // default to mirror view // it is stupid IMO that mirrors require a RT_PORTALSURFACE entity best = NULL; best_d = 100000000; for( i = 0; i < rn.numEntities; i++ ) { ent = R_NUM2ENT( rn.entities[i] ); if( ent->rtype != RT_PORTALSURFACE ) { continue; } d = PlaneDiff( ent->origin, untransformed_plane ); if( ( d >= -64 ) && ( d <= 64 ) ) { d = Distance( ent->origin, portal_centre ); if( d < best_d ) { best = ent; best_d = d; } } } if( best == NULL ) { if( captureTextureId < 0 ) { // still do a push&pop because to ensure the clean state if( R_PushRefInst() ) { R_PopRefInst(); } return; } } else { if( !VectorCompare( best->origin, best->origin2 ) ) { // portal mirror = false; } best->rtype = NUM_RTYPES; } prevRenderFlags = rn.renderFlags; prevFlipped = ( rn.refdef.rdflags & RDF_FLIPPED ) != 0; if( !R_PushRefInst() ) { return; } VectorCopy( rn.viewOrigin, viewerOrigin ); if( prevFlipped ) { VectorInverse( &rn.viewAxis[AXIS_RIGHT] ); } setup_and_render: if( refraction ) { VectorInverse( portal_plane->normal ); portal_plane->dist = -portal_plane->dist; CategorizePlane( portal_plane ); VectorCopy( rn.viewOrigin, origin ); Matrix3_Copy( rn.refdef.viewaxis, axis ); VectorCopy( viewerOrigin, rn.pvsOrigin ); rn.renderFlags |= RF_PORTALVIEW; if( prevFlipped ) { rn.renderFlags |= RF_FLIPFRONTFACE; } } else if( mirror ) { VectorReflect( rn.viewOrigin, portal_plane->normal, portal_plane->dist, origin ); VectorReflect( &rn.viewAxis[AXIS_FORWARD], portal_plane->normal, 0, &axis[AXIS_FORWARD] ); VectorReflect( &rn.viewAxis[AXIS_RIGHT], portal_plane->normal, 0, &axis[AXIS_RIGHT] ); VectorReflect( &rn.viewAxis[AXIS_UP], portal_plane->normal, 0, &axis[AXIS_UP] ); Matrix3_Normalize( axis ); VectorCopy( viewerOrigin, rn.pvsOrigin ); rn.renderFlags = ( prevRenderFlags ^ RF_FLIPFRONTFACE ) | RF_MIRRORVIEW; } else { vec3_t tvec; mat3_t A, B, C, rot; // build world-to-portal rotation matrix VectorNegate( portal_plane->normal, tvec ); NormalVectorToAxis( tvec, A ); // build portal_dest-to-world rotation matrix ByteToDir( best->frame, tvec ); NormalVectorToAxis( tvec, B ); Matrix3_Transpose( B, C ); // multiply to get world-to-world rotation matrix Matrix3_Multiply( C, A, rot ); // translate view origin VectorSubtract( rn.viewOrigin, best->origin, tvec ); Matrix3_TransformVector( rot, tvec, origin ); VectorAdd( origin, best->origin2, origin ); Matrix3_Transpose( A, B ); Matrix3_Multiply( rn.viewAxis, B, rot ); Matrix3_Multiply( best->axis, rot, B ); Matrix3_Transpose( C, A ); Matrix3_Multiply( B, A, axis ); // set up portal_plane VectorCopy( &axis[AXIS_FORWARD], portal_plane->normal ); portal_plane->dist = DotProduct( best->origin2, portal_plane->normal ); CategorizePlane( portal_plane ); // for portals, vis data is taken from portal origin, not // view origin, because the view point moves around and // might fly into (or behind) a wall VectorCopy( best->origin2, rn.pvsOrigin ); VectorCopy( best->origin2, rn.lodOrigin ); rn.renderFlags |= RF_PORTALVIEW; // ignore entities, if asked politely if( best->renderfx & RF_NOPORTALENTS ) { rn.renderFlags |= RF_ENVVIEW; } if( prevFlipped ) { rn.renderFlags |= RF_FLIPFRONTFACE; } } rn.refdef.rdflags &= ~( RDF_UNDERWATER | RDF_CROSSINGWATER | RDF_FLIPPED ); rn.meshlist = &r_portallist; rn.portalmasklist = NULL; rn.renderFlags |= RF_CLIPPLANE; rn.renderFlags &= ~RF_SOFT_PARTICLES; rn.clipPlane = *portal_plane; rn.nearClip = Z_NEAR; rn.farClip = R_DefaultFarClip(); rn.polygonFactor = POLYOFFSET_FACTOR; rn.polygonUnits = POLYOFFSET_UNITS; rn.clipFlags |= 16; rn.frustum[4] = *portal_plane; // nearclip CategorizePlane( &rn.frustum[4] ); // if we want to render to a texture, initialize texture // but do not try to render to it more than once if( captureTextureId >= 0 ) { int texFlags = shader->flags & SHADER_NO_TEX_FILTERING ? IT_NOFILTERING : 0; captureTexture = R_GetPortalTexture( rsc.refdef.width, rsc.refdef.height, texFlags, rsc.frameCount ); portalTexures[captureTextureId] = captureTexture; if( !captureTexture ) { // couldn't register a slot for this plane goto done; } x = y = 0; w = captureTexture->upload_width; h = captureTexture->upload_height; rn.refdef.width = w; rn.refdef.height = h; rn.refdef.x = 0; rn.refdef.y = 0; rn.renderTarget = captureTexture->fbo; rn.renderFlags |= RF_PORTAL_CAPTURE; Vector4Set( rn.viewport, rn.refdef.x + x, rn.refdef.y + y, w, h ); Vector4Set( rn.scissor, rn.refdef.x + x, rn.refdef.y + y, w, h ); } else { rn.renderFlags &= ~RF_PORTAL_CAPTURE; } VectorCopy( origin, rn.refdef.vieworg ); Matrix3_Copy( axis, rn.refdef.viewaxis ); R_SetupViewMatrices( &rn.refdef ); R_SetupFrustum( &rn.refdef, rn.nearClip, rn.farClip, rn.frustum, rn.frustumCorners ); R_SetupPVS( &rn.refdef ); R_RenderView( &rn.refdef ); if( doRefraction && !refraction && ( shader->flags & SHADER_PORTAL_CAPTURE2 ) ) { rn.renderFlags = prevRenderFlags; refraction = true; captureTexture = NULL; captureTextureId = 1; goto setup_and_render; } done: portalSurface->texures[0] = portalTexures[0]; portalSurface->texures[1] = portalTexures[1]; R_PopRefInst(); }
/* * R_DrawSkyportal */ static void R_DrawSkyportal( const entity_t *e, skyportal_t *skyportal ) { if( !R_PushRefInst() ) { return; } rn.renderFlags = ( rn.renderFlags | RF_PORTALVIEW ); //rn.renderFlags &= ~RF_SOFT_PARTICLES; VectorCopy( skyportal->vieworg, rn.pvsOrigin ); rn.nearClip = Z_NEAR; rn.farClip = R_DefaultFarClip(); rn.polygonFactor = POLYOFFSET_FACTOR; rn.polygonUnits = POLYOFFSET_UNITS; rn.clipFlags = 15; rn.meshlist = &r_skyportallist; rn.portalmasklist = NULL; rn.rtLight = NULL; //Vector4Set( rn.scissor, rn.refdef.x + x, rn.refdef.y + y, w, h ); if( skyportal->noEnts ) { rn.renderFlags |= RF_ENVVIEW; } if( skyportal->scale ) { vec3_t centre, diff; VectorAdd( rsh.worldModel->mins, rsh.worldModel->maxs, centre ); VectorScale( centre, 0.5f, centre ); VectorSubtract( centre, rn.viewOrigin, diff ); VectorMA( skyportal->vieworg, -skyportal->scale, diff, rn.refdef.vieworg ); } else { VectorCopy( skyportal->vieworg, rn.refdef.vieworg ); } // FIXME if( !VectorCompare( skyportal->viewanglesOffset, vec3_origin ) ) { vec3_t angles; mat3_t axis; Matrix3_Copy( rn.refdef.viewaxis, axis ); VectorInverse( &axis[AXIS_RIGHT] ); Matrix3_ToAngles( axis, angles ); VectorAdd( angles, skyportal->viewanglesOffset, angles ); AnglesToAxis( angles, axis ); Matrix3_Copy( axis, rn.refdef.viewaxis ); } rn.refdef.rdflags &= ~( RDF_UNDERWATER | RDF_CROSSINGWATER | RDF_SKYPORTALINVIEW ); if( skyportal->fov ) { rn.refdef.fov_y = WidescreenFov( skyportal->fov ); rn.refdef.fov_x = CalcHorizontalFov( rn.refdef.fov_y, rn.refdef.width, rn.refdef.height ); } R_SetupViewMatrices( &rn.refdef ); R_SetupFrustum( &rn.refdef, rn.nearClip, rn.farClip, rn.frustum, rn.frustumCorners ); R_SetupPVS( &rn.refdef ); R_RenderView( &rn.refdef ); // restore modelview and projection matrices, scissoring, etc for the main view R_PopRefInst(); }
/* @@@@@@@@@@@@@@@@@@@@@ RE_RenderScene Draw a 3D view into a part of the window, then return to 2D drawing. Rendering a scene may require multiple views to be rendered to handle mirrors, @@@@@@@@@@@@@@@@@@@@@ */ void RE_RenderScene( const refdef_t *fd ) { viewParms_t parms; int startTime; if ( !tr.registered ) { return; } GLimp_LogComment( "====== RE_RenderScene =====\n" ); if ( r_norefresh->integer ) { return; } startTime = ri.Milliseconds(); if ( !tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) { ri.Error(errorParm_t::ERR_DROP, "R_RenderScene: NULL worldmodel" ); } tr.refdef.x = fd->x; tr.refdef.y = fd->y; tr.refdef.width = fd->width; tr.refdef.height = fd->height; tr.refdef.fov_x = fd->fov_x; tr.refdef.fov_y = fd->fov_y; VectorCopy( fd->vieworg, tr.refdef.vieworg ); VectorCopy( fd->viewaxis[ 0 ], tr.refdef.viewaxis[ 0 ] ); VectorCopy( fd->viewaxis[ 1 ], tr.refdef.viewaxis[ 1 ] ); VectorCopy( fd->viewaxis[ 2 ], tr.refdef.viewaxis[ 2 ] ); VectorCopy( fd->blurVec, tr.refdef.blurVec ); tr.refdef.time = fd->time; tr.refdef.rdflags = fd->rdflags; // copy the areamask data over and note if it has changed, which // will force a reset of the visible leafs even if the view hasn't moved tr.refdef.areamaskModified = false; if ( !( tr.refdef.rdflags & RDF_NOWORLDMODEL ) && !( ( tr.refdef.rdflags & RDF_SKYBOXPORTAL ) && tr.world->numSkyNodes > 0 ) ) { int areaDiff; int i; // compare the area bits areaDiff = 0; for ( i = 0; i < MAX_MAP_AREA_BYTES / 4; i++ ) { areaDiff |= ( ( int * ) tr.refdef.areamask ) [ i ] ^ ( ( int * ) fd->areamask ) [ i ]; ( ( int * ) tr.refdef.areamask ) [ i ] = ( ( int * ) fd->areamask ) [ i ]; } if ( areaDiff ) { // a door just opened or something tr.refdef.areamaskModified = true; } } R_AddWorldLightsToScene(); // derived info tr.refdef.floatTime = float(double(tr.refdef.time) * 0.001); tr.refdef.numDrawSurfs = r_firstSceneDrawSurf; tr.refdef.drawSurfs = backEndData[ tr.smpFrame ]->drawSurfs; tr.refdef.numInteractions = r_firstSceneInteraction; tr.refdef.interactions = backEndData[ tr.smpFrame ]->interactions; tr.refdef.numEntities = r_numEntities - r_firstSceneEntity; tr.refdef.entities = &backEndData[ tr.smpFrame ]->entities[ r_firstSceneEntity ]; tr.refdef.numLights = r_numLights - r_firstSceneLight; tr.refdef.lights = &backEndData[ tr.smpFrame ]->lights[ r_firstSceneLight ]; tr.refdef.numPolys = r_numPolys - r_firstScenePoly; tr.refdef.polys = &backEndData[ tr.smpFrame ]->polys[ r_firstScenePoly ]; tr.refdef.numPolybuffers = r_numPolybuffers - r_firstScenePolybuffer; tr.refdef.polybuffers = &backEndData[ tr.smpFrame ]->polybuffers[ r_firstScenePolybuffer ]; tr.refdef.numDecalProjectors = r_numDecalProjectors - r_firstSceneDecalProjector; tr.refdef.decalProjectors = &backEndData[ tr.smpFrame ]->decalProjectors[ r_firstSceneDecalProjector ]; tr.refdef.numDecals = r_numDecals - r_firstSceneDecal; tr.refdef.decals = &backEndData[ tr.smpFrame ]->decals[ r_firstSceneDecal ]; tr.refdef.numVisTests = r_numVisTests - r_firstSceneVisTest; tr.refdef.visTests = &backEndData[ tr.smpFrame ]->visTests[ r_firstSceneVisTest ]; // a single frame may have multiple scenes draw inside it -- // a 3D game view, 3D status bar renderings, 3D menus, etc. // They need to be distinguished by the light flare code, because // the visibility state for a given surface may be different in // each scene / view. tr.frameSceneNum++; tr.sceneCount++; // Tr3B: a scene can have multiple views caused by mirrors or portals // the number of views is restricted so we can use hardware occlusion queries // and put them into the BSP nodes for each view tr.viewCount = -1; // setup view parms for the initial view // // set up viewport // The refdef takes 0-at-the-top y coordinates, so // convert to GL's 0-at-the-bottom space // Com_Memset( &parms, 0, sizeof( parms ) ); if ( tr.refdef.pixelTarget == nullptr ) { parms.viewportX = tr.refdef.x; parms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height ); } else { //Driver bug, if we try and do pixel target work along the top edge of a window //we can end up capturing part of the status bar. (see screenshot corruption..) //Soooo.. use the middle. parms.viewportX = glConfig.vidWidth / 2; parms.viewportY = glConfig.vidHeight / 2; } parms.viewportWidth = tr.refdef.width; parms.viewportHeight = tr.refdef.height; parms.scissorX = parms.viewportX; parms.scissorY = parms.viewportY; parms.scissorWidth = parms.viewportWidth; parms.scissorHeight = parms.viewportHeight; Vector4Set( parms.viewportVerts[ 0 ], parms.viewportX, parms.viewportY, 0, 1 ); Vector4Set( parms.viewportVerts[ 1 ], parms.viewportX + parms.viewportWidth, parms.viewportY, 0, 1 ); Vector4Set( parms.viewportVerts[ 2 ], parms.viewportX + parms.viewportWidth, parms.viewportY + parms.viewportHeight, 0, 1 ); Vector4Set( parms.viewportVerts[ 3 ], parms.viewportX, parms.viewportY + parms.viewportHeight, 0, 1 ); parms.isPortal = false; parms.fovX = tr.refdef.fov_x; parms.fovY = tr.refdef.fov_y; VectorCopy( fd->vieworg, parms.orientation.origin ); VectorCopy( fd->viewaxis[ 0 ], parms.orientation.axis[ 0 ] ); VectorCopy( fd->viewaxis[ 1 ], parms.orientation.axis[ 1 ] ); VectorCopy( fd->viewaxis[ 2 ], parms.orientation.axis[ 2 ] ); VectorCopy( fd->vieworg, parms.pvsOrigin ); Vector4Copy( fd->gradingWeights, parms.gradingWeights ); R_RenderView( &parms ); R_RenderPostProcess(); // the next scene rendered in this frame will tack on after this one r_firstSceneDrawSurf = tr.refdef.numDrawSurfs; r_firstSceneInteraction = tr.refdef.numInteractions; r_firstSceneEntity = r_numEntities; r_firstSceneLight = r_numLights; r_firstScenePoly = r_numPolys; r_firstScenePolybuffer = r_numPolybuffers; r_firstSceneVisTest = r_numVisTests; tr.frontEndMsec += ri.Milliseconds() - startTime; }
/* * R_EnvShot_f */ void R_EnvShot_f( void ) { int i; int size, maxSize; const char *writedir, *gamedir; int checkname_size; char *checkname; refdef_t fd; struct cubemapSufAndFlip { char *suf; vec3_t angles; int flags; } cubemapShots[6] = { { "px", { 0, 0, 0 }, IT_FLIPX|IT_FLIPY|IT_FLIPDIAGONAL }, { "nx", { 0, 180, 0 }, IT_FLIPDIAGONAL }, { "py", { 0, 90, 0 }, IT_FLIPY }, { "ny", { 0, 270, 0 }, IT_FLIPX }, { "pz", { -90, 180, 0 }, IT_FLIPDIAGONAL }, { "nz", { 90, 180, 0 }, IT_FLIPDIAGONAL } }; if( !R_ScreenEnabled() || !rsh.worldModel ) return; if( ri.Cmd_Argc() != 3 ) { Com_Printf( "usage: envshot <name> <size>\n" ); return; } maxSize = min( min( glConfig.width, glConfig.height ), glConfig.maxTextureSize ); if( maxSize > atoi( ri.Cmd_Argv( 2 ) ) ) maxSize = atoi( ri.Cmd_Argv( 2 ) ); for( size = 1; size < maxSize; size <<= 1 ) ; if( size > maxSize ) size >>= 1; writedir = ri.FS_WriteDirectory(); gamedir = ri.FS_GameDirectory(); checkname_size = strlen( writedir ) + 1 + strlen( gamedir ) + strlen( "/env/" ) + strlen( ri.Cmd_Argv( 1 ) ) + 1 + strlen( cubemapShots[0].suf ) + 4 + 1; checkname = alloca( checkname_size ); fd = rsc.refdef; fd.time = 0; //fd.x = fd.y = 0; fd.width = fd.height = size; fd.fov_x = fd.fov_y = 90; rn.farClip = R_DefaultFarClip(); // do not render non-bmodel entities rn.renderFlags |= RF_CUBEMAPVIEW; rn.clipFlags = 15; rn.shadowGroup = NULL; rn.fbColorAttachment = rn.fbDepthAttachment = NULL; Vector4Set( rn.viewport, fd.x, glConfig.height - size - fd.y, size, size ); Vector4Set( rn.scissor, fd.x, glConfig.height - size - fd.y, size, size ); for( i = 0; i < 6; i++ ) { AnglesToAxis( cubemapShots[i].angles, fd.viewaxis ); R_RenderView( &fd ); Q_snprintfz( checkname, checkname_size, "%s/%s/env/%s_%s", writedir, gamedir, ri.Cmd_Argv( 1 ), cubemapShots[i].suf ); COM_DefaultExtension( checkname, ".tga", checkname_size ); R_ScreenShot( checkname, 0, 0, size, size, 100, ( cubemapShots[i].flags & IT_FLIPX ) ? true : false, ( cubemapShots[i].flags & IT_FLIPY ) ? true : false, ( cubemapShots[i].flags & IT_FLIPDIAGONAL ) ? true : false, false ); } // render non-bmodel entities again rn.renderFlags &= ~RF_CUBEMAPVIEW; }
/* @@@@@@@@@@@@@@@@@@@@@ RE_RenderScene Draw a 3D view into a part of the window, then return to 2D drawing. Rendering a scene may require multiple views to be rendered to handle mirrors, @@@@@@@@@@@@@@@@@@@@@ */ void RE_RenderScene( const refdef_t *fd ) { viewParms_t parms; int startTime; if ( !tr.registered ) { return; } GLimp_LogComment( "====== RE_RenderScene =====\n" ); if ( r_norefresh->integer ) { return; } startTime = ri.RealMilliseconds(); if (!tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) { ri.Error (ERR_DROP, "R_RenderScene: NULL worldmodel"); } RE_BeginScene(fd); // SmileTheory: playing with shadow mapping if (!( fd->rdflags & RDF_NOWORLDMODEL ) && tr.refdef.num_dlights && r_dlightMode->integer >= 2) { R_RenderDlightCubemaps(fd); } /* playing with more shadows */ if(glRefConfig.framebufferObject && !( fd->rdflags & RDF_NOWORLDMODEL ) && r_shadows->integer == 4) { R_RenderPshadowMaps(fd); } // playing with even more shadows if(glRefConfig.framebufferObject && r_sunlightMode->integer && !( fd->rdflags & RDF_NOWORLDMODEL ) && (r_forceSun->integer || tr.sunShadows)) { if (r_shadowCascadeZFar->integer != 0) { R_RenderSunShadowMaps(fd, 0); R_RenderSunShadowMaps(fd, 1); R_RenderSunShadowMaps(fd, 2); } else { Mat4Zero(tr.refdef.sunShadowMvp[0]); Mat4Zero(tr.refdef.sunShadowMvp[1]); Mat4Zero(tr.refdef.sunShadowMvp[2]); } // only rerender last cascade if sun has changed position if (r_forceSun->integer == 2 || !VectorCompare(tr.refdef.sunDir, tr.lastCascadeSunDirection)) { VectorCopy(tr.refdef.sunDir, tr.lastCascadeSunDirection); R_RenderSunShadowMaps(fd, 3); Mat4Copy(tr.refdef.sunShadowMvp[3], tr.lastCascadeSunMvp); } else { Mat4Copy(tr.lastCascadeSunMvp, tr.refdef.sunShadowMvp[3]); } } // playing with cube maps // this is where dynamic cubemaps would be rendered if (0) //(glRefConfig.framebufferObject && !( fd->rdflags & RDF_NOWORLDMODEL )) { int i, j; for (i = 0; i < tr.numCubemaps; i++) { for (j = 0; j < 6; j++) { R_RenderCubemapSide(i, j, qtrue); } } } // setup view parms for the initial view // // set up viewport // The refdef takes 0-at-the-top y coordinates, so // convert to GL's 0-at-the-bottom space // Com_Memset( &parms, 0, sizeof( parms ) ); parms.viewportX = tr.refdef.x; parms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height ); parms.viewportWidth = tr.refdef.width; parms.viewportHeight = tr.refdef.height; parms.isPortal = qfalse; parms.fovX = tr.refdef.fov_x; parms.fovY = tr.refdef.fov_y; parms.stereoFrame = tr.refdef.stereoFrame; VectorCopy( fd->vieworg, parms.or.origin ); VectorCopy( fd->viewaxis[0], parms.or.axis[0] ); VectorCopy( fd->viewaxis[1], parms.or.axis[1] ); VectorCopy( fd->viewaxis[2], parms.or.axis[2] ); VectorCopy( fd->vieworg, parms.pvsOrigin ); if(!( fd->rdflags & RDF_NOWORLDMODEL ) && r_depthPrepass->value && ((r_forceSun->integer) || tr.sunShadows)) { parms.flags = VPF_USESUNLIGHT; } R_RenderView( &parms ); if(!( fd->rdflags & RDF_NOWORLDMODEL )) R_AddPostProcessCmd(); RE_EndScene(); tr.frontEndMsec += ri.RealMilliseconds() - startTime; }
/* @@@@@@@@@@@@@@@@@@@@@ RE_RenderScene Draw a 3D view into a part of the window, then return to 2D drawing. Rendering a scene may require multiple views to be rendered to handle mirrors, @@@@@@@@@@@@@@@@@@@@@ */ void RE_RenderScene( const refdef_t *fd ) { viewParms_t parms; int startTime; if ( !tr.registered ) { return; } GLimp_LogComment( "====== RE_RenderScene =====\n" ); if ( r_norefresh->integer ) { return; } startTime = ri.Milliseconds(); if (!tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) { ri.Error (ERR_DROP, "R_RenderScene: NULL worldmodel"); } Com_Memcpy( tr.refdef.text, fd->text, sizeof( tr.refdef.text ) ); tr.refdef.x = fd->x; tr.refdef.y = fd->y; tr.refdef.width = fd->width; tr.refdef.height = fd->height; tr.refdef.fov_x = fd->fov_x; tr.refdef.fov_y = fd->fov_y; VectorCopy( fd->vieworg, tr.refdef.vieworg ); VectorCopy( fd->viewaxis[0], tr.refdef.viewaxis[0] ); VectorCopy( fd->viewaxis[1], tr.refdef.viewaxis[1] ); VectorCopy( fd->viewaxis[2], tr.refdef.viewaxis[2] ); tr.refdef.time = fd->time; tr.refdef.rdflags = fd->rdflags; // copy the areamask data over and note if it has changed, which // will force a reset of the visible leafs even if the view hasn't moved tr.refdef.areamaskModified = qfalse; if ( ! (tr.refdef.rdflags & RDF_NOWORLDMODEL) ) { int areaDiff; int i; // compare the area bits areaDiff = 0; for (i = 0 ; i < MAX_MAP_AREA_BYTES/4 ; i++) { areaDiff |= ((int *)tr.refdef.areamask)[i] ^ ((int *)fd->areamask)[i]; ((int *)tr.refdef.areamask)[i] = ((int *)fd->areamask)[i]; } if ( areaDiff ) { // a door just opened or something tr.refdef.areamaskModified = qtrue; } } // derived info tr.refdef.floatTime = tr.refdef.time * 0.001f; tr.refdef.numDrawSurfs = r_firstSceneDrawSurf; tr.refdef.drawSurfs = backEndData[tr.smpFrame]->drawSurfs; tr.refdef.num_entities = r_numentities - r_firstSceneEntity; tr.refdef.entities = &backEndData[tr.smpFrame]->entities[r_firstSceneEntity]; tr.refdef.num_dlights = r_numdlights - r_firstSceneDlight; tr.refdef.dlights = &backEndData[tr.smpFrame]->dlights[r_firstSceneDlight]; tr.refdef.numPolys = r_numpolys - r_firstScenePoly; tr.refdef.polys = &backEndData[tr.smpFrame]->polys[r_firstScenePoly]; // turn off dynamic lighting globally by clearing all the // dlights if it needs to be disabled or if vertex lighting is enabled if ( r_dynamiclight->integer == 0 || r_vertexLight->integer == 1 || glConfig.hardwareType == GLHW_PERMEDIA2 ) { tr.refdef.num_dlights = 0; } // a single frame may have multiple scenes draw inside it -- // a 3D game view, 3D status bar renderings, 3D menus, etc. // They need to be distinguished by the light flare code, because // the visibility state for a given surface may be different in // each scene / view. tr.frameSceneNum++; tr.sceneCount++; // setup view parms for the initial view // // set up viewport // The refdef takes 0-at-the-top y coordinates, so // convert to GL's 0-at-the-bottom space // Com_Memset( &parms, 0, sizeof( parms ) ); parms.viewportX = tr.refdef.x; parms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height ); parms.viewportWidth = tr.refdef.width; parms.viewportHeight = tr.refdef.height; parms.isPortal = qfalse; parms.fovX = tr.refdef.fov_x; parms.fovY = tr.refdef.fov_y; VectorCopy( fd->vieworg, parms.or.origin ); VectorCopy( fd->viewaxis[0], parms.or.axis[0] ); VectorCopy( fd->viewaxis[1], parms.or.axis[1] ); VectorCopy( fd->viewaxis[2], parms.or.axis[2] ); VectorCopy( fd->vieworg, parms.pvsOrigin ); R_RenderView( &parms ); // the next scene rendered in this frame will tack on after this one r_firstSceneDrawSurf = tr.refdef.numDrawSurfs; r_firstSceneEntity = r_numentities; r_firstSceneDlight = r_numdlights; r_firstScenePoly = r_numpolys; tr.frontEndMsec += ri.Milliseconds() - startTime; }
/* @@@@@@@@@@@@@@@@@@@@@ RE_RenderScene Draw a 3D view into a part of the window, then return to 2D drawing. Rendering a scene may require multiple views to be rendered to handle mirrors, @@@@@@@@@@@@@@@@@@@@@ */ void RE_RenderScene( const refdef_t *vmRefDef, int vmRefDefSize ) { refdef_t fd; viewParms_t parms; int startTime; if ( !tr.registered ) { return; } GLimp_LogComment( "====== RE_RenderScene =====\n" ); if ( r_norefresh->integer ) { return; } startTime = ri.Milliseconds(); Com_Memcpy2( &fd, sizeof ( refdef_t ), vmRefDef, vmRefDefSize ); if (!tr.world && !( fd.rdflags & RDF_NOWORLDMODEL ) ) { ri.Error (ERR_DROP, "R_RenderScene: NULL worldmodel"); } Com_Memcpy( tr.refdef.text, fd.text, sizeof( tr.refdef.text ) ); tr.refdef.x = fd.x; tr.refdef.y = fd.y; tr.refdef.width = fd.width; tr.refdef.height = fd.height; tr.refdef.fov_x = fd.fov_x; tr.refdef.fov_y = fd.fov_y; VectorCopy( fd.vieworg, tr.refdef.vieworg ); VectorCopy( fd.viewaxis[0], tr.refdef.viewaxis[0] ); VectorCopy( fd.viewaxis[1], tr.refdef.viewaxis[1] ); VectorCopy( fd.viewaxis[2], tr.refdef.viewaxis[2] ); tr.refdef.time = fd.time; tr.refdef.rdflags = fd.rdflags; tr.refdef.skyAlpha = fd.skyAlpha; tr.refdef.fogType = fd.fogType; if ( tr.refdef.fogType < FT_NONE || tr.refdef.fogType >= FT_MAX_FOG_TYPE ) { tr.refdef.fogType = FT_NONE; } tr.refdef.fogColor[0] = fd.fogColor[0] * tr.identityLight; tr.refdef.fogColor[1] = fd.fogColor[1] * tr.identityLight; tr.refdef.fogColor[2] = fd.fogColor[2] * tr.identityLight; tr.refdef.fogColorInt = ColorBytes4( tr.refdef.fogColor[0], tr.refdef.fogColor[1], tr.refdef.fogColor[2], 1.0 ); tr.refdef.fogDensity = fd.fogDensity; if ( r_zfar->value ) { tr.refdef.fogDepthForOpaque = r_zfar->value < 1 ? 1 : r_zfar->value; } else { tr.refdef.fogDepthForOpaque = fd.fogDepthForOpaque < 1 ? 1 : fd.fogDepthForOpaque; } tr.refdef.fogTcScale = R_FogTcScale( tr.refdef.fogType, tr.refdef.fogDepthForOpaque, tr.refdef.fogDensity ); // copy the areamask data over and note if it has changed, which // will force a reset of the visible leafs even if the view hasn't moved tr.refdef.areamaskModified = qfalse; if ( ! (tr.refdef.rdflags & RDF_NOWORLDMODEL) ) { int areaDiff; int i; // compare the area bits areaDiff = 0; for (i = 0 ; i < MAX_MAP_AREA_BYTES/4 ; i++) { areaDiff |= ((int *)tr.refdef.areamask)[i] ^ ((int *)fd.areamask)[i]; ((int *)tr.refdef.areamask)[i] = ((int *)fd.areamask)[i]; } if ( areaDiff ) { // a door just opened or something tr.refdef.areamaskModified = qtrue; } } // derived info tr.refdef.floatTime = tr.refdef.time * 0.001f; tr.refdef.numDrawSurfs = r_firstSceneDrawSurf; tr.refdef.drawSurfs = backEndData->drawSurfs; tr.refdef.numSkins = r_numskins; tr.refdef.skins = backEndData->skins; tr.refdef.num_entities = r_numentities - r_firstSceneEntity; tr.refdef.entities = &backEndData->entities[r_firstSceneEntity]; tr.refdef.num_dlights = r_numdlights - r_firstSceneDlight; tr.refdef.dlights = &backEndData->dlights[r_firstSceneDlight]; tr.refdef.dlightBits = 0; tr.refdef.num_coronas = r_numcoronas - r_firstSceneCorona; tr.refdef.coronas = &backEndData->coronas[r_firstSceneCorona]; tr.refdef.numPolys = r_numpolys - r_firstScenePoly; tr.refdef.polys = &backEndData->polys[r_firstScenePoly]; tr.refdef.numPolyBuffers = r_numpolybuffers - r_firstScenePolybuffer; tr.refdef.polybuffers = &backEndData->polybuffers[r_firstScenePolybuffer]; // turn off dynamic lighting globally by clearing all the // dlights if it needs to be disabled or if vertex lighting is enabled if ( r_dynamiclight->integer == 0 || r_vertexLight->integer == 1 ) { tr.refdef.num_dlights = 0; } // a single frame may have multiple scenes draw inside it -- // a 3D game view, 3D status bar renderings, 3D menus, etc. // They need to be distinguished by the light flare code, because // the visibility state for a given surface may be different in // each scene / view. tr.frameSceneNum++; tr.sceneCount++; // setup view parms for the initial view // // set up viewport // The refdef takes 0-at-the-top y coordinates, so // convert to GL's 0-at-the-bottom space // Com_Memset( &parms, 0, sizeof( parms ) ); parms.viewportX = tr.refdef.x; parms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height ); parms.viewportWidth = tr.refdef.width; parms.viewportHeight = tr.refdef.height; parms.isPortal = qfalse; parms.fovX = tr.refdef.fov_x; parms.fovY = tr.refdef.fov_y; parms.stereoFrame = tr.refdef.stereoFrame; VectorCopy( fd.vieworg, parms.or.origin ); VectorCopy( fd.viewaxis[0], parms.or.axis[0] ); VectorCopy( fd.viewaxis[1], parms.or.axis[1] ); VectorCopy( fd.viewaxis[2], parms.or.axis[2] ); VectorCopy( fd.vieworg, parms.pvsOrigin ); R_RenderView( &parms ); // the next scene rendered in this frame will tack on after this one r_firstSceneDrawSurf = tr.refdef.numDrawSurfs; r_firstSceneEntity = r_numentities; r_firstSceneDlight = r_numdlights; r_firstScenePoly = r_numpolys; r_firstScenePolybuffer = r_numpolybuffers; tr.frontEndMsec += ri.Milliseconds() - startTime; }
/* @@@@@@@@@@@@@@@@@@@@@ RE_RenderScene Draw a 3D view into a part of the window, then return to 2D drawing. Rendering a scene may require multiple views to be rendered to handle mirrors, @@@@@@@@@@@@@@@@@@@@@ */ void RE_RenderScene( const refdef_t *fd ) { viewParms_t parms; int startTime; if ( !tr.registered ) { return; } GLimp_LogComment( "====== RE_RenderScene =====\n" ); if ( r_norefresh->integer ) { return; } startTime = ri.Milliseconds(); if (!tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) { ri.Error (ERR_DROP, "R_RenderScene: NULL worldmodel"); } Com_Memcpy( tr.refdef.text, fd->text, sizeof( tr.refdef.text ) ); tr.refdef.x = fd->x; tr.refdef.y = fd->y; tr.refdef.width = fd->width; tr.refdef.height = fd->height; tr.refdef.fov_x = fd->fov_x; tr.refdef.fov_y = fd->fov_y; VectorCopy( fd->vieworg, tr.refdef.vieworg ); VectorCopy( fd->viewaxis[0], tr.refdef.viewaxis[0] ); VectorCopy( fd->viewaxis[1], tr.refdef.viewaxis[1] ); VectorCopy( fd->viewaxis[2], tr.refdef.viewaxis[2] ); tr.refdef.time = fd->time; tr.refdef.rdflags = fd->rdflags; // copy the areamask data over and note if it has changed, which // will force a reset of the visible leafs even if the view hasn't moved tr.refdef.areamaskModified = qfalse; if ( ! (tr.refdef.rdflags & RDF_NOWORLDMODEL) ) { int areaDiff; int i; // compare the area bits areaDiff = 0; for (i = 0 ; i < MAX_MAP_AREA_BYTES/4 ; i++) { areaDiff |= ((int *)tr.refdef.areamask)[i] ^ ((int *)fd->areamask)[i]; ((int *)tr.refdef.areamask)[i] = ((int *)fd->areamask)[i]; } if ( areaDiff ) { // a door just opened or something tr.refdef.areamaskModified = qtrue; } } tr.refdef.sunDir[3] = 0.0f; tr.refdef.sunCol[3] = 1.0f; tr.refdef.sunAmbCol[3] = 1.0f; VectorCopy(tr.sunDirection, tr.refdef.sunDir); if ( (tr.refdef.rdflags & RDF_NOWORLDMODEL) || !(r_depthPrepass->value) ){ tr.refdef.colorScale = 1.0f; VectorSet(tr.refdef.sunCol, 0, 0, 0); VectorSet(tr.refdef.sunAmbCol, 0, 0, 0); } else if (r_forceSun->integer == 1) { float scale = pow(2, r_mapOverBrightBits->integer - tr.overbrightBits - 8); tr.refdef.colorScale = r_forceSunMapLightScale->value; VectorScale(tr.sunLight, scale * r_forceSunLightScale->value, tr.refdef.sunCol); VectorScale(tr.sunLight, scale * r_forceSunAmbientScale->value, tr.refdef.sunAmbCol); } else { float scale = pow(2, r_mapOverBrightBits->integer - tr.overbrightBits - 8); tr.refdef.colorScale = tr.mapLightScale; VectorScale(tr.sunLight, scale, tr.refdef.sunCol); VectorScale(tr.sunAmbient, scale, tr.refdef.sunAmbCol); } if (r_forceAutoExposure->integer) { tr.refdef.autoExposureMinMax[0] = r_forceAutoExposureMin->value; tr.refdef.autoExposureMinMax[1] = r_forceAutoExposureMax->value; } else { tr.refdef.autoExposureMinMax[0] = tr.autoExposureMinMax[0]; tr.refdef.autoExposureMinMax[1] = tr.autoExposureMinMax[1]; } if (r_forceToneMap->integer) { tr.refdef.toneMinAvgMaxLinear[0] = pow(2, r_forceToneMapMin->value); tr.refdef.toneMinAvgMaxLinear[1] = pow(2, r_forceToneMapAvg->value); tr.refdef.toneMinAvgMaxLinear[2] = pow(2, r_forceToneMapMax->value); } else { tr.refdef.toneMinAvgMaxLinear[0] = pow(2, tr.toneMinAvgMaxLevel[0]); tr.refdef.toneMinAvgMaxLinear[1] = pow(2, tr.toneMinAvgMaxLevel[1]); tr.refdef.toneMinAvgMaxLinear[2] = pow(2, tr.toneMinAvgMaxLevel[2]); } // Makro - copy exta info if present if (fd->rdflags & RDF_EXTRA) { const refdefex_t* extra = (const refdefex_t*) (fd+1); tr.refdef.blurFactor = extra->blurFactor; if (fd->rdflags & RDF_SUNLIGHT) { VectorCopy(extra->sunDir, tr.refdef.sunDir); VectorCopy(extra->sunCol, tr.refdef.sunCol); VectorCopy(extra->sunAmbCol, tr.refdef.sunAmbCol); } } else { tr.refdef.blurFactor = 0.0f; } // derived info tr.refdef.floatTime = tr.refdef.time * 0.001f; tr.refdef.numDrawSurfs = r_firstSceneDrawSurf; tr.refdef.drawSurfs = backEndData->drawSurfs; tr.refdef.num_entities = r_numentities - r_firstSceneEntity; tr.refdef.entities = &backEndData->entities[r_firstSceneEntity]; tr.refdef.num_dlights = r_numdlights - r_firstSceneDlight; tr.refdef.dlights = &backEndData->dlights[r_firstSceneDlight]; tr.refdef.numPolys = r_numpolys - r_firstScenePoly; tr.refdef.polys = &backEndData->polys[r_firstScenePoly]; tr.refdef.num_pshadows = 0; tr.refdef.pshadows = &backEndData->pshadows[0]; // turn off dynamic lighting globally by clearing all the // dlights if it needs to be disabled or if vertex lighting is enabled if ( r_dynamiclight->integer == 0 || r_vertexLight->integer == 1 || glConfig.hardwareType == GLHW_PERMEDIA2 ) { tr.refdef.num_dlights = 0; } // a single frame may have multiple scenes draw inside it -- // a 3D game view, 3D status bar renderings, 3D menus, etc. // They need to be distinguished by the light flare code, because // the visibility state for a given surface may be different in // each scene / view. tr.frameSceneNum++; tr.sceneCount++; // SmileTheory: playing with shadow mapping if (!( fd->rdflags & RDF_NOWORLDMODEL ) && tr.refdef.num_dlights && r_dlightMode->integer >= 2) { R_RenderDlightCubemaps(fd); } /* playing with more shadows */ if(glRefConfig.framebufferObject && !( fd->rdflags & RDF_NOWORLDMODEL ) && r_shadows->integer == 4) { R_RenderPshadowMaps(fd); } // playing with even more shadows if(glRefConfig.framebufferObject && !( fd->rdflags & RDF_NOWORLDMODEL ) && (r_forceSun->integer || tr.sunShadows)) { R_RenderSunShadowMaps(fd, 0); R_RenderSunShadowMaps(fd, 1); R_RenderSunShadowMaps(fd, 2); } // setup view parms for the initial view // // set up viewport // The refdef takes 0-at-the-top y coordinates, so // convert to GL's 0-at-the-bottom space // Com_Memset( &parms, 0, sizeof( parms ) ); parms.viewportX = tr.refdef.x; parms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height ); parms.viewportWidth = tr.refdef.width; parms.viewportHeight = tr.refdef.height; parms.isPortal = qfalse; parms.fovX = tr.refdef.fov_x; parms.fovY = tr.refdef.fov_y; parms.stereoFrame = tr.refdef.stereoFrame; VectorCopy( fd->vieworg, parms.or.origin ); VectorCopy( fd->viewaxis[0], parms.or.axis[0] ); VectorCopy( fd->viewaxis[1], parms.or.axis[1] ); VectorCopy( fd->viewaxis[2], parms.or.axis[2] ); VectorCopy( fd->vieworg, parms.pvsOrigin ); if(!( fd->rdflags & RDF_NOWORLDMODEL ) && r_depthPrepass->value && ((r_forceSun->integer) || tr.sunShadows)) { parms.flags = VPF_USESUNLIGHT; } R_RenderView( &parms ); if(!( fd->rdflags & RDF_NOWORLDMODEL )) R_AddPostProcessCmd(); // the next scene rendered in this frame will tack on after this one r_firstSceneDrawSurf = tr.refdef.numDrawSurfs; r_firstSceneEntity = r_numentities; r_firstSceneDlight = r_numdlights; r_firstScenePoly = r_numpolys; tr.frontEndMsec += ri.Milliseconds() - startTime; }
/* ================== R_GenerateSurfaceSubview ================== */ bool R_GenerateSurfaceSubview( drawSurf_t *drawSurf ) { idBounds ndcBounds; viewDef_t *parms; const idMaterial *shader; // for testing the performance hit if ( r_skipSubviews.GetBool() ) { return false; } if ( R_PreciseCullSurface( drawSurf, ndcBounds ) ) { return false; } shader = drawSurf->material; // never recurse through a subview surface that we are // already seeing through for ( parms = tr.viewDef ; parms ; parms = parms->superView ) { if ( parms->subviewSurface && parms->subviewSurface->geo == drawSurf->geo && parms->subviewSurface->space->entityDef == drawSurf->space->entityDef ) { break; } } if ( parms ) { return false; } // crop the scissor bounds based on the precise cull idScreenRect scissor; idScreenRect *v = &tr.viewDef->viewport; scissor.x1 = v->x1 + (int)( (v->x2 - v->x1 + 1 ) * 0.5f * ( ndcBounds[0][0] + 1.0f )); scissor.y1 = v->y1 + (int)( (v->y2 - v->y1 + 1 ) * 0.5f * ( ndcBounds[0][1] + 1.0f )); scissor.x2 = v->x1 + (int)( (v->x2 - v->x1 + 1 ) * 0.5f * ( ndcBounds[1][0] + 1.0f )); scissor.y2 = v->y1 + (int)( (v->y2 - v->y1 + 1 ) * 0.5f * ( ndcBounds[1][1] + 1.0f )); // nudge a bit for safety scissor.Expand(); scissor.Intersect( tr.viewDef->scissor ); if ( scissor.IsEmpty() ) { // cropped out return false; } // see what kind of subview we are making if ( shader->GetSort() != SS_SUBVIEW ) { for ( int i = 0 ; i < shader->GetNumStages() ; i++ ) { const shaderStage_t *stage = shader->GetStage( i ); switch ( stage->texture.dynamic ) { case DI_REMOTE_RENDER: R_RemoteRender( drawSurf, const_cast<textureStage_t *>(&stage->texture) ); break; case DI_MIRROR_RENDER: R_MirrorRender( drawSurf, const_cast<textureStage_t *>(&stage->texture), scissor ); break; case DI_XRAY_RENDER: R_XrayRender( drawSurf, const_cast<textureStage_t *>(&stage->texture), scissor ); break; } } return true; } // issue a new view command parms = R_MirrorViewBySurface( drawSurf ); if ( !parms ) { return false; } parms->scissor = scissor; parms->superView = tr.viewDef; parms->subviewSurface = drawSurf; // triangle culling order changes with mirroring parms->isMirror = ( ( (int)parms->isMirror ^ (int)tr.viewDef->isMirror ) != 0 ); // generate render commands for it R_RenderView( parms ); return true; }
/* * R_DrawShadowmaps */ void R_DrawShadowmaps( void ) { unsigned int i; image_t *shadowmap; int textureWidth, textureHeight; float lodScale; vec3_t lodOrigin; vec3_t viewerOrigin; shadowGroup_t *group; int shadowBits = rn.shadowBits; refdef_t refdef; int lod; float farClip; float dist; if( !rsc.numShadowGroups ) { return; } if( rn.renderFlags & RF_SHADOWMAPVIEW ) { return; } if( rn.refdef.rdflags & RDF_NOWORLDMODEL ) { return; } if( !shadowBits ) { return; } if( !R_PushRefInst() ) { return; } lodScale = rn.lod_dist_scale_for_fov; VectorCopy( rn.lodOrigin, lodOrigin ); VectorCopy( rn.viewOrigin, viewerOrigin ); refdef = rn.refdef; // find lighting group containing entities with same lightingOrigin as ours for( i = 0; i < rsc.numShadowGroups; i++ ) { if( !shadowBits ) { break; } group = rsc.shadowGroups + i; if( !( shadowBits & group->bit ) ) { continue; } shadowBits &= ~group->bit; // make sure we don't render the same shadowmap twice in the same scene frame if( rsc.renderedShadowBits & group->bit ) { continue; } // calculate LOD for shadowmap dist = DistanceFast( group->origin, lodOrigin ); lod = (int)( dist * lodScale ) / group->projDist - SHADOWMAP_LODBIAS; if( lod < 0 ) { lod = 0; } // allocate/resize the texture if needed shadowmap = R_GetShadowmapTexture( i, rsc.refdef.width, rsc.refdef.height, 0 ); assert( shadowmap && shadowmap->upload_width && shadowmap->upload_height ); group->shadowmap = shadowmap; textureWidth = shadowmap->upload_width; textureHeight = shadowmap->upload_height; if( !shadowmap->fbo ) { continue; } farClip = R_SetupShadowmapView( group, &refdef, lod ); if( farClip <= 0.0f ) { continue; } // ignore shadowmaps of very low detail level if( refdef.width < SHADOWMAP_MIN_VIEWPORT_SIZE || refdef.height < SHADOWMAP_MIN_VIEWPORT_SIZE ) { continue; } rn.renderTarget = shadowmap->fbo; rn.farClip = farClip; rn.renderFlags = RF_SHADOWMAPVIEW | RF_FLIPFRONTFACE; if( !( shadowmap->flags & IT_DEPTH ) ) { rn.renderFlags |= RF_SHADOWMAPVIEW_RGB; } rn.clipFlags |= 16; // clip by far plane too rn.meshlist = &r_shadowlist; rn.portalmasklist = NULL; rn.shadowGroup = group; rn.lod_dist_scale_for_fov = lodScale; VectorCopy( viewerOrigin, rn.pvsOrigin ); VectorCopy( lodOrigin, rn.lodOrigin ); // 3 pixels border on each side to prevent nasty stretching/bleeding of shadows, // also accounting for smoothing done in the fragment shader Vector4Set( rn.viewport, refdef.x + 3,refdef.y + textureHeight - refdef.height + 3, refdef.width - 6, refdef.height - 6 ); Vector4Set( rn.scissor, refdef.x, refdef.y, textureWidth, textureHeight ); R_RenderView( &refdef ); Matrix4_Copy( rn.cameraProjectionMatrix, group->cameraProjectionMatrix ); rsc.renderedShadowBits |= group->bit; } R_PopRefInst(); }
/* * R_RenderScene */ void R_RenderScene( const refdef_t *fd ) { int fbFlags = 0; int ppFrontBuffer = 0; image_t *ppSource; if( r_norefresh->integer ) return; R_Set2DMode( false ); RB_SetTime( fd->time ); if( !( fd->rdflags & RDF_NOWORLDMODEL ) ) rsc.refdef = *fd; rn.refdef = *fd; if( !rn.refdef.minLight ) { rn.refdef.minLight = 0.1f; } fd = &rn.refdef; rn.renderFlags = RF_NONE; rn.farClip = R_DefaultFarClip(); rn.clipFlags = 15; if( rsh.worldModel && !( fd->rdflags & RDF_NOWORLDMODEL ) && rsh.worldBrushModel->globalfog ) rn.clipFlags |= 16; rn.meshlist = &r_worldlist; rn.portalmasklist = &r_portalmasklist; rn.shadowBits = 0; rn.dlightBits = 0; rn.shadowGroup = NULL; fbFlags = 0; rn.fbColorAttachment = rn.fbDepthAttachment = NULL; if( !( fd->rdflags & RDF_NOWORLDMODEL ) ) { if( r_soft_particles->integer && ( rsh.screenTexture != NULL ) ) { rn.fbColorAttachment = rsh.screenTexture; rn.fbDepthAttachment = rsh.screenDepthTexture; rn.renderFlags |= RF_SOFT_PARTICLES; fbFlags |= 1; } if( rsh.screenPPCopies[0] && rsh.screenPPCopies[1] ) { int oldFlags = fbFlags; shader_t *cc = rn.refdef.colorCorrection; if( r_fxaa->integer ) { fbFlags |= 2; } if( cc && cc->numpasses > 0 && cc->passes[0].images[0] && cc->passes[0].images[0] != rsh.noTexture ) { fbFlags |= 4; } if( fbFlags != oldFlags ) { if( !rn.fbColorAttachment ) { rn.fbColorAttachment = rsh.screenPPCopies[0]; ppFrontBuffer = 1; } } } } ppSource = rn.fbColorAttachment; // clip new scissor region to the one currently set Vector4Set( rn.scissor, fd->scissor_x, fd->scissor_y, fd->scissor_width, fd->scissor_height ); Vector4Set( rn.viewport, fd->x, fd->y, fd->width, fd->height ); VectorCopy( fd->vieworg, rn.pvsOrigin ); VectorCopy( fd->vieworg, rn.lodOrigin ); R_BindFrameBufferObject( 0 ); R_BuildShadowGroups(); R_RenderView( fd ); R_RenderDebugSurface( fd ); R_RenderDebugBounds(); R_BindFrameBufferObject( 0 ); R_Set2DMode( true ); if( !( fd->rdflags & RDF_NOWORLDMODEL ) ) { ri.Mutex_Lock( rf.speedsMsgLock ); R_WriteSpeedsMessage( rf.speedsMsg, sizeof( rf.speedsMsg ) ); ri.Mutex_Unlock( rf.speedsMsgLock ); } // blit and blend framebuffers in proper order if( fbFlags == 1 ) { // only blit soft particles directly when we don't have any other post processing // otherwise use the soft particles FBO as the base texture on the next layer // to avoid wasting time on resolves and the fragment shader to blit to a temp texture R_BlitTextureToScrFbo( fd, ppSource, 0, GLSL_PROGRAM_TYPE_NONE, colorWhite, 0, 0, NULL ); } fbFlags &= ~1; // apply FXAA if( fbFlags & 2 ) { image_t *dest; fbFlags &= ~2; dest = fbFlags ? rsh.screenPPCopies[ppFrontBuffer] : NULL; R_BlitTextureToScrFbo( fd, ppSource, dest ? dest->fbo : 0, GLSL_PROGRAM_TYPE_FXAA, colorWhite, 0, 0, NULL ); ppFrontBuffer ^= 1; ppSource = dest; } // apply color correction if( fbFlags & 4 ) { image_t *dest; fbFlags &= ~4; dest = fbFlags ? rsh.screenPPCopies[ppFrontBuffer] : NULL; R_BlitTextureToScrFbo( fd, ppSource, dest ? dest->fbo : 0, GLSL_PROGRAM_TYPE_COLORCORRECTION, colorWhite, 0, 1, &( rn.refdef.colorCorrection->passes[0].images[0] ) ); } }
/* * R_RenderScene */ void R_RenderScene( const refdef_t *fd ) { int fbFlags = 0; if( r_norefresh->integer ) return; R_Set2DMode( qfalse ); RB_SetTime( fd->time ); if( !( fd->rdflags & RDF_NOWORLDMODEL ) ) rsc.refdef = *fd; rn.refdef = *fd; if( !rn.refdef.minLight ) { rn.refdef.minLight = 0.1f; } if( !rsh.screenWeaponTexture || rn.refdef.weaponAlpha == 1 ) { rn.refdef.rdflags &= ~RDF_WEAPONALPHA; } fd = &rn.refdef; rn.renderFlags = RF_NONE; rn.farClip = R_DefaultFarClip(); rn.clipFlags = 15; if( rsh.worldModel && !( fd->rdflags & RDF_NOWORLDMODEL ) && rsh.worldBrushModel->globalfog ) rn.clipFlags |= 16; rn.meshlist = &r_worldlist; rn.shadowBits = 0; rn.dlightBits = 0; rn.shadowGroup = NULL; fbFlags = 0; rn.fbColorAttachment = rn.fbDepthAttachment = NULL; if( !( fd->rdflags & RDF_NOWORLDMODEL ) ) { // soft particles require GL_EXT_framebuffer_blit as we need to copy the depth buffer // attachment into a texture we're going to read from in GLSL shader if( r_soft_particles->integer && glConfig.ext.framebuffer_blit && ( rsh.screenTexture != NULL ) ) { rn.fbColorAttachment = rsh.screenTexture; rn.fbDepthAttachment = rsh.screenDepthTexture; rn.renderFlags |= RF_SOFT_PARTICLES; fbFlags |= 1; } if( ( fd->rdflags & RDF_WEAPONALPHA ) && ( rsh.screenWeaponTexture != NULL ) ) { fbFlags |= 2; } if( r_fxaa->integer && ( rsh.screenFxaaCopy != NULL ) ) { if( !rn.fbColorAttachment ) { rn.fbColorAttachment = rsh.screenFxaaCopy; } fbFlags |= 4; } } // adjust field of view for widescreen if( glConfig.wideScreen && !( fd->rdflags & RDF_NOFOVADJUSTMENT ) ) AdjustFov( &rn.refdef.fov_x, &rn.refdef.fov_y, glConfig.width, glConfig.height, qfalse ); // clip new scissor region to the one currently set Vector4Set( rn.scissor, fd->scissor_x, fd->scissor_y, fd->scissor_width, fd->scissor_height ); Vector4Set( rn.viewport, fd->x, fd->y, fd->width, fd->height ); VectorCopy( fd->vieworg, rn.pvsOrigin ); VectorCopy( fd->vieworg, rn.lodOrigin ); if( gl_finish->integer && !( fd->rdflags & RDF_NOWORLDMODEL ) ) qglFinish(); if( fbFlags & 2 ) { // clear the framebuffer we're going to render the weapon model to // set the alpha to 0, visible parts of the model will overwrite that, // creating proper alpha mask R_BindFrameBufferObject( rsh.screenWeaponTexture->fbo ); RB_Clear( GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT, 0, 0, 0, 0 ); } R_BindFrameBufferObject( 0 ); R_BuildShadowGroups(); R_RenderView( fd ); R_RenderDebugSurface( fd ); R_RenderDebugBounds(); R_BindFrameBufferObject( 0 ); R_Set2DMode( qtrue ); // blit and blend framebuffers in proper order if( fbFlags & 1 ) { // copy to FXAA or default framebuffer R_BlitTextureToScrFbo( fd, rn.fbColorAttachment, fbFlags & 4 ? rsh.screenFxaaCopy->fbo : 0, GLSL_PROGRAM_TYPE_NONE, colorWhite, 0 ); } if( fbFlags & 2 ) { vec4_t color = { 1, 1, 1, 1 }; color[3] = fd->weaponAlpha; // blend to FXAA or default framebuffer R_BlitTextureToScrFbo( fd, rsh.screenWeaponTexture, fbFlags & 4 ? rsh.screenFxaaCopy->fbo : 0, GLSL_PROGRAM_TYPE_NONE, color, GLSTATE_SRCBLEND_SRC_ALPHA|GLSTATE_DSTBLEND_ONE_MINUS_SRC_ALPHA ); } // blit FXAA to default framebuffer if( fbFlags & 4 ) { // blend to FXAA or default framebuffer R_BlitTextureToScrFbo( fd, rsh.screenFxaaCopy, 0, GLSL_PROGRAM_TYPE_FXAA, colorWhite, 0 ); } }
/* * R_DrawPortalSurface * * Renders the portal view and captures the results from framebuffer if * we need to do a $portalmap stage. Note that for $portalmaps we must * use a different viewport. */ static void R_DrawPortalSurface( portalSurface_t *portalSurface ) { unsigned int i; int x, y, w, h; float dist, d, best_d; vec3_t viewerOrigin; vec3_t origin; mat3_t axis; entity_t *ent, *best; const entity_t *portal_ent = portalSurface->entity; cplane_t *portal_plane = &portalSurface->plane, *untransformed_plane = &portalSurface->untransformed_plane; const shader_t *shader = portalSurface->shader; vec_t *portal_mins = portalSurface->mins, *portal_maxs = portalSurface->maxs; vec_t *portal_centre = portalSurface->centre; qboolean mirror, refraction = qfalse; image_t *captureTexture; int captureTextureId = -1; int prevRenderFlags = 0; qboolean doReflection, doRefraction; image_t *portalTexures[2] = { NULL, NULL }; doReflection = doRefraction = qtrue; if( shader->flags & SHADER_PORTAL_CAPTURE ) { shaderpass_t *pass; captureTexture = NULL; captureTextureId = 0; for( i = 0, pass = shader->passes; i < shader->numpasses; i++, pass++ ) { if( pass->program_type == GLSL_PROGRAM_TYPE_DISTORTION ) { if( ( pass->alphagen.type == ALPHA_GEN_CONST && pass->alphagen.args[0] == 1 ) ) doRefraction = qfalse; else if( ( pass->alphagen.type == ALPHA_GEN_CONST && pass->alphagen.args[0] == 0 ) ) doReflection = qfalse; break; } } } else { captureTexture = NULL; captureTextureId = -1; } x = y = 0; w = rn.refdef.width; h = rn.refdef.height; dist = PlaneDiff( rn.viewOrigin, portal_plane ); if( dist <= BACKFACE_EPSILON || !doReflection ) { if( !( shader->flags & SHADER_PORTAL_CAPTURE2 ) || !doRefraction ) return; // even if we're behind the portal, we still need to capture // the second portal image for refraction refraction = qtrue; captureTexture = NULL; captureTextureId = 1; if( dist < 0 ) { VectorInverse( portal_plane->normal ); portal_plane->dist = -portal_plane->dist; } } if( !(rn.renderFlags & RF_NOVIS) && !R_ScissorForEntity( portal_ent, portal_mins, portal_maxs, &x, &y, &w, &h ) ) return; mirror = qtrue; // default to mirror view // it is stupid IMO that mirrors require a RT_PORTALSURFACE entity best = NULL; best_d = 100000000; for( i = 1; i < rsc.numEntities; i++ ) { ent = R_NUM2ENT(i); if( ent->rtype != RT_PORTALSURFACE ) continue; d = PlaneDiff( ent->origin, untransformed_plane ); if( ( d >= -64 ) && ( d <= 64 ) ) { d = Distance( ent->origin, portal_centre ); if( d < best_d ) { best = ent; best_d = d; } } } if( best == NULL ) { if( captureTextureId < 0 ) return; } else { if( !VectorCompare( best->origin, best->origin2 ) ) // portal mirror = qfalse; best->rtype = NUM_RTYPES; } prevRenderFlags = rn.renderFlags; if( !R_PushRefInst() ) { return; } VectorCopy( rn.viewOrigin, viewerOrigin ); setup_and_render: if( refraction ) { VectorInverse( portal_plane->normal ); portal_plane->dist = -portal_plane->dist - 1; CategorizePlane( portal_plane ); VectorCopy( rn.viewOrigin, origin ); Matrix3_Copy( rn.refdef.viewaxis, axis ); VectorCopy( viewerOrigin, rn.pvsOrigin ); rn.renderFlags = RF_PORTALVIEW; if( !mirror ) rn.renderFlags |= RF_PVSCULL; } else if( mirror ) { VectorReflect( rn.viewOrigin, portal_plane->normal, portal_plane->dist, origin ); VectorReflect( &rn.viewAxis[AXIS_FORWARD], portal_plane->normal, 0, &axis[AXIS_FORWARD] ); VectorReflect( &rn.viewAxis[AXIS_RIGHT], portal_plane->normal, 0, &axis[AXIS_RIGHT] ); VectorReflect( &rn.viewAxis[AXIS_UP], portal_plane->normal, 0, &axis[AXIS_UP] ); Matrix3_Normalize( axis ); VectorCopy( viewerOrigin, rn.pvsOrigin ); rn.renderFlags = RF_MIRRORVIEW|RF_FLIPFRONTFACE; } else { vec3_t tvec; mat3_t A, B, C, rot; // build world-to-portal rotation matrix VectorNegate( portal_plane->normal, tvec ); NormalVectorToAxis( tvec, A ); // build portal_dest-to-world rotation matrix ByteToDir( best->frame, tvec ); NormalVectorToAxis( tvec, B ); Matrix3_Transpose( B, C ); // multiply to get world-to-world rotation matrix Matrix3_Multiply( C, A, rot ); // translate view origin VectorSubtract( rn.viewOrigin, best->origin, tvec ); Matrix3_TransformVector( rot, tvec, origin ); VectorAdd( origin, best->origin2, origin ); Matrix3_Transpose( A, B ); Matrix3_Multiply( rn.viewAxis, B, rot ); Matrix3_Multiply( best->axis, rot, B ); Matrix3_Transpose( C, A ); Matrix3_Multiply( B, A, axis ); // set up portal_plane VectorCopy( &axis[AXIS_FORWARD], portal_plane->normal ); portal_plane->dist = DotProduct( best->origin2, portal_plane->normal ); CategorizePlane( portal_plane ); // for portals, vis data is taken from portal origin, not // view origin, because the view point moves around and // might fly into (or behind) a wall rn.renderFlags = RF_PORTALVIEW|RF_PVSCULL; VectorCopy( best->origin2, rn.pvsOrigin ); VectorCopy( best->origin2, rn.lodOrigin ); // ignore entities, if asked politely if( best->renderfx & RF_NOPORTALENTS ) rn.renderFlags |= RF_NOENTS; } rn.renderFlags |= (prevRenderFlags & RF_SOFT_PARTICLES); rn.refdef.rdflags &= ~( RDF_UNDERWATER|RDF_CROSSINGWATER ); rn.shadowGroup = NULL; rn.meshlist = &r_portallist; rn.renderFlags |= RF_CLIPPLANE; rn.clipPlane = *portal_plane; rn.farClip = R_DefaultFarClip(); rn.clipFlags |= ( 1<<5 ); rn.frustum[5] = *portal_plane; CategorizePlane( &rn.frustum[5] ); // if we want to render to a texture, initialize texture // but do not try to render to it more than once if( captureTextureId >= 0 ) { int texFlags = shader->flags & SHADER_NO_TEX_FILTERING ? IT_NOFILTERING : 0; captureTexture = R_GetPortalTexture( rsc.refdef.width, rsc.refdef.height, texFlags, rsc.frameCount ); portalTexures[captureTextureId] = captureTexture; if( !captureTexture ) { // couldn't register a slot for this plane goto done; } x = y = 0; w = captureTexture->upload_width; h = captureTexture->upload_height; rn.refdef.width = w; rn.refdef.height = h; rn.refdef.x = 0; rn.refdef.y = 0; rn.fbColorAttachment = captureTexture; // no point in capturing the depth buffer due to oblique frustum messing up // the far plane and depth values rn.fbDepthAttachment = NULL; Vector4Set( rn.viewport, rn.refdef.x + x, rn.refdef.y + y, w, h ); Vector4Set( rn.scissor, rn.refdef.x + x, rn.refdef.y + y, w, h ); } else { // no point in capturing the depth buffer due to oblique frustum messing up // the far plane and depth values rn.fbDepthAttachment = NULL; Vector4Set( rn.scissor, rn.refdef.x + x, rn.refdef.y + y, w, h ); } VectorCopy( origin, rn.refdef.vieworg ); Matrix3_Copy( axis, rn.refdef.viewaxis ); R_RenderView( &rn.refdef ); if( doRefraction && !refraction && ( shader->flags & SHADER_PORTAL_CAPTURE2 ) ) { refraction = qtrue; captureTexture = NULL; captureTextureId = 1; goto setup_and_render; } done: portalSurface->texures[0] = portalTexures[0]; portalSurface->texures[1] = portalTexures[1]; R_PopRefInst( rn.fbDepthAttachment != NULL ? 0 : GL_DEPTH_BUFFER_BIT ); }
/* * R_DrawSkyPortal */ void R_DrawSkyPortal( const entity_t *e, skyportal_t *skyportal, vec3_t mins, vec3_t maxs ) { int x, y, w, h; if( !R_ScissorForEntity( e, mins, maxs, &x, &y, &w, &h ) ) { return; } if( !R_PushRefInst() ) { return; } rn.renderFlags = ( rn.renderFlags|RF_SKYPORTALVIEW|RF_SOFT_PARTICLES ); VectorCopy( skyportal->vieworg, rn.pvsOrigin ); rn.farClip = R_DefaultFarClip(); rn.clipFlags = 15; rn.shadowGroup = NULL; rn.meshlist = &r_skyportallist; //Vector4Set( rn.scissor, rn.refdef.x + x, rn.refdef.y + y, w, h ); if( skyportal->noEnts ) { rn.renderFlags |= RF_NOENTS; } if( skyportal->scale ) { vec3_t centre, diff; VectorAdd( rsh.worldModel->mins, rsh.worldModel->maxs, centre ); VectorScale( centre, 0.5f, centre ); VectorSubtract( centre, rn.viewOrigin, diff ); VectorMA( skyportal->vieworg, -skyportal->scale, diff, rn.refdef.vieworg ); } else { VectorCopy( skyportal->vieworg, rn.refdef.vieworg ); } // FIXME if( !VectorCompare( skyportal->viewanglesOffset, vec3_origin ) ) { vec3_t angles; mat3_t axis; Matrix3_Copy( rn.refdef.viewaxis, axis ); VectorInverse( &axis[AXIS_RIGHT] ); Matrix3_ToAngles( axis, angles ); VectorAdd( angles, skyportal->viewanglesOffset, angles ); AnglesToAxis( angles, axis ); Matrix3_Copy( axis, rn.refdef.viewaxis ); } rn.refdef.rdflags &= ~( RDF_UNDERWATER|RDF_CROSSINGWATER|RDF_SKYPORTALINVIEW ); if( skyportal->fov ) { rn.refdef.fov_x = skyportal->fov; rn.refdef.fov_y = CalcFov( rn.refdef.fov_x, rn.refdef.width, rn.refdef.height ); if( glConfig.wideScreen && !( rn.refdef.rdflags & RDF_NOFOVADJUSTMENT ) ) AdjustFov( &rn.refdef.fov_x, &rn.refdef.fov_y, glConfig.width, glConfig.height, qfalse ); } R_RenderView( &rn.refdef ); // restore modelview and projection matrices, scissoring, etc for the main view R_PopRefInst( ~GL_COLOR_BUFFER_BIT ); }
/* ======================== R_DoWaterView Returns qtrue if another view has been rendered ======================== */ qboolean R_DoWaterView (drawSurf_t *drawSurf, int entityNum) { // vec4_t clipDest[128]; viewParms_t newParms; viewParms_t oldParms; orientation_t surface, camera; cplane_t plane; srfSurfaceStatic_t *srf; // don't recursively do water if (tr.viewParms.doWater) { // tesselated water has this issue - so we just ignore and not spam console // ri.Printf( PRINT_DEVELOPER, "WARNING: recursive water found\n" ); return qfalse; } srf = (srfSurfaceStatic_t *)drawSurf->surface; // trivially reject portal/mirror //This wont work because vbo surfs dont fill out tess... //if ( SurfIsOffscreen( drawSurf, clipDest ) ) { // return qfalse; //} //Set plane tr.viewParms.doWater = qtrue; tr.viewParms.waterPlane.normal[0] = 0; tr.viewParms.waterPlane.normal[1] = 0; tr.viewParms.waterPlane.normal[2] = -1; tr.viewParms.waterPlane.dist = srf->origin[2]; if ( DotProduct(tr.viewParms.waterPlane.normal,tr.viewParms.or.origin)+tr.viewParms.waterPlane.dist >0) { tr.viewParms.isUnderwater=qtrue; } // save old viewParms so we can return to it after the mirror view oldParms = tr.viewParms; newParms = tr.viewParms; newParms.isWater = 1; newParms.viewportWidth=WATER_RES_X; newParms.viewportHeight=WATER_RES_Y; newParms.viewportX =0;//tr.refdef.x; newParms.viewportY =0;// glConfig.vidHeight - ( tr.refdef.y + WATER_RES_Y ); tr.refdef.rdflags|= RDF_NOEFFECTS ; // render the mirror view R_RenderView (&newParms); //Do the second view now newParms = tr.viewParms; newParms.isWater = 2; newParms.isMirror = qtrue; newParms.viewportWidth = WATER_RES_X; newParms.viewportHeight = WATER_RES_Y; newParms.viewportX = 0;//tr.refdef.x; newParms.viewportY = 0;//glConfig.vidHeight - ( tr.refdef.y + WATER_RES_Y ); plane.dist=tr.viewParms.waterPlane.dist; plane.normal[0]=-tr.viewParms.waterPlane.normal[0]; plane.normal[1]=-tr.viewParms.waterPlane.normal[1]; plane.normal[2]=-tr.viewParms.waterPlane.normal[2]; R_GetSurfaceOrientations( &plane, &surface, &camera ); R_MirrorPoint (oldParms.or.origin, &surface, &camera, newParms.or.origin ); R_MirrorVector (oldParms.or.axis[0], &surface, &camera, newParms.or.axis[0]); R_MirrorVector (oldParms.or.axis[1], &surface, &camera, newParms.or.axis[1]); R_MirrorVector (oldParms.or.axis[2], &surface, &camera, newParms.or.axis[2]); // render the mirror view tr.refdef.rdflags|= RDF_NOEFFECTS; R_RenderView (&newParms); tr.viewParms = oldParms; tr.refdef.rdflags&= ~RDF_NOEFFECTS; return qtrue; }
/* @@@@@@@@@@@@@@@@@@@@@ RE_RenderScene Draw a 3D view into a part of the window, then return to 2D drawing. Rendering a scene may require multiple views to be rendered to handle mirrors, @@@@@@@@@@@@@@@@@@@@@ */ void RE_RenderScene( const refdef_t *fd ) { viewParms_t parms; int startTime; if ( !tr.registered ) { return; } GLimp_LogComment( "====== RE_RenderScene =====\n" ); if ( r_norefresh->integer ) { return; } startTime = ri.Milliseconds(); if (!tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) { ri.Error (ERR_DROP, "R_RenderScene: NULL worldmodel"); } Com_Memcpy( tr.refdef.text, fd->text, sizeof( tr.refdef.text ) ); tr.refdef.x = fd->x; tr.refdef.y = fd->y; tr.refdef.width = fd->width; tr.refdef.height = fd->height; tr.refdef.fov_x = fd->fov_x; tr.refdef.fov_y = fd->fov_y; VectorCopy( fd->vieworg, tr.refdef.vieworg ); VectorCopy( fd->viewaxis[0], tr.refdef.viewaxis[0] ); VectorCopy( fd->viewaxis[1], tr.refdef.viewaxis[1] ); VectorCopy( fd->viewaxis[2], tr.refdef.viewaxis[2] ); tr.refdef.time = fd->time; tr.refdef.rdflags = fd->rdflags; // copy the areamask data over and note if it has changed, which // will force a reset of the visible leafs even if the view hasn't moved tr.refdef.areamaskModified = qfalse; if ( ! (tr.refdef.rdflags & RDF_NOWORLDMODEL) ) { int areaDiff; int i; // compare the area bits areaDiff = 0; for (i = 0 ; i < MAX_MAP_AREA_BYTES/4 ; i++) { areaDiff |= ((int *)tr.refdef.areamask)[i] ^ ((int *)fd->areamask)[i]; ((int *)tr.refdef.areamask)[i] = ((int *)fd->areamask)[i]; } if ( areaDiff ) { // a door just opened or something tr.refdef.areamaskModified = qtrue; } } // derived info tr.refdef.floatTime = tr.refdef.time * 0.001f; tr.refdef.numDrawSurfs = r_firstSceneDrawSurf; tr.refdef.drawSurfs = backEndData->drawSurfs; tr.refdef.num_entities = r_numentities - r_firstSceneEntity; tr.refdef.entities = &backEndData->entities[r_firstSceneEntity]; tr.refdef.num_dlights = r_numdlights - r_firstSceneDlight; tr.refdef.dlights = &backEndData->dlights[r_firstSceneDlight]; tr.refdef.numPolys = r_numpolys - r_firstScenePoly; tr.refdef.polys = &backEndData->polys[r_firstScenePoly]; // turn off dynamic lighting globally by clearing all the // dlights if it needs to be disabled or if vertex lighting is enabled if ( r_dynamiclight->integer == 0 || r_vertexLight->integer == 1 || glConfig.hardwareType == GLHW_PERMEDIA2 ) { tr.refdef.num_dlights = 0; } // a single frame may have multiple scenes draw inside it -- // a 3D game view, 3D status bar renderings, 3D menus, etc. // They need to be distinguished by the light flare code, because // the visibility state for a given surface may be different in // each scene / view. tr.frameSceneNum++; tr.sceneCount++; // setup view parms for the initial view // // set up viewport // The refdef takes 0-at-the-top y coordinates, so // convert to GL's 0-at-the-bottom space // Com_Memset( &parms, 0, sizeof( parms ) ); parms.viewportX = tr.refdef.x; parms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height ); parms.viewportWidth = tr.refdef.width; parms.viewportHeight = tr.refdef.height; parms.isPortal = qfalse; parms.fovX = tr.refdef.fov_x; parms.fovY = tr.refdef.fov_y; // leilei - widescreen // recalculate fov according to widescreen parameters if (!( fd->rdflags & RDF_NOWORLDMODEL ) ) // don't affect interface refdefs { float zoomfov = tr.refdef.fov_x / 90; // figure out our zoom or changed fov magnitiude from cg_fov and cg_zoomfov int thisisit; // find aspect to immediately match our vidwidth for perfect match with resized screens... float erspact = tr.refdef.width / tr.refdef.height; float aspact = glConfig.vidWidth / glConfig.vidHeight; if (erspact == aspact) thisisit = 1; // try not to recalculate fov of ui and hud elements //if (((tr.refdef.fov_x / tr.refdef.fov_y) > 1.3) && (tr.refdef.width > 320) && (tr.refdef.height > 240)) //if (((tr.refdef.fov_x / tr.refdef.fov_y) > 1.3) && (tr.refdef.width > (320 * refdefscalex)) && (tr.refdef.height > (240 * refdefscaley))) if (((tr.refdef.fov_x / tr.refdef.fov_y) > 1.3) && (thisisit)) { // undo vert- parms.fovY = parms.fovY * (73.739792 / tr.refdef.fov_y) * zoomfov; // recalculate the fov parms.fovX = (atan (glConfig.vidWidth / (glConfig.vidHeight / tan ((parms.fovY * M_PI) / 360.0f))) * 360.0f) / M_PI; parms.fovY = (atan (glConfig.vidHeight / (glConfig.vidWidth / tan ((parms.fovX * M_PI) / 360.0f))) * 360.0f) / M_PI; } } // leilei - end parms.stereoFrame = tr.refdef.stereoFrame; VectorCopy( fd->vieworg, parms.or.origin ); VectorCopy( fd->viewaxis[0], parms.or.axis[0] ); VectorCopy( fd->viewaxis[1], parms.or.axis[1] ); VectorCopy( fd->viewaxis[2], parms.or.axis[2] ); VectorCopy( fd->vieworg, parms.pvsOrigin ); R_RenderView( &parms ); // the next scene rendered in this frame will tack on after this one r_firstSceneDrawSurf = tr.refdef.numDrawSurfs; r_firstSceneEntity = r_numentities; r_firstSceneDlight = r_numdlights; r_firstScenePoly = r_numpolys; tr.frontEndMsec += ri.Milliseconds() - startTime; }
void RE_RenderScene( const refdef_t *fd ) { viewParms_t parms; int startTime; static int lastTime = 0; if ( !tr.registered ) { return; } GLimp_LogComment( "====== RE_RenderScene =====\n" ); if ( r_norefresh->integer ) { return; } startTime = ri->Milliseconds()*ri->Cvar_VariableValue( "timescale" ); if (!tr.world && !( fd->rdflags & RDF_NOWORLDMODEL ) ) { Com_Error (ERR_DROP, "R_RenderScene: NULL worldmodel"); } memcpy( tr.refdef.text, fd->text, sizeof( tr.refdef.text ) ); tr.refdef.x = fd->x; tr.refdef.y = fd->y; tr.refdef.width = fd->width; tr.refdef.height = fd->height; tr.refdef.fov_x = fd->fov_x; tr.refdef.fov_y = fd->fov_y; VectorCopy( fd->vieworg, tr.refdef.vieworg ); VectorCopy( fd->viewaxis[0], tr.refdef.viewaxis[0] ); VectorCopy( fd->viewaxis[1], tr.refdef.viewaxis[1] ); VectorCopy( fd->viewaxis[2], tr.refdef.viewaxis[2] ); tr.refdef.time = fd->time; tr.refdef.frametime = fd->time - lastTime; if (fd->rdflags & RDF_SKYBOXPORTAL) { skyboxportal = 1; } else { // pasted this from SP // cdr - only change last time for the real render, not the portal lastTime = fd->time; } if (fd->rdflags & RDF_DRAWSKYBOX) { drawskyboxportal = 1; } else { drawskyboxportal = 0; } if (tr.refdef.frametime > 500) { tr.refdef.frametime = 500; } else if (tr.refdef.frametime < 0) { tr.refdef.frametime = 0; } tr.refdef.rdflags = fd->rdflags; // copy the areamask data over and note if it has changed, which // will force a reset of the visible leafs even if the view hasn't moved tr.refdef.areamaskModified = qfalse; if ( ! (tr.refdef.rdflags & RDF_NOWORLDMODEL) ) { int areaDiff; int i; // compare the area bits areaDiff = 0; for (i = 0 ; i < MAX_MAP_AREA_BYTES/4 ; i++) { areaDiff |= ((int *)tr.refdef.areamask)[i] ^ ((int *)fd->areamask)[i]; ((int *)tr.refdef.areamask)[i] = ((int *)fd->areamask)[i]; } if ( areaDiff ) { // a door just opened or something tr.refdef.areamaskModified = qtrue; } } // derived info tr.refdef.floatTime = tr.refdef.time * 0.001f; tr.refdef.numDrawSurfs = r_firstSceneDrawSurf; tr.refdef.drawSurfs = backEndData->drawSurfs; tr.refdef.num_entities = r_numentities - r_firstSceneEntity; tr.refdef.entities = &backEndData->entities[r_firstSceneEntity]; tr.refdef.miniEntities = &backEndData->miniEntities[r_firstSceneMiniEntity]; #ifndef VV_LIGHTING tr.refdef.num_dlights = r_numdlights - r_firstSceneDlight; tr.refdef.dlights = &backEndData->dlights[r_firstSceneDlight]; #endif // Add the decals here because decals add polys and we need to ensure // that the polys are added before the the renderer is prepared if ( !(tr.refdef.rdflags & RDF_NOWORLDMODEL) ) { R_AddDecals ( ); } tr.refdef.numPolys = r_numpolys - r_firstScenePoly; tr.refdef.polys = &backEndData->polys[r_firstScenePoly]; // turn off dynamic lighting globally by clearing all the // dlights if it needs to be disabled or if vertex lighting is enabled #ifndef VV_LIGHTING if ( r_dynamiclight->integer == 0 || r_vertexLight->integer == 1 ) { tr.refdef.num_dlights = 0; } #endif // a single frame may have multiple scenes draw inside it -- // a 3D game view, 3D status bar renderings, 3D menus, etc. // They need to be distinguished by the light flare code, because // the visibility state for a given surface may be different in // each scene / view. tr.frameSceneNum++; tr.sceneCount++; // setup view parms for the initial view // // set up viewport // The refdef takes 0-at-the-top y coordinates, so // convert to GL's 0-at-the-bottom space // memset( &parms, 0, sizeof( parms ) ); parms.viewportX = tr.refdef.x; parms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.refdef.height ); parms.viewportWidth = tr.refdef.width; parms.viewportHeight = tr.refdef.height; parms.isPortal = qfalse; parms.fovX = tr.refdef.fov_x; parms.fovY = tr.refdef.fov_y; VectorCopy( fd->vieworg, parms.ori.origin ); VectorCopy( fd->viewaxis[0], parms.ori.axis[0] ); VectorCopy( fd->viewaxis[1], parms.ori.axis[1] ); VectorCopy( fd->viewaxis[2], parms.ori.axis[2] ); VectorCopy( fd->vieworg, parms.pvsOrigin ); R_RenderView( &parms ); // the next scene rendered in this frame will tack on after this one r_firstSceneDrawSurf = tr.refdef.numDrawSurfs; r_firstSceneEntity = r_numentities; r_firstSceneMiniEntity = r_numminientities; r_firstSceneDlight = r_numdlights; r_firstScenePoly = r_numpolys; refEntParent = -1; tr.frontEndMsec += ri->Milliseconds()*ri->Cvar_VariableValue( "timescale" ) - startTime; RE_RenderWorldEffects(); if (tr.refdef.rdflags & RDF_AUTOMAP) { RE_RenderAutoMap(); } }