Exemplo n.º 1
0
        /// <summary>
        /// Constructor that blends and image with a background color.
        /// </summary>
        /// <param name="image">An image that will be premultiplied and blended with the background color.</param>
        /// <param name="backgroundColor">Color for lowest blend layer. Must not be premultiplied.</param>
        public RenderBuffer(Color[,] image, Color backgroundColor)
            : this(image.GetLength(0), image.GetLength(1))
        {
            Color background = ColorOperations.PreMultiplyColor(backgroundColor);

            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    // copy image over background color using SRC over alpha blend
                    frameBuffer[x, y] = ColorOperations.PreMultipliedAlphaBlend(
                        ColorOperations.PreMultiplyColor(image[x, y]),
                        background);
                }
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Writes a pixel to the buffer according to depth-test for single pass rendering.
        /// </summary>
        /// <param name="x">x index</param>
        /// <param name="y">y index</param>
        /// <param name="z">Depth buffer value</param>
        /// <param name="premultColor">Premultiplied Frame buffer value</param>
        /// <param name="premultTolerance">Premultiplied Tolerance buffer value</param>
        public void SetPixel(int x, int y, float z, Color premultColor, Color premultTolerance)
        {
            if (x >= 0 && x < width && y >= 0 && y < height && z >= 0 && z <= 1.0f)
            {
                bool isZFightingPossible = IsPixelRendered(x, y);
                bool drawPixel           = DepthTest(z, zBuffer[x, y]);
                if (drawPixel)
                {
                    // Write to frame buffer according to alpha value of pixel
                    frameBuffer[x, y] = ColorOperations.PreMultipliedAlphaBlend(
                        premultColor,
                        frameBuffer[x, y]);

                    // We have a pre-multiplied tolerance value
                    toleranceBuffer[x, y] = ColorOperations.PreMultipliedToleranceBlend(
                        premultTolerance,
                        toleranceBuffer[x, y],
                        premultColor.A);
                }

                // See if we were within tolerance of another test result
                if (isZFightingPossible)
                {
                    if (DepthTestWithinTolerance(z, zBuffer[x, y], RenderTolerance.ZBufferTolerance))
                    {
                        // If so, ignore this pixel, since we can't be sure if it's right
                        toleranceBuffer[x, y] = Color.FromArgb(0, 255, 255, 255);
                    }
                }
                else if (z < RenderTolerance.NearPlaneTolerance || 1.0 - RenderTolerance.FarPlaneTolerance < z)
                {
                    // If we're right on the near/far clipping plane, we can't be sure if this pixel is right.

                    // Note that the tolerance at the near plane will be considerably more than that of the
                    //  far plane if we are using a perspective camera to view this scene.
                    toleranceBuffer[x, y] = Color.FromArgb(0, 255, 255, 255);
                }

                if (drawPixel && writeToZBuffer)
                {
                    zBuffer[x, y] = z;
                }
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Blend the contents of the RenderBuffer with a background color
        /// </summary>
        public void AddBackground(Color opaqueBackgroundColor)
        {
            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    // We keep our colors and tolerances premultiplied.
                    // Do the tolerance blend first so that we have the correct alpha value from the framebuffer
                    toleranceBuffer[x, y] = ColorOperations.PreMultipliedToleranceBlend(
                        toleranceBuffer[x, y],
                        toleranceBufferClearValue,
                        frameBuffer[x, y].A);

                    frameBuffer[x, y] = ColorOperations.PreMultipliedAlphaBlend(
                        frameBuffer[x, y],
                        opaqueBackgroundColor);
                }
            }
        }
