public override idRenderModel InstantiateDynamicModel(idRenderEntity renderEntity, View view, idRenderModel cachedModel)
        {
            if (this.Disposed == true)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }

            idConsole.Warning("TODO: idRenderModel_MD5.InstantiateDynamicModel");
            return(null);
        }
        public override idRenderModel InstantiateDynamicModel(idRenderEntity renderEntity, View view, idRenderModel cachedModel)
        {
            if (cachedModel != null)
            {
                cachedModel.Dispose();
            }

            idConsole.Error("InstantiateDynamicModel called on static model '{0}'", this.Name);

            return(null);
        }
Beispiel #3
0
		/// <summary>
		/// Creates a static model based on the definition and view currently.
		/// </summary>
		/// <remarks>
		/// This will be regenerated for every view, even though
		/// some models, like character meshes, could be used for multiple (mirror)
		/// views in a frame, or may stay static for multiple frames (corpses)
		/// The renderer will delete the returned dynamic model the next view.
		/// </remarks>
		/// <param name="renderEntity"></param>
		/// <param name="view"></param>
		/// <param name="cachedModel"></param>
		/// <returns></returns>
		public abstract idRenderModel InstantiateDynamicModel(idRenderEntity renderEntity, View view, idRenderModel cachedModel);
		public override idRenderModel InstantiateDynamicModel(idRenderEntity renderEntity, View view, idRenderModel cachedModel)
		{
			if(cachedModel != null)
			{
				cachedModel.Dispose();
			}

			idConsole.Error("InstantiateDynamicModel called on static model '{0}'", this.Name);

			return null;
		}
		public override idRenderModel InstantiateDynamicModel(idRenderEntity renderEntity, View view, idRenderModel cachedModel)
		{
			if(this.Disposed == true)
			{
				throw new ObjectDisposedException(this.GetType().Name);
			}

			idConsole.Warning("TODO: idRenderModel_MD5.InstantiateDynamicModel");
			return null;
		}
Beispiel #6
0
		private void AddWorldModelEntities()
		{
			// add the world model for each portal area
			// we can't just call AddEntityDef, because that would place the references
			// based on the bounding box, rather than explicitly into the correct area
			for(int i = 0; i < _portalAreaCount; i++)
			{
				idRenderEntity def = new idRenderEntity();
				int index = _entityDefinitions.FindIndex(x => x == null);

				if(index == -1)
				{
					index = _entityDefinitions.Count;
					_entityDefinitions.Add(def);
				}
				else
				{
					_entityDefinitions[index] = def;
				}

				def.EntityIndex = index;
				def.World = this;
				def.Parameters.Model = idE.RenderModelManager.FindModel(string.Format("_area{0}", i));

				if((def.Parameters.Model.IsDefault == true) || (def.Parameters.Model.IsStaticWorld == false))
				{
					idConsole.Error("idRenderWorld::InitFromMap: bad area model lookup");
				}

				idRenderModel model = def.Parameters.Model;

				for(int j = 0; j < model.SurfaceCount; j++)
				{
					RenderModelSurface surf = model.GetSurface(j);

					if(surf.Material.Name == "textures/smf/portal_sky")
					{
						def.NeedsPortalSky = true;
					}
				}

				def.ReferenceBounds = def.Parameters.Model.GetBounds();
				def.Parameters.Axis = new Matrix(
					1, 0, 0, 0, 
					0, 1, 0, 0, 
					0, 0, 1, 0, 
					0, 0, 0, 0);

				def.ModelMatrix = idHelper.AxisToModelMatrix(def.Parameters.Axis, def.Parameters.Origin);

				// in case an explicit shader is used on the world, we don't
				// want it to have a 0 alpha or color
				def.Parameters.MaterialParameters[0] =
					def.Parameters.MaterialParameters[1] =
					def.Parameters.MaterialParameters[2] =
					def.Parameters.MaterialParameters[3] = 1;

				AddEntityRefToArea(def, _portalAreas[i]);
			}
		}
		private void PreRender()
		{
			if(_needsRender == true)
			{
				_world.InitFromMap(null);

				idDict spawnArgs = new idDict();
				spawnArgs.Set("classname", "light");
				spawnArgs.Set("name", "light_1");
				spawnArgs.Set("origin", _lightOrigin);
				spawnArgs.Set("_color", _lightColor);

				idConsole.Warning("TODO: lighting");
			
				/*gameEdit->ParseSpawnArgsToRenderLight(&spawnArgs, &rLight);
				lightDef = world->AddLightDef(&rLight);
				if(!modelName[0])
				{
					common->Warning("Window '%s' in gui '%s': no model set", GetName(), GetGui()->GetSourceFile());
				}*/

				spawnArgs.Clear();
				spawnArgs.Set("classname", "func_static");
				spawnArgs.Set("model", _modelName);
				spawnArgs.Set("origin", _modelOrigin);

				_worldEntity = idE.GameEdit.ParseSpawnArgsToRenderEntity(spawnArgs);

				if(_worldEntity.Model != null)
				{
					Vector3 v = _modelRotate.ToVector3();

					_worldEntity.Axis = v.ToMatrix();
					_worldEntity.MaterialParameters[0] = 1;
					_worldEntity.MaterialParameters[0] = 1;
					_worldEntity.MaterialParameters[0] = 1;
					_worldEntity.MaterialParameters[0] = 1;

					_renderEntity = _world.AddEntityDefinition(_worldEntity);
				}

				_needsRender.Set(false);
			}
		}
