/* ================ R_RenderScene RI.refdef must be set before the first call ================ */ void R_RenderScene( const ref_params_t *fd ) { RI.refdef = *fd; if( !cl.worldmodel && RI.drawWorld ) Host_Error( "R_RenderScene: NULL worldmodel\n" ); R_PushDlights(); R_SetupFrame(); R_SetupFrustum(); R_SetupGL(); R_Clear( ~0 ); R_MarkLeaves(); R_CheckFog(); R_DrawWorld(); CL_ExtraUpdate (); // don't let sound get messed up if going slow R_DrawEntitiesOnList(); R_DrawWaterSurfaces(); R_EndGL(); }
int R_RunThread (void *p) { while (r_threads->integer) { if (!refdef.ready) { Sys_Sleep(THREAD_SLEEP_INTERVAL); continue; } /* the renderer is up, so busy-wait for it */ while (r_threadstate.state != THREAD_BSP) Sys_Sleep(0); if (!r_threads->integer) break; R_SetupFrustum(); /* draw brushes on current worldlevel */ R_GetLevelSurfaceLists(); /** @todo - update per-model dynamic light list sorting here */ r_threadstate.state = THREAD_RENDERER; } return 0; }
/* ================ R_FindMirrors Build mirror chains for this frame ================ */ void R_FindMirrors( const ref_params_t *fd ) { vec3_t viewOrg, viewAng; if( !world.has_mirrors || RI.drawOrtho || !RI.drawWorld || RI.refdef.onlyClientDraw || !cl.worldmodel ) return; RI.refdef = *fd; // build the transformation matrix for the given view angles if( cl.thirdperson ) { vec3_t cam_ofs, vpn; clgame.dllFuncs.CL_CameraOffset( cam_ofs ); viewAng[PITCH] = cam_ofs[PITCH]; viewAng[YAW] = cam_ofs[YAW]; viewAng[ROLL] = 0; AngleVectors( viewAng, vpn, NULL, NULL ); VectorMA( RI.refdef.vieworg, -cam_ofs[ROLL], vpn, viewOrg ); } else { VectorCopy( RI.refdef.vieworg, viewOrg ); VectorCopy( RI.refdef.viewangles, viewAng ); } // build the transformation matrix for the given view angles VectorCopy( viewOrg, RI.vieworg ); AngleVectors( viewAng, RI.vforward, RI.vright, RI.vup ); VectorCopy( RI.vieworg, RI.pvsorigin ); if( !r_lockcull->integer ) { VectorCopy( RI.vieworg, RI.cullorigin ); VectorCopy( RI.vforward, RI.cull_vforward ); VectorCopy( RI.vright, RI.cull_vright ); VectorCopy( RI.vup, RI.cull_vup ); } R_FindViewLeaf(); R_SetupFrustum(); R_MarkLeaves (); VectorCopy( RI.cullorigin, tr.modelorg ); RI.currententity = clgame.entities; RI.currentmodel = RI.currententity->model; R_RecursiveMirrorNode( cl.worldmodel->nodes, RI.clipFlags ); R_CheckEntitiesOnList(); }
/* =============== R_SetupProjection =============== */ void R_SetupProjection(viewParms_t *dest, float zProj, qboolean computeFrustum) { float xmin, xmax, ymin, ymax; float width, height, stereoSep = r_stereoSeparation->value; /* * offset the view origin of the viewer for stereo rendering * by setting the projection matrix appropriately. */ if(stereoSep != 0) { if(dest->stereoFrame == STEREO_LEFT) stereoSep = zProj / stereoSep; else if(dest->stereoFrame == STEREO_RIGHT) stereoSep = zProj / -stereoSep; else stereoSep = 0; } ymax = zProj * tan(dest->fovY * M_PI / 360.0f); ymin = -ymax; xmax = zProj * tan(dest->fovX * M_PI / 360.0f); xmin = -xmax; width = xmax - xmin; height = ymax - ymin; dest->projectionMatrix[0] = 2 * zProj / width; dest->projectionMatrix[4] = 0; dest->projectionMatrix[8] = (xmax + xmin + 2 * stereoSep) / width; dest->projectionMatrix[12] = 2 * zProj * stereoSep / width; dest->projectionMatrix[1] = 0; dest->projectionMatrix[5] = 2 * zProj / height; dest->projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0 dest->projectionMatrix[13] = 0; dest->projectionMatrix[3] = 0; dest->projectionMatrix[7] = 0; dest->projectionMatrix[11] = -1; dest->projectionMatrix[15] = 0; // Now that we have all the data for the projection matrix we can also setup the view frustum. if(computeFrustum) { // dynamically compute far clip plane distance R_SetFarClip(); R_SetupFrustum(dest, xmin, xmax, ymax, zProj, stereoSep); } }
/* ================ R_FindMirrors Build mirror chains for this frame ================ */ void R_FindMirrors( const ref_params_t *fd ) { if( !world.has_mirrors || RI.drawOrtho || !RI.drawWorld || RI.refdef.onlyClientDraw || !cl.worldmodel ) return; RI.refdef = *fd; // build the transformation matrix for the given view angles VectorCopy( RI.refdef.vieworg, RI.vieworg ); AngleVectors( RI.refdef.viewangles, RI.vforward, RI.vright, RI.vup ); R_FindViewLeaf(); R_SetupFrustum(); R_MarkLeaves (); VectorCopy( RI.cullorigin, tr.modelorg ); RI.currententity = clgame.entities; RI.currentmodel = RI.currententity->model; R_RecursiveMirrorNode( cl.worldmodel->nodes, RI.clipFlags ); R_CheckEntitiesOnList(); }
/* =============== R_SetupProjection =============== */ void R_SetupProjection(viewParms_t *dest, float zProj, qboolean computeFrustum) { float xmin, xmax, ymin, ymax; float width, height, stereoSep = r_stereoSeparation->value; float dx, dy; vec2_t pixelJitter, eyeJitter; /* * offset the view origin of the viewer for stereo rendering * by setting the projection matrix appropriately. */ if(stereoSep != 0) { if(dest->stereoFrame == STEREO_LEFT) stereoSep = zProj / stereoSep; else if(dest->stereoFrame == STEREO_RIGHT) stereoSep = zProj / -stereoSep; else stereoSep = 0; } //ri.Printf(PRINT_ALL, "zProj: %f\n", zProj); ymax = zProj * tan(dest->fovY * M_PI / 360.0f); ymin = -ymax; xmax = zProj * tan(dest->fovX * M_PI / 360.0f); xmin = -xmax; width = xmax - xmin; height = ymax - ymin; if (tr.recordingVideo || mme_dofVisualize->integer) { pixelJitter[0] = pixelJitter[1] = 0; eyeJitter[0] = eyeJitter[1] = 0; /* Jitter the view */ if (mme_dofFrames->integer > 0) { if (r_anaglyphMode->integer == 19 && *ri.SplitVideo && !tr.leftRecorded) { R_MME_JitterView( pixelJitter, eyeJitter, qfalse ); } else { R_MME_JitterView( pixelJitter, eyeJitter, qtrue ); } } dx = ( pixelJitter[0]*width ) / backEnd.viewParms.viewportWidth; dy = ( pixelJitter[1]*height ) / backEnd.viewParms.viewportHeight; dx += eyeJitter[0]; dy += eyeJitter[1]; xmin += dx; xmax += dx; ymin += dy; ymax += dy; } dest->projectionMatrix[0] = 2 * zProj / width; dest->projectionMatrix[4] = 0; dest->projectionMatrix[8] = (xmax + xmin + 2 * stereoSep) / width; dest->projectionMatrix[12] = 2 * zProj * stereoSep / width; dest->projectionMatrix[1] = 0; dest->projectionMatrix[5] = 2 * zProj / height; dest->projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0 dest->projectionMatrix[13] = 0; dest->projectionMatrix[3] = 0; dest->projectionMatrix[7] = 0; dest->projectionMatrix[11] = -1; dest->projectionMatrix[15] = 0; // Now that we have all the data for the projection matrix we can also setup the view frustum. if(computeFrustum) { R_SetupFrustum(dest, xmin, xmax, ymax, zProj, stereoSep); } }
/** * @sa R_BeginFrame * @sa R_EndFrame */ void R_RenderFrame (void) { R_Setup3D(); /* activate wire mode */ if (r_wire->integer) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); if (!(refdef.rendererFlags & RDF_NOWORLDMODEL)) { int tile; if (r_threads->integer) { while (r_threadstate.state != THREAD_RENDERER) Sys_Sleep(0); r_threadstate.state = THREAD_CLIENT; } else { R_SetupFrustum(); /* draw brushes on current worldlevel */ R_GetLevelSurfaceLists(); } R_UpdateSustainedLights(); R_CheckError(); for (tile = 0; tile < r_numMapTiles; tile++) { const model_t *mapTile = r_mapTiles[tile]; const mBspModel_t *bsp = &mapTile->bsp; R_AddBspRRef(bsp, vec3_origin, vec3_origin, false); } R_GetEntityLists(); R_EnableFog(true); R_RenderOpaqueBspRRefs(); R_RenderOpaqueWarpBspRRefs(); R_DrawOpaqueMeshEntities(r_opaque_mesh_entities); R_RenderAlphaTestBspRRefs(); R_EnableBlend(true); R_RenderMaterialBspRRefs(); R_EnableFog(false); R_RenderBlendBspRRefs(); R_RenderBlendWarpBspRRefs(); R_DrawBlendMeshEntities(r_blend_mesh_entities); R_EnableFog(true); R_RenderFlareBspRRefs(); R_EnableFog(false); if (r_debug_lights->integer) { int i; for (i = 0; i < refdef.numStaticLights; i++) { const light_t *l = &refdef.staticLights[i]; R_AddCorona(l->origin, l->radius, l->color); } for (i = 0; i < refdef.numDynamicLights; i++) { const light_t *l = &refdef.dynamicLights[i]; R_AddCorona(l->origin, l->radius, l->color); } } R_DrawCoronas(); R_EnableBlend(false); for (tile = 0; tile < r_numMapTiles; tile++) { R_DrawBspNormals(tile); } R_Color(NULL); R_DrawSpecialEntities(r_special_entities); R_DrawNullEntities(r_null_entities); R_DrawEntityEffects(); } else { glClear(GL_DEPTH_BUFFER_BIT); R_GetEntityLists(); R_RenderOpaqueBspRRefs(); R_RenderOpaqueWarpBspRRefs(); R_DrawOpaqueMeshEntities(r_opaque_mesh_entities); R_RenderAlphaTestBspRRefs(); R_EnableBlend(true); R_RenderMaterialBspRRefs(); R_RenderBlendBspRRefs(); R_RenderBlendWarpBspRRefs(); R_DrawBlendMeshEntities(r_blend_mesh_entities); R_RenderFlareBspRRefs(); R_EnableBlend(false); R_Color(NULL); R_DrawSpecialEntities(r_special_entities); R_DrawNullEntities(r_null_entities); R_DrawEntityEffects(); } R_EnableBlend(true); R_DrawParticles(); R_EnableBlend(false); /* leave wire mode again */ if (r_wire->integer) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); R_DrawBloom(); R_DrawBoundingBoxes(); R_ResetArrayState(); /* go back into 2D mode for hud and the like */ R_Setup2D(); R_CheckError(); }
/* * 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(); }
/* * 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(); }