/* ============= 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; } }
/* ============== R_AddMD5Surfaces ============== */ void R_AddMD5Surfaces(trRefEntity_t * ent) { md5Model_t *model; md5Surface_t *surface; shader_t *shader; int i; qboolean personalModel; int fogNum; model = tr.currentModel->md5; // don't add third_person objects if not in a portal personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal; // cull the entire model if merged bounding box of both frames // is outside the view frustum R_CullMD5(ent); if(ent->cull == CULL_OUT) { return; } // set up world bounds for light intersection tests R_SetupEntityWorldBounds(ent); // set up lighting now that we know we aren't culled if(!personalModel || r_shadows->integer > SHADOWING_BLOB) { R_SetupEntityLighting(&tr.refdef, ent, NULL); } // see if we are in a fog volume fogNum = R_FogWorldBox(ent->worldBounds); if(!r_vboModels->integer || !model->numVBOSurfaces || (!glConfig2.vboVertexSkinningAvailable && ent->e.skeleton.type == SK_ABSOLUTE)) { // finally add surfaces for(i = 0, surface = model->surfaces; i < model->numSurfaces; i++, surface++) { if(ent->e.customShader) { shader = R_GetShaderByHandle(ent->e.customShader); } else if(ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins) { skin_t *skin; skin = R_GetSkinByHandle(ent->e.customSkin); // match the surface name to something in the skin file shader = tr.defaultShader; // FIXME: replace MD3_MAX_SURFACES for skin_t::surfaces if(i >= 0 && i < skin->numSurfaces && skin->surfaces[i]) { shader = skin->surfaces[i]->shader; } if(shader == tr.defaultShader) { ri.Printf(PRINT_DEVELOPER, "WARNING: no shader for surface %i in skin %s\n", i, skin->name); } else if(shader->defaultShader) { ri.Printf(PRINT_DEVELOPER, "WARNING: shader %s in skin %s not found\n", shader->name, skin->name); } } else { shader = R_GetShaderByHandle(surface->shaderIndex); } // we will add shadows even if the main object isn't visible in the view // don't add third_person objects if not viewing through a portal if(!personalModel) { R_AddDrawSurf((void *)surface, shader, -1, fogNum); } } } else { int i; srfVBOMD5Mesh_t *vboSurface; shader_t *shader; for(i = 0; i < model->numVBOSurfaces; i++) { vboSurface = model->vboSurfaces[i]; if(ent->e.customShader) { shader = R_GetShaderByHandle(ent->e.customShader); } else if(ent->e.customSkin > 0 && ent->e.customSkin < tr.numSkins) { skin_t *skin; skin = R_GetSkinByHandle(ent->e.customSkin); // match the surface name to something in the skin file shader = tr.defaultShader; // FIXME: replace MD3_MAX_SURFACES for skin_t::surfaces //if(i >= 0 && i < skin->numSurfaces && skin->surfaces[i]) if(vboSurface->skinIndex >= 0 && vboSurface->skinIndex < skin->numSurfaces && skin->surfaces[vboSurface->skinIndex]) { shader = skin->surfaces[vboSurface->skinIndex]->shader; } if(shader == tr.defaultShader) { ri.Printf(PRINT_DEVELOPER, "WARNING: no shader for surface %i in skin %s\n", i, skin->name); } else if(shader->defaultShader) { ri.Printf(PRINT_DEVELOPER, "WARNING: shader %s in skin %s not found\n", shader->name, skin->name); } } else { shader = vboSurface->shader; } // don't add third_person objects if not viewing through a portal if(!personalModel) { R_AddDrawSurf((void *)vboSurface, shader, -1, fogNum); } } } }
/** * @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; } }