void GL_DrawWorld( void ) { GL_MarkLeaves(); #if USE_DLIGHTS glr.dlightframe++; if( gl_dynamic->integer == 1 ) { GL_MarkLights(); } #endif R_ClearSkyBox(); if( gl_dynamic->integer ) { GL_BeginLights(); } GL_WorldNode_r( gl_static.world.cache->nodes, gl_cull_nodes->integer ? NODE_CLIPPED : NODE_UNCLIPPED ); if( gl_dynamic->integer ) { GL_EndLights(); } GL_DrawSolidFaces(); R_DrawSkyBox(); }
/* * R_DrawSkySurf */ void R_DrawSkySurf( const entity_t *e, const shader_t *shader, const mfog_t *fog, const portalSurface_t *portalSurface, unsigned int shadowBits, drawSurfaceSky_t *drawSurf ) { int i; int numVisSides; visSkySide_t visSkySides[6]; vec3_t mins, maxs; int umin, umax, vmin, vmax; bool skyportal = portalSurface != NULL && portalSurface->skyPortal; skydome_t *skydome = rsh.worldBrushModel->skydome; if( !skydome ) { return; } if( skyportal && !fog ) { return; } numVisSides = 0; ClearBounds( mins, maxs ); memset( visSkySides, 0, sizeof( visSkySides ) ); for( i = 0; i < 6; i++ ) { if( drawSurf->skyMins[0][i] >= drawSurf->skyMaxs[0][i] || drawSurf->skyMins[1][i] >= drawSurf->skyMaxs[1][i] ) { continue; } // increase the visible sides counter numVisSides++; umin = (int)( ( drawSurf->skyMins[0][i] + 1.0f ) * 0.5f * (float)( SIDE_SIZE - 1 ) ); umax = (int)( ( drawSurf->skyMaxs[0][i] + 1.0f ) * 0.5f * (float)( SIDE_SIZE - 1 ) ) + 1; vmin = (int)( ( drawSurf->skyMins[1][i] + 1.0f ) * 0.5f * (float)( SIDE_SIZE - 1 ) ); vmax = (int)( ( drawSurf->skyMaxs[1][i] + 1.0f ) * 0.5f * (float)( SIDE_SIZE - 1 ) ) + 1; clamp( umin, 0, SIDE_SIZE - 1 ); clamp( umax, 0, SIDE_SIZE - 1 ); clamp( vmin, 0, SIDE_SIZE - 1 ); clamp( vmax, 0, SIDE_SIZE - 1 ); visSkySides[i].index = i; visSkySides[i].firstVert = vmin * SIDE_SIZE + umin; visSkySides[i].numVerts = ( vmax - vmin ) * SIDE_SIZE + ( umax - umin ) + 1; visSkySides[i].firstElem = ( vmin * ( SIDE_SIZE - 2 ) + umin ) * 6; visSkySides[i].numElems = ( ( vmax - vmin ) * ( SIDE_SIZE - 2 ) + ( umax - umin ) ) * 6; clamp( visSkySides[i].firstVert, 0, POINTS_LEN - 1 ); clamp( visSkySides[i].numVerts, 0, POINTS_LEN ); clamp( visSkySides[i].firstElem, 0, ELEM_LEN - 1 ); clamp( visSkySides[i].numElems, 0, ELEM_LEN ); skydome->meshes[i].numElems = visSkySides[i].numElems; } // no sides are truly visible, ignore if( !numVisSides ) { return; } // center skydome on camera to give the illusion of a larger space rsc.skyent->scale = shader->skyHeight; VectorCopy( rn.viewOrigin, rsc.skyent->origin ); R_TransformForEntity( rsc.skyent ); if( skyportal ) { // render fake fogged skybox R_DrawSkyBox( skydome, visSkySides, rsh.emptyFogShader, shader, fog, drawSurf ); } else { if( shader->skyboxImages[0] ) { R_DrawSkyBox( skydome, visSkySides, rsh.skyShader, shader, fog, drawSurf ); } else { R_DrawBlackBottom( skydome, visSkySides, fog, drawSurf ); } if( shader->numpasses ) { for( i = 0; i < 5; i++ ) { const visSkySide_t *visSide = visSkySides + i; if( drawSurf->skyMins[0][i] >= drawSurf->skyMaxs[0][i] || drawSurf->skyMins[1][i] >= drawSurf->skyMaxs[1][i] ) { continue; } RB_BindShader( rsc.skyent, shader, NULL ); // must be called for every side to reset backend state RB_BindVBO( skydome->sphereVbos[i]->index, GL_TRIANGLES ); RB_DrawElements( visSide->firstVert, visSide->numVerts, visSide->firstElem, visSide->numElems, 0, 0, 0, 0 ); } } } R_TransformForEntity( e ); }
/* * @brief Main entry point for drawing the scene (world and entities). */ void R_DrawView(void) { R_UpdateFrustum(); R_UpdateVis(); R_MarkBspSurfaces(); R_EnableFog(true); R_DrawSkyBox(); // wait for the client to populate our lights array Thread_Wait(&r_view.thread); // now dispatch another thread to cull entities while we draw the world r_view.thread = Thread_Create(R_CullEntities, NULL); R_MarkLights(); const r_sorted_bsp_surfaces_t *surfs = r_model_state.world->bsp->sorted_surfaces; R_DrawOpaqueBspSurfaces(&surfs->opaque); R_DrawOpaqueWarpBspSurfaces(&surfs->opaque_warp); R_DrawAlphaTestBspSurfaces(&surfs->alpha_test); R_EnableBlend(true); R_DrawBackBspSurfaces(&surfs->back); R_DrawMaterialBspSurfaces(&surfs->material); R_DrawFlareBspSurfaces(&surfs->flare); R_EnableBlend(false); R_DrawBspNormals(); // ensure the thread has finished culling entities Thread_Wait(&r_view.thread); // now dispatch another thread to update particles while we draw entities r_view.thread = Thread_Create(R_UpdateParticles, NULL); R_DrawEntities(); R_EnableBlend(true); R_DrawBspLights(); R_DrawBlendBspSurfaces(&surfs->blend); R_DrawBlendWarpBspSurfaces(&surfs->blend_warp); // ensure the thread has finished updating particles Thread_Wait(&r_view.thread); R_DrawParticles(); R_EnableFog(false); R_DrawCoronas(); R_DrawBspLeafs(); R_EnableBlend(false); R_ResetArrayState(); }
/* * R_DrawSkySurf */ qboolean R_DrawSkySurf( const entity_t *e, const shader_t *shader, const mfog_t *fog, drawSurfaceBSP_t *drawSurf ) { int i; int numVisSides; visSkySide_t visSkySides[6]; vec3_t mins, maxs; int umin, umax, vmin, vmax; entity_t skyent; refdef_t *rd = &rn.refdef; skydome_t *skydome = r_worldbrushmodel->skydome; if( !skydome ) return qfalse; numVisSides = 0; ClearBounds( mins, maxs ); memset( visSkySides, 0, sizeof( visSkySides ) ); for( i = 0; i < 6; i++ ) { if( rn.skyMins[0][i] >= rn.skyMaxs[0][i] || rn.skyMins[1][i] >= rn.skyMaxs[1][i] ) continue; // increase the visible sides counter numVisSides++; umin = (int)( ( rn.skyMins[0][i]+1.0f )*0.5f*(float)( SIDE_SIZE-1 ) ); umax = (int)( ( rn.skyMaxs[0][i]+1.0f )*0.5f*(float)( SIDE_SIZE-1 ) ) + 1; vmin = (int)( ( rn.skyMins[1][i]+1.0f )*0.5f*(float)( SIDE_SIZE-1 ) ); vmax = (int)( ( rn.skyMaxs[1][i]+1.0f )*0.5f*(float)( SIDE_SIZE-1 ) ) + 1; clamp( umin, 0, SIDE_SIZE-1 ); clamp( umax, 0, SIDE_SIZE-1 ); clamp( vmin, 0, SIDE_SIZE-1 ); clamp( vmax, 0, SIDE_SIZE-1 ); visSkySides[i].index = i; visSkySides[i].firstVert = vmin * SIDE_SIZE + umin; visSkySides[i].numVerts = (vmax - vmin) * SIDE_SIZE + (umax - umin); visSkySides[i].firstElem = (vmin * (SIDE_SIZE-1) + umin) * 6; visSkySides[i].numElems = ((vmax - vmin) * (SIDE_SIZE-1) + (umax - umin)) * 6; AddPointToBounds( skydome->meshes[i].xyzArray[vmin*SIDE_SIZE+umin], mins, maxs ); AddPointToBounds( skydome->meshes[i].xyzArray[vmax*SIDE_SIZE+umax], mins, maxs ); skydome->meshes[i].numElems = visSkySides[i].numElems; } // no sides are truly visible, ignore if( !numVisSides ) return qfalse; VectorAdd( mins, rn.viewOrigin, mins ); VectorAdd( maxs, rn.viewOrigin, maxs ); if( rd->rdflags & RDF_SKYPORTALINVIEW ) { R_DrawSkyPortal( e, &rd->skyportal, mins, maxs ); return qfalse; } // center skydome on camera to give the illusion of a larger space skyent = *rsc.worldent; skyent.scale = shader->skyHeight; VectorCopy( rn.viewOrigin, skyent.origin ); R_TransformForEntity( &skyent ); if( shader->skyboxImages[0] ) R_DrawSkyBox( skydome, visSkySides, shader ); else R_DrawBlackBottom( skydome, visSkySides ); if( shader->numpasses ) { RB_BindShader( rsc.worldent, shader, rn.skyFog ); for( i = 0; i < 5; i++ ) { const visSkySide_t *visSide = visSkySides + i; if( rn.skyMins[0][i] >= rn.skyMaxs[0][i] || rn.skyMins[1][i] >= rn.skyMaxs[1][i] ) continue; RB_BindVBO( skydome->sphereVbos[i]->index, GL_TRIANGLES ); RB_DrawElements( visSide->firstVert, visSide->numVerts, visSide->firstElem, visSide->numElems ); } } R_TransformForEntity( e ); return qfalse; }
/* ============== R_DrawSky Draw either the classic cloudy quake sky or a skybox ============== */ void R_DrawSky (void) { msurface_t *fa; qbool ignore_z; extern msurface_t *skychain; GL_DisableMultitexture (); if (r_fastsky.value) { glDisable (GL_TEXTURE_2D); glColor3ubv (r_skycolor.color); for (fa = skychain; fa; fa = fa->texturechain) EmitFlatPoly (fa); skychain = NULL; glEnable (GL_TEXTURE_2D); glColor3f (1, 1, 1); return; } if (r_viewleaf->contents == CONTENTS_SOLID) { // always draw if we're in a solid leaf (probably outside the level) // FIXME: we don't really want to add all six planes every time! // FIXME: also handle r_fastsky case int i; for (i = 0; i < 6; i++) { skymins[0][i] = skymins[1][i] = -1; skymaxs[0][i] = skymaxs[1][i] = 1; } ignore_z = true; } else { if (!skychain) return; // no sky at all // figure out how much of the sky box we need to draw ClearSky (); for (fa = skychain; fa; fa = fa->texturechain) R_AddSkyBoxSurface (fa); ignore_z = false; } // turn off Z tests & writes to avoid problems on large maps glDisable (GL_DEPTH_TEST); // draw a skybox or classic quake clouds if (r_skyboxloaded) R_DrawSkyBox (); else R_DrawSkyDome (); glEnable (GL_DEPTH_TEST); // draw the sky polys into the Z buffer // don't need depth test yet if (!ignore_z) { if (gl_fogenable.value && gl_fogsky.value) { glEnable(GL_FOG); glColor4f(gl_fogred.value, gl_foggreen.value, gl_fogblue.value, 1); glBlendFunc(GL_ONE, GL_ZERO); } else { glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glBlendFunc(GL_ZERO, GL_ONE); } glDisable(GL_TEXTURE_2D); glEnable(GL_BLEND); for (fa = skychain; fa; fa = fa->texturechain) EmitFlatPoly (fa); if (gl_fogenable.value && gl_fogsky.value) glDisable (GL_FOG); else { glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable (GL_TEXTURE_2D); glDisable(GL_BLEND); } skychain = NULL; skychain_tail = &skychain; }
/* * @brief Main entry point for drawing the scene (world and entities). */ void R_DrawView(void) { R_UpdateFrustum(); R_UpdateVis(); R_MarkBspSurfaces(); R_EnableFog(true); R_DrawSkyBox(); // wait for the client to fully populate the scene Thread_Wait(r_view.thread); // dispatch threads to cull entities and sort elements while we draw the world thread_t *cull_entities = Thread_Create(R_CullEntities, NULL); thread_t *sort_elements = Thread_Create(R_SortElements, NULL); R_MarkLights(); const r_sorted_bsp_surfaces_t *surfs = r_model_state.world->bsp->sorted_surfaces; R_DrawOpaqueBspSurfaces(&surfs->opaque); R_DrawOpaqueWarpBspSurfaces(&surfs->opaque_warp); R_DrawAlphaTestBspSurfaces(&surfs->alpha_test); R_EnableBlend(true); R_DrawBackBspSurfaces(&surfs->back); R_DrawMaterialBspSurfaces(&surfs->material); R_DrawFlareBspSurfaces(&surfs->flare); R_EnableBlend(false); // wait for entity culling to complete Thread_Wait(cull_entities); R_DrawEntities(); R_EnableBlend(true); // wait for element sorting to complete Thread_Wait(sort_elements); R_DrawElements(); R_EnableFog(false); R_DrawDeveloperTools(); R_DrawCoronas(); R_EnableBlend(false); R_ResetArrayState(); #if 0 vec3_t tmp; VectorMA(r_view.origin, MAX_WORLD_DIST, r_view.forward, tmp); cm_trace_t tr = Cl_Trace(r_view.origin, tmp, NULL, NULL, cl.client_num + 1, MASK_SOLID); if (tr.fraction > 0.0 && tr.fraction < 1.0) { Com_Print("%s: %d: %s\n", tr.surface->name, tr.plane.num, vtos(tr.plane.normal)); } #endif }