Пример #1
0
 public override void release()
 {
     ObjectPool <CmdLayer> .release(this);
 }
Пример #2
0
 public override void release()
 {
     ObjectPool <CmdDraw> .release(this);
 }
Пример #3
0
        void _drawRRectShadow(uiPath path, uiPaint paint)
        {
            D.assert(path.isNaiveRRect, () => "Cannot draw fast Shadow for non-NaiveRRect shapes");
            D.assert(paint.style == PaintingStyle.fill, () => "Cannot draw fast Shadow for stroke lines");
            var layer = this._currentLayer;
            var state = layer.currentState;

            var  cache = path.flatten(state.scale * this._devicePixelRatio);
            bool convex;

            cache.computeFillMesh(this._fringeWidth, out convex);
            var fillMesh   = cache.fillMesh;
            var meshBounds = fillMesh.transform(state.matrix);
            var clipBounds = layer.layerBounds;

            uiRect?stackBounds;
            bool   iior;

            layer.clipStack.getBounds(out stackBounds, out iior);

            if (stackBounds != null)
            {
                clipBounds = uiRectHelper.intersect(clipBounds, stackBounds.Value);
            }

            if (clipBounds.isEmpty)
            {
                ObjectPool <uiMeshMesh> .release(meshBounds);

                return;
            }

            var maskBounds = meshBounds.bounds;

            maskBounds = uiRectHelper.intersect(maskBounds, clipBounds);
            if (maskBounds.isEmpty)
            {
                ObjectPool <uiMeshMesh> .release(meshBounds);

                return;
            }

            var blurMesh = ImageMeshGenerator.imageMesh(null, uiRectHelper.one, maskBounds);

            if (!this._applyClip(blurMesh.bounds))
            {
                ObjectPool <uiMeshMesh> .release(meshBounds);

                ObjectPool <uiMeshMesh> .release(blurMesh);

                return;
            }

            var bound = path.getBounds();
            var sigma = state.scale * paint.maskFilter.Value.sigma;

            var vertices = ObjectPool <uiList <Vector3> > .alloc();

            vertices.SetCapacity(4);
            vertices.Add(new Vector2(0, 0));
            vertices.Add(new Vector2(1, 0));
            vertices.Add(new Vector2(0, 1));
            vertices.Add(new Vector2(1, 1));

            var _triangles = ObjectPool <uiList <int> > .alloc();

            _triangles.SetCapacity(6);
            _triangles.Add(0);
            _triangles.Add(1);
            _triangles.Add(2);
            _triangles.Add(2);
            _triangles.Add(1);
            _triangles.Add(3);

            ObjectPool <uiMeshMesh> .release(meshBounds);

            ObjectPool <uiMeshMesh> .release(blurMesh);

            var mesh = uiMeshMesh.create(state.matrix, vertices, _triangles);

            layer.draws.Add(CanvasShader.fastShadow(layer, mesh, sigma, path.isRect, path.isCircle, path.rRectCorner, new Vector4(bound.left, bound.top, bound.right, bound.bottom), paint.color));
        }
Пример #4
0
 public override void release()
 {
     ObjectPool <CmdScissor> .release(this);
 }
