public override void Extract()
        {
            var objectInfoDataHolder    = RootRenderFeature.RenderData.GetData(_objectInfoPropertyKey);
            var blendMatricesDataHolder = RootRenderFeature.RenderData.GetData(_blendMatricesPropertyKey);

            foreach (var objectNodeReference in RootRenderFeature.ObjectNodeReferences)
            {
                var objectNode = RootRenderFeature.GetObjectNode(objectNodeReference);
                if (!(objectNode.RenderObject is RenderMesh renderMesh))
                {
                    continue;
                }

                blendMatricesDataHolder[objectNodeReference] = renderMesh.BlendMatrices;    // This is for our skinned models.

                int meshIndex = 0;
                if (!(renderMesh.Source is ModelComponent modelComponent))
                {
                    continue;
                }

                for (int i = 0; i < modelComponent.Model.Meshes.Count; i++)
                {
                    if (modelComponent.Model.Meshes[i] == renderMesh.Mesh)
                    {
                        meshIndex = i;
                        break;
                    }
                }

                // RuntimeIdHelper.ToRuntimeId is how Xenko does it for its 'Picking' scene.
                // We should probably change this to use something more appropriate for our data.
                var modelCompId    = RuntimeIdHelper.ToRuntimeId(modelComponent);
                var objectInfoData = new ObjectInfoData((uint)modelCompId, (ushort)meshIndex, (ushort)renderMesh.Mesh.MaterialIndex);
                objectInfoDataHolder[objectNodeReference] = objectInfoData;

#if DEBUG
                // This is only for debugging purposes, it can be removed.
                if (_isFirstRun)
                {
                    System.Diagnostics.Debug.WriteLine($"Entity: {modelComponent.Entity.Name} - modelCompId: {objectInfoData.ModelComponentId} - meshIndex: {objectInfoData.MeshIndex} - matIndex: {objectInfoData.MaterialIndex}");
                }
#endif
            }
#if DEBUG
            _isFirstRun = false;
#endif
        }
        /// <summary>
        ///   Invalidates the cached identifiers of all the <see cref="EntityComponent"/>s of the specified <see cref="Entity"/>.
        /// </summary>
        /// <param name="entity">The entity for which to invalidate the cached identifiers of its components.</param>
        /// <param name="isRecursive">A value indicating whether to also invalidate the cached identifiers of the components of child entities, recursively.</param>
        public void UncacheEntity([NotNull] Entity entity, bool isRecursive)
        {
            if (entity is null)
            {
                throw new ArgumentNullException(nameof(entity));
            }

            foreach (var component in entity.Components)
            {
                idToEntity.Remove(RuntimeIdHelper.ToRuntimeId(component));
            }

            if (isRecursive)
            {
                foreach (var component in entity.GetChildren().BreadthFirst(x => x.GetChildren()).SelectMany(e => e.Components))
                {
                    idToEntity.Remove(RuntimeIdHelper.ToRuntimeId(component));
                }
            }
        }
Example #3
0
        /// <summary>
        /// Cache identifier of all components of the specified <paramref name="entity"/>.
        /// </summary>
        /// <param name="entity">The entity which components to cache.</param>
        /// <param name="isRecursive"><c>true</c> if the components of child entities should also be cached, recursively; otherwise, <c>false</c>.</param>
        public void CacheEntity([NotNull] Entity entity, bool isRecursive)
        {
            if (entity == null)
            {
                throw new ArgumentNullException(nameof(entity));
            }

            foreach (var component in entity.Components)
            {
                idToEntity[RuntimeIdHelper.ToRuntimeId(component)] = component.Entity;
            }

            if (!isRecursive)
            {
                return;
            }

            foreach (var component in entity.GetChildren().BreadthFirst(x => x.GetChildren()).SelectMany(e => e.Components))
            {
                idToEntity[RuntimeIdHelper.ToRuntimeId(component)] = component.Entity;
            }
        }
Example #4
0
        public override void Draw(RenderDrawContext context, RenderView renderView, RenderViewStage renderViewStage, int startIndex, int endIndex)
        {
            base.Draw(context, renderView, renderViewStage, startIndex, endIndex);

            BlendStateDescription?       previousBlendState        = null;
            DepthStencilStateDescription?previousDepthStencilState = null;
            EffectInstance previousEffect = null;

            //TODO string comparison ...?
            var isPicking = RenderSystem.RenderStages[renderViewStage.Index].Name == "Picking";

            var hasBegin = false;

            for (var index = startIndex; index < endIndex; index++)
            {
                var renderNodeReference = renderViewStage.SortedRenderNodes[index].RenderNode;
                var renderNode          = GetRenderNode(renderNodeReference);

                var spriteState = (RenderSpriteStudio)renderNode.RenderObject;

                var depthStencilState = DepthStencilStates.DepthRead;

                foreach (var node in spriteState.SortedNodes)
                {
                    if (node.Sprite?.Texture == null || node.Sprite.Region.Width <= 0 || node.Sprite.Region.Height <= 0f || node.Hide != 0)
                    {
                        continue;
                    }

                    // Update the sprite batch

                    BlendStateDescription spriteBlending;
                    switch (node.BaseNode.AlphaBlending)
                    {
                    case SpriteStudioBlending.Mix:
                        spriteBlending = BlendStates.AlphaBlend;
                        break;

                    case SpriteStudioBlending.Multiplication:
                        spriteBlending = MultBlendState;
                        break;

                    case SpriteStudioBlending.Addition:
                        spriteBlending = BlendStates.Additive;
                        break;

                    case SpriteStudioBlending.Subtraction:
                        spriteBlending = SubBlendState;
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }

                    // TODO: this should probably be moved to Prepare()
                    // Project the position
                    // TODO: This could be done in a SIMD batch, but we need to figure-out how to plugin in with RenderMesh object
                    var worldPosition = new Vector4(spriteState.WorldMatrix.TranslationVector, 1.0f);

                    Vector4 projectedPosition;
                    Vector4.Transform(ref worldPosition, ref renderView.ViewProjection, out projectedPosition);
                    var projectedZ = projectedPosition.Z / projectedPosition.W;

                    var blendState = isPicking ? BlendStates.Default : spriteBlending;
                    // TODO: the current impementation to determine if the sprite is selected does not work. This should be fixed later at some point
                    //var currentEffect = isPicking ? GetOrCreatePickingSpriteEffect() : ShadowObject.IsObjectSelected(spriteState.SpriteStudioComponent) ? GetOrCreateSelectedSpriteEffect() : null;
                    var currentEffect = isPicking ? GetOrCreatePickingSpriteEffect() : null;
                    // TODO remove this code when material are available
                    if (previousEffect != currentEffect || blendState != previousBlendState || depthStencilState != previousDepthStencilState)
                    {
                        if (hasBegin)
                        {
                            sprite3DBatch.End();
                        }
                        sprite3DBatch.Begin(context.GraphicsContext, renderView.ViewProjection, SpriteSortMode.Deferred, blendState, null, depthStencilState, RasterizerStates.CullNone, currentEffect);
                        hasBegin = true;
                    }

                    previousEffect            = currentEffect;
                    previousBlendState        = blendState;
                    previousDepthStencilState = depthStencilState;

                    var sourceRegion = node.Sprite.Region;
                    var texture      = node.Sprite.Texture;

                    // skip the sprite if no texture is set.
                    if (texture == null)
                    {
                        continue;
                    }

                    var color4 = Color4.White;
                    if (isPicking)
                    {
                        // TODO move this code corresponding to picking out of the runtime code.
                        color4 = new Color4(RuntimeIdHelper.ToRuntimeId(spriteState.Source));
                    }
                    else
                    {
                        if (node.BlendFactor > 0.0f)
                        {
                            switch (node.BlendType) //todo this should be done in a shader
                            {
                            case SpriteStudioBlending.Mix:
                                color4 = Color4.Lerp(color4, node.BlendColor, node.BlendFactor) * node.FinalTransparency;
                                break;

                            case SpriteStudioBlending.Multiplication:
                                color4 = Color4.Lerp(color4, node.BlendColor, node.BlendFactor) * node.FinalTransparency;
                                break;

                            case SpriteStudioBlending.Addition:
                                color4 = Color4.Lerp(color4, node.BlendColor, node.BlendFactor) * node.FinalTransparency;
                                break;

                            case SpriteStudioBlending.Subtraction:
                                color4 = Color4.Lerp(color4, node.BlendColor, node.BlendFactor) * node.FinalTransparency;
                                break;

                            default:
                                throw new ArgumentOutOfRangeException();
                            }
                        }
                        else
                        {
                            color4 *= node.FinalTransparency;
                        }
                    }

                    Matrix.Multiply(ref node.ModelTransform, ref spriteState.WorldMatrix, out var worldMatrix);

                    // calculate normalized position of the center of the sprite (takes into account the possible rotation of the image)
                    var normalizedCenter = new Vector2(node.Sprite.Center.X / sourceRegion.Width - 0.5f, 0.5f - node.Sprite.Center.Y / sourceRegion.Height);
                    if (node.Sprite.Orientation == ImageOrientation.Rotated90)
                    {
                        var oldCenterX = normalizedCenter.X;
                        normalizedCenter.X = -normalizedCenter.Y;
                        normalizedCenter.Y = oldCenterX;
                    }
                    // apply the offset due to the center of the sprite
                    var size         = node.Sprite.Size;
                    var centerOffset = Vector2.Modulate(normalizedCenter, size);
                    worldMatrix.M41 -= centerOffset.X * worldMatrix.M11 + centerOffset.Y * worldMatrix.M21;
                    worldMatrix.M42 -= centerOffset.X * worldMatrix.M12 + centerOffset.Y * worldMatrix.M22;

                    // draw the sprite
                    sprite3DBatch.Draw(texture, ref worldMatrix, ref sourceRegion, ref size, ref color4, node.Sprite.Orientation, SwizzleMode.None, projectedZ);
                }
            }

            if (hasBegin)
            {
                sprite3DBatch.End();
            }
        }
