/* =================== R_EntityDefDynamicModel Issues a deferred entity callback if necessary. If the model isn't dynamic, it returns the original. Returns the cached dynamic model if present, otherwise creates it and any necessary overlays =================== */ idRenderModel *R_EntityDefDynamicModel( idRenderEntityLocal *def ) { bool callbackUpdate; // allow deferred entities to construct themselves if( def->parms.callback ) { callbackUpdate = R_IssueEntityDefCallback( def ); } else { callbackUpdate = false; } idRenderModel *model = def->parms.hModel; if( !model ) { common->Error( "R_EntityDefDynamicModel: NULL model" ); } if( model->IsDynamicModel() == DM_STATIC ) { def->dynamicModel = NULL; def->dynamicModelFrameCount = 0; return model; } // continously animating models (particle systems, etc) will have their snapshot updated every single view if( callbackUpdate || ( model->IsDynamicModel() == DM_CONTINUOUS && def->dynamicModelFrameCount != tr.frameCount ) ) { R_ClearEntityDefDynamicModel( def ); } // if we don't have a snapshot of the dynamic model, generate it now if( !def->dynamicModel ) { // instantiate the snapshot of the dynamic model, possibly reusing memory from the cached snapshot def->cachedDynamicModel = model->InstantiateDynamicModel( &def->parms, tr.viewDef, def->cachedDynamicModel ); if( def->cachedDynamicModel ) { // add any overlays to the snapshot of the dynamic model if( def->overlay && !r_skipOverlays.GetBool() ) { def->overlay->AddOverlaySurfacesToModel( def->cachedDynamicModel ); } else { idRenderModelOverlay::RemoveOverlaySurfacesFromModel( def->cachedDynamicModel ); } if( r_checkBounds.GetBool() ) { idBounds b = def->cachedDynamicModel->Bounds(); if( b[0][0] < def->referenceBounds[0][0] - CHECK_BOUNDS_EPSILON || b[0][1] < def->referenceBounds[0][1] - CHECK_BOUNDS_EPSILON || b[0][2] < def->referenceBounds[0][2] - CHECK_BOUNDS_EPSILON || b[1][0] > def->referenceBounds[1][0] + CHECK_BOUNDS_EPSILON || b[1][1] > def->referenceBounds[1][1] + CHECK_BOUNDS_EPSILON || b[1][2] > def->referenceBounds[1][2] + CHECK_BOUNDS_EPSILON ) { common->Printf( "entity %i dynamic model exceeded reference bounds\n", def->index ); } } } def->dynamicModel = def->cachedDynamicModel; def->dynamicModelFrameCount = tr.frameCount; } // set model depth hack value if( def->dynamicModel && model->DepthHack() != 0.0f && tr.viewDef ) { idPlane eye, clip; idVec3 ndc; R_TransformModelToClip( def->parms.origin, tr.viewDef->worldSpace.modelViewMatrix, tr.viewDef->projectionMatrix, eye, clip ); R_TransformClipToDevice( clip, ndc ); def->parms.modelDepthHack = model->DepthHack() * ( 1.0f - ndc.z ); } // FIXME: if any of the surfaces have deforms, create a frame-temporary model with references to the // undeformed surfaces. This would allow deforms to be light interacting. return def->dynamicModel; }
/* =================== R_EntityDefDynamicModel This is also called by the game code for idRenderWorldLocal::ModelTrace(), and idRenderWorldLocal::Trace() which is bad for performance... Issues a deferred entity callback if necessary. If the model isn't dynamic, it returns the original. Returns the cached dynamic model if present, otherwise creates it. =================== */ idRenderModel* R_EntityDefDynamicModel( idRenderEntityLocal* def ) { if( def->dynamicModelFrameCount == tr.frameCount ) { return def->dynamicModel; } // allow deferred entities to construct themselves bool callbackUpdate; if( def->parms.callback != NULL ) { SCOPED_PROFILE_EVENT( "R_IssueEntityDefCallback" ); callbackUpdate = R_IssueEntityDefCallback( def ); } else { callbackUpdate = false; } idRenderModel* model = def->parms.hModel; if( model == NULL ) { common->Error( "R_EntityDefDynamicModel: NULL model" ); return NULL; } if( model->IsDynamicModel() == DM_STATIC ) { def->dynamicModel = NULL; def->dynamicModelFrameCount = 0; return model; } // continously animating models (particle systems, etc) will have their snapshot updated every single view if( callbackUpdate || ( model->IsDynamicModel() == DM_CONTINUOUS && def->dynamicModelFrameCount != tr.frameCount ) ) { R_ClearEntityDefDynamicModel( def ); } // if we don't have a snapshot of the dynamic model, generate it now if( def->dynamicModel == NULL ) { SCOPED_PROFILE_EVENT( "InstantiateDynamicModel" ); // instantiate the snapshot of the dynamic model, possibly reusing memory from the cached snapshot def->cachedDynamicModel = model->InstantiateDynamicModel( &def->parms, tr.viewDef, def->cachedDynamicModel ); if( def->cachedDynamicModel != NULL && r_checkBounds.GetBool() ) { idBounds b = def->cachedDynamicModel->Bounds(); if( b[0][0] < def->localReferenceBounds[0][0] - CHECK_BOUNDS_EPSILON || b[0][1] < def->localReferenceBounds[0][1] - CHECK_BOUNDS_EPSILON || b[0][2] < def->localReferenceBounds[0][2] - CHECK_BOUNDS_EPSILON || b[1][0] > def->localReferenceBounds[1][0] + CHECK_BOUNDS_EPSILON || b[1][1] > def->localReferenceBounds[1][1] + CHECK_BOUNDS_EPSILON || b[1][2] > def->localReferenceBounds[1][2] + CHECK_BOUNDS_EPSILON ) { common->Printf( "entity %i dynamic model exceeded reference bounds\n", def->index ); } } def->dynamicModel = def->cachedDynamicModel; def->dynamicModelFrameCount = tr.frameCount; } // set model depth hack value if( def->dynamicModel != NULL && model->DepthHack() != 0.0f && tr.viewDef != NULL ) { idPlane eye, clip; idVec3 ndc; R_TransformModelToClip( def->parms.origin, tr.viewDef->worldSpace.modelViewMatrix, tr.viewDef->projectionMatrix, eye, clip ); R_TransformClipToDevice( clip, ndc ); def->parms.modelDepthHack = model->DepthHack() * ( 1.0f - ndc.z ); } else { def->parms.modelDepthHack = 0.0f; } return def->dynamicModel; }