protected override void DrawRenderer(RenderContext context, IEntityComponentRenderer renderer) { if (!context.IsPicking() || renderer.SupportPicking) { renderer.Prepare(context, opaqueRenderItems, transparentRenderItems); } }
protected override void DrawCore(RenderContext context, RenderItemCollection renderItems, int fromIndex, int toIndex) { var viewParameters = context.Parameters; var device = context.GraphicsDevice; var viewInverse = Matrix.Invert(viewParameters.Get(TransformationKeys.View)); var viewProjection = viewParameters.Get(TransformationKeys.ViewProjection); BlendState previousBlendState = null; DepthStencilState previousDepthStencilState = null; Effect previousEffect = null; var isPicking = context.IsPicking(); bool hasBegin = false; for (var i = fromIndex; i <= toIndex; i++) { var renderItem = renderItems[i]; var spriteState = (SpriteProcessor.SpriteComponentState)renderItem.DrawContext; var spriteComp = spriteState.SpriteComponent; var transfoComp = spriteState.TransformComponent; var depthStencilState = spriteState.SpriteComponent.IgnoreDepth ? device.DepthStencilStates.None : device.DepthStencilStates.Default; var sprite = spriteComp.CurrentSprite; if (sprite == null) { continue; } // Update the sprite batch var blendState = isPicking ? device.BlendStates.Opaque : renderItems.HasTransparency ? (spriteComp.PremultipliedAlpha ? device.BlendStates.AlphaBlend : device.BlendStates.NonPremultiplied) : device.BlendStates.Opaque; var currentEffect = isPicking? GetOrCreatePickingSpriteEffect(): spriteComp.Tags.Get(IsEntitySelected)? GetOrCreateSelectedSpriteEffect(): null; // TODO remove this code when material are available if (previousEffect != currentEffect || blendState != previousBlendState || depthStencilState != previousDepthStencilState) { if (hasBegin) { sprite3DBatch.End(); } sprite3DBatch.Begin(viewProjection, SpriteSortMode.Deferred, blendState, null, depthStencilState, device.RasterizerStates.CullNone, currentEffect); hasBegin = true; } previousEffect = currentEffect; previousBlendState = blendState; previousDepthStencilState = depthStencilState; var sourceRegion = sprite.Region; var texture = sprite.Texture; var color = spriteComp.Color; if (isPicking) // TODO move this code corresponding to picking out of the runtime code. { color = (Color) new Color4(spriteComp.Id); } // skip the sprite if no texture is set. if (texture == null) { continue; } // determine the element world matrix depending on the type of sprite var worldMatrix = transfoComp.WorldMatrix; if (spriteComp.SpriteType == SpriteType.Billboard) { worldMatrix = viewInverse; // remove scale of the camera worldMatrix.Row1 /= ((Vector3)viewInverse.Row1).Length(); worldMatrix.Row2 /= ((Vector3)viewInverse.Row2).Length(); // set the scale of the object worldMatrix.Row1 *= ((Vector3)transfoComp.WorldMatrix.Row1).Length(); worldMatrix.Row2 *= ((Vector3)transfoComp.WorldMatrix.Row2).Length(); // set the position worldMatrix.TranslationVector = transfoComp.WorldMatrix.TranslationVector; } // apply the offset due to the center of the sprite var normalizedCenter = new Vector2(sprite.SizeInternal.X * (sprite.Center.X / sourceRegion.Width - 0.5f), sprite.SizeInternal.Y * (0.5f - sprite.Center.Y / sourceRegion.Height)); worldMatrix.M41 -= normalizedCenter.X * worldMatrix.M11 + normalizedCenter.Y * worldMatrix.M21; worldMatrix.M42 -= normalizedCenter.X * worldMatrix.M12 + normalizedCenter.Y * worldMatrix.M22; worldMatrix.M43 -= normalizedCenter.X * worldMatrix.M13 + normalizedCenter.Y * worldMatrix.M23; // draw the sprite sprite3DBatch.Draw(texture, ref worldMatrix, ref sourceRegion, ref sprite.SizeInternal, ref color, sprite.Orientation, SwizzleMode.None, renderItem.Depth); } sprite3DBatch.End(); }
/// <summary> /// Draw this effect mesh. /// </summary> public void Draw(RenderContext context) { // Retrieve effect parameters var graphicsDevice = context.GraphicsDevice; var mesh = Mesh; var currentRenderData = mesh.Draw; var material = Material; var vao = vertexArrayObject; var drawCount = currentRenderData.DrawCount; var primitiveType = currentRenderData.PrimitiveType; parameters.Set(TransformationKeys.World, WorldMatrix); // TODO: We should clarify exactly how to override rasterizer states. Currently setup here on Context.Parameters to allow Material/ModelComponent overrides, but this is ugly // Apply rasterizer var rasterizer = RasterizerState; if (!ForceRasterizer && Material.CullMode.HasValue && Material.CullMode.Value != RasterizerState.Description.CullMode) { switch (Material.CullMode.Value) { case CullMode.Back: rasterizer = graphicsDevice.RasterizerStates.CullBack; break; case CullMode.Front: rasterizer = graphicsDevice.RasterizerStates.CullFront; break; case CullMode.None: rasterizer = graphicsDevice.RasterizerStates.CullNone; break; } } context.Parameters.Set(Effect.RasterizerStateKey, rasterizer); // Handle picking if (context.IsPicking()) // TODO move this code corresponding to picking outside of the runtime code! { parameters.Set(ModelComponentPickingShaderKeys.ModelComponentId, new Color4(RenderModel.ModelComponent.Id)); parameters.Set(ModelComponentPickingShaderKeys.MeshId, new Color4(RenderModel.ModelComponent.Model.Meshes.IndexOf(Mesh))); parameters.Set(ModelComponentPickingShaderKeys.MaterialId, new Color4(Mesh.MaterialIndex)); // Don't use the materials blend state on picking targets parameters.Set(Effect.BlendStateKey, null); } if (material != null && material.TessellationMethod != ParadoxTessellationMethod.None) { var tessellationMethod = material.TessellationMethod; // adapt the primitive type and index buffer to the tessellation used if (tessellationMethod.PerformsAdjacentEdgeAverage()) { vao = GetOrCreateVertexArrayObjectAEN(context); drawCount = 12 / 3 * drawCount; } primitiveType = tessellationMethod.GetPrimitiveType(); } //using (Profiler.Begin(ProfilingKeys.PrepareMesh)) { // Order of application of parameters: // - RenderPass.Parameters // - ModelComponent.Parameters // - RenderMesh.Parameters (originally copied from mesh parameters) // The order is based on the granularity level of each element and how shared it can be. Material is heavily shared, a model contains many meshes. An renderMesh is unique. // TODO: really copy mesh parameters into renderMesh instead of just referencing the meshDraw parameters. //var modelComponent = RenderModel.ModelComponent; //var hasModelComponentParams = modelComponent != null && modelComponent.Parameters != null; //var materialParameters = material != null && material.Parameters != null ? material.Parameters : null; parameterCollections.Clear(); parameterCollections.Add(context.Parameters); FillParameterCollections(ref parameterCollections); // Check if we need to recreate the EffectParameterCollectionGroup // TODO: We can improve performance by redesigning FillParameterCollections to avoid ArrayExtensions.ArraysReferenceEqual (or directly check the appropriate parameter collections) // This also happens in another place: DynamicEffectCompiler (we probably want to factorize it when doing additional optimizations) if (parameterCollectionGroup == null || parameterCollectionGroup.Effect != Effect || !ArrayExtensions.ArraysReferenceEqual(ref previousParameterCollections, ref parameterCollections)) { previousParameterCollections.Clear(); previousParameterCollections.AddRange(parameterCollections); parameterCollectionGroup = new EffectParameterCollectionGroup(context.GraphicsDevice, Effect, previousParameterCollections.Count, previousParameterCollections.Items); } Effect.Apply(context.GraphicsDevice, parameterCollectionGroup, true); } //using (Profiler.Begin(ProfilingKeys.RenderMesh)) { if (currentRenderData != null) { graphicsDevice.SetVertexArrayObject(vao); if (currentRenderData.IndexBuffer == null) { graphicsDevice.Draw(primitiveType, drawCount, currentRenderData.StartLocation); } else { graphicsDevice.DrawIndexed(primitiveType, drawCount, currentRenderData.StartLocation); } } } }
protected override void DrawCore(RenderContext context, RenderItemCollection renderItems, int fromIndex, int toIndex) { // TODO: Check how to integrate sprites in a Camera renderer instead of this var viewParameters = context.Parameters; var device = context.GraphicsDevice; var cullMode = device.RasterizerStates.CullNone; var viewInverse = Matrix.Invert(viewParameters.Get(TransformationKeys.View)); var viewProjection = viewParameters.Get(TransformationKeys.ViewProjection); BlendState previousBlendState = null; Effect previousEffect = null; var isPicking = context.IsPicking(); bool hasBegin = false; for (var i = fromIndex; i <= toIndex; i++) { var renderItem = renderItems[i]; var spriteState = (SpriteProcessor.SpriteComponentState)renderItem.DrawContext; var spriteComp = spriteState.SpriteComponent; var transfoComp = spriteState.TransformComponent; var sprite = spriteComp.CurrentSprite; if (sprite == null) { continue; } // Update the sprite batch var blendState = isPicking ? device.BlendStates.Opaque : renderItems.HasTransparency ? (spriteComp.PremultipliedAlpha ? device.BlendStates.AlphaBlend : device.BlendStates.NonPremultiplied) : device.BlendStates.Opaque; var currentEffect = (!isPicking && spriteComp.Tags.Get(IsEntitySelected)) ? GetOrCreateSelectedSpriteEffect(): null; // TODO remove this code when material are available if (previousEffect != currentEffect || blendState != previousBlendState) { if (hasBegin) { sprite3DBatch.End(); } sprite3DBatch.Begin(viewProjection, SpriteSortMode.Deferred, blendState, null, context.GraphicsDevice.DepthStencilStates.None, cullMode, currentEffect); hasBegin = true; } previousEffect = currentEffect; previousBlendState = blendState; var sourceRegion = sprite.Region; var texture = sprite.Texture; var color = spriteComp.Color; if (isPicking) // TODO move this code corresponding to picking out of the runtime code. { texture = device.GetSharedWhiteTexture(); color = (Color) new Color4(spriteComp.Id); } // skip the sprite if no texture is set. if (texture == null) { continue; } // determine the size of the element depending on the extrusion method. var elementSize = Vector2.One; if (spriteComp.ExtrusionMethod == SpriteExtrusionMethod.UnitHeightSpriteRatio) { elementSize.X = sourceRegion.Width / sourceRegion.Height; } else if (spriteComp.ExtrusionMethod == SpriteExtrusionMethod.UnitWidthSpriteRatio) { elementSize.Y = sourceRegion.Height / sourceRegion.Width; } // determine the element world matrix depending on the type of sprite var worldMatrix = transfoComp.WorldMatrix; if (spriteComp.SpriteType == SpriteType.Billboard) { worldMatrix = viewInverse; // remove scale of the camera worldMatrix.Row1 /= ((Vector3)viewInverse.Row1).Length(); worldMatrix.Row2 /= ((Vector3)viewInverse.Row2).Length(); // set the scale of the object worldMatrix.Row1 *= ((Vector3)transfoComp.WorldMatrix.Row1).Length(); worldMatrix.Row2 *= ((Vector3)transfoComp.WorldMatrix.Row2).Length(); // set the position worldMatrix.TranslationVector = transfoComp.WorldMatrix.TranslationVector; } // draw the sprite sprite3DBatch.Draw(texture, ref worldMatrix, ref sourceRegion, ref elementSize, ref color, sprite.Orientation, SwizzleMode.None, renderItem.Depth); } sprite3DBatch.End(); }
/// <summary> /// Draw this effect mesh. /// </summary> public void Draw(RenderContext context) { // Retrieve effect parameters var mesh = Mesh; var currentRenderData = mesh.Draw; var material = Material; var vao = vertexArrayObject; var drawCount = currentRenderData.DrawCount; if (context.IsPicking()) // TODO move this code corresponding to picking outside of the runtime code! { parameters.Set(ModelComponentPickingShaderKeys.ModelComponentId, new Color4(RenderModel.ModelComponent.Id)); parameters.Set(ModelComponentPickingShaderKeys.MeshId, new Color4(Mesh.NodeIndex)); parameters.Set(ModelComponentPickingShaderKeys.MaterialId, new Color4(Mesh.MaterialIndex)); } if (material != null && material.TessellationMethod != ParadoxTessellationMethod.None) { var tessellationMethod = material.TessellationMethod; // adapt the primitive type and index buffer to the tessellation used if (tessellationMethod.PerformsAdjacentEdgeAverage()) { vao = GetOrCreateVertexArrayObjectAEN(context); drawCount = 12 / 3 * drawCount; } currentRenderData.PrimitiveType = tessellationMethod.GetPrimitiveType(); } //using (Profiler.Begin(ProfilingKeys.PrepareMesh)) { // Order of application of parameters: // - RenderPass.Parameters // - ModelComponent.Parameters // - RenderMesh.Parameters (originally copied from mesh parameters) // The order is based on the granularity level of each element and how shared it can be. Material is heavily shared, a model contains many meshes. An renderMesh is unique. // TODO: really copy mesh parameters into renderMesh instead of just referencing the meshDraw parameters. //var modelComponent = RenderModel.ModelComponent; //var hasModelComponentParams = modelComponent != null && modelComponent.Parameters != null; //var materialParameters = material != null && material.Parameters != null ? material.Parameters : null; parameterCollections.Clear(); parameterCollections.Add(context.Parameters); FillParameterCollections(parameterCollections); // Check if we need to recreate the EffectParameterCollectionGroup // TODO: We can improve performance by redesigning FillParameterCollections to avoid ArrayExtensions.ArraysReferenceEqual (or directly check the appropriate parameter collections) // This also happens in another place: DynamicEffectCompiler (we probably want to factorize it when doing additional optimizations) if (parameterCollectionGroup == null || parameterCollectionGroup.Effect != Effect || !ArrayExtensions.ArraysReferenceEqual(previousParameterCollections, parameterCollections)) { parameterCollectionGroup = new EffectParameterCollectionGroup(context.GraphicsDevice, Effect, parameterCollections); previousParameterCollections = parameterCollections.ToArray(); } Effect.Apply(context.GraphicsDevice, parameterCollectionGroup, true); } //using (Profiler.Begin(ProfilingKeys.RenderMesh)) { if (currentRenderData != null) { var graphicsDevice = context.GraphicsDevice; graphicsDevice.SetVertexArrayObject(vao); if (currentRenderData.IndexBuffer == null) { graphicsDevice.Draw(currentRenderData.PrimitiveType, drawCount, currentRenderData.StartLocation); } else { graphicsDevice.DrawIndexed(currentRenderData.PrimitiveType, drawCount, currentRenderData.StartLocation); } } } }