Пример #5
0
        public void addDrawCmd(uiDrawCmd drawCmd)
        {
            this._drawCmds.Add(drawCmd);

            switch (drawCmd)
            {
            case uiDrawSave _:
                this._states.Add(this._getState().copy());
                break;

            case uiDrawSaveLayer cmd: {
                this._states.Add(new uiCanvasState {
                        xform       = uiMatrix3.I(),
                        scissor     = cmd.rect.Value.shift(-cmd.rect.Value.topLeft),
                        saveLayer   = true,
                        layerOffset = cmd.rect.Value.topLeft,
                        paintBounds = uiRectHelper.zero
                    });
                break;
            }

            case uiDrawRestore _: {
                var stateToRestore = this._getState();
                this._states.RemoveAt(this._states.Count - 1);
                var state = this._getState();

                if (!stateToRestore.saveLayer)
                {
                    state.paintBounds = stateToRestore.paintBounds;
                }
                else
                {
                    var paintBounds = stateToRestore.paintBounds.shift(stateToRestore.layerOffset.Value);
                    paintBounds = state.xform.mapRect(paintBounds);
                    this._addPaintBounds(paintBounds);
                }

                this._setState(state);
                break;
            }

            case uiDrawTranslate cmd: {
                var state = this._getState();
                state.xform = new uiMatrix3(state.xform);
                state.xform.preTranslate(cmd.dx, cmd.dy);
                this._setState(state);
                break;
            }

            case uiDrawScale cmd: {
                var state = this._getState();
                state.xform = new uiMatrix3(state.xform);
                state.xform.preScale(cmd.sx, (cmd.sy ?? cmd.sx));
                this._setState(state);
                break;
            }

            case uiDrawRotate cmd: {
                var state = this._getState();
                state.xform = new uiMatrix3(state.xform);
                if (cmd.offset == null)
                {
                    state.xform.preRotate(cmd.radians);
                }
                else
                {
                    state.xform.preRotate(cmd.radians,
                                          cmd.offset.Value.dx,
                                          cmd.offset.Value.dy);
                }

                this._setState(state);
                break;
            }

            case uiDrawSkew cmd: {
                var state = this._getState();
                state.xform = new uiMatrix3(state.xform);
                state.xform.preSkew(cmd.sx, cmd.sy);
                this._setState(state);
                break;
            }

            case uiDrawConcat cmd: {
                var state = this._getState();
                state.xform = new uiMatrix3(state.xform);
                state.xform.preConcat(cmd.matrix.Value);
                this._setState(state);
                break;
            }

            case uiDrawResetMatrix _: {
                var state = this._getState();
                state.xform = uiMatrix3.I();
                this._setState(state);
                break;
            }

            case uiDrawSetMatrix cmd: {
                var state = this._getState();
                state.xform = new uiMatrix3(cmd.matrix.Value);
                this._setState(state);
                break;
            }

            case uiDrawClipRect cmd: {
                var state = this._getState();

                var rect = state.xform.mapRect(cmd.rect.Value);
                state.scissor = state.scissor == null ? rect : state.scissor.Value.intersect(rect);
                this._setState(state);
                break;
            }

            case uiDrawClipRRect cmd: {
                var state = this._getState();

                var rect = state.xform.mapRect(uiRectHelper.fromRect(cmd.rrect.outerRect).Value);
                state.scissor = state.scissor == null ? rect : state.scissor.Value.intersect(rect);
                this._setState(state);
                break;
            }

            case uiDrawClipPath cmd: {
                var state = this._getState();
                var scale = uiXformUtils.getScale(state.xform);

                var rectPathCache = cmd.path.flatten(
                    scale * Window.instance.devicePixelRatio);
                rectPathCache.computeFillMesh(0.0f, out _);
                var rectMesh        = rectPathCache.fillMesh;
                var transformedMesh = rectMesh.transform(state.xform);
                var rect            = transformedMesh.bounds;
                state.scissor = state.scissor == null ? rect : state.scissor.Value.intersect(rect);
                this._setState(state);
                ObjectPool <uiMeshMesh> .release(transformedMesh);

                break;
            }

            case uiDrawPath cmd: {
                var state            = this._getState();
                var scale            = uiXformUtils.getScale(state.xform);
                var path             = cmd.path;
                var paint            = cmd.paint;
                var devicePixelRatio = Window.instance.devicePixelRatio;

                uiMeshMesh mesh;
                if (paint.style == PaintingStyle.fill)
                {
                    var cache = path.flatten(scale * devicePixelRatio);
                    cache.computeFillMesh(0.0f, out _);
                    var fillMesh = cache.fillMesh;
                    mesh = fillMesh.transform(state.xform);
                }
                else
                {
                    float strokeWidth = (paint.strokeWidth * scale).clamp(0, 200.0f);
                    float fringeWidth = 1 / devicePixelRatio;

                    if (strokeWidth < fringeWidth)
                    {
                        strokeWidth = fringeWidth;
                    }

                    var cache = path.flatten(scale * devicePixelRatio);
                    cache.computeStrokeMesh(
                        strokeWidth / scale * 0.5f,
                        0.0f,
                        paint.strokeCap,
                        paint.strokeJoin,
                        paint.strokeMiterLimit);
                    var strokenMesh = cache.strokeMesh;

                    mesh = strokenMesh.transform(state.xform);
                }

                if (paint.maskFilter != null && paint.maskFilter.Value.sigma != 0)
                {
                    float sigma  = scale * paint.maskFilter.Value.sigma;
                    float sigma3 = 3 * sigma;
                    this._addPaintBounds(uiRectHelper.inflate(mesh.bounds, sigma3));
                }
                else
                {
                    this._addPaintBounds(mesh.bounds);
                }

                ObjectPool <uiMeshMesh> .release(mesh);

                break;
            }

            case uiDrawImage cmd: {
                var state = this._getState();
                var rect  = uiRectHelper.fromLTWH(cmd.offset.Value.dx, cmd.offset.Value.dy,
                                                  cmd.image.width, cmd.image.height);
                rect = state.xform.mapRect(rect);
                this._addPaintBounds(rect);
                break;
            }

            case uiDrawImageRect cmd: {
                var state = this._getState();
                var rect  = state.xform.mapRect(cmd.dst.Value);
                this._addPaintBounds(rect);
                break;
            }

            case uiDrawImageNine cmd: {
                var state = this._getState();
                var rect  = state.xform.mapRect(cmd.dst.Value);
                this._addPaintBounds(rect);
                break;
            }

            case uiDrawPicture cmd: {
                var state = this._getState();
                var rect  = state.xform.mapRect(uiRectHelper.fromRect(cmd.picture.paintBounds).Value);
                this._addPaintBounds(rect);
                break;
            }

            case uiDrawTextBlob cmd: {
                var state = this._getState();
                var scale = uiXformUtils.getScale(state.xform);
                var rect  = uiRectHelper.fromRect(
                    cmd.textBlob.Value.shiftedBoundsInText(cmd.offset.Value.dx, cmd.offset.Value.dy)).Value;
                rect = state.xform.mapRect(rect);

                var paint = cmd.paint;
                if (paint.maskFilter != null && paint.maskFilter.Value.sigma != 0)
                {
                    float sigma  = scale * paint.maskFilter.Value.sigma;
                    float sigma3 = 3 * sigma;
                    this._addPaintBounds(uiRectHelper.inflate(rect, sigma3));
                }
                else
                {
                    this._addPaintBounds(rect);
                }

                break;
            }

            default:
                throw new Exception("unknown drawCmd: " + drawCmd);
            }
        }
