protected override void OnFillRegionComputed(Point[][] polygonSet) { using (PdnGraphicsPath path = new PdnGraphicsPath()) { path.AddPolygons(polygonSet); using (PdnRegion fillRegion = new PdnRegion(path)) { Rectangle boundingBox = fillRegion.GetBoundsInt(); Surface surface = ((BitmapLayer)ActiveLayer).Surface; RenderArgs ra = new RenderArgs(surface); HistoryMemento ha; using (PdnRegion affected = Utility.SimplifyAndInflateRegion(fillRegion)) { ha = new BitmapHistoryMemento(Name, Image, DocumentWorkspace, DocumentWorkspace.ActiveLayerIndex, affected); } ra.Graphics.CompositingMode = AppEnvironment.GetCompositingMode(); ra.Graphics.FillRegion(brush, fillRegion.GetRegionReadOnly()); HistoryStack.PushNewMemento(ha); ActiveLayer.Invalidate(boundingBox); Update(); } } }
protected override void OnStylusMove(StylusEventArgs e) { base.OnStylusMove(e); PointF currMouseXY = new PointF(e.Fx, e.Fy); if (mouseDown && ((e.Button & mouseButton) != MouseButtons.None)) { float pressure = GetWidth(e.Pressure); float length; PointF a = lastMouseXY; PointF b = currMouseXY; PointF dir = new PointF(b.X - a.X, b.Y - a.Y); PointF norm; PointF[] poly; RectangleF dotRect = Utility.RectangleFromCenter(currMouseXY, pressure); if (pressure > 0.5f) { renderArgs.Graphics.PixelOffsetMode = PixelOffsetMode.Half; } else { renderArgs.Graphics.PixelOffsetMode = PixelOffsetMode.None; } // save direction before normalizing lastDir = dir; // normalize length = Utility.Magnitude(dir); dir.X /= length; dir.Y /= length; // compute normal vector, calculate perpendicular offest from stroke for width norm = new PointF(dir.Y, -dir.X); norm.X *= pressure; norm.Y *= pressure; a.X -= dir.X * 0.1666f; a.Y -= dir.Y * 0.1666f; lastNorm = norm; poly = MakePolygon( new PointF(a.X - lastNorm.X, a.Y - lastNorm.Y), new PointF(a.X + lastNorm.X, a.Y + lastNorm.Y), new PointF(b.X + norm.X, b.Y + norm.Y), new PointF(b.X - norm.X, b.Y - norm.Y)); RectangleF saveRect = RectangleF.Union( dotRect, RectangleF.Union( Utility.PointsToRectangle(poly[0], poly[1]), Utility.PointsToRectangle(poly[2], poly[3]))); saveRect.Inflate(2.0f, 2.0f); // account for anti-aliasing saveRect.Intersect(ActiveLayer.Bounds); // drawing outside of the canvas is a no-op, so don't do anything in that case! // also make sure we're within the clip region if (saveRect.Width > 0 && saveRect.Height > 0 && renderArgs.Graphics.IsVisible(saveRect)) { Rectangle saveRectRounded = Utility.RoundRectangle(saveRect); saveRectRounded.Intersect(ActiveLayer.Bounds); if (saveRectRounded.Width > 0 && saveRectRounded.Height > 0) { SaveRegion(null, saveRectRounded); this.savedRects.Add(saveRectRounded); if (AppEnvironment.AntiAliasing) { renderArgs.Graphics.SmoothingMode = SmoothingMode.AntiAlias; } else { renderArgs.Graphics.SmoothingMode = SmoothingMode.None; } renderArgs.Graphics.CompositingMode = AppEnvironment.GetCompositingMode(); renderArgs.Graphics.FillEllipse(brush, dotRect); // bail out early if the mouse hasn't even moved. If we don't bail out, we'll get a 0-distance move, which will result in a div-by-0 if (lastMouseXY != currMouseXY) { renderArgs.Graphics.FillPolygon(brush, poly, FillMode.Winding); } } bitmapLayer.Invalidate(saveRectRounded); } lastNorm = norm; lastMouseXY = currMouseXY; } else { lastMouseXY = currMouseXY; lastNorm = PointF.Empty; lastDir = PointF.Empty; this.previewRenderer.BrushSize = AppEnvironment.PenInfo.Width / 2.0f; } this.previewRenderer.BrushLocation = currMouseXY; }
private void RenderGradient() { ColorBgra startColor = AppEnvironment.PrimaryColor; ColorBgra endColor = AppEnvironment.SecondaryColor; if (this.shouldSwapColors) { if (AppEnvironment.GradientInfo.AlphaOnly) { // In transparency mode, the color values don't matter. We just need to reverse // and invert the alpha values. byte startAlpha = startColor.A; startColor.A = (byte)(255 - endColor.A); endColor.A = (byte)(255 - startAlpha); } else { Utility.Swap(ref startColor, ref endColor); } } PointF startPointF = this.startPoint; PointF endPointF = this.endPoint; if (this.shouldConstrain) { if (this.mouseNub == this.startNub) { ConstrainPoints(endPointF, ref startPointF); } else { ConstrainPoints(startPointF, ref endPointF); } } RestoreSavedRegion(); Surface surface = ((BitmapLayer)DocumentWorkspace.ActiveLayer).Surface; PdnRegion clipRegion = DocumentWorkspace.Selection.CreateRegion(); SaveRegion(clipRegion, clipRegion.GetBoundsInt()); RenderGradient(surface, clipRegion, AppEnvironment.GetCompositingMode(), startPointF, startColor, endPointF, endColor); using (PdnRegion simplified = Utility.SimplifyAndInflateRegion(clipRegion, Utility.DefaultSimplificationFactor, 0)) { DocumentWorkspace.ActiveLayer.Invalidate(simplified); } clipRegion.Dispose(); // Set up status bar text double angle = -180.0 * Math.Atan2(endPointF.Y - startPointF.Y, endPointF.X - startPointF.X) / Math.PI; MeasurementUnit units = AppWorkspace.Units; double offsetXPhysical = Document.PixelToPhysicalX(endPointF.X - startPointF.X, units); double offsetYPhysical = Document.PixelToPhysicalY(endPointF.Y - startPointF.Y, units); double offsetLengthPhysical = Math.Sqrt(offsetXPhysical * offsetXPhysical + offsetYPhysical * offsetYPhysical); string numberFormat; string unitsAbbreviation; if (units != MeasurementUnit.Pixel) { string unitsAbbreviationName = "MeasurementUnit." + units.ToString() + ".Abbreviation"; unitsAbbreviation = PdnResources.GetString(unitsAbbreviationName); numberFormat = "F2"; } else { unitsAbbreviation = string.Empty; numberFormat = "F0"; } string unitsString = PdnResources.GetString("MeasurementUnit." + units.ToString() + ".Plural"); string statusText = string.Format( this.helpTextWhileAdjustingFormat, offsetXPhysical.ToString(numberFormat), unitsAbbreviation, offsetYPhysical.ToString(numberFormat), unitsAbbreviation, offsetLengthPhysical.ToString("F2"), unitsString, angle.ToString("F2")); SetStatus(this.toolIcon, statusText); // Make sure everything is on screen. Update(); }
protected void RenderShape() { // create the Pen we will use to draw with Pen outlinePen = null; Brush interiorBrush = null; PenInfo pi = AppEnvironment.PenInfo; BrushInfo bi = AppEnvironment.BrushInfo; ColorBgra primary = AppEnvironment.PrimaryColor; ColorBgra secondary = AppEnvironment.SecondaryColor; if (!ForceShapeDrawType && AppEnvironment.ShapeDrawType == ShapeDrawType.Interior) { Utility.Swap(ref primary, ref secondary); } // Initialize pens and brushes to the correct colors if ((mouseButton & MouseButtons.Left) == MouseButtons.Left) { outlinePen = pi.CreatePen(AppEnvironment.BrushInfo, primary.ToColor(), secondary.ToColor()); interiorBrush = bi.CreateBrush(secondary.ToColor(), primary.ToColor()); } else if ((mouseButton & MouseButtons.Right) == MouseButtons.Right) { outlinePen = pi.CreatePen(AppEnvironment.BrushInfo, secondary.ToColor(), primary.ToColor()); interiorBrush = bi.CreateBrush(primary.ToColor(), secondary.ToColor()); } if (!this.UseDashStyle) { outlinePen.DashStyle = DashStyle.Solid; } outlinePen.LineJoin = LineJoin.MiterClipped; outlinePen.MiterLimit = 2; // redraw the old saveSurface if (interiorSaveRegion != null) { RestoreRegion(interiorSaveRegion); interiorSaveRegion.Dispose(); interiorSaveRegion = null; } if (outlineSaveRegion != null) { RestoreRegion(outlineSaveRegion); outlineSaveRegion.Dispose(); outlineSaveRegion = null; } // anti-aliasing? Don't mind if I do if (AppEnvironment.AntiAliasing) { renderArgs.Graphics.SmoothingMode = SmoothingMode.AntiAlias; } else { renderArgs.Graphics.SmoothingMode = SmoothingMode.None; } // also set the pixel offset mode renderArgs.Graphics.PixelOffsetMode = GetPixelOffsetMode(); // figure out how we're going to draw ShapeDrawType drawType; if (ForceShapeDrawType) { drawType = ForcedShapeDrawType; } else { drawType = AppEnvironment.ShapeDrawType; } // get the region we want to save points = this.TrimShapePath(points); PointF[] pointsArray = points.ToArray(); PdnGraphicsPath shapePath = CreateShapePath(pointsArray); if (shapePath != null) { // create non-optimized interior region PdnRegion interiorRegion = new PdnRegion(shapePath); // create non-optimized outline region PdnRegion outlineRegion; using (PdnGraphicsPath outlinePath = (PdnGraphicsPath)shapePath.Clone()) { try { outlinePath.Widen(outlinePen); outlineRegion = new PdnRegion(outlinePath); } // Sometimes GDI+ gets cranky if we have a very small shape (e.g. all points // are coincident). catch (OutOfMemoryException) { outlineRegion = new PdnRegion(shapePath); } } // create optimized outlineRegion for purposes of rendering, if it is possible to do so // shapes will often provide an "optimized" region that circumvents the fact that // we'd otherwise get a region that encompasses the outline *and* the interior, thus // slowing rendering significantly in many cases. RectangleF[] optimizedOutlineRegion = GetOptimizedShapeOutlineRegion(pointsArray, shapePath); PdnRegion invalidOutlineRegion; if (optimizedOutlineRegion != null) { Utility.InflateRectanglesInPlace(optimizedOutlineRegion, (int)(outlinePen.Width + 2)); invalidOutlineRegion = Utility.RectanglesToRegion(optimizedOutlineRegion); } else { invalidOutlineRegion = Utility.SimplifyAndInflateRegion(outlineRegion, Utility.DefaultSimplificationFactor, (int)(outlinePen.Width + 2)); } // create optimized interior region PdnRegion invalidInteriorRegion = Utility.SimplifyAndInflateRegion(interiorRegion, Utility.DefaultSimplificationFactor, 3); PdnRegion invalidRegion = new PdnRegion(); invalidRegion.MakeEmpty(); // set up alpha blending renderArgs.Graphics.CompositingMode = AppEnvironment.GetCompositingMode(); SaveRegion(invalidOutlineRegion, invalidOutlineRegion.GetBoundsInt()); this.outlineSaveRegion = invalidOutlineRegion; if ((drawType & ShapeDrawType.Outline) != 0) { shapePath.Draw(renderArgs.Graphics, outlinePen); } invalidRegion.Union(invalidOutlineRegion); // draw shape if ((drawType & ShapeDrawType.Interior) != 0) { SaveRegion(invalidInteriorRegion, invalidInteriorRegion.GetBoundsInt()); this.interiorSaveRegion = invalidInteriorRegion; renderArgs.Graphics.FillPath(interiorBrush, shapePath); invalidRegion.Union(invalidInteriorRegion); } else { invalidInteriorRegion.Dispose(); invalidInteriorRegion = null; } bitmapLayer.Invalidate(invalidRegion); invalidRegion.Dispose(); invalidRegion = null; outlineRegion.Dispose(); outlineRegion = null; interiorRegion.Dispose(); interiorRegion = null; } Update(); if (shapePath != null) { shapePath.Dispose(); shapePath = null; } outlinePen.Dispose(); interiorBrush.Dispose(); }