Beispiel #8
0
		protected bool UpdateRenderEntity(idRenderEntity renderEntity, idRenderView renderView)
		{
			// TODO: cinematic
			/*if ( gameLocal.inCinematic && gameLocal.skipCinematic ) {
				return false;
			}*/

			idAnimator animator = this.Animator;

			if(animator != null)
			{
				return animator.CreateFrame(idR.Game.Time, false);
			}

			return false;
		}
Beispiel #9
0
		/// <summary>
		/// If the entityDef isn't already on the viewEntity list, create
		/// a viewEntity and add it to the list with an empty scissor rect.
		/// </summary>
		/// <remarks>
		/// This does not instantiate dynamic models for the entity yet.
		/// </remarks>
		/// <param name="def"></param>
		/// <returns></returns>
		private ViewEntity SetEntityDefViewEntity(idRenderEntity def)
		{
			if(def.ViewCount == idE.RenderSystem.ViewCount)
			{
				return def.ViewEntity;
			}

			def.ViewCount = idE.RenderSystem.ViewCount;

			// set the model and modelview matricies
			ViewEntity viewModel = new ViewEntity();
			viewModel.EntityDef = def;

			// the scissorRect will be expanded as the model bounds is accepted into visible portal chains
			viewModel.ScissorRectangle.Clear();

			// copy the model and weapon depth hack for back-end use
			viewModel.ModelDepthHack = def.Parameters.ModelDepthHack;
			viewModel.WeaponDepthHack = def.Parameters.WeaponDepthHack;

			viewModel.ModelMatrix = idHelper.AxisToModelMatrix(def.Parameters.Axis, def.Parameters.Origin);

			// we may not have a viewDef if we are just creating shadows at entity creation time
			if(idE.RenderSystem.ViewDefinition != null)
			{
				idHelper.ConvertMatrix(viewModel.ModelMatrix, idE.RenderSystem.ViewDefinition.WorldSpace.ModelViewMatrix, out viewModel.ModelViewMatrix);

				idE.RenderSystem.ViewDefinition.ViewEntities = new List<ViewEntity>();
				idE.RenderSystem.ViewDefinition.ViewEntities.Add(viewModel);
			}

			def.ViewEntity = viewModel;

			return viewModel;
		}