Пример #6
0
        bool _applyClip(uiRect?queryBounds)
        {
            if (queryBounds == null || queryBounds.Value.isEmpty)
            {
                return(false);
            }

            var         layer       = this._currentLayer;
            var         layerBounds = layer.layerBounds;
            ReducedClip reducedClip = ReducedClip.create(layer.clipStack, layerBounds, queryBounds.Value);

            if (reducedClip.isEmpty())
            {
                ObjectPool <ReducedClip> .release(reducedClip);

                return(false);
            }

            var scissor      = reducedClip.scissor;
            var physicalRect = uiRectHelper.fromLTRB(0, 0, layer.width, layer.height);

            if (uiRectHelper.equals(scissor, layerBounds))
            {
                this._tryAddScissor(layer, null);
            }
            else
            {
                var deviceScissor = uiRectHelper.fromLTRB(
                    scissor.Value.left - layerBounds.left, layerBounds.bottom - scissor.Value.bottom,
                    scissor.Value.right - layerBounds.left, layerBounds.bottom - scissor.Value.top
                    );
                deviceScissor = uiRectHelper.scale(deviceScissor, layer.width / layerBounds.width,
                                                   layer.height / layerBounds.height);
                deviceScissor = uiRectHelper.roundOut(deviceScissor);
                deviceScissor = uiRectHelper.intersect(deviceScissor, physicalRect);

                if (deviceScissor.isEmpty)
                {
                    ObjectPool <ReducedClip> .release(reducedClip);

                    return(false);
                }

                this._tryAddScissor(layer, deviceScissor);
            }

            var maskGenID = reducedClip.maskGenID();

            if (this._mustRenderClip(maskGenID, reducedClip.scissor.Value))
            {
                if (maskGenID == ClipStack.wideOpenGenID)
                {
                    layer.ignoreClip = true;
                }
                else
                {
                    layer.ignoreClip = false;

                    // need to inflate a bit to make sure all area is cleared.
                    var inflatedScissor = uiRectHelper.inflate(reducedClip.scissor.Value, this._fringeWidth);
                    var boundsMesh      = uiMeshMesh.create(inflatedScissor);
                    layer.draws.Add(CanvasShader.stencilClear(layer, boundsMesh));

                    foreach (var maskElement in reducedClip.maskElements)
                    {
                        layer.draws.Add(CanvasShader.stencil0(layer, maskElement.mesh.duplicate()));
                        layer.draws.Add(CanvasShader.stencil1(layer, boundsMesh.duplicate()));
                    }
                }

                this._setLastClipGenId(maskGenID, reducedClip.scissor.Value);
            }

            ObjectPool <ReducedClip> .release(reducedClip);

            return(true);
        }
Пример #7
0
 public override void clear()
 {
     //the recorder will dispose the draw commands
     this.drawCmds = null;
     ObjectPool <uiList <int> > .release(this.stateUpdatesIndices);
 }
