internal static void PreviewSizeAndLocation(Shape shape, MsdfGenParams genParams, out int imgW, out int imgH, out Vector2 translate1) { double left = MAX; double bottom = MAX; double right = -MAX; double top = -MAX; shape.findBounds(ref left, ref bottom, ref right, ref top); int w = (int)Math.Ceiling((right - left)); int h = (int)Math.Ceiling((top - bottom)); if (w < genParams.minImgWidth) { w = genParams.minImgWidth; } if (h < genParams.minImgHeight) { h = genParams.minImgHeight; } //temp, for debug with glyph 'I', tahoma font //double edgeThreshold = 1.00000001;//default, if edgeThreshold < 0 then set edgeThreshold=1 //Msdfgen.Vector2 scale = new Msdfgen.Vector2(0.98714652956298199, 0.98714652956298199); //double pxRange = 4; //translate = new Msdfgen.Vector2(12.552083333333332, 4.0520833333333330); //double range = pxRange / Math.Min(scale.x, scale.y); int borderW = (int)((float)w / 5f); //org //var translate = new ExtMsdfgen.Vector2(left < 0 ? -left + borderW : borderW, bottom < 0 ? -bottom + borderW : borderW); //test w += borderW * 2; //borders,left- right h += borderW * 2; //borders, top- bottom imgW = w; imgH = h; translate1 = new Vector2(-left + borderW, -bottom + borderW); }
internal static PixelFarm.CpuBlit.BitmapAtlas.BitmapAtlasItemSource CreateMsdfImage(Shape shape, MsdfGenParams genParams, int w, int h, Vector2 translate, EdgeBmpLut lutBuffer = null) { double edgeThreshold = genParams.edgeThreshold; if (edgeThreshold < 0) { edgeThreshold = 1.00000001; //use default if edgeThreshold <0 } var scale = new Vector2(genParams.scaleX, genParams.scaleY); //scale double range = genParams.pxRange / Math.Min(scale.x, scale.y); //--------- FloatRGBBmp frgbBmp = new FloatRGBBmp(w, h); EdgeColoring.edgeColoringSimple(shape, genParams.angleThreshold); bool flipY = false; if (lutBuffer != null) { GenerateMSDF3(frgbBmp, shape, range, scale, translate,//translate to positive quadrant edgeThreshold, lutBuffer); flipY = shape.InverseYAxis; } else { //use original msdf MsdfGenerator.generateMSDF(frgbBmp, shape, range, scale, translate,//translate to positive quadrant edgeThreshold); } return(new PixelFarm.CpuBlit.BitmapAtlas.BitmapAtlasItemSource(w, h) { Source = ConvertToIntBmp(frgbBmp, flipY), TextureXOffset = (float)translate.x, TextureYOffset = (float)translate.y }); }
public PixelFarm.CpuBlit.BitmapAtlas.BitmapAtlasItemSource GenerateMsdfTexture(VertexStore vxs) { Shape shape = CreateShape(vxs, out EdgeBmpLut edgeBmpLut); if (MsdfGenParams == null) { MsdfGenParams = new MsdfGenParams();//use default } //---preview v1 bounds----------- PreviewSizeAndLocation( shape, MsdfGenParams, out int imgW, out int imgH, out Vector2 translateVec); _dx = translateVec.x; _dy = translateVec.y; //------------------------------------ List <ContourCorner> corners = edgeBmpLut.Corners; TranslateCorners(corners, _dx, _dy); //[1] create lookup table (lut) bitmap that contains area/corner/shape information //each pixel inside it contains data that map to area/corner/shape // using (MemBitmap bmpLut = new MemBitmap(imgW, imgH)) using (Tools.BorrowAggPainter(bmpLut, out var painter)) using (Tools.BorrowShapeBuilder(out var sh)) { _msdfEdgePxBlender.ClearOverlapList();//reset painter.RenderSurface.SetCustomPixelBlender(_msdfEdgePxBlender); //1. clear all bg to black painter.Clear(PixelFarm.Drawing.Color.Black); sh.InitVxs(vxs) //... .TranslateToNewVxs(_dx, _dy) .Flatten(); //--------- //2. force fill the shape (this include hole(s) inside shape to) //( we set threshold to 50 and do force fill) painter.RenderSurface.SetGamma(_prebuiltThresholdGamma_50); _msdfEdgePxBlender.FillMode = MsdfEdgePixelBlender.BlenderFillMode.Force; painter.Fill(sh.CurrentSharedVxs, EdgeBmpLut.EncodeToColor(0, AreaKind.AreaInsideCoverage50)); painter.RenderSurface.SetGamma(_prebuiltThresholdGamma_50);//restore #if DEBUG //debug for output //painter.Fill(v7, Color.Red); //bmpLut.SaveImage("dbug_step0.png"); //int curr_step = 1; #endif //--------- int cornerCount = corners.Count; List <int> cornerOfNextContours = edgeBmpLut.CornerOfNextContours; int startAt = 0; int n = 1; int corner_index = 1; for (int cnt_index = 0; cnt_index < cornerOfNextContours.Count; ++cnt_index) { //contour scope int next_corner_startAt = cornerOfNextContours[cnt_index]; //----------- //AA-borders of the contour painter.RenderSurface.SetGamma(_prebuiltThresholdGamma_OverlappedBorder); //this creates overlapped area for (; n < next_corner_startAt; ++n) { //0-> 1 //1->2 ... n FillBorders(painter, corners[n - 1], corners[n]); #if DEBUG //bmpLut.SaveImage("dbug_step" + curr_step + ".png"); //curr_step++; #endif } { //the last one //close contour, n-> 0 FillBorders(painter, corners[next_corner_startAt - 1], corners[startAt]); #if DEBUG //bmpLut.SaveImage("dbug_step" + curr_step + ".png"); //curr_step++; #endif } startAt = next_corner_startAt; n++; corner_index++; } #if DEBUG //bmpLut.SaveImage("dbug_step2.png"); #endif //painter.RenderSurface.SetGamma(_prebuiltThresholdGamma_100); //_msdfEdgePxBlender.FillMode = MsdfEdgePixelBlender.BlenderFillMode.InnerAreaX; //painter.Fill(sh.CurrentSharedVxs, EdgeBmpLut.EncodeToColor(0, AreaKind.AreaInsideCoverage100)); painter.RenderSurface.SetCustomPixelBlender(null); painter.RenderSurface.SetGamma(null); // List <CornerList> overlappedList = MakeUniqueList(_msdfEdgePxBlender._overlapList); edgeBmpLut.SetOverlappedList(overlappedList); #if DEBUG if (dbugWriteMsdfTexture) { //save for debug //we save to msdf_shape_lut2.png //and check it from external program //but we generate msdf bitmap from msdf_shape_lut.png bmpLut.SaveImage(dbug_msdf_shape_lutName); var bmp5 = MemBitmap.LoadBitmap(dbug_msdf_shape_lutName); int[] lutBuffer5 = bmp5.CopyImgBuffer(bmpLut.Width, bmpLut.Height); if (bmpLut.Width == 338 && bmpLut.Height == 477) { dbugBreak = true; } edgeBmpLut.SetBmpBuffer(bmpLut.Width, bmpLut.Height, lutBuffer5); //generate actual sprite PixelFarm.CpuBlit.BitmapAtlas.BitmapAtlasItemSource item = CreateMsdfImage(shape, MsdfGenParams, imgW, imgH, translateVec, edgeBmpLut); //save msdf bitmap to file using (MemBitmap memBmp = MemBitmap.CreateFromCopy(item.Width, item.Height, item.Source)) { memBmp.SaveImage(dbug_msdf_output); } return(item); } #endif //[B] after we have a lookup table int[] lutBuffer = bmpLut.CopyImgBuffer(bmpLut.Width, bmpLut.Height); edgeBmpLut.SetBmpBuffer(bmpLut.Width, bmpLut.Height, lutBuffer); return(CreateMsdfImage(shape, MsdfGenParams, imgW, imgH, translateVec, edgeBmpLut)); } }