Beispiel #10
0
		/// <remarks>
		/// Used for both light volumes and model volumes.
		/// <para/>
		/// This does not clip the points by the planes, so some slop occurs.
		/// <para/>
		/// tr.viewCount should be bumped before calling, allowing it
		/// to prevent double checking areas.
		/// <para/>
		/// We might alternatively choose to do this with an area flow.
		/// </remarks>
		/// <param name="def"></param>
		/// <param name="?"></param>
		/// <param name="sphere"></param>
		/// <param name="pointCount"></param>
		/// <param name="points"></param>
		private void PushVolumeIntoTree_r(idRenderEntity def, /* idRenderLight */ object light, idSphere sphere, int pointCount, Vector3[] points, int nodeNumber)
		{
			if(nodeNumber < 0)
			{
				int areaNumber = -1 - nodeNumber;
				PortalArea area = _portalAreas[areaNumber];

				if(area.ViewCount == idE.RenderSystem.ViewCount)
				{
					return;	// already added a reference here
				}

				area.ViewCount = idE.RenderSystem.ViewCount;

				if(def != null)
				{
					AddEntityRefToArea(def, area);
				}

				if(light != null)
				{
					idConsole.Warning("TODO: AddLightRefToArea( light, area );");
				}

				return;
			}

			AreaNode node = _areaNodes[nodeNumber];

			// if we know that all possible children nodes only touch an area
			// we have already marked, we can early out
			if((idE.CvarSystem.GetBool("r_useNodeCommonChildren") == true) && (node.CommonChildrenArea != idRenderWorld.ChildrenHaveMultipleAreas))
			{
				// note that we do NOT try to set a reference in this area
				// yet, because the test volume may yet wind up being in the
				// solid part, which would cause bounds slightly poked into
				// a wall to show up in the next room
				if(_portalAreas[node.CommonChildrenArea].ViewCount == idE.RenderSystem.ViewCount)
				{
					return;
				}
			}

			// if the bounding sphere is completely on one side, don't
			// bother checking the individual points
			float distance = node.Plane.Distance(sphere.Origin);

			if(distance >= sphere.Radius)
			{
				nodeNumber = node.Children[0];

				if(nodeNumber != 0) // 0 = solid
				{
					PushVolumeIntoTree_r(def, light, sphere, pointCount, points, nodeNumber);
				}

				return;
			}

			if(distance <= -sphere.Radius)
			{
				nodeNumber = node.Children[1];

				if(nodeNumber != 0) // 0 = solid
				{
					PushVolumeIntoTree_r(def, light, sphere, pointCount, points, nodeNumber);
				}

				return;
			}

			// exact check all the points against the node plane
			bool front = false;
			bool back = false;

			for(int i = 0; i < pointCount; i++)
			{
				float d = ((points[i] * node.Plane.Normal) + new Vector3(node.Plane.Normal.Z, node.Plane.Normal.Z, node.Plane.Normal.Z)).Length();

				if(d >= 0.0f)
				{
					front = true;
				}
				else if(d <= 0.0f)
				{
					back = true;
				}

				if((back == true) && (front == true))
				{
					break;
				}
			}

			if(front == true)
			{
				nodeNumber = node.Children[0];

				if(nodeNumber != 0) // 0 = solid
				{
					PushVolumeIntoTree_r(def, light, sphere, pointCount, points, nodeNumber);
				}
			}

			if(back == true)
			{
				nodeNumber = node.Children[1];

				if(nodeNumber != 0) // 0 = solid
				{
					PushVolumeIntoTree_r(def, light, sphere, pointCount, points, nodeNumber);
				}
			}
		}
Beispiel #11
0
		private void PushVolumeIntoTree(idRenderEntity def, /* idRenderLight */ object light, int pointCount, Vector3[] points)
		{
			if(_areaNodes == null)
			{
				return;
			}

			// calculate a bounding sphere for the points
			Vector3 mid = Vector3.Zero;
			Vector3 dir;
			float radSquared = 0;
			float lr = 0;

			for(int i = 0; i < pointCount; i++)
			{
				mid += points[i];
			}

			mid *= (1.0f / pointCount);

			for(int i = 0; i < pointCount; i++)
			{
				dir = points[i] - mid;
				lr = (dir * dir).Length();

				if(lr > radSquared)
				{
					radSquared = lr;
				}
			}

			idSphere sphere = new idSphere(mid, idMath.Sqrt(radSquared));

			PushVolumeIntoTree_r(def, light, sphere, pointCount, points, 0);
		}
Beispiel #12
0
		private void FreeEntityDefDerivedData(idRenderEntity def, bool keepDecals, bool keepCachedDynamicModel) 
		{
			// TODO: demo

			// demo playback needs to free the joints, while normal play
			// leaves them in the control of the game			
			/*if ( session->readDemo ) {
				if ( def->parms.joints ) {
					Mem_Free16( def->parms.joints );
					def->parms.joints = NULL;
				}
				if ( def->parms.callbackData ) {
					Mem_Free( def->parms.callbackData );
					def->parms.callbackData = NULL;
				}
				for ( i = 0; i < MAX_RENDERENTITY_GUI; i++ ) {
					if ( def->parms.gui[ i ] ) {
						delete def->parms.gui[ i ];
						def->parms.gui[ i ] = NULL;
					}
				}
			}*/

			// TODO: interactions
			// free all the interactions
			/*while ( def->firstInteraction != NULL ) {
				def->firstInteraction->UnlinkAndFree();
			}*/

			// clear the dynamic model if present
			if(def.DynamicModel != null)
			{
				def.DynamicModel = null;
			}

			if(keepDecals == false)
			{
				idConsole.Warning("TODO: free decals");

				/*R_FreeEntityDefDecals( def );
				R_FreeEntityDefOverlay( def );*/
			}

			if(keepCachedDynamicModel == false)
			{
				if(def.CachedDynamicModel != null)
				{
					def.CachedDynamicModel.Dispose();
					def.CachedDynamicModel = null;
				}
			}

			// free the entityRefs from the areas
			AreaReference areaRef, next;

			for(areaRef = def.EntityReference; areaRef != null;  areaRef = next)
			{
				next = areaRef.NextOwner;

				// unlink from the area
				areaRef.NextArea.PreviousArea = areaRef.PreviousArea;
				areaRef.PreviousArea.NextArea = areaRef.NextArea;
			}	

			def.EntityReference = null;
		}
Beispiel #13
0
		/// <summary>
		/// Creates all needed model references in portal areas, chaining them to both the area and the entityDef.		
		/// </summary>
		/// <remarks>
		/// Bumps tr.viewCount..
		/// </remarks>
		private void CreateEntityReferences(idRenderEntity def)
		{
			if(def.Parameters.Model == null)
			{
				def.Parameters.Model = idE.RenderModelManager.DefaultModel;
			}
			
			// if the entity hasn't been fully specified due to expensive animation calcs
			// for md5 and particles, use the provided conservative bounds.
			if(def.Parameters.Callback != null)
			{
				def.ReferenceBounds = def.Parameters.Bounds;
			}
			else
			{
				def.ReferenceBounds = def.Parameters.Model.GetBounds(def.Parameters);
			}

			// some models, like empty particles, may not need to be added at all
			if(def.ReferenceBounds.IsCleared == true)
			{
				return;
			}

			if((idE.CvarSystem.GetBool("r_showUpdates") == true)
				&& (((def.ReferenceBounds.Max.X - def.ReferenceBounds.Min.X) > 1024)
						|| ((def.ReferenceBounds.Max.Y - def.ReferenceBounds.Min.Y) > 1024)))
			{
				idConsole.WriteLine("big entityRef: {0}, {1}", def.ReferenceBounds.Max.X - def.ReferenceBounds.Min.X, def.ReferenceBounds.Max.Y - def.ReferenceBounds.Min.Y);
			}

			Vector3[] transformed = new Vector3[8];
			Vector3 v;

			for(int i = 0; i < 8; i++)
			{
				v.X = ((i & 1) == 0) ? def.ReferenceBounds.Min.X : def.ReferenceBounds.Max.X;
				v.Y = (((i >> 1) & 1) == 0) ? def.ReferenceBounds.Min.Y : def.ReferenceBounds.Max.Y;
				v.Z = (((i >> 2) & 1) == 0) ? def.ReferenceBounds.Min.Z : def.ReferenceBounds.Max.Z;

				idHelper.LocalPointToGlobal(def.ModelMatrix, v, out transformed[i]);
			}

			// bump the view count so we can tell if an
			// area already has a reference
			idE.RenderSystem.ViewCount++;

			// push these points down the BSP tree into areas
			def.World.PushVolumeIntoTree(def, null, 8, transformed);
		}
Beispiel #14
0
		/// <summary>
		/// Return true if the entity reference bounds do not intersect the current portal chain.
		/// </summary>
		/// <param name="entity"></param>
		/// <param name="portalStack"></param>
		/// <returns></returns>
		private bool CullEntityByPortals(idRenderEntity entity, PortalStack portalStack)
		{
			if(idE.CvarSystem.GetBool("r_useEntityCulling") == false)
			{
				return false;
			}

			// try to cull the entire thing using the reference bounds.
			// we do not yet do callbacks or dynamic model creation,
			// because we want to do all touching of the model after
			// we have determined all the lights that may effect it,
			// which optimizes cache usage
			return idHelper.CullLocalBox(entity.ReferenceBounds, entity.ModelMatrix, portalStack.PortalPlaneCount, portalStack.PortalPlanes);
		}