Пример #8
0
        public uiMeshMesh resolveMesh()
        {
            if (this._resolved)
            {
                return(this._mesh);
            }

            this._resolved = true;

            var style = this.textBlob.style;

            var text     = this.textBlob.text;
            var key      = MeshKey.create(this.textBlob.instanceId, this.scale);
            var fontInfo = FontManager.instance.getOrCreate(style.fontFamily, style.fontWeight, style.fontStyle);
            var font     = fontInfo.font;

            _meshes.TryGetValue(key, out var meshInfo);
            if (meshInfo != null && meshInfo.textureVersion == fontInfo.textureVersion)
            {
                ObjectPool <MeshKey> .release(key);

                meshInfo.touch();
                this._mesh = meshInfo.mesh.transform(this.matrix);
                return(this._mesh);
            }

            // Handling Emoji
            char startingChar = text[this.textBlob.textOffset];

            if (char.IsHighSurrogate(startingChar) || EmojiUtils.isSingleCharEmoji(startingChar))
            {
                var vert = ObjectPool <uiList <Vector3> > .alloc();

                var tri = ObjectPool <uiList <int> > .alloc();

                var uvCoord = ObjectPool <uiList <Vector2> > .alloc();

                var metrics    = FontMetrics.fromFont(font, style.UnityFontSize);
                var minMaxRect = EmojiUtils.getMinMaxRect(style.fontSize, metrics.ascent, metrics.descent);
                var minX       = minMaxRect.left;
                var maxX       = minMaxRect.right;
                var minY       = minMaxRect.top;
                var maxY       = minMaxRect.bottom;

                for (int i = 0; i < this.textBlob.textSize; i++)
                {
                    char a    = text[this.textBlob.textOffset + i];
                    int  code = a;
                    if (char.IsHighSurrogate(a))
                    {
                        D.assert(i + 1 < this.textBlob.textSize);
                        D.assert(this.textBlob.textOffset + i + 1 < this.textBlob.text.Length);
                        char b = text[this.textBlob.textOffset + i + 1];
                        D.assert(char.IsLowSurrogate(b));
                        code = char.ConvertToUtf32(a, b);
                    }
                    else if (char.IsLowSurrogate(a) || EmojiUtils.isEmptyEmoji(a))
                    {
                        continue;
                    }
                    var uvRect = EmojiUtils.getUVRect(code);

                    var pos = this.textBlob.positions[i];

                    int baseIndex = vert.Count;
                    vert.Add(new Vector3(pos.x + minX, pos.y + minY, 0));
                    vert.Add(new Vector3(pos.x + maxX, pos.y + minY, 0));
                    vert.Add(new Vector3(pos.x + maxX, pos.y + maxY, 0));
                    vert.Add(new Vector3(pos.x + minX, pos.y + maxY, 0));

                    tri.Add(baseIndex);
                    tri.Add(baseIndex + 1);
                    tri.Add(baseIndex + 2);
                    tri.Add(baseIndex);
                    tri.Add(baseIndex + 2);
                    tri.Add(baseIndex + 3);
                    uvCoord.Add(uvRect.bottomLeft.toVector());
                    uvCoord.Add(uvRect.bottomRight.toVector());
                    uvCoord.Add(uvRect.topRight.toVector());
                    uvCoord.Add(uvRect.topLeft.toVector());

                    if (char.IsHighSurrogate(a))
                    {
                        i++;
                    }
                }

                uiMeshMesh meshMesh = uiMeshMesh.create(null, vert, tri, uvCoord);

                if (_meshes.ContainsKey(key))
                {
                    ObjectPool <MeshInfo> .release(_meshes[key]);

                    _meshes.Remove(key);
                }
                _meshes[key] = MeshInfo.create(key, meshMesh, 0);

                this._mesh = meshMesh.transform(this.matrix);
                return(this._mesh);
            }

            var length         = this.textBlob.textSize;
            var fontSizeToLoad = Mathf.CeilToInt(style.UnityFontSize * this.scale);

            var vertices = ObjectPool <uiList <Vector3> > .alloc();

            vertices.SetCapacity(length * 4);

            var triangles = ObjectPool <uiList <int> > .alloc();

            triangles.SetCapacity(length * 6);

            var uv = ObjectPool <uiList <Vector2> > .alloc();

            uv.SetCapacity(length * 4);

            for (int charIndex = 0; charIndex < length; ++charIndex)
            {
                var ch = text[charIndex + this.textBlob.textOffset];
                // first char as origin for mesh position
                var position = this.textBlob.positions[charIndex];
                if (LayoutUtils.isWordSpace(ch) || LayoutUtils.isLineEndSpace(ch) || ch == '\t')
                {
                    continue;
                }

                if (fontSizeToLoad == 0)
                {
                    continue;
                }

                font.getGlyphInfo(ch, out var glyphInfo, fontSizeToLoad, style.UnityFontStyle);

                var minX = glyphInfo.minX / this.scale;
                var maxX = glyphInfo.maxX / this.scale;
                var minY = -glyphInfo.maxY / this.scale;
                var maxY = -glyphInfo.minY / this.scale;

                var baseIndex = vertices.Count;

                vertices.Add(new Vector3((position.x + minX), (position.y + minY), 0));
                vertices.Add(new Vector3((position.x + maxX), (position.y + minY), 0));
                vertices.Add(new Vector3((position.x + maxX), (position.y + maxY), 0));
                vertices.Add(new Vector3((position.x + minX), (position.y + maxY), 0));

                triangles.Add(baseIndex);
                triangles.Add(baseIndex + 1);
                triangles.Add(baseIndex + 2);
                triangles.Add(baseIndex);
                triangles.Add(baseIndex + 2);
                triangles.Add(baseIndex + 3);

                uv.Add(glyphInfo.uvTopLeft);
                uv.Add(glyphInfo.uvTopRight);
                uv.Add(glyphInfo.uvBottomRight);
                uv.Add(glyphInfo.uvBottomLeft);
            }

            if (vertices.Count == 0)
            {
                this._mesh = null;
                ObjectPool <uiList <Vector3> > .release(vertices);

                ObjectPool <uiList <Vector2> > .release(uv);

                ObjectPool <uiList <int> > .release(triangles);

                ObjectPool <MeshKey> .release(key);

                return(null);
            }

            uiMeshMesh mesh = vertices.Count > 0 ? uiMeshMesh.create(null, vertices, triangles, uv) : null;

            if (_meshes.ContainsKey(key))
            {
                ObjectPool <MeshInfo> .release(_meshes[key]);

                _meshes.Remove(key);
            }
            _meshes[key] = MeshInfo.create(key, mesh, fontInfo.textureVersion);

            this._mesh = mesh.transform(this.matrix);
            return(this._mesh);
        }
