浏览代码

Fix issues.

/main
Yuncong Zhang 5 年前
当前提交
ad55f93e
共有 7 个文件被更改,包括 528 次插入269 次删除
  1. 2
      Runtime/Resources/UIWidgets_canvas_strokeAlpha.shader
  2. 669
      Runtime/ui/painting/path.cs
  3. 15
      Runtime/ui/painting/picture.cs
  4. 76
      Runtime/ui/renderer/cmdbufferCanvas/rendering/canvas_impl.cs
  5. 25
      Runtime/ui/renderer/common/geometry/path/path_cache.cs
  6. 7
      Runtime/ui/renderer/common/geometry/path/path_utils.cs
  7. 3
      Runtime/ui/renderer/common/picture.cs

2
Runtime/Resources/UIWidgets_canvas_strokeAlpha.shader


SubShader {
ZTest Always
ZWrite Off
Blend One OneMinusSrcAlpha
Blend [_SrcBlend] [_DstBlend]
Stencil {
Ref 128

669
Runtime/ui/painting/path.cs


using System.Text;
using Unity.UIWidgets.foundation;
using UnityEngine;
using Vector2 = UnityEngine.Vector2;
using Vector3 = UnityEngine.Vector3;
struct VertexUV {
public List<Vector3> fillVertices;
public List<Vector2> fillUV;
public List<Vector3> strokeVertices;
public List<Vector2> strokeUV;
}
public class Path {
const float _KAPPA90 = 0.5522847493f;

float _minX, _minY;
float _maxX, _maxY;
PathCache _cache;
static uint pathGlobalKey = 0;

public uint pathKey {
get {
return this._pathKey;
}
get { return this._pathKey; }
}
public Path(int capacity = 128) {

public List<float> commands => this._commands;
public List<float> commands {
get { return this._commands; }
}
public override string ToString() {
var sb = new StringBuilder("Path: count = " + this._commands.Count);

internal PathCache flatten(float scale) {
scale = Mathf.Round(scale * 2.0f) / 2.0f; // round to 0.5f
this._cache = new PathCache(scale);
var i = 0;

if (x < this._minX) {
this._minX = x;
}
if (y < this._minY) {
this._minY = y;
}

}
if (y > this._maxY) {
this._maxY = y;
}

this._commandx = x;
this._commandy = y;
this._pathKey = pathGlobalKey++;
this._cache = null;
}

this._commandx = x;
this._commandy = y;
this._pathKey = pathGlobalKey++;
this._cache = null;
}

this._expandBounds(x1, y1);
this._expandBounds(x2, y2);
this._expandBounds(x3, y3);
this._commands.Add((float) PathCommand.bezierTo);
this._commands.Add(x1);
this._commands.Add(y1);

this._commands.Add(y3);
this._pathKey = pathGlobalKey++;
this._cache = null;
}

this._commands.Add(winding);
this._pathKey = pathGlobalKey++;
this._cache = null;
}

var y0 = this._commandy;
this._appendMoveTo(x + x0, y + y0);
}

public void relativeLineTo(float x, float y) {
var x0 = this._commandx;
var y0 = this._commandy;
public void lineTo(float x, float y) {
this._appendLineTo(x, y);
}

}
this.cubicTo(x0 + c1x, y0 + c1y, x0 + c2x, y0 + c2y, x0 + x, y0 + y);
}

if (!(w > 0)) {
this.lineTo(x2, y2);
return;
}
}
}
}
if (w == 1) {
this.quadraticBezierTo(x1, y1, x2, y2);
return;

var quadX = new float[5];
var quadY = new float[5];
conic.chopIntoQuadsPOW2(quadX, quadY, 1);
this.quadraticBezierTo(quadX[1], quadY[1], quadX[2], quadY[2]);
this.quadraticBezierTo(quadX[3], quadY[3], quadX[4], quadY[4]);
}

var y0 = this._commandy;
this.conicTo(x0 + x1, y0 + y1, x0 + x2, y0 + y2, w);
}

var squareRy = ry * ry;
var squareX = transformedMidPoint.dx * transformedMidPoint.dx;
var squareY = transformedMidPoint.dy * transformedMidPoint.dy;
// Check if the radii are big enough to draw the arc, scale radii if not.
// http://www.w3.org/TR/SVG/implnote.html#ArcCorrectionOutOfRangeRadii
var radiiScale = squareX / squareRx + squareY / squareRy;