Beispiel #15
0
		/// <summary>
		/// Present is called to allow entities to generate refEntities, lights, etc for the renderer.
		/// </summary>
		public virtual void Present()
		{
			if(this.Disposed == true)
			{
				throw new ObjectDisposedException(this.GetType().Name);
			}

			// TODO:
			/*if ( !gameLocal.isNewFrame ) {
				return;
			}*/

			// don't present to the renderer if the entity hasn't changed
			/*if ( !( thinkFlags & TH_UPDATEVISUALS ) ) {
				return;
			}
			BecomeInactive( TH_UPDATEVISUALS );*/

			// camera target for remote render views
			/*if ( cameraTarget && gameLocal.InPlayerPVS( this ) ) {
				renderEntity.remoteRenderView = cameraTarget->GetRenderView();
			}*/

			// if set to invisible, skip
			if((_renderEntity.Model == null) || (this.IsHidden == true))
			{
				return;
			}

			// add to refresh list
			if(_renderModel == null)
			{
				_renderModel = idR.Game.CurrentRenderWorld.AddEntityDefinition(_renderEntity);
			}
			else
			{
				idR.Game.CurrentRenderWorld.UpdateEntityDefinition(_renderModel, _renderEntity);
			}
		}
Beispiel #16
0
		/// <summary>
		/// 
		/// </summary>
		/// <remarks>
		/// May not change the game state whatsoever!
		/// </remarks>
		/// <param name="renderEntity"></param>
		/// <param name="renderView"></param>
		/// <returns></returns>
		protected bool ModelCallback(idRenderEntity renderEntity, idRenderView renderView)
		{
			idEntity ent = idR.Game.Entities[renderEntity.EntityIndex];

			if(ent == null)
			{
				idConsole.Error("idEntity::ModelCallback: callback with null game entity");
			}

			return ent.UpdateRenderEntity(renderEntity, renderView);
		}
Beispiel #17
0
		/// <summary>
		/// Does not write to the demo file, which will only be updated for visible entities.
		/// </summary>
		/// <param name="index"></param>
		/// <param name="renderComponent"></param>
		public void UpdateEntityDefinition(idRenderEntity renderEntity, RenderEntityComponent renderComponent)
		{
			UpdateEntityDefinition(_entityDefinitions[_entityDefinitions.IndexOf(renderEntity)], renderComponent);
		}
Beispiel #18
0
		/// <summary>
		/// Does not write to the demo file, which will only be updated for visible entities.
		/// </summary>
		/// <param name="index"></param>
		/// <param name="renderComponent"></param>
		public void UpdateEntityDefinition(int index, RenderEntityComponent renderComponent)
		{
			if(idE.CvarSystem.GetBool("r_skipUpdates") == true)
			{
				return;
			}

			// TODO: tr.pc.c_entityUpdates++;

			if((renderComponent.Model == null) && (renderComponent.Callback == null))
			{
				idConsole.Error("idRenderWorld::UpdateEntityDefinition: NULL model");
			}

			// create new slots if needed
			if((index < 0) || (index > idE.LudicrousEntityIndex))
			{
				idConsole.Error("idRenderWorld::UpdateEntityDefinitionL index = {0}", index);
			}

			while(index >= _entityDefinitions.Count)
			{
				_entityDefinitions.Add(null);
			}

			idRenderEntity def = _entityDefinitions[index];

			if(def != null)
			{
				if(renderComponent.ForceUpdate == false)
				{
					idConsole.Warning("TODO: force update - quite important!");

					/*// check for exact match (OPTIMIZE: check through pointers more)
					if ( !re->joints && !re->callbackData && !def->dynamicModel && !memcmp( re, &def->parms, sizeof( *re ) ) ) {
						return;
					}

					// if the only thing that changed was shaderparms, we can just leave things as they are
					// after updating parms

					// if we have a callback function and the bounds, origin, axis and model match,
					// then we can leave the references as they are
					if ( re->callback ) {

						bool axisMatch = ( re->axis == def->parms.axis );
						bool originMatch = ( re->origin == def->parms.origin );
						bool boundsMatch = ( re->bounds == def->referenceBounds );
						bool modelMatch = ( re->hModel == def->parms.hModel );

						if ( boundsMatch && originMatch && axisMatch && modelMatch ) {
							// only clear the dynamic model and interaction surfaces if they exist
							c_callbackUpdate++;
							R_ClearEntityDefDynamicModel( def );
							def->parms = *re;
							return;
						}
					}*/
				}

				// save any decals if the model is the same, allowing marks to move with entities
				if(def.Parameters.Model == renderComponent.Model)
				{
					FreeEntityDefDerivedData(def, true, true);
				}
				else
				{
					FreeEntityDefDerivedData(def, false, false);
				}
			}
			else
			{
				// creating a new one
				def = new idRenderEntity();
				_entityDefinitions[index] = def;

				def.World = this;
				def.EntityIndex = index;
			}

			def.Parameters = renderComponent;
			def.ModelMatrix = idHelper.AxisToModelMatrix(def.Parameters.Axis, def.Parameters.Origin);
			def.LastModifiedFrameNumber = idE.RenderSystem.FrameCount;

			// TODO: demo
			/*if ( session->writeDemo && def->archived ) {
				WriteFreeEntity( entityHandle );
				def->archived = false;
			}*/

			// optionally immediately issue any callbacks
			if((idE.CvarSystem.GetBool("r_useEntityCallbacks") == false) && (def.Parameters.Callback != null))
			{
				idConsole.Warning("TODO: R_IssueEntityDefCallback( def );");
			}

			// based on the model bounds, add references in each area
			// that may contain the updated surface
			CreateEntityReferences(def);
		}