Example #5
0
        public override void Draw(RenderDrawContext context, RenderView renderView, RenderViewStage renderViewStage, int startIndex, int endIndex)
        {
            base.Draw(context, renderView, renderViewStage, startIndex, endIndex);

            Matrix viewInverse;

            Matrix.Invert(ref renderView.View, out viewInverse);

            BlendStateDescription?       previousBlendState        = null;
            DepthStencilStateDescription?previousDepthStencilState = null;
            EffectInstance previousEffect = null;

            //TODO string comparison ...?
            var isPicking = renderViewStage.RenderStage.Name == "Picking";

            bool hasBegin = false;

            for (var index = startIndex; index < endIndex; index++)
            {
                var renderNodeReference = renderViewStage.SortedRenderNodes[index].RenderNode;
                var renderNode          = GetRenderNode(renderNodeReference);

                var renderSprite = (RenderSprite)renderNode.RenderObject;

                var spriteComp        = renderSprite.SpriteComponent;
                var transfoComp       = renderSprite.TransformComponent;
                var depthStencilState = renderSprite.SpriteComponent.IgnoreDepth ? DepthStencilStates.None : DepthStencilStates.Default;

                var sprite = spriteComp.CurrentSprite;
                if (sprite == null)
                {
                    continue;
                }

                // TODO: this should probably be moved to Prepare()
                // Project the position
                // TODO: This could be done in a SIMD batch, but we need to figure-out how to plugin in with RenderMesh object
                var worldPosition = new Vector4(renderSprite.TransformComponent.WorldMatrix.TranslationVector, 1.0f);

                Vector4 projectedPosition;
                Vector4.Transform(ref worldPosition, ref renderView.ViewProjection, out projectedPosition);
                var projectedZ = projectedPosition.Z / projectedPosition.W;

                // Update the sprite batch
                var blendState    = isPicking ? BlendStates.Default : sprite.IsTransparent ? (spriteComp.PremultipliedAlpha ? BlendStates.AlphaBlend : BlendStates.NonPremultiplied) : BlendStates.Opaque;
                var currentEffect = isPicking ? GetOrCreatePickingSpriteEffect() : null; // TODO remove this code when material are available
                if (previousEffect != currentEffect || blendState != previousBlendState || depthStencilState != previousDepthStencilState)
                {
                    if (hasBegin)
                    {
                        sprite3DBatch.End();
                    }
                    sprite3DBatch.Begin(context.GraphicsContext, renderView.ViewProjection, SpriteSortMode.Deferred, blendState, null, depthStencilState, 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.
                {
                    var compId = RuntimeIdHelper.ToRuntimeId(spriteComp);
                    color = new Color4(compId);
                }

                // 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;
                }

                // calculate normalized position of the center of the sprite (takes into account the possible rotation of the image)
                var normalizedCenter = new Vector2(sprite.Center.X / sourceRegion.Width - 0.5f, 0.5f - sprite.Center.Y / sourceRegion.Height);
                if (sprite.Orientation == ImageOrientation.Rotated90)
                {
                    var oldCenterX = normalizedCenter.X;
                    normalizedCenter.X = -normalizedCenter.Y;
                    normalizedCenter.Y = oldCenterX;
                }
                // apply the offset due to the center of the sprite
                var centerOffset = Vector2.Modulate(normalizedCenter, sprite.SizeInternal);
                worldMatrix.M41 -= centerOffset.X * worldMatrix.M11 + centerOffset.Y * worldMatrix.M21;
                worldMatrix.M42 -= centerOffset.X * worldMatrix.M12 + centerOffset.Y * worldMatrix.M22;
                worldMatrix.M43 -= centerOffset.X * worldMatrix.M13 + centerOffset.Y * worldMatrix.M23;

                // draw the sprite
                sprite3DBatch.Draw(texture, ref worldMatrix, ref sourceRegion, ref sprite.SizeInternal, ref color, sprite.Orientation, SwizzleMode.None, projectedZ);
            }

            if (hasBegin)
            {
                sprite3DBatch.End();
            }
        }
Example #6
0
        public override void Draw(RenderDrawContext context, RenderView renderView, RenderViewStage renderViewStage, int startIndex, int endIndex)
        {
            base.Draw(context, renderView, renderViewStage, startIndex, endIndex);

            var isMultisample = RenderSystem.RenderStages[renderViewStage.Index].Output.MultisampleCount != MultisampleCount.None;

            var batchContext = threadContext.Value;

            Matrix viewInverse;

            Matrix.Invert(ref renderView.View, out viewInverse);

            uint previousBatchState = uint.MaxValue;

            //TODO string comparison ...?
            var isPicking = RenderSystem.RenderStages[renderViewStage.Index].Name == "Picking";

            bool hasBegin = false;

            for (var index = startIndex; index < endIndex; index++)
            {
                var renderNodeReference = renderViewStage.SortedRenderNodes[index].RenderNode;
                var renderNode          = GetRenderNode(renderNodeReference);

                var renderSprite = (RenderSprite)renderNode.RenderObject;

                var sprite = renderSprite.Sprite;
                if (sprite == null)
                {
                    continue;
                }

                // TODO: this should probably be moved to Prepare()
                // Project the position
                // TODO: This could be done in a SIMD batch, but we need to figure-out how to plugin in with RenderMesh object
                var worldPosition = new Vector4(renderSprite.WorldMatrix.TranslationVector, 1.0f);

                Vector4 projectedPosition;
                Vector4.Transform(ref worldPosition, ref renderView.ViewProjection, out projectedPosition);
                var projectedZ = projectedPosition.Z / projectedPosition.W;

                BlendModes     blendMode;
                EffectInstance currentEffect = null;
                if (isPicking)
                {
                    blendMode     = BlendModes.Default;
                    currentEffect = batchContext.GetOrCreatePickingSpriteEffect(RenderSystem.EffectSystem);
                }
                else
                {
                    var spriteBlend = renderSprite.BlendMode;
                    if (spriteBlend == SpriteBlend.Auto)
                    {
                        spriteBlend = sprite.IsTransparent ? SpriteBlend.AlphaBlend : SpriteBlend.None;
                    }

                    if (spriteBlend == SpriteBlend.AlphaBlend)
                    {
                        blendMode = renderSprite.PremultipliedAlpha ? BlendModes.Alpha : BlendModes.NonPremultiplied;
                    }
                    else
                    {
                        blendMode = spriteBlendToBlendMode[spriteBlend];
                    }
                }

                // Check if the current blend state has changed in any way, if not
                // Note! It doesn't really matter in what order we build the bitmask, the result is not preserved anywhere except in this method
                var currentBatchState = (uint)blendMode;
                currentBatchState = (currentBatchState << 1) + ((uint)renderSprite.DepthMode);
                currentBatchState = (currentBatchState << 1) + (renderSprite.IsAlphaCutoff ? 1U : 0U);
                currentBatchState = (currentBatchState << 2) + ((uint)renderSprite.Sampler);

                if (previousBatchState != currentBatchState)
                {
                    var blendState = blendModeToDescription[blendMode];

                    if (renderSprite.IsAlphaCutoff)
                    {
                        currentEffect = batchContext.GetOrCreateAlphaCutoffSpriteEffect(RenderSystem.EffectSystem);
                    }

                    DepthStencilStateDescription depthStencilState;
                    switch (renderSprite.DepthMode)
                    {
                    case RenderSprite.SpriteDepthMode.Ignore:
                        depthStencilState = DepthStencilStates.None;
                        break;

                    case RenderSprite.SpriteDepthMode.ReadOnly:
                        depthStencilState = DepthStencilStates.DepthRead;
                        break;

                    default:
                        depthStencilState = DepthStencilStates.Default;
                        break;

                    case RenderSprite.SpriteDepthMode.WriteOnly:
                        depthStencilState = new DepthStencilStateDescription(false, true);
                        break;
                    }

                    var samplerState = context.GraphicsDevice.SamplerStates.LinearClamp;
                    if (renderSprite.Sampler != SpriteSampler.LinearClamp)
                    {
                        switch (renderSprite.Sampler)
                        {
                        case SpriteSampler.PointClamp:
                            samplerState = context.GraphicsDevice.SamplerStates.PointClamp;
                            break;

                        case SpriteSampler.AnisotropicClamp:
                            samplerState = context.GraphicsDevice.SamplerStates.AnisotropicClamp;
                            break;
                        }
                    }

                    if (hasBegin)
                    {
                        lock (batchEndLocker)
                        {
                            batchContext.SpriteBatch.End();
                        }
                    }

                    var rasterizerState = RasterizerStates.CullNone;
                    if (isMultisample)
                    {
                        rasterizerState.MultisampleCount         = RenderSystem.RenderStages[renderViewStage.Index].Output.MultisampleCount;
                        rasterizerState.MultisampleAntiAliasLine = true;
                    }

                    batchContext.SpriteBatch.Begin(context.GraphicsContext, renderView.ViewProjection, SpriteSortMode.Deferred, blendState, samplerState, depthStencilState, rasterizerState, currentEffect);
                    hasBegin = true;
                }
                previousBatchState = currentBatchState;

                var sourceRegion = sprite.Region;
                var texture      = sprite.Texture;
                var color        = renderSprite.Color;
                if (isPicking) // TODO move this code corresponding to picking out of the runtime code.
                {
                    var compId = RuntimeIdHelper.ToRuntimeId(renderSprite.Source);
                    color = new Color4(compId, 0.0f, 0.0f, 0.0f);
                }

                // 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 = renderSprite.WorldMatrix;
                if (renderSprite.SpriteType == SpriteType.Billboard)
                {
                    worldMatrix = viewInverse;

                    var worldMatrixRow1 = worldMatrix.Row1;
                    var worldMatrixRow2 = worldMatrix.Row2;

                    // remove scale of the camera
                    worldMatrixRow1 /= ((Vector3)viewInverse.Row1).Length();
                    worldMatrixRow2 /= ((Vector3)viewInverse.Row2).Length();

                    // set the scale of the object
                    worldMatrixRow1 *= ((Vector3)renderSprite.WorldMatrix.Row1).Length();
                    worldMatrixRow2 *= ((Vector3)renderSprite.WorldMatrix.Row2).Length();

                    worldMatrix.Row1 = worldMatrixRow1;
                    worldMatrix.Row2 = worldMatrixRow2;

                    // set the position
                    worldMatrix.TranslationVector = renderSprite.WorldMatrix.TranslationVector;

                    // set the rotation
                    var localRotationZ = renderSprite.RotationEulerZ;
                    if (localRotationZ != 0)
                    {
                        worldMatrix = Matrix.RotationZ(localRotationZ) * worldMatrix;
                    }
                }

                // calculate normalized position of the center of the sprite (takes into account the possible rotation of the image)
                var normalizedCenter = new Vector2(sprite.Center.X / sourceRegion.Width - 0.5f, 0.5f - sprite.Center.Y / sourceRegion.Height);
                if (sprite.Orientation == ImageOrientation.Rotated90)
                {
                    var oldCenterX = normalizedCenter.X;
                    normalizedCenter.X = -normalizedCenter.Y;
                    normalizedCenter.Y = oldCenterX;
                }
                // apply the offset due to the center of the sprite
                var centerOffset = Vector2.Modulate(normalizedCenter, sprite.SizeInternal);
                worldMatrix.M41 -= centerOffset.X * worldMatrix.M11 + centerOffset.Y * worldMatrix.M21;
                worldMatrix.M42 -= centerOffset.X * worldMatrix.M12 + centerOffset.Y * worldMatrix.M22;
                worldMatrix.M43 -= centerOffset.X * worldMatrix.M13 + centerOffset.Y * worldMatrix.M23;

                // adapt the source region to match what is expected at full resolution
                if (texture.ViewType == ViewType.Full && texture.ViewWidth != texture.FullQualitySize.Width)
                {
                    var fullQualitySize = texture.FullQualitySize;
                    var horizontalRatio = texture.ViewWidth / (float)fullQualitySize.Width;
                    var verticalRatio   = texture.ViewHeight / (float)fullQualitySize.Height;
                    sourceRegion.X      *= horizontalRatio;
                    sourceRegion.Width  *= horizontalRatio;
                    sourceRegion.Y      *= verticalRatio;
                    sourceRegion.Height *= verticalRatio;
                }

                // register resource usage.
                Context.StreamingManager?.StreamResources(texture);

                // draw the sprite
                batchContext.SpriteBatch.Draw(texture, ref worldMatrix, ref sourceRegion, ref sprite.SizeInternal, ref color, sprite.Orientation, renderSprite.Swizzle, projectedZ);
            }

            if (hasBegin)
            {
                lock (batchEndLocker)
                {
                    batchContext.SpriteBatch.End();
                }
            }
        }
Example #7
0
        /// <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(RuntimeIdHelper.ToRuntimeId(RenderModel.ModelComponent)));
                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 != XenkoTessellationMethod.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);
                    }
                }
            }
        }
        public override void Draw(RenderDrawContext context, RenderView renderView, RenderViewStage renderViewStage, int startIndex, int endIndex)
        {
            base.Draw(context, renderView, renderViewStage, startIndex, endIndex);

            var batchContext = threadContext.Value;

            Matrix viewInverse;

            Matrix.Invert(ref renderView.View, out viewInverse);

            uint previousBatchState = uint.MaxValue;

            //TODO string comparison ...?
            var isPicking = renderViewStage.RenderStage.Name == "Picking";

            bool hasBegin = false;

            for (var index = startIndex; index < endIndex; index++)
            {
                var renderNodeReference = renderViewStage.SortedRenderNodes[index].RenderNode;
                var renderNode          = GetRenderNode(renderNodeReference);

                var renderSprite = (RenderSprite)renderNode.RenderObject;

                var spriteComp  = renderSprite.SpriteComponent;
                var transfoComp = renderSprite.TransformComponent;

                var sprite = spriteComp.CurrentSprite;
                if (sprite == null)
                {
                    continue;
                }

                // TODO: this should probably be moved to Prepare()
                // Project the position
                // TODO: This could be done in a SIMD batch, but we need to figure-out how to plugin in with RenderMesh object
                var worldPosition = new Vector4(renderSprite.TransformComponent.WorldMatrix.TranslationVector, 1.0f);

                Vector4 projectedPosition;
                Vector4.Transform(ref worldPosition, ref renderView.ViewProjection, out projectedPosition);
                var projectedZ = projectedPosition.Z / projectedPosition.W;

                // Check if the current blend state has changed in any way, if not
                // Note! It doesn't really matter in what order we build the bitmask, the result is not preserved anywhere except in this method
                var currentBatchState = isPicking ? 0U : sprite.IsTransparent ? (spriteComp.PremultipliedAlpha ? 1U : 2U) : 3U;
                currentBatchState = (currentBatchState << 1) + (renderSprite.SpriteComponent.IgnoreDepth ? 1U : 0U);
                currentBatchState = (currentBatchState << 2) + ((uint)renderSprite.SpriteComponent.Sampler);

                if (previousBatchState != currentBatchState)
                {
                    var blendState        = isPicking ? BlendStates.Default : sprite.IsTransparent ? (spriteComp.PremultipliedAlpha ? BlendStates.AlphaBlend : BlendStates.NonPremultiplied) : BlendStates.Opaque;
                    var currentEffect     = isPicking ? batchContext.GetOrCreatePickingSpriteEffect(RenderSystem.EffectSystem) : null; // TODO remove this code when material are available
                    var depthStencilState = renderSprite.SpriteComponent.IgnoreDepth ? DepthStencilStates.None : DepthStencilStates.Default;

                    var samplerState = context.GraphicsDevice.SamplerStates.LinearClamp;
                    if (renderSprite.SpriteComponent.Sampler != SpriteComponent.SpriteSampler.LinearClamp)
                    {
                        switch (renderSprite.SpriteComponent.Sampler)
                        {
                        case SpriteComponent.SpriteSampler.PointClamp:
                            samplerState = context.GraphicsDevice.SamplerStates.PointClamp;
                            break;

                        case SpriteComponent.SpriteSampler.AnisotropicClamp:
                            samplerState = context.GraphicsDevice.SamplerStates.AnisotropicClamp;
                            break;
                        }
                    }

                    if (hasBegin)
                    {
                        batchContext.SpriteBatch.End();
                    }

                    batchContext.SpriteBatch.Begin(context.GraphicsContext, renderView.ViewProjection, SpriteSortMode.Deferred, blendState, samplerState, depthStencilState, RasterizerStates.CullNone, currentEffect);
                    hasBegin = true;
                }
                previousBatchState = currentBatchState;

                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.
                {
                    var compId = RuntimeIdHelper.ToRuntimeId(spriteComp);
                    color = new Color4(compId, 0.0f, 0.0f, 0.0f);
                }

                // 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;
                }

                // calculate normalized position of the center of the sprite (takes into account the possible rotation of the image)
                var normalizedCenter = new Vector2(sprite.Center.X / sourceRegion.Width - 0.5f, 0.5f - sprite.Center.Y / sourceRegion.Height);
                if (sprite.Orientation == ImageOrientation.Rotated90)
                {
                    var oldCenterX = normalizedCenter.X;
                    normalizedCenter.X = -normalizedCenter.Y;
                    normalizedCenter.Y = oldCenterX;
                }
                // apply the offset due to the center of the sprite
                var centerOffset = Vector2.Modulate(normalizedCenter, sprite.SizeInternal);
                worldMatrix.M41 -= centerOffset.X * worldMatrix.M11 + centerOffset.Y * worldMatrix.M21;
                worldMatrix.M42 -= centerOffset.X * worldMatrix.M12 + centerOffset.Y * worldMatrix.M22;
                worldMatrix.M43 -= centerOffset.X * worldMatrix.M13 + centerOffset.Y * worldMatrix.M23;

                // draw the sprite
                batchContext.SpriteBatch.Draw(texture, ref worldMatrix, ref sourceRegion, ref sprite.SizeInternal, ref color, sprite.Orientation, spriteComp.Swizzle, projectedZ);
            }

            if (hasBegin)
            {
                batchContext.SpriteBatch.End();
            }
        }
