Пример #1
0
        protected void fillGeometry(iPathGeometry path, SolidColorData color, bool vaa, int instance = 0)
        {
            getCurrentTransform(out Matrix3x2 tform, out float pixel);
            if (!path.testApproximateBounds(ref tform) || color.brushType == eBrushType.Null)
            {
                return;
            }

            eBuildFilledMesh fillOptions = DrawUtilsPrivate.fillFlagsFromColor(color.brushType, false);

            if (fillOptions == eBuildFilledMesh.None)
            {
                return;                 // Null brush
            }
            if (!vaa)
            {
                fillOptions &= ~eBuildFilledMesh.VAA;
            }

            sPendingDrawCall pdc = tesselatorThread.fill(path, ref tform, pixel, fillOptions, instance);

            flushIfNeeded(pdc.drawInfo.drawCallsCount);

            Order o = order();

            drawMeshes.meshes.add(ref pdc);
            calls.add(sDrawCall.solidColorFill(o, ref tform, color.paletteIndex));
        }
Пример #2
0
 sDrawCommand(iPathGeometry geometry, eMesh command, sStrokeStyle ss, float w)
 {
     this.geometry = geometry;
     this.command  = command;
     strokeStyle   = ss;
     width         = w;
 }
Пример #3
0
        void iDrawContext.fillAndStroke(iGeometry geometry, iBrush fill, iBrush stroke, float strokeWidth, iStrokeStyle strokeStyle)
        {
            sStrokeStyle  ss   = strokeStyle?.strokeStyle ?? defaultStrokeStyle();
            iPathGeometry path = (iPathGeometry)geometry;

            fillAndStrokeGeometry(path, fill.data(), stroke.data(), strokeWidth, ref ss);
        }
Пример #4
0
 /// <summary>True if the transformed approximate bounds of the geometry + stroke intersects with a specified clipping rectangle</summary>
 public static bool testApproximateBounds(this iPathGeometry pathGeometry, ref Matrix3x2 transform, ref Rect clipRect, float strokeWidth = 0)
 {
     unsafe
     {
         fixed(Rect *pointer = &clipRect)
         return(pathGeometry.ioTestApproximateBounds(ref transform, strokeWidth, (IntPtr)pointer));
     }
 }
Пример #5
0
 /// <summary>Tessellate splines and clip the result to viewport, using specified clipping rectangle</summary>
 public static eClipResult buildClippedPolylines(this iPathGeometry path, iPolylinePath poly, Rect clipRect, Matrix3x2 transform, float precision, float strokeWidth = 0)
 {
     unsafe
     {
         Rect *clip = &clipRect;
         path.buildPolylines(precision, strokeWidth, ref transform, (IntPtr)clip, poly, out var res);
         return(res);
     }
 }
Пример #6
0
        sPendingDrawCall iTesselator.fillAndStroke(iPathGeometry path, ref Matrix3x2 tform, float pixel, eBuildFilledMesh fillOptions, sStrokeInfo stroke, int instance)
        {
            var job = postJob(path, instance, ref tform, fillOptions, pixel, stroke);

            if (!fillOptions.HasFlag(eBuildFilledMesh.BrushHasTransparency))
            {
                return(new sPendingDrawCall(job, eRenderPassFlags.Opaque | eRenderPassFlags.Transparent, 2));
            }
            return(new sPendingDrawCall(job, eRenderPassFlags.Transparent, 1));
        }
Пример #7
0
        protected void fillAndStrokeGeometry(iPathGeometry path, SolidColorData?fill, SolidColorData stroke, float width, ref sStrokeStyle strokeStyle, int instance = 0)
        {
            if ((fill?.brushType ?? eBrushType.Null) == eBrushType.Null)
            {
                // No fill, just stroke
                if (stroke.brushType != eBrushType.Null)
                {
                    strokeGeometry(path, stroke, null, width, ref strokeStyle, instance);
                }
                return;
            }
            if (stroke.brushType == eBrushType.Null)
            {
                // No stroke, just fill
                fillGeometry(path, fill.Value, true, instance);
                return;
            }

            getCurrentTransform(out Matrix3x2 tform, out float pixel);
            if (!path.testApproximateBounds(ref tform, width))
            {
                return;
            }

            eBuildFilledMesh   fillOptions = DrawUtilsPrivate.fillFlagsFromColor(fill.Value.brushType, true);
            StrokeRenderParams srp         = StrokeRenderParams.strokedPath(stroke.paletteIndex, width, pixel);
            Order o;

            if (fill.Value == stroke)
            {
                // Colors are the same, combine the draw calls
                sPendingDrawCall pdc = tesselatorThread.fillAndStroke(path, ref tform, pixel, fillOptions, new sStrokeInfo(strokeStyle, srp.meshWidth), instance);
                flushIfNeeded(pdc.drawInfo.drawCallsCount);
                o = order();
                drawMeshes.meshes.add(ref pdc);
                calls.add(sDrawCall.solidColorStroke(o, ref tform, ref srp));
                return;
            }

            var  pendingCalls = tesselatorThread.fillAndStrokeSeparate(path, ref tform, pixel, fillOptions, new sStrokeInfo(strokeStyle, srp.meshWidth), instance);
            byte dcc          = pendingCalls.Item1.drawInfo.drawCallsCount;

            dcc += pendingCalls.Item2.drawInfo.drawCallsCount;
            flushIfNeeded(dcc);

            o = order();
            drawMeshes.meshes.add(ref pendingCalls.Item1);
            calls.add(sDrawCall.solidColorFill(o, ref tform, fill.Value.paletteIndex));

            o = order();
            drawMeshes.meshes.add(ref pendingCalls.Item2);
            calls.add(sDrawCall.solidColorStroke(o, ref tform, ref srp));
        }
Пример #8
0
        iTessellatedMeshes postJob(iPathGeometry path, int instance, ref Matrix3x2 tform, eBuildFilledMesh filled, float pixel, sStrokeInfo?stroke)
        {
            if (null == path)
            {
                throw new ArgumentNullException();
            }

            // We use MD4 to detect changes in re-tessellated polylines. To make that more efficient for small changes of scaling, rounding the precision and pixel values.
            float   precision = pixel.floorBitwise();
            Options options   = new Options(ref tform, precision, pixel, filled, stroke, false);

            Meshes meshes;
            Table  table;

            if (0 == instance)
            {
                table = zeroInstances;
            }
            else if (1 == instance)
            {
                table = oneInstances;
            }
            else
            {
                var dict = multiTable.GetOrCreateValue(path);

                if (dict.TryGetValue(instance, out meshes))
                {
                    return(updateOldJob(meshes, ref options));
                }

                meshes = new Meshes(path, factory);
                dict.Add(instance, meshes);
                return(createNewJob(meshes, ref options));
            }

            if (table.TryGetValue(path, out meshes))
            {
                return(updateOldJob(meshes, ref options));
            }

            meshes = new Meshes(path, factory);
            table.Add(path, meshes);
            return(createNewJob(meshes, ref options));
        }
Пример #9
0
        protected void strokeGeometry(iPathGeometry path, SolidColorData color, SolidColorData?filledColor, float width, ref sStrokeStyle strokeStyle, int instance = 0)
        {
            getCurrentTransform(out Matrix3x2 tform, out float pixel);
            if (!path.testApproximateBounds(ref tform, width) || color.brushType == eBrushType.Null)
            {
                return;
            }

            int fillColorIndex     = filledColor?.paletteIndex ?? (int)eNamedColor.Transparent;
            StrokeRenderParams srp = StrokeRenderParams.strokedPath(color.paletteIndex, width, pixel, fillColorIndex);
            sPendingDrawCall   pdc = tesselatorThread.stroke(path, ref tform, pixel, new sStrokeInfo(strokeStyle, srp.meshWidth), instance);

            flushIfNeeded(pdc.drawInfo.drawCallsCount);

            Order o = order();

            drawMeshes.meshes.add(ref pdc);
            calls.add(sDrawCall.solidColorStroke(o, ref tform, ref srp));
        }
Пример #10
0
        sPendingDrawCall iTesselator.stroke(iPathGeometry path, ref Matrix3x2 tform, float pixel, sStrokeInfo stroke, int instance)
        {
            var job = postJob(path, instance, ref tform, eBuildFilledMesh.None, pixel, stroke);

            return(new sPendingDrawCall(job, eRenderPassFlags.Transparent, 1));
        }
Пример #11
0
        sPendingDrawCall iTesselator.fill(iPathGeometry path, ref Matrix3x2 tform, float pixel, eBuildFilledMesh fillOptions, int instance)
        {
            var job = postJob(path, instance, ref tform, fillOptions, pixel, null);

            return(new sPendingDrawCall(job, filledCallInfo(fillOptions)));
        }
Пример #12
0
 /// <summary>True if the transformed approximate bounds of the geometry + stroke intersects with a default clipping rectangle [ -1, -1, +1, +1 ]</summary>
 public static bool testApproximateBounds(this iPathGeometry pathGeometry, ref Matrix3x2 transform, float strokeWidth = 0)
 {
     return(pathGeometry.ioTestApproximateBounds(ref transform, strokeWidth, IntPtr.Zero));
 }
Пример #13
0
 /// <summary>Tessellate splines and clip the result to viewport, using default clipping rectangle</summary>
 public static eClipResult buildClippedPolylines(this iPathGeometry path, iPolylinePath poly, Matrix3x2 transform, float precision, float strokeWidth = 0)
 {
     path.buildPolylines(precision, strokeWidth, ref transform, IntPtr.Zero, poly, out var res);
     return(res);
 }
Пример #14
0
 public static sDrawCommand fill(iPathGeometry geometry)
 {
     return(new sDrawCommand(geometry, eMesh.Filled, default, default));
Пример #15
0
 public Meshes(iPathGeometry path, iVrmacDraw factory)
 {
     this.path   = path;
     frontBuffer = factory.createTriangleMesh();
     backBuffer  = factory.createTriangleMesh();
 }