Beispiel #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));
        }
Beispiel #2
0
 /// <summary>Build both meshes</summary>
 public static void createMesh(this iPolylinePath path, iTriangleMesh result, eBuildFilledMesh filledMesh, float pixel, sStrokeInfo strokeInfo)
 {
     unsafe
     {
         sStrokeInfo *si = &strokeInfo;
         path.createMesh(result, filledMesh, pixel, ( IntPtr)si);
     }
 }
Beispiel #3
0
 public Options(ref Matrix3x2 transform, float precision, float pixel, eBuildFilledMesh fill, sStrokeInfo?stroke, bool strokeSeparate)
 {
     this.transform     = transform;
     this.precision     = precision;
     this.pixel         = pixel;
     this.fill          = fill;
     this.stroke        = stroke ?? default;
     separateStrokeMesh = strokeSeparate;
 }
Beispiel #4
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));
        }
Beispiel #5
0
        public static eBuildFilledMesh fillFlagsFromColor(eBrushType brushType, bool hasStroke)
        {
            eBuildFilledMesh vaaBit = hasStroke ? eBuildFilledMesh.None : eBuildFilledMesh.VAA;

            switch (brushType)
            {
            case eBrushType.Null:
                return(eBuildFilledMesh.None);

            case eBrushType.Transparent:
                return(eBuildFilledMesh.FilledMesh | eBuildFilledMesh.BrushHasTransparency | vaaBit);

            case eBrushType.Opaque:
                return(eBuildFilledMesh.FilledMesh | vaaBit);
            }
            throw new ArgumentException();
        }
Beispiel #6
0
        static sDrawCallInfo filledCallInfo(eBuildFilledMesh fillOptions)
        {
            switch (fillOptions & (eBuildFilledMesh.VAA | eBuildFilledMesh.BrushHasTransparency))
            {
            case eBuildFilledMesh.None:
                // Opaque brush without VAA
                return(new sDrawCallInfo(eRenderPassFlags.Opaque, 1));

            case eBuildFilledMesh.VAA:
                // VAA emits both opaque and transparent triangles in that mode. It even partitions vertices in the buffer for better GPU cache utilization.
                return(new sDrawCallInfo(eRenderPassFlags.Opaque | eRenderPassFlags.Transparent, 2));

            case eBuildFilledMesh.BrushHasTransparency:
            case eBuildFilledMesh.BrushHasTransparency | eBuildFilledMesh.VAA:
                // When the brush has transparency, VAA or not, the complete mesh will go to the transparent index buffer
                return(new sDrawCallInfo(eRenderPassFlags.Transparent, 1));
            }
            throw new ApplicationException();
        }
Beispiel #7
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));
        }
Beispiel #8
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)));
        }
Beispiel #9
0
 /// <summary>Build just the filled mesh</summary>
 public static void createMesh(this iPolylinePath path, iTriangleMesh result, eBuildFilledMesh filledMesh, float pixel)
 {
     Debug.Assert(filledMesh != eBuildFilledMesh.None);
     path.createMesh(result, filledMesh, pixel, IntPtr.Zero);
 }
Beispiel #10
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));
        }