Example #9
0
        protected override void DrawCore(RenderContext context, RenderItemCollection renderItems, int fromIndex, int toIndex)
        {
            var viewParameters = context.Parameters;

            var device         = context.GraphicsDevice;
            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       = (SpriteStudioProcessor.Data)renderItem.DrawContext;
                var transfoComp       = spriteState.TransformComponent;
                var depthStencilState = device.DepthStencilStates.None;

                foreach (var node in spriteState.SpriteStudioComponent.SortedNodes)
                {
                    if (node.Sprite?.Texture == null || node.Sprite.Region.Width <= 0 || node.Sprite.Region.Height <= 0f || node.Hide != 0)
                    {
                        continue;
                    }

                    // Update the sprite batch

                    BlendState spriteBlending;
                    switch (node.BaseNode.AlphaBlending)
                    {
                    case SpriteStudioBlending.Mix:
                        spriteBlending = device.BlendStates.AlphaBlend;
                        break;

                    case SpriteStudioBlending.Multiplication:
                        spriteBlending = MultBlendState;
                        break;

                    case SpriteStudioBlending.Addition:
                        spriteBlending = device.BlendStates.Additive;
                        break;

                    case SpriteStudioBlending.Subtraction:
                        spriteBlending = SubBlendState;
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }

                    var blendState    = isPicking ? device.BlendStates.Opaque : renderItems.HasTransparency ? spriteBlending : device.BlendStates.Opaque;
                    var currentEffect = isPicking ? GetOrCreatePickingSpriteEffect() : ShadowObject.IsObjectSelected(spriteState.SpriteStudioComponent) ? 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 = node.Sprite.Region;
                    var texture      = node.Sprite.Texture;

                    // skip the sprite if no texture is set.
                    if (texture == null)
                    {
                        continue;
                    }

                    var color4 = Color4.White;
                    if (isPicking)
                    {
                        // TODO move this code corresponding to picking out of the runtime code.
                        color4 = new Color4(RuntimeIdHelper.ToRuntimeId(spriteState.SpriteStudioComponent));
                    }
                    else
                    {
                        if (node.BlendFactor > 0.0f)
                        {
                            switch (node.BlendType) //todo this should be done in a shader
                            {
                            case SpriteStudioBlending.Mix:
                                color4 = Color4.Lerp(color4, node.BlendColor, node.BlendFactor) * node.FinalTransparency;
                                break;

                            case SpriteStudioBlending.Multiplication:
                                color4 = Color4.Lerp(color4, node.BlendColor, node.BlendFactor) * node.FinalTransparency;
                                break;

                            case SpriteStudioBlending.Addition:
                                color4 = Color4.Lerp(color4, node.BlendColor, node.BlendFactor) * node.FinalTransparency;
                                break;

                            case SpriteStudioBlending.Subtraction:
                                color4 = Color4.Lerp(color4, node.BlendColor, node.BlendFactor) * node.FinalTransparency;
                                break;

                            default:
                                throw new ArgumentOutOfRangeException();
                            }
                        }
                        else
                        {
                            color4 *= node.FinalTransparency;
                        }
                    }

                    var worldMatrix = node.ModelTransform * transfoComp.WorldMatrix;

                    // calculate normalized position of the center of the sprite (takes into account the possible rotation of the image)
                    var normalizedCenter = new Vector2(node.Sprite.Center.X / sourceRegion.Width - 0.5f, 0.5f - node.Sprite.Center.Y / sourceRegion.Height);
                    if (node.Sprite.Orientation == ImageOrientation.Rotated90)
                    {
                        var oldCenterX = normalizedCenter.X;
                        normalizedCenter.X = -normalizedCenter.Y;
                        normalizedCenter.Y = oldCenterX;
                    }
                    // apply the offset due to the center of the sprite
                    var size         = node.Sprite.Size;
                    var centerOffset = Vector2.Modulate(normalizedCenter, size);
                    worldMatrix.M41 -= centerOffset.X * worldMatrix.M11 + centerOffset.Y * worldMatrix.M21;
                    worldMatrix.M42 -= centerOffset.X * worldMatrix.M12 + centerOffset.Y * worldMatrix.M22;

                    // draw the sprite
                    sprite3DBatch.Draw(texture, ref worldMatrix, ref sourceRegion, ref size, ref color4, node.Sprite.Orientation, SwizzleMode.None, renderItem.Depth);
                }
            }

            sprite3DBatch.End();
        }
Example #10
0
        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(): ShadowObject.IsObjectSelected(spriteComp) ? 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 = new Color4(RuntimeIdHelper.ToRuntimeId(spriteComp));
                }

                // 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;
                }

                // calculate normalized position of the center of the sprite (takes into account the possible rotation of the image)
                var normalizedCenter = new Vector2(sprite.Center.X / sourceRegion.Width - 0.5f, 0.5f - sprite.Center.Y / sourceRegion.Height);
                if (sprite.Orientation == ImageOrientation.Rotated90)
                {
                    var oldCenterX = normalizedCenter.X;
                    normalizedCenter.X = -normalizedCenter.Y;
                    normalizedCenter.Y = oldCenterX;
                }
                // apply the offset due to the center of the sprite
                var centerOffset = Vector2.Modulate(normalizedCenter, sprite.SizeInternal);
                worldMatrix.M41 -= centerOffset.X * worldMatrix.M11 + centerOffset.Y * worldMatrix.M21;
                worldMatrix.M42 -= centerOffset.X * worldMatrix.M12 + centerOffset.Y * worldMatrix.M22;
                worldMatrix.M43 -= centerOffset.X * worldMatrix.M13 + centerOffset.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();
        }