ry *= radiiScale;
}
var unitPts = new [] {
var unitPts = new[] {
if (!clockwise != largeArc) { // flipped from the original implementation
if (!clockwise != largeArc) {
// flipped from the original implementation
if (thetaArc < 0 && clockwise) { // arcSweep flipped from the original implementation
if (thetaArc < 0 && clockwise) {
// arcSweep flipped from the original implementation
} else if (thetaArc > 0 && !clockwise) { // arcSweep flipped from the original implementation
}
else if (thetaArc > 0 && !clockwise) {
// arcSweep flipped from the original implementation
// the arc may be slightly bigger than 1/4 circle, so allow up to 1/3rd
int segments = Mathf.CeilToInt(Mathf.Abs(thetaArc / (2 * Mathf.PI / 3)));
var thetaWidth = thetaArc / segments;

}
bool expectIntegers = ScalarUtils.ScalarNearlyZero(Mathf.PI/2 - Mathf.Abs(thetaWidth)) &&
bool expectIntegers = ScalarUtils.ScalarNearlyZero(Mathf.PI / 2 - Mathf.Abs(thetaWidth)) &&
ScalarUtils.ScalarIsInteger(rx) && ScalarUtils.ScalarIsInteger(ry) &&
ScalarUtils.ScalarIsInteger(x1) && ScalarUtils.ScalarIsInteger(y1);

unitPts[1] += centerPoint;
unitPts[0] = unitPts[1];
unitPts[0] = unitPts[0].translate(t * sinEndTheta, -t * cosEndTheta);
var mapped = new [] {
var mapped = new[] {
/*
Computing the arc width introduces rounding errors that cause arcs to start
outside their marks. A round rect may lose convexity as a result. If the input

a0 = Mathf.Atan2(dx0, -dy0);
a1 = Mathf.Atan2(-dx1, dy1);
dir = PathWinding.clockwise;
} else {
}
else {
cx = x1 + dx0 * d + -dy0 * radius;
cy = y1 + dy0 * d + dx0 * radius;
a0 = Mathf.Atan2(-dx0, dy0);

if (dir == PathWinding.clockwise) {
if (Mathf.Abs(da) >= Mathf.PI * 2) {
da = Mathf.PI * 2;
} else {
}
else {
} else {
}
else {
} else {
}
else {
// Split arc into max 90 degree segments.
int ndivs = Mathf.Max(1, Mathf.Min((int) (Mathf.Abs(da) / (Mathf.PI * 0.5f) + 0.5f), 5));
float hda = (da / ndivs) / 2.0f;

if (move == PathCommand.moveTo) {
this._appendMoveTo(x1, y1);
} else {
}
else {
} else {
}
else {
float c1x = px + ptanx;
float c1y = py + ptany;
float c2x = x - tanx;

this._appendBezierTo(c1x, c1y, c2x, c2y, x1, y1);
}
px = x;
py = y;
ptanx = tanx;

if (points.Count == 0) {
return;
}
this._appendMoveTo(points[0].dx, points[0].dy);
for (int i = 1; i < points.Count; i++) {

this.addPath(path);
return;
}
var transform = Matrix3.makeTrans(offset.dx, offset.dy);
this.addPath(path, transform);
}

if (transform != null) {
transform.mapXY(x, y, out x, out y);
}
this._appendMoveTo(x, y);
}
i += 3;

if (transform != null) {
transform.mapXY(x, y, out x, out y);
}
this._appendLineTo(x, y);
}
i += 3;

transform.mapXY(c2x, c2y, out c2x, out c2y);
transform.mapXY(x1, y1, out x1, out y1);
}
this._appendBezierTo(c1x, c1y, c2x, c2y, x1, y1);
}
i += 7;

return totalW != 0;
}
static int windingLine(float x0, float y0, float x1, float y1, float x, float y) {
if (y0 == y1) {
return 0;

var closerY = Mathf.Abs(midY - startY) < Mathf.Abs(midY - endY) ? startY : endY;
c1.y2 = c2.y0 = closerY;
}
// Verify that all five points are in order.
D.assert(_between(startY, c1.y1, c1.y2));
D.assert(_between(c1.y1, c1.y2, c2.y1));

readonly ArrayRef<PathPath> _paths = new ArrayRef<PathPath>();
readonly ArrayRef<PathPoint> _points = new ArrayRef<PathPoint>();
List<Vector3> _vertices = null;
List<Vector2> _uv = null;
List<Vector3> _strokeVertices = null;
List<Vector2> _strokeUV = null;
bool _fillConvex;
bool _fillConvex;
public MeshMesh fillMesh {
get { return this._fillMesh; }
}
public MeshMesh strokeMesh {
get { return this._strokeMesh; }
}
float _fringe;
public PathCache(float scale) {
this._scale = scale;

this.addPath();
this.addPoint(0, 0, PointFlags.corner);
}
ref var path = ref this._paths.array[this._paths.length - 1];
if (path.count > 0) {
ref var pt = ref this._points.array[this._points.length - 1];

y = point.y + y1,
flags = flags,
});
} else {
}
else {
this._addPoint(new PathPoint {
x = point.x + x1,
y = point.y + y1,

public void normalize() {
var points = this._points;
var paths = this._paths;
var paths = this._paths;
for (var j = 0; j < paths.length; j++) {
ref var path = ref paths.array[j];
if (path.count <= 1) {

}
}
void _expandFill() {
var points = this._points;
var paths = this._paths;
for (var j = 0; j < paths.length; j++) {
ref var path = ref paths.array[j];
if (path.count <= 2) {
continue;
}
var ip0 = path.first + path.count - 1;
var ip1 = path.first;
for (var i = 0; i < path.count; i++) {
ref var p0 = ref points.array[ip0];
ref var p1 = ref points.array[ip1];
p0.dx = p1.x - p0.x; // no need to normalize
p0.dy = p1.y - p0.y;
ip0 = ip1++;
}
path.convex = true;
ip0 = path.first + path.count - 1;
ip1 = path.first;
for (var i = 0; i < path.count; i++) {
ref var p0 = ref points.array[ip0];
ref var p1 = ref points.array[ip1];
float cross = p1.dx * p0.dy - p0.dx * p1.dy;
if (cross < 0.0f) {
path.convex = false;
}
ip0 = ip1++;
}
}
var cvertices = 0;
for (var i = 0; i < paths.length; i++) {
ref var path = ref paths.array[i];
if (path.count <= 2) {
continue;
}
cvertices += path.count;
}
this._vertices = new List<Vector3>(cvertices);
for (var i = 0; i < paths.length; i++) {
ref var path = ref paths.array[i];
if (path.count <= 2) {
continue;
}
path.ifill = this._vertices.Count;
for (var j = 0; j < path.count; j++) {
ref var p = ref points.array[path.first + j];
this._vertices.Add(new Vector2(p.x, p.y));
}
path.nfill = this._vertices.Count - path.ifill;
}
}
public MeshMesh getFillMesh(out bool convex) {
if (this._fillMesh != null) {
convex = this._fillConvex;
return this._fillMesh;
}
this._expandFill();
var paths = this._paths;
var cindices = 0;
for (var i = 0; i < paths.length; i++) {
ref var path = ref paths.array[i];
if (path.count <= 2) {
continue;
}
if (path.nfill > 0) {
D.assert(path.nfill >= 2);
cindices += (path.nfill - 2) * 3;
}
}
var indices = new List<int>(cindices);
for (var i = 0; i < paths.length; i++) {
ref var path = ref paths.array[i];
if (path.count <= 2) {
continue;
}
if (path.nfill > 0) {
for (var j = 2; j < path.nfill; j++) {
indices.Add(path.ifill);
indices.Add(path.ifill + j);
indices.Add(path.ifill + j - 1);
}
}
}
D.assert(indices.Count == cindices);
var mesh = new MeshMesh(null, this._vertices, indices);
this._fillMesh = mesh;
this._fillConvex = false;
for (var i = 0; i < paths.length; i++) {
ref var path = ref paths.array[i];
if (path.count <= 2) {
continue;
}
if (this._fillConvex) {
// if more than two paths, convex is false.
this._fillConvex = false;
break;
}
if (!path.convex) {
// if not convex, convex is false.
break;
}
this._fillConvex = true;
}
convex = this._fillConvex;
return this._fillMesh;
}
void _calculateJoins(float w, StrokeJoin lineJoin, float miterLimit) {
float iw = w > 0.0f ? 1.0f / w : 0.0f;

}
}
void _expandStroke(float w, StrokeCap lineCap, StrokeJoin lineJoin, float miterLimit) {
this._calculateJoins(w, lineJoin, miterLimit);
VertexUV _expandStroke(float w, float fringe, StrokeCap lineCap, StrokeJoin lineJoin, float miterLimit) {
float aa = fringe;
float u0 = 0.0f, u1 = 1.0f;
ncap = PathUtils.curveDivs(w, Mathf.PI, this._tessTol);
ncap = uiPathUtils.curveDivs(w, Mathf.PI, this._tessTol);
}
w += aa * 0.5f;
if (aa == 0.0f) {
u0 = 0.5f;
u1 = 0.5f;
this._calculateJoins(w, lineJoin, miterLimit);
ref var path = ref paths.array[i];
var path = paths.array[i];
cvertices += 4;
cvertices += 8;
this._uv = new List<Vector2>(cvertices);
ref var path = ref paths.array[i];
var path = paths.array[i];
if (path.count <= 1) {
continue;
}

e = path.count - 1;
}
ref var p0 = ref points.array[ip0];
ref var p1 = ref points.array[ip1];
var p0 = points.array[ip0];
var p1 = points.array[ip1];
this._vertices.buttCapStart(p0, p0.dx, p0.dy, w, 0.0f);
this._vertices.buttCapStart(this._uv, p0, p0.dx, p0.dy, w, 0.0f, aa, u0, u1);
this._vertices.buttCapStart(p0, p0.dx, p0.dy, w, w);
this._vertices.buttCapStart(this._uv, p0, p0.dx, p0.dy, w, w, aa, u0, u1);
this._vertices.roundCapStart(p0, p0.dx, p0.dy, w, ncap);
this._vertices.roundCapStart(this._uv, p0, p0.dx, p0.dy, w, ncap, u0, u1);
p0 = ref points.array[ip0];
p1 = ref points.array[ip1];
p0 = points.array[ip0];
p1 = points.array[ip1];
this._vertices.roundJoin(p0, p1, w, w, ncap);
this._vertices.roundJoin(this._uv, p0, p1, w, w, ncap, u0, u1, aa);
this._vertices.bevelJoin(p0, p1, w, w);
this._vertices.bevelJoin(this._uv, p0, p1, w, w, u0, u1, aa);
this._uv.Add(new Vector2(u0, 1));
this._uv.Add(new Vector2(u1, 1));
}
ip0 = ip1++;

p0 = ref points.array[ip0];
p1 = ref points.array[ip1];
p0 = points.array[ip0];
p1 = points.array[ip1];
this._vertices.buttCapEnd(p1, p0.dx, p0.dy, w, 0.0f);
this._vertices.buttCapEnd(this._uv, p1, p0.dx, p0.dy, w, 0.0f, aa, u0, u1);
this._vertices.buttCapEnd(p1, p0.dx, p0.dy, w, w);
this._vertices.buttCapEnd(this._uv, p1, p0.dx, p0.dy, w, w, aa, u0, u1);
this._vertices.roundCapEnd(p1, p0.dx, p0.dy, w, ncap);
this._vertices.roundCapEnd(this._uv, p1, p0.dx, p0.dy, w, ncap, u0, u1);
this._uv.Add(new Vector2(u0, 1));
this._uv.Add(new Vector2(u1, 1));
paths.array[i] = path;
D.assert(this._uv.Count == this._vertices.Count);
return new VertexUV {
strokeVertices = this._vertices,
strokeUV = this._uv,
};
public MeshMesh getStrokeMesh(float strokeWidth, StrokeCap lineCap, StrokeJoin lineJoin, float miterLimit) {
VertexUV _expandFill(float fringe) {
float aa = fringe;
float woff = aa * 0.5f;
var points = this._points;
var paths = this._paths;
this._calculateJoins(fringe, StrokeJoin.miter, 4.0f);
var cvertices = 0;
for (var i = 0; i < paths.length; i++) {
var path = paths.array[i];
if (path.count <= 2) {
continue;
}
cvertices += path.count;
}
this._fillConvex = false;
for (var i = 0; i < paths.length; i++) {
var path = paths.array[i];
if (path.count <= 2) {
continue;
}
if (this._fillConvex) {
// if more than two paths, convex is false.
this._fillConvex = false;
break;
}
if (!path.convex) {
// if not convex, convex is false.
break;
}
this._fillConvex = true;
}
this._vertices = new List<Vector3>(cvertices);
this._uv = new List<Vector2>(cvertices);
for (var i = 0; i < paths.length; i++) {
var path = paths.array[i];
if (path.count <= 2) {
continue;
}
path.ifill = this._vertices.Count;
for (var j = 0; j < path.count; j++) {
var p = points.array[path.first + j];
if (aa > 0.0f) {
this._vertices.Add(new Vector2(p.x + p.dmx * woff, p.y + p.dmy * woff));
}
else {
this._vertices.Add(new Vector2(p.x, p.y));
}
this._uv.Add(new Vector2(0.5f, 1.0f));
}
path.nfill = this._vertices.Count - path.ifill;
paths.array[i] = path;
}
if (aa > 0.0f) {
this._strokeVertices = new List<Vector3>();
this._strokeUV = new List<Vector2>();
cvertices = 0;
for (var i = 0; i < paths.length; i++) {
var path = paths.array[i];
if (path.count <= 2) {
continue;
}
cvertices += path.count * 2;
}
this._strokeVertices.Capacity = cvertices;
this._strokeUV.Capacity = cvertices;
float lw = this._fillConvex ? woff : aa + woff;
float rw = aa - woff;
float lu = this._fillConvex ? 0.5f : 0.0f;
float ru = 1.0f;
for (var i = 0; i < paths.length; i++) {
var path = paths.array[i];
if (path.count <= 2) {
continue;
}
path.istroke = this._strokeVertices.Count;
for (var j = 0; j < path.count; j++) {
var p = points.array[path.first + j];
this._strokeVertices.Add(new Vector2(p.x + p.dmx * lw, p.y + p.dmy * lw));
this._strokeUV.Add(new Vector2(lu, 1.0f));
this._strokeVertices.Add(new Vector2(p.x - p.dmx * rw, p.y - p.dmy * rw));
this._strokeUV.Add(new Vector2(ru, 1.0f));
}
path.nstroke = this._strokeVertices.Count - path.istroke;
paths.array[i] = path;
}
}
return new VertexUV {
fillVertices = this._vertices,
fillUV = this._uv,
strokeVertices = this._strokeVertices,
strokeUV = this._strokeUV,
};
}
public void computeStrokeMesh(float strokeWidth, float fringe, StrokeCap lineCap, StrokeJoin lineJoin,
float miterLimit) {
this._fillMesh == null && // Ensure that the cached stroke mesh was not calculated in computeFillMesh
this._fringe == fringe &&
return this._strokeMesh;
return;
this._expandStroke(strokeWidth, lineCap, lineJoin, miterLimit);
var verticesUV = this._expandStroke(strokeWidth, fringe, lineCap, lineJoin, miterLimit);
ref var path = ref paths.array[i];
var path = paths.array[i];
if (path.count <= 1) {
continue;
}

var indices = new List<int>(cindices);
for (var i = 0; i < paths.length; i++) {
ref var path = ref paths.array[i];
var path = paths.array[i];
if (path.count <= 1) {
continue;
}

D.assert(indices.Count == cindices);
this._strokeMesh = new MeshMesh(null, this._vertices, indices);
this._strokeMesh = new MeshMesh(null, verticesUV.strokeVertices, indices, verticesUV.strokeUV);
this._fillMesh = null;
this._fringe = fringe;
return this._strokeMesh;
}
public void computeFillMesh(float fringe, out bool convex) {
if (this._fillMesh != null && (fringe != 0.0f || this._strokeMesh != null) && this._fringe == fringe) {
convex = this._fillConvex;
return;
}
var verticesUV = this._expandFill(fringe);
convex = this._fillConvex;
var paths = this._paths;
var cindices = 0;
for (var i = 0; i < paths.length; i++) {
var path = paths.array[i];
if (path.count <= 2) {
continue;
}
if (path.nfill > 0) {
D.assert(path.nfill >= 2);
cindices += (path.nfill - 2) * 3;
}
}
var indices = new List<int>(cindices);
for (var i = 0; i < paths.length; i++) {
var path = paths.array[i];
if (path.count <= 2) {
continue;
}
if (path.nfill > 0) {
for (var j = 2; j < path.nfill; j++) {
indices.Add(path.ifill);
indices.Add(path.ifill + j);
indices.Add(path.ifill + j - 1);
}
}
}
D.assert(indices.Count == cindices);
if (verticesUV.strokeVertices != null) {
cindices = 0;
for (var i = 0; i < paths.length; i++) {
var path = paths.array[i];
if (path.count <= 2) {
continue;
}
if (path.nstroke > 0) {
D.assert(path.nstroke >= 6);
cindices += path.nstroke * 3;
}
}
var strokeIndices = new List<int>(cindices);
for (var i = 0; i < paths.length; i++) {
var path = paths.array[i];
if (path.count <= 2) {
continue;
}
if (path.nstroke > 0) {
strokeIndices.Add(path.istroke + path.nstroke - 1);
strokeIndices.Add(path.istroke + path.nstroke - 2);
strokeIndices.Add(path.istroke);
strokeIndices.Add(path.istroke + path.nstroke - 1);
strokeIndices.Add(path.istroke);
strokeIndices.Add(path.istroke + 1);
for (var j = 2; j < path.nstroke; j++) {
if ((j & 1) == 0) {
strokeIndices.Add(path.istroke + j - 1);
strokeIndices.Add(path.istroke + j - 2);
strokeIndices.Add(path.istroke + j);
}
else {
strokeIndices.Add(path.istroke + j - 2);
strokeIndices.Add(path.istroke + j - 1);
strokeIndices.Add(path.istroke + j);
}
}
}
}
D.assert(strokeIndices.Count == cindices);
this._strokeMesh = new MeshMesh(null, verticesUV.strokeVertices, strokeIndices, verticesUV.strokeUV);
}
var mesh = new MeshMesh(null, verticesUV.fillVertices, indices, verticesUV.fillUV);
this._fillMesh = mesh;
this._fringe = fringe;
}
}

return d;
}
public static void buttCapStart(this List<Vector3> dst, PathPoint p,
float dx, float dy, float w, float d) {
public static void buttCapStart(this List<Vector3> dst, List<Vector2> uv, PathPoint p,
float dx, float dy, float w, float d, float aa, float u0, float u1) {
dst.Add(new Vector2(px + dlx * w - dx * aa, py + dly * w - dy * aa));
dst.Add(new Vector2(px - dlx * w - dx * aa, py - dly * w - dy * aa));
uv.Add(new Vector2(u0, 0));
uv.Add(new Vector2(u1, 0));
uv.Add(new Vector2(u0, 1));
uv.Add(new Vector2(u1, 1));
public static void buttCapEnd(this List<Vector3> dst, PathPoint p,
float dx, float dy, float w, float d) {
public static void buttCapEnd(this List<Vector3> dst, List<Vector2> uv, PathPoint p,
float dx, float dy, float w, float d, float aa, float u0, float u1) {
float px = p.x + dx * d;
float py = p.y + dy * d;
float dlx = dy;

dst.Add(new Vector2(px - dlx * w, py - dly * w));
dst.Add(new Vector2(px + dlx * w + dx * aa, py + dly * w + dy * aa));
dst.Add(new Vector2(px - dlx * w + dx * aa, py - dly * w + dy * aa));
uv.Add(new Vector2(u0, 1));
uv.Add(new Vector2(u1, 1));
uv.Add(new Vector2(u0, 0));
uv.Add(new Vector2(u1, 0));
public static void roundCapStart(this List<Vector3> dst, PathPoint p,
float dx, float dy, float w, int ncap) {
public static void roundCapStart(this List<Vector3> dst, List<Vector2> uv, PathPoint p,
float dx, float dy, float w, int ncap, float u0, float u1) {
float px = p.x;
float py = p.y;
float dlx = dy;

float ax = Mathf.Cos(a) * w, ay = Mathf.Sin(a) * w;
dst.Add(new Vector2(px - dlx * ax - dx * ay, py - dly * ax - dy * ay));
dst.Add(new Vector2(px, py));
uv.Add(new Vector2(u0, 1));
uv.Add(new Vector2(0.5f, 1));
uv.Add(new Vector2(u0, 1));
uv.Add(new Vector2(u1, 1));
public static void roundCapEnd(this List<Vector3> dst, PathPoint p,
float dx, float dy, float w, int ncap) {
public static void roundCapEnd(this List<Vector3> dst, List<Vector2> uv, PathPoint p,
float dx, float dy, float w, int ncap, float u0, float u1) {
float px = p.x;
float py = p.y;
float dlx = dy;

dst.Add(new Vector2(px - dlx * w, py - dly * w));
uv.Add(new Vector2(u0, 1));
uv.Add(new Vector2(u1, 1));
for (var i = 0; i < ncap; i++) {
float a = (float) i / (ncap - 1) * Mathf.PI;

uv.Add(new Vector2(0.5f, 1));
uv.Add(new Vector2(u0, 1));
}
}

return Mathf.Max(2, Mathf.CeilToInt(arc / da));
}
public static void roundJoin(this List<Vector3> dst, PathPoint p0, PathPoint p1,
float lw, float rw, int ncap) {
public static void roundJoin(this List<Vector3> dst, List<Vector2> uv, PathPoint p0, PathPoint p1,
float lw, float rw, int ncap, float lu, float ru, float fringe) {
float dlx0 = p0.dy;
float dly0 = -p0.dx;
float dlx1 = p1.dy;

dst.Add(new Vector2(lx0, ly0));
dst.Add(new Vector2(p1.x - dlx0 * rw, p1.y - dly0 * rw));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(ru, 1));
var n = Mathf.CeilToInt((a0 - a1) / Mathf.PI * ncap).clamp(2, ncap);
for (var i = 0; i < n; i++) {

dst.Add(new Vector2(p1.x, p1.y));
dst.Add(new Vector2(rx, ry));
uv.Add(new Vector2(0.5f, 1));
uv.Add(new Vector2(ru, 1));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(ru, 1));
}
else {
float rx0, ry0, rx1, ry1;

dst.Add(new Vector2(p1.x + dlx0 * lw, p1.y + dly0 * lw));
dst.Add(new Vector2(rx0, ry0));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(ru, 1));
var n = Mathf.CeilToInt((a1 - a0) / Mathf.PI * ncap).clamp(2, ncap);
for (var i = 0; i < n; i++) {

dst.Add(new Vector2(lx, ly));
dst.Add(new Vector2(p1.x, p1.y));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(0.5f, 1));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(ru, 1));
public static void bevelJoin(this List<Vector3> dst, PathPoint p0, PathPoint p1,
float lw, float rw) {
public static void bevelJoin(this List<Vector3> dst, List<Vector2> uv, PathPoint p0, PathPoint p1,
float lw, float rw, float lu, float ru, float fringe) {
float rx0, ry0, rx1, ry1;
float lx0, ly0, lx1, ly1;

dst.Add(new Vector2 {x = lx0, y = ly0});
dst.Add(new Vector2 {x = p1.x - dlx0 * rw, y = p1.y - dly0 * rw});
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(ru, 1));
if ((p1.flags & PointFlags.bevel) != 0) {
dst.Add(new Vector2(lx0, ly0));

uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(ru, 1));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(ru, 1));
}
else {
rx0 = p1.x - p1.dmx * rw;

dst.Add(new Vector2(rx0, ry0));
dst.Add(new Vector2(p1.x, p1.y));
dst.Add(new Vector2(p1.x - dlx1 * rw, p1.y - dly1 * rw));
uv.Add(new Vector2(0.5f, 1));
uv.Add(new Vector2(ru, 1));
uv.Add(new Vector2(ru, 1));
uv.Add(new Vector2(ru, 1));
uv.Add(new Vector2(0.5f, 1));
uv.Add(new Vector2(ru, 1));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(ru, 1));
}
else {
chooseBevel((p1.flags & PointFlags.innerBevel) != 0, p0, p1, -rw,

dst.Add(new Vector2(rx0, ry0));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(ru, 1));
if ((p1.flags & PointFlags.bevel) != 0) {
dst.Add(new Vector2(p1.x + dlx0 * lw, p1.y + dly0 * lw));

uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(ru, 1));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(ru, 1));
}
else {
lx0 = p1.x + p1.dmx * lw;

dst.Add(new Vector2(lx0, ly0));
dst.Add(new Vector2(p1.x + dlx1 * lw, p1.y + dly1 * lw));
dst.Add(new Vector2(p1.x, p1.y));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(0.5f, 1));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(0.5f, 1));
uv.Add(new Vector2(lu, 1));
uv.Add(new Vector2(ru, 1));
}
}
}

15
Runtime/ui/painting/picture.cs


var state = this._getState();
var scale = XformUtils.getScale(state.xform);
var rect = cmd.path.flatten(
var cache = cmd.path.flatten(
).getFillMesh(out _).transform(state.xform).bounds;
);
cache.computeFillMesh(0.0f, out _);
var rect = cache.fillMesh.transform(state.xform).bounds;
state.scissor = state.scissor == null ? rect : state.scissor.intersect(rect);
break;
}

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

}
var cache = path.flatten(scale * devicePixelRatio);
mesh = cache.getStrokeMesh(
cache.computeStrokeMesh(
0.0f,
paint.strokeMiterLimit).transform(state.xform);
paint.strokeMiterLimit);
mesh = cache.strokeMesh.transform(state.xform);
}
if (paint.maskFilter != null && paint.maskFilter.sigma != 0) {

76
Runtime/ui/renderer/cmdbufferCanvas/rendering/canvas_impl.cs


RenderLayer _createMaskLayer(RenderLayer parentLayer, uiRect maskBounds,
_drawPathDrawMeshCallbackDelegate drawCallback,
uiPaint paint, bool convex, float alpha, float strokeMult, Texture tex, uiRect texBound, TextBlobMesh textMesh,
uiPaint paint, bool convex, float alpha, float strokeMult, Texture tex, uiRect texBound,
TextBlobMesh textMesh,
uiMeshMesh fillMesh, uiMeshMesh strokeMesh, bool notEmoji) {
var textureWidth = Mathf.CeilToInt(maskBounds.width * this._devicePixelRatio);
if (textureWidth < 1) {

var maskState = maskLayer.states[maskLayer.states.Count - 1];
maskState.matrix = parentState.matrix;
drawCallback.Invoke(uiPaint.shapeOnly(paint), fillMesh, strokeMesh, convex, alpha, strokeMult, tex, texBound, textMesh, notEmoji);
drawCallback.Invoke(uiPaint.shapeOnly(paint), fillMesh, strokeMesh, convex, alpha, strokeMult, tex,
texBound, textMesh, notEmoji);
var removed = this._layers.removeLast();
D.assert(removed == maskLayer);

}
void _drawWithMaskFilter(uiRect meshBounds, uiPaint paint, uiMaskFilter maskFilter,
uiMeshMesh fillMesh, uiMeshMesh strokeMesh, bool convex, float alpha, float strokeMult, Texture tex, uiRect texBound, TextBlobMesh textMesh, bool notEmoji,
uiMeshMesh fillMesh, uiMeshMesh strokeMesh, bool convex, float alpha, float strokeMult, Texture tex,
uiRect texBound, TextBlobMesh textMesh, bool notEmoji,
_drawPathDrawMeshCallbackDelegate drawCallback) {
var layer = this._currentLayer;
var clipBounds = layer.layerBounds;

return;
}
var maskLayer = this._createMaskLayer(layer, maskBounds, drawCallback, paint, convex, alpha, strokeMult, tex, texBound,
var maskLayer = this._createMaskLayer(layer, maskBounds, drawCallback, paint, convex, alpha, strokeMult,
tex, texBound,
textMesh, fillMesh, strokeMesh, notEmoji);
var blurLayer = this._createBlurLayer(maskLayer, sigma, sigma, layer);

layer.draws.Add(CanvasShader.texRT(layer, paint, blurMesh, blurLayer));
}
delegate void _drawPathDrawMeshCallbackDelegate(uiPaint p, uiMeshMesh fillMesh, uiMeshMesh strokeMesh, bool convex, float alpha, float strokeMult,
delegate void _drawPathDrawMeshCallbackDelegate(uiPaint p, uiMeshMesh fillMesh, uiMeshMesh strokeMesh,
bool convex, float alpha, float strokeMult,
void _drawPathDrawMeshCallback(uiPaint p, uiMeshMesh fillMesh, uiMeshMesh strokeMesh, bool convex, float alpha, float strokeMult, Texture tex,
void _drawPathDrawMeshCallback(uiPaint p, uiMeshMesh fillMesh, uiMeshMesh strokeMesh, bool convex, float alpha,
float strokeMult, Texture tex,
ObjectPool<uiMeshMesh>.release(strokeMesh);
return;
}

}
}
void _drawPathDrawMeshCallback2(uiPaint p, uiMeshMesh fillMesh, uiMeshMesh strokeMesh, bool convex, float alpha, float strokeMult, Texture tex,
void _drawPathDrawMeshCallback2(uiPaint p, uiMeshMesh fillMesh, uiMeshMesh strokeMesh, bool convex, float alpha,
float strokeMult, Texture tex,
uiRect textBlobBounds, TextBlobMesh textMesh, bool notEmoji) {
if (!this._applyClip(strokeMesh.bounds)) {
ObjectPool<uiMeshMesh>.release(strokeMesh);

layer.draws.Add(CanvasShader.stroke1(layer, strokeMesh.duplicate()));
}
void _drawTextDrawMeshCallback(uiPaint p, uiMeshMesh fillMesh, uiMeshMesh strokeMesh, bool convex, float alpha, float strokeMult, Texture tex,
void _drawTextDrawMeshCallback(uiPaint p, uiMeshMesh fillMesh, uiMeshMesh strokeMesh, bool convex, float alpha,
float strokeMult, Texture tex,
uiRect textBlobBounds, TextBlobMesh textMesh, bool notEmoji) {
if (!this._applyClip(textBlobBounds)) {
ObjectPool<TextBlobMesh>.release(textMesh);

float strokeMult = 1.0f;
if (paint.maskFilter != null && paint.maskFilter.Value.sigma != 0) {
this._drawWithMaskFilter(fmesh.bounds, paint, paint.maskFilter.Value, fmesh, smesh, convex, 0, strokeMult, null,
this._drawWithMaskFilter(fmesh.bounds, paint, paint.maskFilter.Value, fmesh, smesh, convex, 0,
strokeMult, null,
this._drawPathDrawMeshCallback(paint, fmesh, smesh, convex, 1.0f, strokeMult, null, uiRectHelper.zero, null, false);
this._drawPathDrawMeshCallback(paint, fmesh, smesh, convex, 1.0f, strokeMult, null, uiRectHelper.zero,
null, false);
}
else {
var state = this._currentLayer.currentState;

var cache = path.flatten(state.scale * this._devicePixelRatio);
var strokeMesh = cache.computeStrokeMesh(
cache.computeStrokeMesh(
var strokeMesh = cache.strokeMesh;
this._drawWithMaskFilter(mesh.bounds, paint, paint.maskFilter.Value, null, mesh, false, alpha, strokeMult, null,
this._drawWithMaskFilter(mesh.bounds, paint, paint.maskFilter.Value, null, mesh, false, alpha,
strokeMult, null,
this._drawPathDrawMeshCallback2(paint, null, mesh, false, alpha, strokeMult, null, uiRectHelper.zero, null, false);
this._drawPathDrawMeshCallback2(paint, null, mesh, false, alpha, strokeMult, null, uiRectHelper.zero,
null, false);
}
}

this._saveLayer(uiRectHelper.fromRect(cmd.rect), uiPaint.fromPaint(cmd.paint));
break;
}
case DrawRestore _: {
saveCount--;
if (saveCount < 0) {

this._restore();
break;
}
case DrawResetMatrix _:
this._resetMatrix();
break;

}
case DrawClipPath cmd: {
var uipath = uiPath.fromPath(cmd.path);
this._clipPath(uipath);

case DrawPath cmd: {
var uipath = uiPath.fromPath(cmd.path);
this._drawPath(uipath, uiPaint.fromPaint(cmd.paint));

case DrawImageNine cmd: {
this._drawImageNine(cmd.image, uiRectHelper.fromRect(cmd.src),
uiRectHelper.fromRect(cmd.center), uiRectHelper.fromRect(cmd.dst),

default:
throw new Exception("unknown drawCmd: " + drawCmd);
}

this._saveLayer(cmd.rect.Value, cmd.paint);
break;
}
case uiDrawRestore _: {
saveCount--;
if (saveCount < 0) {

this._restore();
break;
}
case uiDrawResetMatrix _:
this._resetMatrix();
break;

}
default:
throw new Exception("unknown drawCmd: " + drawCmd);
}

this._lastScissor = null;
this._layers.Clear();
}
AllocDebugger.onFrameEnd();
}
int _lastRtID;

25
Runtime/ui/renderer/common/geometry/path/path_cache.cs


float _scale;
bool _fillConvex;
//mesh cache
uiMeshMesh _fillMesh;

bool _fillConvex;
uiMeshMesh _strokeMesh;

}
}
struct VertexUV {
public uiList<Vector3> fillVertices;
public uiList<Vector2> fillUV;
public uiList<Vector3> strokeVertices;
public uiList<Vector2> strokeUV;
}
VertexUV _expandStroke(float w, float fringe, StrokeCap lineCap, StrokeJoin lineJoin, float miterLimit) {
uiVertexUV _expandStroke(float w, float fringe, StrokeCap lineCap, StrokeJoin lineJoin, float miterLimit) {
float aa = fringe;
float u0 = 0.0f, u1 = 1.0f;
int ncap = 0;

}
D.assert(_uv.Count == _vertices.Count);
return new VertexUV {
return new uiVertexUV {
VertexUV _expandFill(float fringe) {
uiVertexUV _expandFill(float fringe) {
float aa = fringe;
float woff = aa * 0.5f;
var points = this._points;

}
}
return new VertexUV {
return new uiVertexUV {
fillVertices = _vertices,
fillUV = _uv,
strokeVertices = _strokeVertices,

public uiMeshMesh computeStrokeMesh(float strokeWidth, float fringe, StrokeCap lineCap, StrokeJoin lineJoin, float miterLimit) {
public void computeStrokeMesh(float strokeWidth, float fringe, StrokeCap lineCap, StrokeJoin lineJoin, float miterLimit) {
if (this._strokeMesh != null &&
this._fillMesh == null && // Ensure that the cached stroke mesh was not calculated in computeFillMesh
this._strokeWidth == strokeWidth &&

this._miterLimit == miterLimit) {
return this._strokeMesh;
return;
}
var verticesUV = this._expandStroke(strokeWidth, fringe, lineCap, lineJoin, miterLimit);

this._lineCap = lineCap;
this._lineJoin = lineJoin;
this._miterLimit = miterLimit;
return this._strokeMesh;
return;
}
public void computeFillMesh(float fringe, out bool convex) {

7
Runtime/ui/renderer/common/geometry/path/path_utils.cs


}
}
struct uiVertexUV {
public uiList<Vector3> fillVertices;
public uiList<Vector2> fillUV;
public uiList<Vector3> strokeVertices;
public uiList<Vector2> strokeUV;
}
static class uiPathUtils {
public static bool ptEquals(float x1, float y1, float x2, float y2, float tol) {
float dx = x2 - x1;

3
Runtime/ui/renderer/common/picture.cs


}
var cache = path.flatten(scale * devicePixelRatio);
var strokenMesh = cache.computeStrokeMesh(
cache.computeStrokeMesh(
var strokenMesh = cache.strokeMesh;
mesh = strokenMesh.transform(state.xform);
}

正在加载...
取消
保存