public GlyphImage CreateGlyphImage(GlyphPathBuilder builder, float pxscale) { _txToVxs.Reset(); //1. builder read shape and translate it with _txToVxs builder.ReadShapes(_txToVxs); using (VxsTemp.Borrow(out var glyphVxs, out var vxs2)) { //2. write translated data (in the _txToVxs) to glyphVxs _txToVxs.WriteOutput(glyphVxs, pxscale); RectD bounds = glyphVxs.GetBoundingRect(); //-------------------------------------------- int w = (int)System.Math.Ceiling(bounds.Width); int h = (int)System.Math.Ceiling(bounds.Height); if (w < 5) { w = 5; } if (h < 5) { h = 5; } //we need some margin int horizontal_margin = 1; int vertical_margin = 1; //translate to positive quadrant and use minimum space int dx = (int)Math.Ceiling((bounds.Left < 0) ? -bounds.Left : 0); int dy = 0; //vertical adjust =>since we need to move it, then move it with integer value if (bounds.Bottom < 0) { dy = (int)Math.Ceiling(-bounds.Bottom); } else if (bounds.Bottom > 0) { dy = (int)Math.Floor(-bounds.Bottom); } dx += horizontal_margin; //margin left dy += vertical_margin; //-------------------------------------------- w = dx + w + horizontal_margin; //+right margin h = vertical_margin + h + vertical_margin; //+bottom margin AggPainter painter = Painter; if (TextureKind == TextureKind.StencilLcdEffect) { glyphVxs.TranslateToNewVxs(dx + 0.33f, dy, vxs2); //offset to proper x of subpixel rendering *** glyphVxs = vxs2; RectD bounds2 = vxs2.GetBoundingRect(); if (w < bounds2.Right) { w = (int)Math.Ceiling(bounds2.Right); } // painter.UseSubPixelLcdEffect = true; //we use white glyph on black bg for this texture painter.Clear(Color.Black); painter.FillColor = Color.White; painter.Fill(glyphVxs); //apply sharpen filter //painter.DoFilter(new RectInt(0, h, w, 0), 2); //painter.DoFilter(new RectInt(0, h, w, 0), 2); //? } else { glyphVxs.TranslateToNewVxs(dx, dy, vxs2); glyphVxs = vxs2; painter.UseSubPixelLcdEffect = false; if (TextureKind == TextureKind.StencilGreyScale) { painter.Clear(Color.Empty); painter.FillColor = Color.Black; } else { painter.Clear(BackGroundColor); painter.FillColor = this.GlyphColor; } painter.Fill(glyphVxs); } // if (w > painter.RenderSurface.DestBitmap.Width) { w = painter.RenderSurface.DestBitmap.Width; } if (h > painter.RenderSurface.DestBitmap.Height) { h = painter.RenderSurface.DestBitmap.Height; } var glyphImage = new GlyphImage(w, h); #if DEBUG if (dx < short.MinValue || dx > short.MaxValue) { throw new NotSupportedException(); } if (dy < short.MinValue || dy > short.MaxValue) { throw new NotSupportedException(); } #endif glyphImage.TextureOffsetX = (short)dx; glyphImage.TextureOffsetY = (short)dy; glyphImage.SetImageBuffer(MemBitmapExtensions.CopyImgBuffer(painter.RenderSurface.DestBitmap, w, h), false); //copy data from agg canvas to glyph image return(glyphImage); } }
public GlyphImage CreateGlyphImage(GlyphPathBuilder builder, float pxscale) { //1. create var txToVxs = new GlyphTranslatorToVxs(); builder.ReadShapes(txToVxs); // //create new one var glyphVxs = new VertexStore(); txToVxs.WriteOutput(glyphVxs, pxscale); //find bound //-------------------------------------------- //GlyphImage glyphImg = new GlyphImage() RectD bounds = RectD.ZeroIntersection; PixelFarm.CpuBlit.VertexProcessing.BoundingRect.GetBoundingRect(new VertexStoreSnap(glyphVxs), ref bounds); ////-------------------------------------------- int w = (int)System.Math.Ceiling(bounds.Width); int h = (int)System.Math.Ceiling(bounds.Height); if (w < 5) { w = 5; } if (h < 5) { h = 5; } //translate to positive quadrant // double dx = (bounds.Left < 0) ? -bounds.Left : 0; double dy = (bounds.Bottom < 0) ? -bounds.Bottom : 0; // dx = Math.Ceiling(dx); //since we need to move it, then move it with integer value dy = Math.Ceiling(dy); //since we need to move it, then move it with integer value //we need some borders int horizontal_margin = 1; //'margin' 1px int vertical_margin = 1; //margin 1 px dx += horizontal_margin; //+ left margin dy += vertical_margin; //+ top margin //-------------------------------------------- //create glyph img w = (int)Math.Ceiling(dx + w + horizontal_margin); //+right margin h = (int)Math.Ceiling(dy + h + vertical_margin); //+bottom margin ActualBitmap img = new ActualBitmap(w, h); AggPainter painter = AggPainter.Create(img); if (TextureKind == TextureKind.StencilLcdEffect) { VertexStore vxs2 = new VertexStore(); glyphVxs.TranslateToNewVxs(dx + 0.33f, dy, vxs2); //offset to proper x of subpixel rendering *** glyphVxs = vxs2; // painter.UseSubPixelLcdEffect = true; //we use white glyph on black bg for this texture painter.Clear(Color.Black); painter.FillColor = Color.White; painter.Fill(glyphVxs); //apply sharpen filter //painter.DoFilter(new RectInt(0, h, w, 0), 2); //painter.DoFilter(new RectInt(0, h, w, 0), 2); //? } else { VertexStore vxs2 = new VertexStore(); glyphVxs.TranslateToNewVxs(dx, dy, vxs2); glyphVxs = vxs2; painter.UseSubPixelLcdEffect = false; if (TextureKind == TextureKind.StencilGreyScale) { painter.Clear(Color.Empty); painter.FillColor = Color.Black; } else { painter.Clear(BackGroundColor); painter.FillColor = this.GlyphColor; } painter.Fill(glyphVxs); } // var glyphImage = new GlyphImage(w, h); glyphImage.TextureOffsetX = dx; glyphImage.TextureOffsetY = dy; glyphImage.SetImageBuffer(ActualBitmapExtensions.CopyImgBuffer(img, w), false); //copy data from agg canvas to glyph image return(glyphImage); }
//template<class Scanline, class Ras> public void RenderGourand(Painter p) { float alpha = this.AlphaValue; float brc = 1; #if SourceDepth24 pixfmt_alpha_blend_rgb pf = new pixfmt_alpha_blend_rgb(backBuffer, new blender_bgr()); #else #endif ////var destImage = gx.DestImage; ////span_allocator span_alloc = new span_allocator(); //specific for agg AggPainter painter = p as AggPainter; if (painter == null) { return; } // AggRenderSurface aggRdsf = painter.RenderSurface; SpanGenGouraudRGBA gouraudSpanGen = new SpanGenGouraudRGBA(); aggRdsf.ScanlineRasterizer.ResetGamma(new GammaLinear(0.0f, this.LinearGamma)); double d = this.DilationValue; // Six triangles double xc = (m_x[0] + m_x[1] + m_x[2]) / 3.0; double yc = (m_y[0] + m_y[1] + m_y[2]) / 3.0; double x1 = (m_x[1] + m_x[0]) / 2 - (xc - (m_x[1] + m_x[0]) / 2); double y1 = (m_y[1] + m_y[0]) / 2 - (yc - (m_y[1] + m_y[0]) / 2); double x2 = (m_x[2] + m_x[1]) / 2 - (xc - (m_x[2] + m_x[1]) / 2); double y2 = (m_y[2] + m_y[1]) / 2 - (yc - (m_y[2] + m_y[1]) / 2); double x3 = (m_x[0] + m_x[2]) / 2 - (xc - (m_x[0] + m_x[2]) / 2); double y3 = (m_y[0] + m_y[2]) / 2 - (yc - (m_y[0] + m_y[2]) / 2); gouraudSpanGen.SetColor(ColorEx.Make(1, 0, 0, alpha), ColorEx.Make(0, 1, 0, alpha), ColorEx.Make(brc, brc, brc, alpha)); gouraudSpanGen.SetTriangle(m_x[0], m_y[0], m_x[1], m_y[1], xc, yc, d); var tmpVxs = _tmpVxs; painter.Fill(gouraudSpanGen.MakeVxs(tmpVxs), gouraudSpanGen); tmpVxs.Clear(); gouraudSpanGen.SetColor(ColorEx.Make(0, 1, 0, alpha), ColorEx.Make(0, 0, 1, alpha), ColorEx.Make(brc, brc, brc, alpha)); gouraudSpanGen.SetTriangle(m_x[1], m_y[1], m_x[2], m_y[2], xc, yc, d); painter.Fill(gouraudSpanGen.MakeVxs(tmpVxs), gouraudSpanGen); tmpVxs.Clear(); gouraudSpanGen.SetColor(ColorEx.Make(0, 0, 1, alpha), ColorEx.Make(1, 0, 0, alpha), ColorEx.Make(brc, brc, brc, alpha)); gouraudSpanGen.SetTriangle(m_x[2], m_y[2], m_x[0], m_y[0], xc, yc, d); painter.Fill(gouraudSpanGen.MakeVxs(tmpVxs), gouraudSpanGen); tmpVxs.Clear(); brc = 1 - brc; gouraudSpanGen.SetColor(ColorEx.Make(1, 0, 0, alpha), ColorEx.Make(0, 1, 0, alpha), ColorEx.Make(brc, brc, brc, alpha)); gouraudSpanGen.SetTriangle(m_x[0], m_y[0], m_x[1], m_y[1], x1, y1, d); painter.Fill(gouraudSpanGen.MakeVxs(tmpVxs), gouraudSpanGen); tmpVxs.Clear(); gouraudSpanGen.SetColor(ColorEx.Make(0, 1, 0, alpha), ColorEx.Make(0, 0, 1, alpha), ColorEx.Make(brc, brc, brc, alpha)); gouraudSpanGen.SetTriangle(m_x[1], m_y[1], m_x[2], m_y[2], x2, y2, d); painter.Fill(gouraudSpanGen.MakeVxs(tmpVxs), gouraudSpanGen); tmpVxs.Clear(); gouraudSpanGen.SetColor(ColorEx.Make(0, 0, 1, alpha), ColorEx.Make(1, 0, 0, alpha), ColorEx.Make(brc, brc, brc, alpha)); gouraudSpanGen.SetTriangle(m_x[2], m_y[2], m_x[0], m_y[0], x3, y3, d); painter.Fill(gouraudSpanGen.MakeVxs(tmpVxs), gouraudSpanGen); tmpVxs.Clear(); }
//template<class Scanline, class Ras> public void RenderGourand(Painter p) { float alpha = this.AlphaValue; float brc = 1; #if SourceDepth24 pixfmt_alpha_blend_rgb pf = new pixfmt_alpha_blend_rgb(backBuffer, new blender_bgr()); #else #endif ////var destImage = gx.DestImage; ////span_allocator span_alloc = new span_allocator(); //specific for agg AggPainter painter = p as AggPainter; if (painter == null) { return; } // AggRenderSurface aggsx = painter.RenderSurface; RGBAGouraudSpanGen gouraudSpanGen = new RGBAGouraudSpanGen(); GouraudVerticeBuilder grBuilder = new GouraudVerticeBuilder(); aggsx.ScanlineRasterizer.ResetGamma(new GammaLinear(0.0f, this.LinearGamma)); grBuilder.DilationValue = (float)this.DilationValue; // Six triangles double xc = (_x[0] + _x[1] + _x[2]) / 3.0; double yc = (_y[0] + _y[1] + _y[2]) / 3.0; double x1 = (_x[1] + _x[0]) / 2 - (xc - (_x[1] + _x[0]) / 2); double y1 = (_y[1] + _y[0]) / 2 - (yc - (_y[1] + _y[0]) / 2); double x2 = (_x[2] + _x[1]) / 2 - (xc - (_x[2] + _x[1]) / 2); double y2 = (_y[2] + _y[1]) / 2 - (yc - (_y[2] + _y[1]) / 2); double x3 = (_x[0] + _x[2]) / 2 - (xc - (_x[0] + _x[2]) / 2); double y3 = (_y[0] + _y[2]) / 2 - (yc - (_y[0] + _y[2]) / 2); grBuilder.SetColor(ColorEx.Make(1, 0, 0, alpha), ColorEx.Make(0, 1, 0, alpha), ColorEx.Make(brc, brc, brc, alpha)); grBuilder.SetTriangle(_x[0], _y[0], _x[1], _y[1], xc, yc); GouraudVerticeBuilder.CoordAndColor c0, c1, c2; grBuilder.GetArrangedVertices(out c0, out c1, out c2); gouraudSpanGen.SetColorAndCoords(c0, c1, c2); using (Tools.BorrowVxs(out var v1)) { painter.Fill(grBuilder.MakeVxs(v1), gouraudSpanGen); v1.Clear(); // grBuilder.SetColor( ColorEx.Make(0, 1, 0, alpha), ColorEx.Make(0, 0, 1, alpha), ColorEx.Make(brc, brc, brc, alpha)); grBuilder.SetTriangle(_x[1], _y[1], _x[2], _y[2], xc, yc); grBuilder.GetArrangedVertices(out c0, out c1, out c2); gouraudSpanGen.SetColorAndCoords(c0, c1, c2); painter.Fill(grBuilder.MakeVxs(v1), gouraudSpanGen); v1.Clear(); // grBuilder.SetColor(ColorEx.Make(0, 0, 1, alpha), ColorEx.Make(1, 0, 0, alpha), ColorEx.Make(brc, brc, brc, alpha)); grBuilder.SetTriangle(_x[2], _y[2], _x[0], _y[0], xc, yc); grBuilder.GetArrangedVertices(out c0, out c1, out c2); gouraudSpanGen.SetColorAndCoords(c0, c1, c2); painter.Fill(grBuilder.MakeVxs(v1), gouraudSpanGen); v1.Clear(); // brc = 1 - brc; grBuilder.SetColor(ColorEx.Make(1, 0, 0, alpha), ColorEx.Make(0, 1, 0, alpha), ColorEx.Make(brc, brc, brc, alpha)); grBuilder.SetTriangle(_x[0], _y[0], _x[1], _y[1], x1, y1); grBuilder.GetArrangedVertices(out c0, out c1, out c2); gouraudSpanGen.SetColorAndCoords(c0, c1, c2); painter.Fill(grBuilder.MakeVxs(v1), gouraudSpanGen); v1.Clear(); grBuilder.SetColor(ColorEx.Make(0, 1, 0, alpha), ColorEx.Make(0, 0, 1, alpha), ColorEx.Make(brc, brc, brc, alpha)); grBuilder.SetTriangle(_x[1], _y[1], _x[2], _y[2], x2, y2); grBuilder.GetArrangedVertices(out c0, out c1, out c2); gouraudSpanGen.SetColorAndCoords(c0, c1, c2); painter.Fill(grBuilder.MakeVxs(v1), gouraudSpanGen); v1.Clear(); // grBuilder.SetColor(ColorEx.Make(0, 0, 1, alpha), ColorEx.Make(1, 0, 0, alpha), ColorEx.Make(brc, brc, brc, alpha)); grBuilder.SetTriangle(_x[2], _y[2], _x[0], _y[0], x3, y3); grBuilder.GetArrangedVertices(out c0, out c1, out c2); gouraudSpanGen.SetColorAndCoords(c0, c1, c2); painter.Fill(grBuilder.MakeVxs(v1), gouraudSpanGen); v1.Clear(); } }
static Vertex2d ConvToV2d(PointD p) => new Vertex2d(p.X, p.Y); //temp /// <summary> /// fill inner and outer border from corner0 to corner1 /// </summary> /// <param name="painter"></param> /// <param name="c0"></param> /// <param name="c1"></param> void FillBorders(AggPainter painter, ContourCorner c0, ContourCorner c1) { //counter-clockwise if (!c0.MiddlePoint_IsTouchPoint) { return; } //with a given corner, have have information of 3 points //left-point of the corner,=> from vertex //middle-point, current vertex //right-point,=> next vertex //a vertex may be touch-curve vertext, or 'not-touch-curve' vertex //'is not touch-curve point', => this vertex is a control point of C3 or C4 curve, //------------------------------------------------------- if (c0.RightPoint_IsTouchPoint) { //c0 => touch curve //c1 => touch curve, //we create an imaginary line from c0 to c1 //then we create an 'inner border' of a line from c0 to c1 //and we create an 'outer border' of a line from c0 to c1 // using (Tools.BorrowVxs(out var v1)) { //1. inner-border, set fill mode to inform proper color encoding of inner border _msdfEdgePxBlender.FillMode = MsdfEdgePixelBlender.BlenderFillMode.InnerBorder; //2020-03-13, version 3 fill is still better than v3.1, //TODO: review version v3.1 if (_use_v3_1) { //version 3.1 fill technique CreateBorder(v1, ConvToV2d(c1.RightPoint), ConvToV2d(c1.MiddlePoint), ConvToV2d(c0.MiddlePoint), ConvToV2d(c0.LeftPoint)); } else { //version 3 fill technique CreateInnerBorder(v1, c0.MiddlePoint.X, c0.MiddlePoint.Y, c1.MiddlePoint.X, c1.MiddlePoint.Y, INNER_BORDER_W); } painter.Fill(v1, c0.InnerColor); //------------- v1.Clear(); //reuse //2. outer-border, set fill mode too. _msdfEdgePxBlender.FillMode = MsdfEdgePixelBlender.BlenderFillMode.OuterBorder; if (_use_v3_1) { //version 3.1 fill technique CreateBorder(v1, ConvToV2d(c0.LeftPoint), ConvToV2d(c0.MiddlePoint), ConvToV2d(c1.MiddlePoint), ConvToV2d(c1.RightPoint)); } else { //version 3 fill technique CreateOuterBorder(v1, c0.MiddlePoint.X, c0.MiddlePoint.Y, c1.MiddlePoint.X, c1.MiddlePoint.Y, OUTER_BORDER_W); } painter.Fill(v1, c0.OuterColor); } } else { //painter.CurrentBxtBlendOp = null; //** //c0 is touch line, //but c1 is not, this means=> next segment will be a curve(C3 or C4 curve) // EdgeSegment ownerSeg = c1.CenterSegment; switch (ownerSeg.SegmentKind) { default: throw new NotSupportedException(); case EdgeSegmentKind.CubicSegment: { //approximate CubicSegment cs = (CubicSegment)ownerSeg; using (Tools.BorrowVxs(out var v1)) using (Tools.BorrowShapeBuilder(out var b)) using (Tools.BorrowStroke(out var strk)) { b.MoveTo(cs.P0.x + _dx, cs.P0.y + _dy) //... .Curve4To(cs.P1.x + _dx, cs.P1.y + _dy, cs.P2.x + _dx, cs.P2.y + _dy, cs.P3.x + _dx, cs.P3.y + _dy) .NoMore() .Flatten(); //----------------------- //fill outside part of the curve strk.Width = CURVE_STROKE_EACHSIDE * 2; strk.StrokeSideForOpenShape = StrokeSideForOpenShape.Outside; strk.MakeVxs(b.CurrentSharedVxs, v1); painter.Fill(v1, c0.OuterColor); //----------------------- //fill inside part of the curve v1.Clear(); //reuse strk.StrokeSideForOpenShape = StrokeSideForOpenShape.Inside; strk.MakeVxs(b.CurrentSharedVxs, v1); painter.Fill(v1, c0.InnerColor); //----------------------- } } break; case EdgeSegmentKind.QuadraticSegment: { QuadraticSegment qs = (QuadraticSegment)ownerSeg; using (Tools.BorrowVxs(out var v1)) using (Tools.BorrowShapeBuilder(out var b)) using (Tools.BorrowStroke(out var strk)) { b.MoveTo(qs.P0.x + _dx, qs.P0.y + _dy)//... .Curve3To(qs.P1.x + _dx, qs.P1.y + _dy, qs.P2.x + _dx, qs.P2.y + _dy) .NoMore() .Flatten(); //----------------------- //fill outside part of the curve strk.Width = CURVE_STROKE_EACHSIDE * 2; strk.StrokeSideForOpenShape = StrokeSideForOpenShape.Outside; strk.MakeVxs(b.CurrentSharedVxs, v1); painter.Fill(v1, c0.OuterColor); //----------------------- //fill inside part of the curve v1.Clear();//reuse strk.StrokeSideForOpenShape = StrokeSideForOpenShape.Inside; strk.MakeVxs(b.CurrentSharedVxs, v1); painter.Fill(v1, c0.InnerColor); //----------------------- } } break; } } }