Exemplo n.º 4
0
        private void ApplyDropShadow(DropShadowBitmapEffect effect, Rect effectInput)
        {
            RenderBuffer clone = Clone();

            clone.boundsOverride = effectInput;
            double depth       = MathEx.ConvertToAbsolutePixels(effect.ShadowDepth);
            double angle       = MathEx.ToRadians(effect.Direction);
            Vector pixelOffset = new Vector(depth * Math.Cos(angle), depth * Math.Sin(-angle));
            Color  effectColor = effect.Color;

            effectColor = ColorOperations.ScaleAlpha(effectColor, effect.Opacity);
            double blurRadius = 1.0 + (effect.Softness * 9.0);

            int xEnd = (int)effectInput.Right;
            int yEnd = (int)effectInput.Bottom;

            for (int y = (int)effectInput.Y; y < yEnd; y++)
            {
                for (int x = (int)effectInput.X; x < xEnd; x++)
                {
                    Point point = new Point(x + Const.pixelCenterX, y + Const.pixelCenterY) - pixelOffset;
                    Color?color = clone.GetPixelSample(point, blurRadius);

                    if (color.HasValue)
                    {
                        double opacity = ColorOperations.ByteToDouble(color.Value.A);
                        Color  shadow  = ColorOperations.ScaleAlpha(effectColor, opacity);
                        shadow            = ColorOperations.PreMultiplyColor(shadow);
                        frameBuffer[x, y] = ColorOperations.PreMultipliedAlphaBlend(clone.frameBuffer[x, y], shadow);

                        if (frameBuffer[x, y] != clone.frameBuffer[x, y])
                        {
                            // Transfer the tolerance (silhouette, etc) over too
                            Color tolerance = clone.GetToleranceSample(point, blurRadius);
                            toleranceBuffer[x, y] = ColorOperations.Max(tolerance, clone.toleranceBuffer[x, y]);
                        }
                    }
                }
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// Lights this pixel using precomputed lighting information.
        /// </summary>
        /// <param name="v">Interpolated vertex for this pixel position.</param>
        protected override void ComputePixelProgram(Vertex v)
        {
            bool  rendered = false;
            Color totalTexturingTolerance = emptyColor;

            for (int pass = 0; pass < textures.Length; pass++)
            {
                // A Filter can be null if the Material or the Brush are null.
                // For those cases, we skip the material entirely.
                if (textures[pass] == null)
                {
                    continue;
                }
                TextureFilter currentTexture = textures[pass];
                rendered = true;

                // We need extra information for trilinear
                if (currentTexture is TrilinearTextureFilter)
                {
                    ((TrilinearTextureFilter)currentTexture).MipMapFactor = v.MipMapFactor;
                }

                // Textures are not stored in premultiplied color space.
                // This means that we have to wait until we find the lookup tolerance before we can premultiply
                //  (otherwise Alpha will be way off)

                Color texel          = currentTexture.FilteredTextureLookup(v.TextureCoordinates);
                Color texelTolerance = emptyColor;
                if (currentTexture.HasErrorEstimation)
                {
                    texelTolerance = currentTexture.FilteredErrorLookup(
                        v.UVToleranceMin,
                        v.UVToleranceMax,
                        texel);
                }

                // Now we can premultiply.
                Color premultTexel          = ColorOperations.PreMultiplyColor(texel);
                Color premultTexelTolerance = ColorOperations.PreMultiplyTolerance(texelTolerance, texel.A);

                // Modulate precomputed lighting (which is also premultiplied) by the Brush value
                Color premultColor     = ColorOperations.Modulate(v.PrecomputedLight[pass], premultTexel);
                Color premultTolerance = ColorOperations.Modulate(v.PrecomputedLight[pass], premultTexelTolerance);

                // PrecomputedLightTolerance is NOT premultipled yet (see ComputeVertexProgram above).
                //  This is because we needed to know the final alpha value of lighting * texture.
                //
                Color premultLightTolerance = ColorOperations.PreMultiplyTolerance(v.PrecomputedLightTolerance[pass], premultColor.A);
                premultTolerance = ColorOperations.Add(premultTolerance, premultLightTolerance);

                // For additive materials, we need to force the alpha channel to zero.
                // See notes on premultiplied blending in ColorOperations.cs
                if (currentTexture.MaterialType != MaterialType.Diffuse)
                {
                    premultColor.A = 0x00;
                    // Nothing needs to be done to tolerance's alpha
                    //  because the framebuffer's alpha value will be used in the blend
                }

                // we need to blend
                // Write to frame buffer according to alpha value of pixel
                v.Color = ColorOperations.PreMultipliedAlphaBlend(premultColor, v.Color);

                // Accumulate tolerance for each material pass
                totalTexturingTolerance = ColorOperations.PreMultipliedToleranceBlend(
                    premultTolerance,
                    totalTexturingTolerance,
                    premultColor.A);
            }

            // Only set a pixel if we actually rendered at least one material for it ...
            if (rendered)
            {
                // Add texturing tolerance to our existing lighting tolerance.
                v.ColorTolerance = ColorOperations.Add(v.ColorTolerance, totalTexturingTolerance);

                // Send the pixel to be rendered
                buffer.SetPixel(
                    (int)Math.Floor(v.ProjectedPosition.X),
                    (int)Math.Floor(v.ProjectedPosition.Y),
                    (float)v.ProjectedPosition.Z,
                    v.Color,
                    v.ColorTolerance
                    );
            }
        }