Пример #9
0
        public override void clear()
        {
            ObjectPool <MeshKey> .release(this.key);

            ObjectPool <uiMeshMesh> .release(this.mesh);
        }
Пример #10
0
 public override void clear()
 {
     ObjectPool <uiList <Vector2> > .release(this.points);
 }
Пример #11
0
        public uiMeshMesh getStrokeMesh(float strokeWidth, StrokeCap lineCap, StrokeJoin lineJoin, float miterLimit)
        {
            if (this._strokeMesh != null &&
                this._strokeWidth == strokeWidth &&
                this._lineCap == lineCap &&
                this._lineJoin == lineJoin &&
                this._miterLimit == miterLimit)
            {
                return(this._strokeMesh);
            }

            var vertices = this._expandStroke(strokeWidth, lineCap, lineJoin, miterLimit);

            var paths = this._paths;

            var cindices = 0;

            for (var i = 0; i < paths.Count; i++)
            {
                var path = paths[i];
                if (path.count <= 1)
                {
                    continue;
                }

                if (path.nstroke > 0)
                {
                    D.assert(path.nstroke >= 2);
                    cindices += (path.nstroke - 2) * 3;
                }
            }

            var indices = ObjectPool <uiList <int> > .alloc();

            indices.SetCapacity(cindices);
            for (var i = 0; i < paths.Count; i++)
            {
                var path = paths[i];
                if (path.count <= 1)
                {
                    continue;
                }

                if (path.nstroke > 0)
                {
                    for (var j = 2; j < path.nstroke; j++)
                    {
                        if ((j & 1) == 0)
                        {
                            indices.Add(path.istroke + j - 1);
                            indices.Add(path.istroke + j - 2);
                            indices.Add(path.istroke + j);
                        }
                        else
                        {
                            indices.Add(path.istroke + j - 2);
                            indices.Add(path.istroke + j - 1);
                            indices.Add(path.istroke + j);
                        }
                    }
                }
            }

            D.assert(indices.Count == cindices);

            ObjectPool <uiMeshMesh> .release(this._strokeMesh);

            this._strokeMesh  = uiMeshMesh.create(null, vertices, indices);
            this._strokeWidth = strokeWidth;
            this._lineCap     = lineCap;
            this._lineJoin    = lineJoin;
            this._miterLimit  = miterLimit;
            return(this._strokeMesh);
        }