Beispiel #19
0
		/// <summary>
		/// This is called by R_PushVolumeIntoTree and also directly
		/// for the world model references that are precalculated.
		/// </summary>
		/// <param name="def"></param>
		/// <param name="area"></param>
		private void AddEntityRefToArea(idRenderEntity def, PortalArea area)
		{
			if(def == null)
			{
				idConsole.Error("idRenderWorld::AddEntityRefToArea: null def");
			}

			AreaReference areaRef = new AreaReference();

			// TODO: counters tr.pc.c_entityReferences++;

			areaRef.Entity = def;

			// link to entityDef
			areaRef.NextOwner = def.EntityReference;
			def.EntityReference = areaRef;

			// link to end of area list
			areaRef.Area = area;
			areaRef.NextArea = area.EntityReference;
			areaRef.PreviousArea = area.EntityReference.PreviousArea;
			areaRef.NextArea.PreviousArea = areaRef;
			areaRef.PreviousArea.NextArea = areaRef;
		}
Beispiel #20
0
 /// <summary>
 /// Creates a static model based on the definition and view currently.
 /// </summary>
 /// <remarks>
 /// This will be regenerated for every view, even though
 /// some models, like character meshes, could be used for multiple (mirror)
 /// views in a frame, or may stay static for multiple frames (corpses)
 /// The renderer will delete the returned dynamic model the next view.
 /// </remarks>
 /// <param name="renderEntity"></param>
 /// <param name="view"></param>
 /// <param name="cachedModel"></param>
 /// <returns></returns>
 public abstract idRenderModel InstantiateDynamicModel(idRenderEntity renderEntity, View view, idRenderModel cachedModel);
Beispiel #21
0
		/// <summary>
		/// 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
		/// </summary>
		/// <param name="def"></param>
		/// <returns></returns>
		private idRenderModel EntityDefinitionDynamicModel(idRenderEntity def) 
		{
			bool callbackUpdate;

			// allow deferred entities to construct themselves
			if(def.Parameters.Callback != null)
			{
				callbackUpdate = false;
				idConsole.Warning("TODO: R_IssueEntityDefCallback( def );");
			} 
			else 
			{
				callbackUpdate = false;
			}

			idRenderModel model = def.Parameters.Model;

			if(model == null)
			{
				idConsole.Error("EntityDefinitionDynamicModel: null model");
			}

			if(model.IsDynamic == DynamicModel.Static)
			{
				def.DynamicModel = null;
				def.DynamicModelFrameCount = 0;

				return model;
			}

			idConsole.Warning("TODO: dynamic model rendering!");
	// 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, tr.viewDef, 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;
		}