public HdrColor(Color color) { a = ColorOperations.ByteToDouble(color.A); r = ColorOperations.ByteToDouble(color.R); g = ColorOperations.ByteToDouble(color.G); b = ColorOperations.ByteToDouble(color.B); }
public static Color WeightedSum(Color c1, Color c2, Color c3, Weights weights) { double a, r, g, b; a = WeightedSum(ColorOperations.ByteToDouble(c1.A), ColorOperations.ByteToDouble(c2.A), ColorOperations.ByteToDouble(c3.A), weights); r = WeightedSum(ColorOperations.ByteToDouble(c1.R), ColorOperations.ByteToDouble(c2.R), ColorOperations.ByteToDouble(c3.R), weights); g = WeightedSum(ColorOperations.ByteToDouble(c1.G), ColorOperations.ByteToDouble(c2.G), ColorOperations.ByteToDouble(c3.G), weights); b = WeightedSum(ColorOperations.ByteToDouble(c1.B), ColorOperations.ByteToDouble(c2.B), ColorOperations.ByteToDouble(c3.B), weights); return(ColorOperations.ColorFromArgb(a, r, g, b)); }
/// <summary> /// Apply an opacity mask based on the alpha values of a brush. /// </summary> public void ApplyOpacityMask(Brush brush) { if (brush == null) { return; } Color[,] colors = TextureGenerator.RenderBrushToColorArray(brush, width, height); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { double opacity = ColorOperations.ByteToDouble(colors[x, y].A); frameBuffer[x, y] = ColorOperations.PreMultipliedOpacityScale(frameBuffer[x, y], opacity); } } }
/// <summary> /// This function sums over the tolerance buffer and returns what /// percentage of an image's color information is being thrown out /// (We don't include alpha in our sum) /// </summary> public static string GetErrorStatistics(RenderBuffer buffer) { double percentage = 0.0; for (int y = 0; y < buffer.Height; y++) { for (int x = 0; x < buffer.Width; x++) { percentage += ColorOperations.ByteToDouble(buffer.ToleranceBuffer[x, y].R); percentage += ColorOperations.ByteToDouble(buffer.ToleranceBuffer[x, y].G); percentage += ColorOperations.ByteToDouble(buffer.ToleranceBuffer[x, y].B); } } // We multiply by 100 for percent, then divide by 3 for "R" "G" and "B" percentage = 100.0 * percentage / (3.0 * (double)buffer.Width * (double)buffer.Height); return(String.Format("Color data ignored due to tolerance criteria: {0}%.", percentage.ToString("##0.00###"))); }
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]); } } } } }
/// <summary> /// Clip the regions specified by the Geometry out of the frame buffer. /// </summary> public void ApplyClip(Geometry clip) { if (clip == null) { return; } Color[,] clipColors = TextureGenerator.RenderBrushToColorArray(GetClipBrush(clip), width, height); // Clipping is anti-aliased. Need tolerance around clip edges. Color[,] tolColors = TextureGenerator.RenderBrushToColorArray(GetClipTolerance(clip), width, height); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { double opacity = ColorOperations.ByteToDouble(clipColors[x, y].A); frameBuffer[x, y] = ColorOperations.PreMultipliedOpacityScale(frameBuffer[x, y], opacity); Color tolerance = new Color(); tolerance.A = tolerance.R = tolerance.G = tolerance.B = tolColors[x, y].A; toleranceBuffer[x, y] = ColorOperations.Add(toleranceBuffer[x, y], tolerance); } } }
/// <summary> /// Gouraud shading computes lighting per-vertex, in this method. /// Final pixel values are gathered from interpolating between pixels. /// Lighting is precomputed in this step per material. /// </summary> /// <param name="v">Input/Output per-vertex data.</param> protected override void ComputeVertexProgram(Vertex v) { // No color here ... v.Color = emptyColor; // Tolerance v.ColorTolerance = emptyColor; v.PrecomputedLight = new Color[textures.Length]; v.PrecomputedLightTolerance = new Color[textures.Length]; int textureIndex = 0; Point3D position = v.PositionAsPoint3D; Vector3D normal = v.Normal; // Precompute lighting for all textures foreach (TextureFilter texture in textures) { HdrColor color = emptyColor; HdrColor tolerance = emptyColor; if (texture != null) { // Lighting is done in Premultiplied color space. // // - BIG NOTE! - We do not actually premultiply the light contribution // because lighting is always opaque and premultiplying opaque colors // is a no-op. // // - Tolerance CANNOT be done in Premultiplied color space because // it needs to know the final pixel color in order to premultiply properly. // We won't know the final pixel color until ComputePixelProgram is called. // We ignore Alpha values during the computation and set the final value to // materialColor.A at the end. This is why you will not see any clamping of // light values, etc in the code below. Color materialColor = ColorOperations.PreMultiplyColor(texture.MaterialColor); switch (texture.MaterialType) { case MaterialType.Diffuse: foreach (LightEquation light in lightEquations) { Color lightContribution = light.IluminateDiffuse(position, normal); if (light is AmbientLightEquation) { // AmbientColor knobs are reminiscent of additive material passes // because the alpha value will not be considered in the final color value // (i.e. premultiply to scale RGB by alpha, then never use alpha again) Color ambientColor = ColorOperations.PreMultiplyColor(texture.AmbientColor); color += ColorOperations.Modulate(lightContribution, ambientColor); } else { color += ColorOperations.Modulate(lightContribution, materialColor); } tolerance += light.GetLastError(); } break; case MaterialType.Specular: foreach (LightEquation light in lightEquations) { // Don't need to check light equation type, since Ambient will return black Color lightContribution = light.IluminateSpecular(position, normal, texture.SpecularPower); color += ColorOperations.Modulate(lightContribution, materialColor); tolerance += light.GetLastError(); } break; case MaterialType.Emissive: color = materialColor; break; } // Alpha is only considered at the end. Overwrite whatever happened during the precomputation. // - Note that the alpha of the AmbientColor knob is NOT considered in the final value. color.A = ColorOperations.ByteToDouble(materialColor.A); } v.PrecomputedLight[textureIndex] = color.ClampedValue; v.PrecomputedLightTolerance[textureIndex] = tolerance.ClampedValue; textureIndex++; } }
public override Color FilteredTextureLookup(Point uv) { double x = uv.X * width; double y = uv.Y * height; // Define where we want to have texel centers double texelCenterX = 0.5; double texelCenterY = 0.5; // Compute integer array indices of texel above and to the left of (x,y) int topLeftX = (int)Math.Floor(x - (1 - texelCenterX)); int topLeftY = (int)Math.Floor(y - (1 - texelCenterY)); // Get colors of 4 nearest neighbours Color ctl = GetColor(topLeftX, topLeftY); Color ctr = GetColor(topLeftX + 1, topLeftY); Color cbl = GetColor(topLeftX, topLeftY + 1); Color cbr = GetColor(topLeftX + 1, topLeftY + 1); // Shift (x,y) to align it with array indices x -= texelCenterX; y -= texelCenterY; // Compute position within our texel double dx = x - Math.Floor(x); double dy = y - Math.Floor(y); // Argh! double ctlA = ColorOperations.ByteToDouble(ctl.A); double ctlR = ColorOperations.ByteToDouble(ctl.R); double ctlG = ColorOperations.ByteToDouble(ctl.G); double ctlB = ColorOperations.ByteToDouble(ctl.B); double cblA = ColorOperations.ByteToDouble(cbl.A); double cblR = ColorOperations.ByteToDouble(cbl.R); double cblG = ColorOperations.ByteToDouble(cbl.G); double cblB = ColorOperations.ByteToDouble(cbl.B); double ctrA = ColorOperations.ByteToDouble(ctr.A); double ctrR = ColorOperations.ByteToDouble(ctr.R); double ctrG = ColorOperations.ByteToDouble(ctr.G); double ctrB = ColorOperations.ByteToDouble(ctr.B); double cbrA = ColorOperations.ByteToDouble(cbr.A); double cbrR = ColorOperations.ByteToDouble(cbr.R); double cbrG = ColorOperations.ByteToDouble(cbr.G); double cbrB = ColorOperations.ByteToDouble(cbr.B); // Precompute values for perf reasons double ddx = 1 - dx; double ddy = 1 - dy; double k1 = ddx * ddy; double k2 = dx * ddy; double k3 = ddx * dy; double k4 = dx * dy; // Perform interpolation, store result in a, r, g, and b double a = k1 * ctlA + k2 * ctrA + k3 * cblA + k4 * cbrA; double r = k1 * ctlR + k2 * ctrR + k3 * cblR + k4 * cbrR; double g = k1 * ctlG + k2 * ctrG + k3 * cblG + k4 * cbrG; double b = k1 * ctlB + k2 * ctrB + k3 * cblB + k4 * cbrB; return(ColorOperations.ColorFromArgb(a, r, g, b)); }