/** * @brief Recurse down the bsp tree and mark surfaces that are visible (not culled) * for being rendered * @sa R_DrawWorld * @sa R_RecurseWorld * @sa R_RecursiveVisibleWorldNode * @param[in] node The bsp node to check * @param[in] tile The maptile (map assembly) */ static void R_RecursiveWorldNode (const mBspNode_t* node, int tile) { int i; int cullState; mBspSurface_t* surf; /* if a leaf node, nothing to mark */ if (node->contents > CONTENTS_NODE) return; cullState = R_CullBox(node->minmaxs, node->minmaxs + 3); if (cullState == PSIDE_BACK) return; /* culled out */ /* pathfinding nodes are invalid here */ assert(node->plane); surf = r_mapTiles[tile]->bsp.surfaces + node->firstsurface; for (i = 0; i < node->numsurfaces; i++, surf++) surf->frame = r_locals.frame; /* recurse down the children */ /** @todo avoid being too precise, it's a waste of CPU time; possibly, granularity of 256x256x256 should be enough */ if (cullState == PSIDE_FRONT) { /* completely inside the frustum - no need to do any further checks */ R_RecursiveVisibleWorldNode(node->children[0], tile); R_RecursiveVisibleWorldNode(node->children[1], tile); } else { /* partially clipped by frustum - recurse to do finer checks */ R_RecursiveWorldNode(node->children[0], tile); R_RecursiveWorldNode(node->children[1], tile); } }
bool R_CullModelForEntity(entity_t *e) { vec3_t mins, maxs; if(e == &cl.viewent) return false; if(e->angles[PITCH] || e->angles[ROLL]) { Math_VectorAdd (e->origin, e->model->rmins, mins); Math_VectorAdd (e->origin, e->model->rmaxs, maxs); } else if(e->angles[YAW]) { Math_VectorAdd (e->origin, e->model->ymins, mins); Math_VectorAdd (e->origin, e->model->ymaxs, maxs); } else //no rotation { Math_VectorAdd(e->origin,e->model->mins,mins); Math_VectorAdd(e->origin,e->model->maxs,maxs); } return R_CullBox(mins, maxs); }
/* ================ CL_CullTracer check tracer bbox ================ */ static qboolean CL_CullTracer( const vec3_t start, const vec3_t end ) { vec3_t mins, maxs; int i; // compute the bounding box for( i = 0; i < 3; i++ ) { if( start[i] < end[i] ) { mins[i] = start[i]; maxs[i] = end[i]; } else { mins[i] = end[i]; maxs[i] = start[i]; } // don't let it be zero sized if( mins[i] == maxs[i] ) { maxs[i] += 1; } } // check bbox return R_CullBox( mins, maxs, RI.clipFlags ); }
void R_SetupBrushInstantForLight(entity_t *e) { brushlightinstant_t *brushlightinstant; vec3_t mins, maxs; qboolean update; brushlightinstant = R_AllocateBrushLightInstant(e); VectorAdd (e->origin,e->model->mins, mins); VectorAdd (e->origin,e->model->maxs, maxs); if (R_CullBox (mins, maxs)) brushlightinstant->shadowonly = true; else brushlightinstant->shadowonly = false; e->brushlightinstant = brushlightinstant; R_SetupBrushObjectSpace(e, brushlightinstant); update = CheckBrushLightUpdate(e, brushlightinstant); if (update) { R_CalcBrushVolumeVerts(e, brushlightinstant); if (!brushlightinstant->shadowonly) { if ( gl_cardtype == GENERIC || gl_cardtype == GEFORCE ) {//PA: R_CalcBrushAttenCoords(e, brushlightinstant); } //R_SetupBrushLightHAV(e, brushlightinstant); } //make sure that we can compare the next frame VectorCopy(e->origin, brushlightinstant->lasteorg); VectorCopy(currentshadowlight->origin, brushlightinstant->lastlorg); VectorCopy(e->angles, brushlightinstant->lasteangles); brushlightinstant->lastlradius = currentshadowlight->radius; brushlightinstant->lastlight = currentshadowlight; brushlightinstant->lastent = e; brushlightinstant->lastshadowonly = brushlightinstant->shadowonly; } brushCacheRequests++; //Half angles only change when the viewer changes his position //this happens a lot so recalculate only this. if ((update) || CheckBrushHalfAngle(brushlightinstant)) { if (!brushlightinstant->shadowonly) R_SetupBrushLightHAV(e, brushlightinstant); VectorCopy(r_refdef.vieworg,brushlightinstant->lastvorg); if(!update) brushPartialCacheHits++; } else { brushFullCacheHits++; } //lock it for this frame brushlightinstant->lockframe = r_framecount; }
/* * R_CullModelEntity */ int R_CullModelEntity( const entity_t *e, vec3_t mins, vec3_t maxs, float radius, bool sphereCull, bool pvsCull ) { if( e->flags & RF_NOSHADOW ) { if( rn.renderFlags & RF_SHADOWMAPVIEW ) return 3; } if( e->flags & RF_WEAPONMODEL ) { if( rn.renderFlags & RF_NONVIEWERREF ) return 1; return 0; } if( e->flags & RF_VIEWERMODEL ) { //if( !(rn.renderFlags & RF_NONVIEWERREF) ) if( !( rn.renderFlags & ( RF_MIRRORVIEW|RF_SHADOWMAPVIEW ) ) ) return 1; } if( e->flags & RF_NODEPTHTEST ) return 0; // account for possible outlines if( e->outlineHeight ) radius += e->outlineHeight * r_outlines_scale->value * 1.73/*sqrt(3)*/; if( sphereCull ) { if( R_CullSphere( e->origin, radius, rn.clipFlags ) ) return 1; } else { if( R_CullBox( mins, maxs, rn.clipFlags ) ) return 1; } if( pvsCull ) { if( sphereCull ) { if( R_VisCullSphere( e->origin, radius ) ) return 2; } else { if( R_VisCullBox( mins, maxs ) ) return 2; } } return 0; }
/* * R_CullSurface */ qboolean R_CullSurface( const entity_t *e, const msurface_t *surf, unsigned int clipflags ) { const shader_t *shader = surf->shader; if( r_nocull->integer ) return qfalse; if( ( shader->flags & SHADER_ALLDETAIL ) && !r_detailtextures->integer ) return qtrue; return ( clipflags && R_CullBox( surf->mins, surf->maxs, clipflags ) ); }
//----------------------------------------------------------------------------- // Do we have reflective glass in view? //----------------------------------------------------------------------------- bool IsReflectiveGlassInView( const CViewSetup& view, cplane_t &plane ) { // Early out if no cameras C_FuncReflectiveGlass *pReflectiveGlass = GetReflectiveGlassList(); if ( !pReflectiveGlass ) return false; Frustum_t frustum; GeneratePerspectiveFrustum( view.origin, view.angles, view.zNear, view.zFar, view.fov, view.m_flAspectRatio, frustum ); cplane_t localPlane; Vector vecOrigin, vecWorld, vecDelta, vecForward; AngleVectors( view.angles, &vecForward, NULL, NULL ); for ( ; pReflectiveGlass != NULL; pReflectiveGlass = pReflectiveGlass->m_pNext ) { if ( pReflectiveGlass->IsDormant() ) continue; Vector vecMins, vecMaxs; pReflectiveGlass->GetRenderBoundsWorldspace( vecMins, vecMaxs ); if ( R_CullBox( vecMins, vecMaxs, frustum ) ) continue; const model_t *pModel = pReflectiveGlass->GetModel(); const matrix3x4_t& mat = pReflectiveGlass->EntityToWorldTransform(); int nCount = modelinfo->GetBrushModelPlaneCount( pModel ); for ( int i = 0; i < nCount; ++i ) { modelinfo->GetBrushModelPlane( pModel, i, localPlane, &vecOrigin ); MatrixTransformPlane( mat, localPlane, plane ); // Transform to world space VectorTransform( vecOrigin, mat, vecWorld ); if ( view.origin.Dot( plane.normal ) <= plane.dist ) // Check for view behind plane continue; VectorSubtract( vecWorld, view.origin, vecDelta ); // Backface cull if ( vecDelta.Dot( plane.normal ) >= 0 ) continue; return true; } } return false; }
/* ============= R_CullIQM ============= */ static void R_CullIQM( trRefEntity_t *ent ) { vec3_t localBounds[ 2 ]; float scale = ent->e.skeleton.scale; IQModel_t *model = tr.currentModel->iqm; IQAnim_t *anim = model->anims; float *bounds; // use the bounding box by the model bounds = model->bounds[0]; VectorCopy( bounds, localBounds[ 0 ] ); VectorCopy( bounds + 3, localBounds[ 1 ] ); if ( anim && ( bounds = anim->bounds ) ) { // merge bounding box provided by the animation BoundsAdd( localBounds[ 0 ], localBounds[ 1 ], bounds, bounds + 3 ); } // merge bounding box provided by skeleton BoundsAdd( localBounds[ 0 ], localBounds[ 1 ], ent->e.skeleton.bounds[ 0 ], ent->e.skeleton.bounds[ 1 ] ); VectorScale( localBounds[0], scale, ent->localBounds[ 0 ] ); VectorScale( localBounds[1], scale, ent->localBounds[ 1 ] ); R_SetupEntityWorldBounds(ent); switch ( R_CullBox( ent->worldBounds ) ) { case cullResult_t::CULL_IN: tr.pc.c_box_cull_md5_in++; ent->cull = cullResult_t::CULL_IN; return; case cullResult_t::CULL_CLIP: tr.pc.c_box_cull_md5_clip++; ent->cull = cullResult_t::CULL_CLIP; return; case cullResult_t::CULL_OUT: default: tr.pc.c_box_cull_md5_out++; ent->cull = cullResult_t::CULL_OUT; return; } }
/** * @brief Returns true if the specified entity is completely culled by the view * frustum, false otherwise. * @param[in] e The entity to check * @sa R_CullBox */ bool R_CullBspModel (const entity_t* e) { vec3_t mins, maxs; /* no surfaces */ if (!e->model->bsp.nummodelsurfaces) return true; if (e->isOriginBrushModel) { int i; for (i = 0; i < 3; i++) { mins[i] = e->origin[i] - e->model->radius; maxs[i] = e->origin[i] + e->model->radius; } } else { e->model->modBox.shift(e->origin); } return R_CullBox(mins, maxs) == PSIDE_BACK; }
/* =============== R_CullModelForEntity -- johnfitz -- uses correct bounds based on rotation =============== */ qboolean R_CullModelForEntity (entity_t *e) { vec3_t mins, maxs; if (e->angles[0] || e->angles[2]) //pitch or roll { VectorAdd (e->origin, e->model->rmins, mins); VectorAdd (e->origin, e->model->rmaxs, maxs); } else if (e->angles[1]) //yaw { VectorAdd (e->origin, e->model->ymins, mins); VectorAdd (e->origin, e->model->ymaxs, maxs); } else //no rotation { VectorAdd (e->origin, e->model->mins, mins); VectorAdd (e->origin, e->model->maxs, maxs); } return R_CullBox (mins, maxs); }
/* * R_CullBrushModel */ qboolean R_CullBrushModel( entity_t *e ) { qboolean rotated; vec3_t mins, maxs; float radius; model_t *model = e->model; mbrushmodel_t *bmodel = ( mbrushmodel_t * )model->extradata; if( bmodel->nummodelsurfaces == 0 ) return qtrue; radius = R_BrushModelBBox( e, mins, maxs, &rotated ); if( rotated ) { if( R_CullSphere( e->origin, radius, ri.clipFlags ) ) return qtrue; } else { if( R_CullBox( mins, maxs, ri.clipFlags ) ) return qtrue; } if( ri.params & RP_PVSCULL ) { if( rotated ) { if( R_VisCullSphere( e->origin, radius ) ) return qtrue; } else { if( R_VisCullBox( mins, maxs ) ) return qtrue; } } return qfalse; }
void R_SetupAliasModel (entity_t *e) { aliashdr_t *paliashdr; int anim; aliasstate_t *state = &e->aliasstate; // initially not visible e->visframe = -1; // setup pose/lerp data -- do it first so we don't miss updates due to culling paliashdr = (aliashdr_t *) Mod_Extradata (e->model); R_SetupAliasFrame (e, paliashdr, e->frame, state); R_SetupEntityTransform (e, state); R_BBoxForEnt (e); // cull it (the viewmodel is never culled) if (r_shadows.value > 0.01f) { if (!(e->renderfx & RF_WEAPONMODEL)) { if (R_CullBox (e->mins, e->maxs)) e->visframe = -1; else e->visframe = r_framecount; } } else { if (!(e->renderfx & RF_WEAPONMODEL)) { if (R_CullBox (e->mins, e->maxs)) return; } // the ent is visible now e->visframe = r_framecount; } // set up lighting overbright = gl_overbright.value; rs_aliaspolys += paliashdr->numtris; R_SetupAliasLighting (e, state->shadelight); // store out the alpha value state->shadelight[3] = ((float) e->alpha / 255.0f); // set up textures anim = (int) (cl.time * 10) & 3; state->tx = paliashdr->gltextures[e->skinnum][anim]; // ensure we have a valid texture if (!state->tx) state->tx = notexture; if (!gl_fullbrights.value) state->fb = NULL; else state->fb = paliashdr->fbtextures[e->skinnum][anim]; if (e->colormap && (e->model->modhint == MOD_PLAYER || e->renderfx & RF_PLAYERMODEL) && !gl_nocolors.value) R_GetTranslatedPlayerSkin (e->colormap, &state->tx, &state->fb); }
/** * @brief R_CullMDV * @param[in] model * @param[in,out] ent */ static void R_CullMDV(mdvModel_t *model, trRefEntity_t *ent) { int i; // compute frame pointers mdvFrame_t *newFrame = model->frames + ent->e.frame; mdvFrame_t *oldFrame = model->frames + ent->e.oldframe; // calculate a bounding box in the current coordinate system for (i = 0; i < 3; i++) { ent->localBounds[0][i] = oldFrame->bounds[0][i] < newFrame->bounds[0][i] ? oldFrame->bounds[0][i] : newFrame->bounds[0][i]; ent->localBounds[1][i] = oldFrame->bounds[1][i] > newFrame->bounds[1][i] ? oldFrame->bounds[1][i] : newFrame->bounds[1][i]; } // setup world bounds for intersection tests R_SetupEntityWorldBounds(ent); // cull bounding sphere ONLY if this is not an upscaled entity if (!ent->e.nonNormalizedAxes) { if (ent->e.frame == ent->e.oldframe) { switch (R_CullLocalPointAndRadius(newFrame->localOrigin, newFrame->radius)) { case CULL_OUT: tr.pc.c_sphere_cull_mdx_out++; ent->cull = CULL_OUT; return; case CULL_IN: tr.pc.c_sphere_cull_mdx_in++; ent->cull = CULL_IN; return; case CULL_CLIP: tr.pc.c_sphere_cull_mdx_clip++; break; } } else { int sphereCull, sphereCullB; sphereCull = R_CullLocalPointAndRadius(newFrame->localOrigin, newFrame->radius); if (newFrame == oldFrame) { sphereCullB = sphereCull; } else { sphereCullB = R_CullLocalPointAndRadius(oldFrame->localOrigin, oldFrame->radius); } if (sphereCull == sphereCullB) { if (sphereCull == CULL_OUT) { tr.pc.c_sphere_cull_mdx_out++; ent->cull = CULL_OUT; return; } else if (sphereCull == CULL_IN) { tr.pc.c_sphere_cull_mdx_in++; ent->cull = CULL_IN; return; } else { tr.pc.c_sphere_cull_mdx_clip++; } } } } switch (R_CullBox(ent->worldBounds)) { case CULL_IN: tr.pc.c_box_cull_mdx_in++; ent->cull = CULL_IN; return; case CULL_CLIP: tr.pc.c_box_cull_mdx_clip++; ent->cull = CULL_CLIP; return; case CULL_OUT: default: tr.pc.c_box_cull_mdx_out++; ent->cull = CULL_OUT; return; } }
/* ================= R_ShadowPassDrawBrushModel ================= */ void R_ShadowPassDrawBrushModel( cl_entity_t *e, const plight_t *pl ) { Vector mins, maxs; model_t *clmodel; bool rotated; clmodel = e->model; if( e->angles != g_vecZero ) { for( int i = 0; i < 3; i++ ) { mins[i] = e->origin[i] - clmodel->radius; maxs[i] = e->origin[i] + clmodel->radius; } rotated = true; } else { mins = e->origin + clmodel->mins; maxs = e->origin + clmodel->maxs; rotated = false; } if( R_CullBox( mins, maxs, RI.clipFlags )) return; if( RI.params & ( RP_SKYPORTALVIEW|RP_PORTALVIEW|RP_SCREENVIEW )) { if( rotated ) { if( R_VisCullSphere( e->origin, clmodel->radius )) return; } else { if( R_VisCullBox( mins, maxs )) return; } } if( rotated ) R_RotateForEntity( e ); else R_TranslateForEntity( e ); if( rotated ) tr.modelorg = RI.objectMatrix.VectorITransform( RI.vieworg ); else tr.modelorg = RI.vieworg - e->origin; // accumulate lit surfaces msurface_t *psurf = &clmodel->surfaces[clmodel->firstmodelsurface]; for( int i = 0; i < clmodel->nummodelsurfaces; i++, psurf++ ) { float *v; int k; if( psurf->flags & (SURF_DRAWTILED|SURF_PORTAL|SURF_REFLECT)) continue; R_AddToGrassChain( psurf, pl->frustum, pl->clipflags, false ); if( R_CullSurfaceExt( psurf, pl->frustum, 0 )) continue; // draw depth-mask on transparent textures if( psurf->flags & SURF_TRANSPARENT ) { pglEnable( GL_ALPHA_TEST ); pglEnable( GL_TEXTURE_2D ); pglAlphaFunc( GL_GREATER, 0.0f ); GL_Bind( GL_TEXTURE0, psurf->texinfo->texture->gl_texturenum ); } pglBegin( GL_POLYGON ); for( k = 0, v = psurf->polys->verts[0]; k < psurf->polys->numverts; k++, v += VERTEXSIZE ) { if( psurf->flags & SURF_TRANSPARENT ) pglTexCoord2f( v[3], v[4] ); pglVertex3fv( v ); } pglEnd(); if( psurf->flags & SURF_TRANSPARENT ) { pglDisable( GL_ALPHA_TEST ); pglDisable( GL_TEXTURE_2D ); } } R_LoadIdentity(); // restore worldmatrix }
/* ================= R_DrawAliasModel ================= */ void R_DrawAliasModel (entity_t *e) { int i, j; int lnum; vec3_t dist; float add; model_t *clmodel; vec3_t mins, maxs; aliashdr_t *paliashdr; trivertx_t *verts, *v; int index; float s, t, an; int anim; clmodel = currententity->model; VectorAdd (currententity->origin, clmodel->mins, mins); VectorAdd (currententity->origin, clmodel->maxs, maxs); if (R_CullBox (mins, maxs)) return; VectorCopy (currententity->origin, r_entorigin); VectorSubtract (r_origin, r_entorigin, modelorg); // // get lighting information // ambientlight = shadelight = R_LightPoint (currententity->origin); // allways give the gun some light if (e == &cl.viewent && ambientlight < 24) ambientlight = shadelight = 24; for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++) { if (cl_dlights[lnum].die >= cl.time) { VectorSubtract (currententity->origin, cl_dlights[lnum].origin, dist); add = cl_dlights[lnum].radius - Length(dist); if (add > 0) { ambientlight += add; //ZOID models should be affected by dlights as well shadelight += add; } } } // clamp lighting so it doesn't overbright as much if (ambientlight > 128) ambientlight = 128; if (ambientlight + shadelight > 192) shadelight = 192 - ambientlight; // ZOID: never allow players to go totally black i = currententity - cl_entities; if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */) if (ambientlight < 8) ambientlight = shadelight = 8; // HACK HACK HACK -- no fullbright colors, so make torches full light if (!strcmp (clmodel->name, "progs/flame2.mdl") || !strcmp (clmodel->name, "progs/flame.mdl") ) ambientlight = shadelight = 256; shadedots = r_avertexnormal_dots[((int)(e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; shadelight = shadelight / 200.0; an = e->angles[1]/180*M_PI; shadevector[0] = cos(-an); shadevector[1] = sin(-an); shadevector[2] = 1; VectorNormalize (shadevector); // // locate the proper data // paliashdr = (aliashdr_t *)Mod_Extradata (currententity->model); c_alias_polys += paliashdr->numtris; // // draw all the triangles // GL_DisableMultitexture(); glPushMatrix (); R_RotateForEntity (e); if (!strcmp (clmodel->name, "progs/eyes.mdl") && gl_doubleeyes.value) { glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2] - (22 + 8)); // double size of eyes, since they are really hard to see in gl glScalef (paliashdr->scale[0]*2, paliashdr->scale[1]*2, paliashdr->scale[2]*2); } else { glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]); glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]); } anim = (int)(cl.time*10) & 3; GL_Bind(paliashdr->gl_texturenum[currententity->skinnum][anim]); // we can't dynamically colormap textures, so they are cached // seperately for the players. Heads are just uncolored. if (currententity->colormap != vid.colormap && !gl_nocolors.value) { i = currententity - cl_entities; if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */) GL_Bind(playertextures - 1 + i); } if (gl_smoothmodels.value) glShadeModel (GL_SMOOTH); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); if (gl_affinemodels.value) glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); R_SetupAliasFrame (currententity->frame, paliashdr); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glShadeModel (GL_FLAT); if (gl_affinemodels.value) glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); glPopMatrix (); if (r_shadows.value) { glPushMatrix (); R_RotateForEntity (e); glDisable (GL_TEXTURE_2D); glEnable (GL_BLEND); glColor4f (0,0,0,0.5); GL_DrawAliasShadow (paliashdr, lastposenum); glEnable (GL_TEXTURE_2D); glDisable (GL_BLEND); glColor4f (1,1,1,1); glPopMatrix (); } }
/* ================= R_FindBmodelMirrors Check all bmodel surfaces and make personal mirror chain ================= */ void R_FindBmodelMirrors( cl_entity_t *e, qboolean static_entity ) { mextrasurf_t *extrasurf; vec3_t mins, maxs; msurface_t *psurf; model_t *clmodel; qboolean rotated; int i, clipFlags; clmodel = e->model; if( static_entity ) { Matrix4x4_LoadIdentity( RI.objectMatrix ); if( R_CullBox( clmodel->mins, clmodel->maxs, RI.clipFlags )) return; VectorCopy( RI.cullorigin, tr.modelorg ); clipFlags = RI.clipFlags; } else { if( !VectorIsNull( e->angles )) { for( i = 0; i < 3; i++ ) { mins[i] = e->origin[i] - clmodel->radius; maxs[i] = e->origin[i] + clmodel->radius; } rotated = true; } else { VectorAdd( e->origin, clmodel->mins, mins ); VectorAdd( e->origin, clmodel->maxs, maxs ); rotated = false; } if( R_CullBox( mins, maxs, RI.clipFlags )) return; if( !VectorIsNull( e->origin ) || !VectorIsNull( e->angles )) { if( rotated ) Matrix4x4_CreateFromEntity( RI.objectMatrix, e->angles, e->origin, 1.0f ); else Matrix4x4_CreateFromEntity( RI.objectMatrix, vec3_origin, e->origin, 1.0f ); } else Matrix4x4_LoadIdentity( RI.objectMatrix ); e->visframe = tr.framecount; // visible if( rotated ) Matrix4x4_VectorITransform( RI.objectMatrix, RI.cullorigin, tr.modelorg ); else VectorSubtract( RI.cullorigin, e->origin, tr.modelorg ); clipFlags = 0; } psurf = &clmodel->surfaces[clmodel->firstmodelsurface]; for( i = 0; i < clmodel->nummodelsurfaces; i++, psurf++ ) { if(!( psurf->flags & SURF_REFLECT )) continue; if( R_CullSurface( psurf, clipFlags )) continue; extrasurf = SURF_INFO( psurf, RI.currentmodel ); extrasurf->mirrorchain = tr.mirror_entities[tr.num_mirror_entities].chain; tr.mirror_entities[tr.num_mirror_entities].chain = extrasurf; } // store new mirror entity if( !static_entity && tr.mirror_entities[tr.num_mirror_entities].chain != NULL ) { tr.mirror_entities[tr.num_mirror_entities].ent = RI.currententity; tr.num_mirror_entities++; } }
void R_DrawBrushModel(entity_t *e) { int k; vec3_t mins, maxs; model_t *clmodel; bool rotated; int i; extern vec3_t lightcolor; int lnum; vec3_t dist; float add; float modelorg[3]; clmodel = e->model; if (e->angles[0] || e->angles[1] || e->angles[2]) { rotated = true; for (i = 0; i < 3; i++) { mins[i] = e->origin[i] - clmodel->radius; maxs[i] = e->origin[i] + clmodel->radius; } } else { rotated = false; VectorAdd(e->origin, clmodel->mins, mins); VectorAdd(e->origin, clmodel->maxs, maxs); } if (R_CullBox(mins, maxs)) return; //Lighting for model //dynamic lights for non lightmaped bmodels if (clmodel->firstmodelsurface == 0) { R_LightPoint(e->origin); for (lnum = 0; lnum < MAX_DLIGHTS; lnum++) { if (cl_dlights[lnum].die >= cl.time) { VectorSubtract(e->origin, cl_dlights[lnum].origin, dist); add = cl_dlights[lnum].radius - VectorLength(dist); if (add > 0) { lightcolor[0] += add * cl_dlights[lnum].colour[0]; lightcolor[1] += add * cl_dlights[lnum].colour[1]; lightcolor[2] += add * cl_dlights[lnum].colour[2]; } } } VectorScale(lightcolor, 1.0f / 100.0f, lightcolor); if (gl_ammoflash.getBool()) { lightcolor[0] += sin(2 * cl.time * M_PI) / 4; lightcolor[1] += sin(2 * cl.time * M_PI) / 4; lightcolor[2] += sin(2 * cl.time * M_PI) / 4; } glColor3fv(lightcolor); } else { glColor3f(1.0, 1.0, 1.0); memset(lightmap_polys, 0, sizeof (lightmap_polys)); } VectorSubtract(r_refdef.vieworg, e->origin, modelorg); if (rotated) { vec3_t temp; vec3_t forward, right, up; VectorCopy(modelorg, temp); AngleVectors(e->angles, forward, right, up); modelorg[0] = DotProduct(temp, forward); modelorg[1] = -DotProduct(temp, right); modelorg[2] = DotProduct(temp, up); } glPushMatrix(); e->angles[0] = -e->angles[0]; // stupid quake bug R_RotateForEntity(e); e->angles[0] = -e->angles[0]; // stupid quake bug // calculate dynamic lighting for bmodel if it's not an // instanced model if (clmodel->firstmodelsurface != 0 && !gl_flashblend.getBool()) { for (k = 0; k < MAX_DLIGHTS; k++) { if ((cl_dlights[k].die < cl.time) || (!cl_dlights[k].radius)) continue; R_MarkLights(&cl_dlights[k], 1 << k, clmodel->nodes + clmodel->hulls[0].firstclipnode); } } R_DrawBrush(clmodel, &modelorg[0]); glPopMatrix(); }
void R_RecursiveWorldNode(mnode_t *node, float *modelorg) { int c, side; mplane_t *plane; msurface_t *surf, **mark; mleaf_t *pleaf; double dot; //make sure we are still inside the world if (node->contents == CONTENTS_SOLID) return; // solid //is this node visable if (node->visframe != r_visframecount) return; //i think this checks if its on the screen and not behind the viewer if (R_CullBox(node->minmaxs, node->minmaxs + 3)) return; // if a leaf node, draw stuff if (node->contents < 0) { pleaf = (mleaf_t *) node; mark = pleaf->firstmarksurface; c = pleaf->nummarksurfaces; if (c) { do { (*mark)->visframe = r_framecount; mark++; } while (--c); } // deal with model fragments in this leaf if (pleaf->efrags) R_StoreEfrags(&pleaf->efrags); return; } // node is just a decision point, so go down the apropriate sides // find which side of the node we are on plane = node->plane; switch (plane->type) { case PLANE_X: dot = modelorg[0] - plane->dist; break; case PLANE_Y: dot = modelorg[1] - plane->dist; break; case PLANE_Z: dot = modelorg[2] - plane->dist; break; default: dot = DotProduct(modelorg, plane->normal) - plane->dist; break; } if (dot >= 0) side = 0; else side = 1; // recurse down the children, front side first R_RecursiveWorldNode(node->children[side], modelorg); // recurse down the back side if (r_outline.getBool()) R_RecursiveWorldNode(node->children[!side], modelorg); // draw stuff c = node->numsurfaces; if (c) { surf = cl.worldmodel->surfaces + node->firstsurface; { for (; c; c--, surf++) { if (surf->visframe != r_framecount) continue; if (surf->flags & SURF_DRAWSKY) { surf->texturechain = skychain; skychain = surf; } else if (surf->flags & SURF_DRAWTURB) { surf->texturechain = waterchain; waterchain = surf; } else { //add chain for drawing. surf->texturechain = surf->texinfo->texture->texturechain; surf->texinfo->texture->texturechain = surf; //setup eyecandy chain if ((surf->flags & SURF_UNDERWATER && gl_caustics.getBool()) || (surf->flags & SURF_SHINY_METAL && gl_shiny.getBool()) || (surf->flags & SURF_SHINY_GLASS && gl_shiny.getBool())) { surf->extra = extrachain; extrachain = surf; } if (r_outline.getBool()) { surf->outline = outlinechain; outlinechain = surf; } } } } } // recurse down the back side if (!r_outline.getBool()) R_RecursiveWorldNode(node->children[!side], modelorg); }
void R_DrawAliasModel(entity_t *e) { extern void AddFire(vec3_t org, float size); int lnum; vec3_t dist; float add; model_t *clmodel; vec3_t mins, maxs; aliashdr_t *paliashdr; float an; //s, t, int anim; md2_t *pheader; // LH / muff int shell; //QMB :model shells //not implemented yet // byte c, *color; //QMB :color map //does the model need a shell? if (cl.items & IT_QUAD && e == &cl.viewent) shell = true; else shell = false; //set get the model from the e clmodel = e->model; //work out its max and mins VectorAdd(e->origin, clmodel->mins, mins); VectorAdd(e->origin, clmodel->maxs, maxs); //make sure its in screen if (R_CullBox(mins, maxs) && e != &cl.viewent) return; //QMB: FIXME //should use a particle emitter linked to the model for its org //needs to be linked when the model is created and distroyed when //the entity is distroyed //check if its a fire and add the particle effect if (!strcmp(clmodel->name, "progs/flame.mdl")) AddFire(e->origin, 4); if (!strcmp(clmodel->name, "progs/flame2.mdl")) { AddFire(e->origin, 10); return; //do not draw the big fire model, its just a place holder for the particles } // get lighting information //QMB: FIXME //SHOULD CHANGE TO A PASSED VAR //get vertex normals (for lighting and shells) shadedots = r_avertexnormal_dots[((int) (e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; //make a default lighting direction an = e->angles[1] / 180 * M_PI; shadevector[0] = cos(-an); shadevector[1] = sin(-an); shadevector[2] = 1; //e->angles[0]; VectorNormalize(shadevector); //get the light for the model R_LightPoint(e->origin); // LordHavoc: lightcolor is all that matters from this //work out lighting from the dynamic lights for (lnum = 0; lnum < MAX_DLIGHTS; lnum++) { //if the light is alive if (cl_dlights[lnum].die >= cl.time) { //work out the distance to the light VectorSubtract(e->origin, cl_dlights[lnum].origin, dist); add = cl_dlights[lnum].radius - VectorLength(dist); //if its close enough add light from it if (add > 0) { lightcolor[0] += add * cl_dlights[lnum].colour[0]; lightcolor[1] += add * cl_dlights[lnum].colour[1]; lightcolor[2] += add * cl_dlights[lnum].colour[2]; } } } //scale lighting to floating point VectorScale(lightcolor, 1.0f / 200.0f, lightcolor); // locate the proper data glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); if (gl_n_patches && gl_npatches.getBool()) { glEnable(GL_PN_TRIANGLES_ATI); glPNTrianglesiATI(GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI, gl_npatches.getInt()); if (true) glPNTrianglesiATI(GL_PN_TRIANGLES_POINT_MODE_ATI, GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI); else glPNTrianglesiATI(GL_PN_TRIANGLES_POINT_MODE_ATI, GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI); if (true) glPNTrianglesiATI(GL_PN_TRIANGLES_NORMAL_MODE_ATI, GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI); else glPNTrianglesiATI(GL_PN_TRIANGLES_NORMAL_MODE_ATI, GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI); } if (clmodel->aliastype == MD3IDHEADER) { //do nothing for testing if (!r_modeltexture.getBool()) { GL_DisableTMU(GL_TEXTURE0_ARB); }//disable texture if needed R_DrawQ3Model(e, false, false); if (!r_modeltexture.getBool()) { GL_EnableTMU(GL_TEXTURE0_ARB); }//enable texture if needed if (r_celshading.getBool() || r_outline.getBool()) { glCullFace(GL_BACK); glEnable(GL_BLEND); glPolygonMode(GL_FRONT, GL_LINE); if (e == &cl.viewent) { glLineWidth(1.0f); } else { glLineWidth(5.0f); } glEnable(GL_LINE_SMOOTH); GL_DisableTMU(GL_TEXTURE0_ARB); glColor3f(0.0, 0.0, 0.0); R_DrawQ3Model(e, false, true); glColor3f(1.0, 1.0, 1.0); GL_EnableTMU(GL_TEXTURE0_ARB); glPolygonMode(GL_FRONT, GL_FILL); glDisable(GL_BLEND); glCullFace(GL_FRONT); } if (shell) { glBindTexture(GL_TEXTURE_2D, quadtexture); glColor4f(1.0, 1.0, 1.0, 0.5); glEnable(GL_BLEND); R_DrawQ3Model(e, true, false); glDisable(GL_BLEND); glColor3f(1.0, 1.0, 1.0); } } else if (clmodel->aliastype != ALIASTYPE_MD2) { paliashdr = (aliashdr_t *) Mod_Extradata(e->model); c_alias_polys += paliashdr->numtris; glPushMatrix(); //interpolate unless its the viewmodel if (e != &cl.viewent) R_BlendedRotateForEntity(e); else R_RotateForEntity(e); glTranslatef(paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]); glScalef(paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]); anim = (int) (cl.time * 10) & 3; glBindTexture(GL_TEXTURE_2D, paliashdr->gl_texturenum[e->skinnum][anim]); // draw all the triangles if (!r_modeltexture.getBool()) { GL_DisableTMU(GL_TEXTURE0_ARB); } else { //highlighting test code if (0 && gl_textureunits > 2) { GL_EnableTMU(GL_TEXTURE1_ARB); glBindTexture(GL_TEXTURE_2D, TextureManager::highlighttexture); glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); //need correct mode glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD); glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.0); //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD); } } glColor3fv(lightcolor); R_SetupAliasBlendedFrame(e->frame, paliashdr, e, false, false); glDisable(GL_TEXTURE_1D); if (r_celshading.getBool() || r_outline.getBool()) { glColor3f(0.0, 0.0, 0.0); R_SetupAliasBlendedFrame(e->frame, paliashdr, e, false, true); glColor3f(1.0, 1.0, 1.0); } if (!r_modeltexture.getBool()) { GL_EnableTMU(GL_TEXTURE0_ARB); } else { if (0 && gl_textureunits > 2) { //highlighting test code glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); GL_DisableTMU(GL_TEXTURE1_ARB); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } } glActiveTexture(GL_TEXTURE0_ARB); //colour map code... not working yet... /* if (e->colormap != vid.colormap && !gl_nocolors.value) { if (paliashdr->gl_texturenumColorMap&&paliashdr->gl_texturenumColorMap){ glBindTexture(GL_TEXTURE_2D,paliashdr->gl_texturenumColorMap); c = (byte)e->colormap & 0xF0; c += (c >= 128 && c < 224) ? 4 : 12; // 128-224 are backwards ranges color = (byte *) (&d_8to24table[c]); //glColor3fv(color); glColor3f(1.0,1.0,1.0); } }*/ if (shell) { glBindTexture(GL_TEXTURE_2D, quadtexture); glColor4f(1.0, 1.0, 1.0, 0.5); glEnable(GL_BLEND); R_SetupAliasBlendedFrame(e->frame, paliashdr, e, true, false); glDisable(GL_BLEND); glColor3f(1.0, 1.0, 1.0); } glPopMatrix(); } else { pheader = (md2_t *) Mod_Extradata(e->model); c_alias_polys += pheader->num_tris; glBindTexture(GL_TEXTURE_2D, pheader->gl_texturenum[e->skinnum]); R_SetupQ2AliasFrame(e, pheader); } if (gl_n_patches && gl_npatches.getBool()) { glDisable(GL_PN_TRIANGLES_ATI); } glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); }
/* * R_DrawWorld */ void R_DrawWorld( void ) { unsigned int i; int clipFlags, msec = 0; unsigned int dlightBits; unsigned int shadowBits; bool worldOutlines; if( !r_drawworld->integer ) return; if( !rsh.worldModel ) return; if( rn.renderFlags & RF_SHADOWMAPVIEW ) return; VectorCopy( rn.refdef.vieworg, modelOrg ); worldOutlines = mapConfig.forceWorldOutlines || ( rn.refdef.rdflags & RDF_WORLDOUTLINES ); if( worldOutlines && (rf.viewcluster != -1) && r_outlines_scale->value > 0 ) rsc.worldent->outlineHeight = max( 0.0f, r_outlines_world->value ); else rsc.worldent->outlineHeight = 0; Vector4Copy( mapConfig.outlineColor, rsc.worldent->outlineColor ); clipFlags = rn.clipFlags; dlightBits = 0; shadowBits = 0; if( r_nocull->integer ) clipFlags = 0; // cull dynamic lights if( !( rn.renderFlags & RF_ENVVIEW ) ) { if( r_dynamiclight->integer == 1 && !r_fullbright->integer ) { for( i = 0; i < rsc.numDlights; i++ ) { if( R_CullSphere( rsc.dlights[i].origin, rsc.dlights[i].intensity, clipFlags ) ) { continue; } dlightBits |= 1<<i; } } } // cull shadowmaps if( !( rn.renderFlags & RF_ENVVIEW ) ) { for( i = 0; i < rsc.numShadowGroups; i++ ) { shadowGroup_t *grp = rsc.shadowGroups + i; if( R_CullBox( grp->visMins, grp->visMaxs, clipFlags ) ) { continue; } shadowBits |= grp->bit; } } rn.dlightBits = dlightBits; rn.shadowBits = shadowBits; if( r_speeds->integer ) msec = ri.Sys_Milliseconds(); R_RecursiveWorldNode( rsh.worldBrushModel->nodes, clipFlags, dlightBits, shadowBits ); if( r_speeds->integer ) rf.stats.t_world_node += ri.Sys_Milliseconds() - msec; }