|
|
|
|
|
|
innerBevel = 0x08, |
|
|
|
} |
|
|
|
|
|
|
|
struct uiPathPoint { |
|
|
|
class uiPathPoint { |
|
|
|
public float x, y; |
|
|
|
public float dx, dy; |
|
|
|
public float len; |
|
|
|
|
|
|
|
|
|
|
struct uiPathPath { |
|
|
|
class uiPathPath { |
|
|
|
public int first; |
|
|
|
public int count; |
|
|
|
public bool closed; |
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
class uiPathCache { |
|
|
|
readonly float _scale; |
|
|
|
readonly float _distTol; |
|
|
|
readonly float _tessTol; |
|
|
|
|
|
|
|
readonly ArrayRef<uiPathPath> _paths = new ArrayRef<uiPathPath>(); |
|
|
|
readonly ArrayRef<uiPathPoint> _points = new ArrayRef<uiPathPoint>(); |
|
|
|
List<Vector3> _vertices = null; |
|
|
|
float _scale; |
|
|
|
float _distTol; |
|
|
|
float _tessTol; |
|
|
|
uiMeshMesh _fillMesh; |
|
|
|
bool _fillConvex; |
|
|
|
|
|
|
|
uiMeshMesh _strokeMesh; |
|
|
|
float _strokeWidth; |
|
|
|
StrokeCap _lineCap; |
|
|
|
StrokeJoin _lineJoin; |
|
|
|
float _miterLimit; |
|
|
|
List<uiPathPath> _paths = new List<uiPathPath>(); |
|
|
|
List<uiPathPoint> _points = new List<uiPathPoint>(); |
|
|
|
|
|
|
|
public uiPathCache(float scale) { |
|
|
|
this._scale = scale; |
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
public void addPath() { |
|
|
|
this._paths.add(new uiPathPath { |
|
|
|
first = this._points.length, |
|
|
|
this._paths.Add(new uiPathPath { |
|
|
|
first = this._points.Count, |
|
|
|
winding = uiPathWinding.counterClockwise |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
void _addPoint(uiPathPoint point) { |
|
|
|
if (this._paths.length == 0) { |
|
|
|
if (this._paths.Count == 0) { |
|
|
|
ref var path = ref this._paths.array[this._paths.length - 1]; |
|
|
|
var path = this._paths[this._paths.Count - 1]; |
|
|
|
ref var pt = ref this._points.array[this._points.length - 1]; |
|
|
|
var pt = this._points[this._points.Count - 1]; |
|
|
|
if (uiPathUtils.ptEquals(pt.x, pt.y, point.x, point.y, this._distTol)) { |
|
|
|
pt.flags |= point.flags; |
|
|
|
return; |
|
|
|
|
|
|
this._points.add(point); |
|
|
|
this._points.Add(point); |
|
|
|
path.count++; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
uiPointFlags flags) { |
|
|
|
float x1, y1; |
|
|
|
if (this._points.length == 0) { |
|
|
|
if (this._points.Count == 0) { |
|
|
|
ref var pt = ref this._points.array[this._points.length - 1]; |
|
|
|
var pt = this._points[this._points.Count - 1]; |
|
|
|
x1 = pt.x; |
|
|
|
y1 = pt.y; |
|
|
|
} |
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
public void closePath() { |
|
|
|
if (this._paths.length == 0) { |
|
|
|
if (this._paths.Count == 0) { |
|
|
|
ref var path = ref this._paths.array[this._paths.length - 1]; |
|
|
|
var path = this._paths[this._paths.Count - 1]; |
|
|
|
if (this._paths.length == 0) { |
|
|
|
if (this._paths.Count == 0) { |
|
|
|
ref var path = ref this._paths.array[this._paths.length - 1]; |
|
|
|
var path = this._paths[this._paths.Count - 1]; |
|
|
|
path.winding = winding; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
for (var j = 0; j < paths.length; j++) { |
|
|
|
ref var path = ref paths.array[j]; |
|
|
|
for (var j = 0; j < paths.Count; j++) { |
|
|
|
var path = paths[j]; |
|
|
|
if (path.count <= 1) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
ref var p0 = ref points.array[ip0]; |
|
|
|
ref var p1 = ref points.array[ip1]; |
|
|
|
var p0 = points[ip0]; |
|
|
|
var p1 = points[ip1]; |
|
|
|
if (uiPathUtils.ptEquals(p0.x, p0.y, p1.x, p1.y, this._distTol)) { |
|
|
|
path.count--; |
|
|
|
path.closed = true; |
|
|
|
|
|
|
if (path.winding == uiPathWinding.clockwise) { |
|
|
|
uiPathUtils.polyReverse(points.array, path.first, path.count); |
|
|
|
uiPathUtils.polyReverse(points, path.first, path.count); |
|
|
|
void _expandFill() { |
|
|
|
uiList<Vector3> _expandFill() { |
|
|
|
for (var j = 0; j < paths.length; j++) { |
|
|
|
ref var path = ref paths.array[j]; |
|
|
|
for (var j = 0; j < paths.Count; j++) { |
|
|
|
var path = paths[j]; |
|
|
|
if (path.count <= 2) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
for (var i = 0; i < path.count; i++) { |
|
|
|
ref var p0 = ref points.array[ip0]; |
|
|
|
ref var p1 = ref points.array[ip1]; |
|
|
|
var p0 = points[ip0]; |
|
|
|
var p1 = points[ip1]; |
|
|
|
p0.dx = p1.x - p0.x; // no need to normalize
|
|
|
|
p0.dy = p1.y - p0.y; |
|
|
|
ip0 = ip1++; |
|
|
|
|
|
|
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]; |
|
|
|
var p0 = points[ip0]; |
|
|
|
var p1 = points[ip1]; |
|
|
|
|
|
|
|
float cross = p1.dx * p0.dy - p0.dx * p1.dy; |
|
|
|
if (cross < 0.0f) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var cvertices = 0; |
|
|
|
for (var i = 0; i < paths.length; i++) { |
|
|
|
ref var path = ref paths.array[i]; |
|
|
|
for (var i = 0; i < paths.Count; i++) { |
|
|
|
var path = paths[i]; |
|
|
|
if (path.count <= 2) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
this._vertices = new List<Vector3>(cvertices); |
|
|
|
for (var i = 0; i < paths.length; i++) { |
|
|
|
ref var path = ref paths.array[i]; |
|
|
|
|
|
|
|
var _vertices = ItemPoolManager.alloc<uiList<Vector3>>(); |
|
|
|
_vertices.SetCapacity(cvertices); |
|
|
|
for (var i = 0; i < paths.Count; i++) { |
|
|
|
var path = paths[i]; |
|
|
|
path.ifill = this._vertices.Count; |
|
|
|
path.ifill = _vertices.Count; |
|
|
|
ref var p = ref points.array[path.first + j]; |
|
|
|
this._vertices.Add(new Vector2(p.x, p.y)); |
|
|
|
var p = points[path.first + j]; |
|
|
|
_vertices.Add(new Vector2(p.x, p.y)); |
|
|
|
path.nfill = this._vertices.Count - path.ifill; |
|
|
|
path.nfill = _vertices.Count - path.ifill; |
|
|
|
|
|
|
|
return _vertices; |
|
|
|
if (this._fillMesh != null) { |
|
|
|
convex = this._fillConvex; |
|
|
|
return this._fillMesh; |
|
|
|
} |
|
|
|
|
|
|
|
this._expandFill(); |
|
|
|
var vertices = this._expandFill(); |
|
|
|
for (var i = 0; i < paths.length; i++) { |
|
|
|
ref var path = ref paths.array[i]; |
|
|
|
for (var i = 0; i < paths.Count; i++) { |
|
|
|
var path = paths[i]; |
|
|
|
if (path.count <= 2) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
var indices = new List<int>(cindices); |
|
|
|
for (var i = 0; i < paths.length; i++) { |
|
|
|
ref var path = ref paths.array[i]; |
|
|
|
var indices = ItemPoolManager.alloc<uiList<int>>(); |
|
|
|
indices.SetCapacity(cindices); |
|
|
|
for (var i = 0; i < paths.Count; i++) { |
|
|
|
var path = paths[i]; |
|
|
|
if (path.count <= 2) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
D.assert(indices.Count == cindices); |
|
|
|
|
|
|
|
var mesh = new uiMeshMesh(null, this._vertices, indices); |
|
|
|
this._fillMesh = mesh; |
|
|
|
var mesh = new uiMeshMesh(null, vertices.data, indices.data); |
|
|
|
var _fillMesh = mesh; |
|
|
|
this._fillConvex = false; |
|
|
|
for (var i = 0; i < paths.length; i++) { |
|
|
|
ref var path = ref paths.array[i]; |
|
|
|
var _fillConvex = false; |
|
|
|
for (var i = 0; i < paths.Count; i++) { |
|
|
|
var path = paths[i]; |
|
|
|
if (this._fillConvex) { |
|
|
|
if (_fillConvex) { |
|
|
|
this._fillConvex = false; |
|
|
|
_fillConvex = false; |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
this._fillConvex = true; |
|
|
|
_fillConvex = true; |
|
|
|
convex = this._fillConvex; |
|
|
|
return this._fillMesh; |
|
|
|
convex = _fillConvex; |
|
|
|
return _fillMesh; |
|
|
|
} |
|
|
|
|
|
|
|
void _calculateJoins(float w, StrokeJoin lineJoin, float miterLimit) { |
|
|
|
|
|
|
var paths = this._paths; |
|
|
|
for (var i = 0; i < paths.length; i++) { |
|
|
|
ref var path = ref paths.array[i]; |
|
|
|
for (var i = 0; i < paths.Count; i++) { |
|
|
|
var path = paths[i]; |
|
|
|
if (path.count <= 1) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
for (var j = 0; j < path.count; j++) { |
|
|
|
ref var p0 = ref points.array[ip0]; |
|
|
|
ref var p1 = ref points.array[ip1]; |
|
|
|
var p0 = points[ip0]; |
|
|
|
var p1 = points[ip1]; |
|
|
|
p0.dx = p1.x - p0.x; |
|
|
|
p0.dy = p1.y - p0.y; |
|
|
|
p0.len = uiPathUtils.normalize(ref p0.dx, ref p0.dy); |
|
|
|
|
|
|
ip0 = path.first + path.count - 1; |
|
|
|
ip1 = path.first; |
|
|
|
for (var j = 0; j < path.count; j++) { |
|
|
|
ref var p0 = ref points.array[ip0]; |
|
|
|
ref var p1 = ref points.array[ip1]; |
|
|
|
var p0 = points[ip0]; |
|
|
|
var p1 = points[ip1]; |
|
|
|
float dlx0 = p0.dy; |
|
|
|
float dly0 = -p0.dx; |
|
|
|
float dlx1 = p1.dy; |
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void _expandStroke(float w, StrokeCap lineCap, StrokeJoin lineJoin, float miterLimit) { |
|
|
|
uiList<Vector3> _expandStroke(float w, StrokeCap lineCap, StrokeJoin lineJoin, float miterLimit) { |
|
|
|
this._calculateJoins(w, lineJoin, miterLimit); |
|
|
|
|
|
|
|
int ncap = 0; |
|
|
|
|
|
|
var paths = this._paths; |
|
|
|
|
|
|
|
var cvertices = 0; |
|
|
|
for (var i = 0; i < paths.length; i++) { |
|
|
|
ref var path = ref paths.array[i]; |
|
|
|
for (var i = 0; i < paths.Count; i++) { |
|
|
|
var path = paths[i]; |
|
|
|
if (path.count <= 1) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
this._vertices = new List<Vector3>(cvertices); |
|
|
|
for (var i = 0; i < paths.length; i++) { |
|
|
|
ref var path = ref paths.array[i]; |
|
|
|
var _vertices = ItemPoolManager.alloc<uiList<Vector3>>(); |
|
|
|
_vertices.SetCapacity(cvertices); |
|
|
|
for (var i = 0; i < paths.Count; i++) { |
|
|
|
var path = paths[i]; |
|
|
|
path.istroke = this._vertices.Count; |
|
|
|
path.istroke = _vertices.Count; |
|
|
|
|
|
|
|
int s, e, ip0, ip1; |
|
|
|
if (path.closed) { |
|
|
|
|
|
|
e = path.count - 1; |
|
|
|
} |
|
|
|
|
|
|
|
ref var p0 = ref points.array[ip0]; |
|
|
|
ref var p1 = ref points.array[ip1]; |
|
|
|
var p0 = points[ip0]; |
|
|
|
var p1 = points[ip1]; |
|
|
|
this._vertices.buttCapStart(p0, p0.dx, p0.dy, w, 0.0f); |
|
|
|
_vertices.buttCapStart(p0, p0.dx, p0.dy, w, 0.0f); |
|
|
|
this._vertices.buttCapStart(p0, p0.dx, p0.dy, w, w); |
|
|
|
_vertices.buttCapStart(p0, p0.dx, p0.dy, w, w); |
|
|
|
this._vertices.roundCapStart(p0, p0.dx, p0.dy, w, ncap); |
|
|
|
_vertices.roundCapStart(p0, p0.dx, p0.dy, w, ncap); |
|
|
|
p0 = ref points.array[ip0]; |
|
|
|
p1 = ref points.array[ip1]; |
|
|
|
p0 = points[ip0]; |
|
|
|
p1 = points[ip1]; |
|
|
|
this._vertices.roundJoin(p0, p1, w, w, ncap); |
|
|
|
_vertices.roundJoin(p0, p1, w, w, ncap); |
|
|
|
this._vertices.bevelJoin(p0, p1, w, w); |
|
|
|
_vertices.bevelJoin(p0, p1, w, w); |
|
|
|
this._vertices.Add(new Vector2(p1.x + p1.dmx * w, p1.y + p1.dmy * w)); |
|
|
|
this._vertices.Add(new Vector2(p1.x - p1.dmx * w, p1.y - p1.dmy * w)); |
|
|
|
_vertices.Add(new Vector2(p1.x + p1.dmx * w, p1.y + p1.dmy * w)); |
|
|
|
_vertices.Add(new Vector2(p1.x - p1.dmx * w, p1.y - p1.dmy * w)); |
|
|
|
} |
|
|
|
|
|
|
|
ip0 = ip1++; |
|
|
|
|
|
|
p0 = ref points.array[ip0]; |
|
|
|
p1 = ref points.array[ip1]; |
|
|
|
p0 = points[ip0]; |
|
|
|
p1 = points[ip1]; |
|
|
|
this._vertices.buttCapEnd(p1, p0.dx, p0.dy, w, 0.0f); |
|
|
|
_vertices.buttCapEnd(p1, p0.dx, p0.dy, w, 0.0f); |
|
|
|
this._vertices.buttCapEnd(p1, p0.dx, p0.dy, w, w); |
|
|
|
_vertices.buttCapEnd(p1, p0.dx, p0.dy, w, w); |
|
|
|
this._vertices.roundCapEnd(p1, p0.dx, p0.dy, w, ncap); |
|
|
|
_vertices.roundCapEnd(p1, p0.dx, p0.dy, w, ncap); |
|
|
|
this._vertices.Add(this._vertices[path.istroke]); |
|
|
|
this._vertices.Add(this._vertices[path.istroke + 1]); |
|
|
|
_vertices.Add(_vertices[path.istroke]); |
|
|
|
_vertices.Add(_vertices[path.istroke + 1]); |
|
|
|
path.nstroke = this._vertices.Count - path.istroke; |
|
|
|
path.nstroke = _vertices.Count - path.istroke; |
|
|
|
|
|
|
|
return _vertices; |
|
|
|
if (this._strokeMesh != null && |
|
|
|
this._strokeWidth == strokeWidth && |
|
|
|
this._lineCap == lineCap && |
|
|
|
this._lineJoin == lineJoin && |
|
|
|
this._miterLimit == miterLimit) { |
|
|
|
return this._strokeMesh; |
|
|
|
} |
|
|
|
|
|
|
|
this._expandStroke(strokeWidth, lineCap, lineJoin, miterLimit); |
|
|
|
var vertices = this._expandStroke(strokeWidth, lineCap, lineJoin, miterLimit); |
|
|
|
for (var i = 0; i < paths.length; i++) { |
|
|
|
ref var path = ref paths.array[i]; |
|
|
|
for (var i = 0; i < paths.Count; i++) { |
|
|
|
var path = paths[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 indices = ItemPoolManager.alloc<uiList<int>>(); |
|
|
|
indices.SetCapacity(cindices); |
|
|
|
for (var i = 0; i < paths.Count; i++) { |
|
|
|
var path = paths[i]; |
|
|
|
if (path.count <= 1) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
D.assert(indices.Count == cindices); |
|
|
|
|
|
|
|
this._strokeMesh = new uiMeshMesh(null, this._vertices, indices); |
|
|
|
this._strokeWidth = strokeWidth; |
|
|
|
this._lineCap = lineCap; |
|
|
|
this._lineJoin = lineJoin; |
|
|
|
this._miterLimit = miterLimit; |
|
|
|
return this._strokeMesh; |
|
|
|
var _strokeMesh = new uiMeshMesh(null, vertices.data, indices.data); |
|
|
|
return _strokeMesh; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
return area * 0.5f; |
|
|
|
} |
|
|
|
|
|
|
|
public static void polyReverse(uiPathPoint[] pts, int s, int npts) { |
|
|
|
public static void polyReverse(List<uiPathPoint> pts, int s, int npts) { |
|
|
|
int i = s, j = s + npts - 1; |
|
|
|
while (i < j) { |
|
|
|
var tmp = pts[i]; |
|
|
|
|
|
|
return d; |
|
|
|
} |
|
|
|
|
|
|
|
public static void buttCapStart(this List<Vector3> dst, uiPathPoint p, |
|
|
|
public static void buttCapStart(this uiList<Vector3> dst, uiPathPoint p, |
|
|
|
float dx, float dy, float w, float d) { |
|
|
|
float px = p.x - dx * d; |
|
|
|
float py = p.y - dy * d; |
|
|
|
|
|
|
dst.Add(new Vector2(px - dlx * w, py - dly * w)); |
|
|
|
} |
|
|
|
|
|
|
|
public static void buttCapEnd(this List<Vector3> dst, uiPathPoint p, |
|
|
|
public static void buttCapEnd(this uiList<Vector3> dst, uiPathPoint p, |
|
|
|
float dx, float dy, float w, float d) { |
|
|
|
float px = p.x + dx * d; |
|
|
|
float py = p.y + dy * d; |
|
|
|
|
|
|
dst.Add(new Vector2(px - dlx * w, py - dly * w)); |
|
|
|
} |
|
|
|
|
|
|
|
public static void roundCapStart(this List<Vector3> dst, uiPathPoint p, |
|
|
|
public static void roundCapStart(this uiList<Vector3> dst, uiPathPoint p, |
|
|
|
float dx, float dy, float w, int ncap) { |
|
|
|
float px = p.x; |
|
|
|
float py = p.y; |
|
|
|
|
|
|
dst.Add(new Vector2(px - dlx * w, py - dly * w)); |
|
|
|
} |
|
|
|
|
|
|
|
public static void roundCapEnd(this List<Vector3> dst, uiPathPoint p, |
|
|
|
public static void roundCapEnd(this uiList<Vector3> dst, uiPathPoint p, |
|
|
|
float dx, float dy, float w, int ncap) { |
|
|
|
float px = p.x; |
|
|
|
float py = p.y; |
|
|
|
|
|
|
return Mathf.Max(2, Mathf.CeilToInt(arc / da)); |
|
|
|
} |
|
|
|
|
|
|
|
public static void roundJoin(this List<Vector3> dst, uiPathPoint p0, uiPathPoint p1, |
|
|
|
public static void roundJoin(this uiList<Vector3> dst, uiPathPoint p0, uiPathPoint p1, |
|
|
|
float lw, float rw, int ncap) { |
|
|
|
float dlx0 = p0.dy; |
|
|
|
float dly0 = -p0.dx; |
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public static void bevelJoin(this List<Vector3> dst, uiPathPoint p0, uiPathPoint p1, |
|
|
|
public static void bevelJoin(this uiList<Vector3> dst, uiPathPoint p0, uiPathPoint p1, |
|
|
|
float lw, float rw) { |
|
|
|
float rx0, ry0, rx1, ry1; |
|
|
|
float lx0, ly0, lx1, ly1; |
|
|
|
|
|
|
|
|
|
|
public uiMeshMesh transform(uiMatrix3 matrix) { |
|
|
|
return new uiMeshMesh(matrix, this.vertices, this.triangles, this.uv, this.rawBounds); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public class uiMeshPool : IDisposable { |
|
|
|
readonly Queue<Mesh> _pool = new Queue<Mesh>(); |
|
|
|
|
|
|
|
public Mesh getMesh() { |
|
|
|
if (this._pool.Count > 0) { |
|
|
|
var mesh = this._pool.Dequeue(); |
|
|
|
return mesh; |
|
|
|
} |
|
|
|
else { |
|
|
|
var mesh = new Mesh(); |
|
|
|
mesh.MarkDynamic(); |
|
|
|
mesh.hideFlags = HideFlags.HideAndDontSave; |
|
|
|
return mesh; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public void returnMesh(Mesh mesh) { |
|
|
|
D.assert(mesh != null); |
|
|
|
D.assert(mesh.hideFlags == HideFlags.HideAndDontSave); |
|
|
|
this._pool.Enqueue(mesh); |
|
|
|
} |
|
|
|
|
|
|
|
public void Dispose() { |
|
|
|
foreach (var mesh in this._pool) { |
|
|
|
ObjectUtils.SafeDestroy(mesh); |
|
|
|
} |
|
|
|
|
|
|
|
this._pool.Clear(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |