|
|
|
|
|
|
|
|
|
|
//mesh cache
|
|
|
|
uiMeshMesh _fillMesh; |
|
|
|
|
|
|
|
public uiMeshMesh fillMesh { |
|
|
|
get { return this._fillMesh; } |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public uiMeshMesh strokeMesh { |
|
|
|
get { return this._strokeMesh; } |
|
|
|
} |
|
|
|
|
|
|
|
float _strokeWidth; |
|
|
|
StrokeCap _lineCap; |
|
|
|
StrokeJoin _lineJoin; |
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
uiList<Vector3> _expandFill() { |
|
|
|
var points = this._points; |
|
|
|
var paths = this._paths; |
|
|
|
for (var j = 0; j < paths.Count; j++) { |
|
|
|
var path = paths[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++) { |
|
|
|
var p0 = points[ip0]; |
|
|
|
var p1 = points[ip1]; |
|
|
|
p0.dx = p1.x - p0.x; // no need to normalize
|
|
|
|
p0.dy = p1.y - p0.y; |
|
|
|
points[ip0] = p0; |
|
|
|
ip0 = ip1++; |
|
|
|
} |
|
|
|
|
|
|
|
path.convex = true; |
|
|
|
|
|
|
|
ip0 = path.first + path.count - 1; |
|
|
|
ip1 = path.first; |
|
|
|
for (var i = 0; i < path.count; i++) { |
|
|
|
var p0 = points[ip0]; |
|
|
|
var p1 = points[ip1]; |
|
|
|
|
|
|
|
float cross = p1.dx * p0.dy - p0.dx * p1.dy; |
|
|
|
if (cross < 0.0f) { |
|
|
|
path.convex = false; |
|
|
|
} |
|
|
|
|
|
|
|
ip0 = ip1++; |
|
|
|
} |
|
|
|
|
|
|
|
paths[j] = path; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var cvertices = 0; |
|
|
|
for (var i = 0; i < paths.Count; i++) { |
|
|
|
var path = paths[i]; |
|
|
|
if (path.count <= 2) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
cvertices += path.count; |
|
|
|
} |
|
|
|
|
|
|
|
var _vertices = ObjectPool<uiList<Vector3>>.alloc(); |
|
|
|
_vertices.SetCapacity(cvertices); |
|
|
|
for (var i = 0; i < paths.Count; i++) { |
|
|
|
var path = paths[i]; |
|
|
|
if (path.count <= 2) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
path.ifill = _vertices.Count; |
|
|
|
for (var j = 0; j < path.count; j++) { |
|
|
|
var p = points[path.first + j]; |
|
|
|
_vertices.Add(new Vector2(p.x, p.y)); |
|
|
|
} |
|
|
|
|
|
|
|
path.nfill = _vertices.Count - path.ifill; |
|
|
|
paths[i] = path; |
|
|
|
} |
|
|
|
|
|
|
|
return _vertices; |
|
|
|
} |
|
|
|
|
|
|
|
public uiMeshMesh getFillMesh(out bool convex) { |
|
|
|
if (this._fillMesh != null) { |
|
|
|
convex = this._fillConvex; |
|
|
|
return this._fillMesh; |
|
|
|
} |
|
|
|
|
|
|
|
var vertices = this._expandFill(); |
|
|
|
|
|
|
|
var paths = this._paths; |
|
|
|
|
|
|
|
var cindices = 0; |
|
|
|
for (var i = 0; i < paths.Count; i++) { |
|
|
|
var path = paths[i]; |
|
|
|
if (path.count <= 2) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
if (path.nfill > 0) { |
|
|
|
D.assert(path.nfill >= 2); |
|
|
|
cindices += (path.nfill - 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 <= 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 = uiMeshMesh.create(null, vertices, indices); |
|
|
|
this._fillMesh = mesh; |
|
|
|
|
|
|
|
this._fillConvex = false; |
|
|
|
for (var i = 0; i < paths.Count; i++) { |
|
|
|
var path = paths[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; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ip0 = path.first + path.count - 1; |
|
|
|
ip1 = path.first; |
|
|
|
path.convex = true; |
|
|
|
for (var j = 0; j < path.count; j++) { |
|
|
|
var p0 = points[ip0]; |
|
|
|
var p1 = points[ip1]; |
|
|
|
|
|
|
|
|
|
|
// Keep track of left turns.
|
|
|
|
float cross = p1.dx * p0.dy - p0.dx * p1.dy; |
|
|
|
|
|
|
|
} else if (cross < 0.0f) { |
|
|
|
path.convex = false; |
|
|
|
} |
|
|
|
|
|
|
|
// Calculate if we should use bevel or miter for inner join.
|
|
|
|
|
|
|
|
|
|
|
ip0 = ip1++; |
|
|
|
} |
|
|
|
|
|
|
|
paths[i] = path; |
|
|
|
uiList<Vector3> _expandStroke(float w, StrokeCap lineCap, StrokeJoin lineJoin, float miterLimit) { |
|
|
|
this._calculateJoins(w, lineJoin, miterLimit); |
|
|
|
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) { |
|
|
|
float aa = fringe; |
|
|
|
float u0 = 0.0f, u1 = 1.0f; |
|
|
|
w += aa * 0.5f; |
|
|
|
|
|
|
|
if (aa == 0.0f) { |
|
|
|
u0 = 0.5f; |
|
|
|
u1 = 0.5f; |
|
|
|
} |
|
|
|
this._calculateJoins(w, lineJoin, miterLimit); |
|
|
|
|
|
|
|
var points = this._points; |
|
|
|
var paths = this._paths; |
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
cvertices += path.count * 2; |
|
|
|
cvertices += 4; |
|
|
|
cvertices += 8; |
|
|
|
var _uv = ObjectPool<uiList<Vector2>>.alloc(); |
|
|
|
_uv.SetCapacity(cvertices); |
|
|
|
for (var i = 0; i < paths.Count; i++) { |
|
|
|
var path = paths[i]; |
|
|
|
if (path.count <= 1) { |
|
|
|
|
|
|
|
|
|
|
if (!path.closed) { |
|
|
|
if (lineCap == StrokeCap.butt) { |
|
|
|
_vertices.buttCapStart(p0, p0.dx, p0.dy, w, 0.0f); |
|
|
|
_vertices.buttCapStart(_uv, p0, p0.dx, p0.dy, w, 0.0f, aa, u0, u1); |
|
|
|
_vertices.buttCapStart(p0, p0.dx, p0.dy, w, w); |
|
|
|
_vertices.buttCapStart(_uv, p0, p0.dx, p0.dy, w, w, aa, u0, u1); |
|
|
|
_vertices.roundCapStart(p0, p0.dx, p0.dy, w, ncap); |
|
|
|
_vertices.roundCapStart(_uv, p0, p0.dx, p0.dy, w, ncap, u0, u1); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ((p1.flags & (uiPointFlags.bevel | uiPointFlags.innerBevel)) != 0) { |
|
|
|
if (lineJoin == StrokeJoin.round) { |
|
|
|
_vertices.roundJoin(p0, p1, w, w, ncap); |
|
|
|
_vertices.roundJoin(_uv, p0, p1, w, w, ncap, u0, u1, aa); |
|
|
|
_vertices.bevelJoin(p0, p1, w, w); |
|
|
|
_vertices.bevelJoin(_uv, p0, p1, w, w, u0, u1, aa); |
|
|
|
_uv.Add(new Vector2(u0, 1)); |
|
|
|
_uv.Add(new Vector2(u1, 1)); |
|
|
|
} |
|
|
|
|
|
|
|
ip0 = ip1++; |
|
|
|
|
|
|
p0 = points[ip0]; |
|
|
|
p1 = points[ip1]; |
|
|
|
if (lineCap == StrokeCap.butt) { |
|
|
|
_vertices.buttCapEnd(p1, p0.dx, p0.dy, w, 0.0f); |
|
|
|
_vertices.buttCapEnd(_uv, p1, p0.dx, p0.dy, w, 0.0f, aa, u0, u1); |
|
|
|
_vertices.buttCapEnd(p1, p0.dx, p0.dy, w, w); |
|
|
|
_vertices.buttCapEnd(_uv, p1, p0.dx, p0.dy, w, w, aa, u0, u1); |
|
|
|
_vertices.roundCapEnd(p1, p0.dx, p0.dy, w, ncap); |
|
|
|
_vertices.roundCapEnd(_uv, p1, p0.dx, p0.dy, w, ncap, u0, u1); |
|
|
|
_uv.Add(new Vector2(u0, 1)); |
|
|
|
_uv.Add(new Vector2(u1, 1)); |
|
|
|
D.assert(_uv.Count == _vertices.Count); |
|
|
|
return _vertices; |
|
|
|
return new VertexUV { |
|
|
|
strokeVertices = _vertices, |
|
|
|
strokeUV = _uv, |
|
|
|
}; |
|
|
|
public uiMeshMesh getStrokeMesh(float strokeWidth, StrokeCap lineCap, StrokeJoin lineJoin, float miterLimit) { |
|
|
|
VertexUV _expandFill(float fringe) { |
|
|
|
float aa = fringe; |
|
|
|
var points = this._points; |
|
|
|
var paths = this._paths; |
|
|
|
this._calculateJoins(fringe, StrokeJoin.miter, 4.0f); |
|
|
|
|
|
|
|
var cvertices = 0; |
|
|
|
for (var i = 0; i < paths.Count; i++) { |
|
|
|
var path = paths[i]; |
|
|
|
if (path.count <= 2) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
cvertices += path.count; |
|
|
|
} |
|
|
|
|
|
|
|
this._fillConvex = false; |
|
|
|
for (var i = 0; i < paths.Count; i++) { |
|
|
|
var path = paths[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; |
|
|
|
} |
|
|
|
|
|
|
|
var _vertices = ObjectPool<uiList<Vector3>>.alloc(); |
|
|
|
_vertices.SetCapacity(cvertices); |
|
|
|
var _uv = ObjectPool<uiList<Vector2>>.alloc(); |
|
|
|
_uv.SetCapacity(cvertices); |
|
|
|
for (var i = 0; i < paths.Count; i++) { |
|
|
|
var path = paths[i]; |
|
|
|
if (path.count <= 2) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
path.ifill = _vertices.Count; |
|
|
|
for (var j = 0; j < path.count; j++) { |
|
|
|
var p = points[path.first + j]; |
|
|
|
_vertices.Add(new Vector2(p.x, p.y)); |
|
|
|
_uv.Add(new Vector2(0.5f, 1.0f)); |
|
|
|
} |
|
|
|
|
|
|
|
path.nfill = _vertices.Count - path.ifill; |
|
|
|
paths[i] = path; |
|
|
|
} |
|
|
|
|
|
|
|
uiList<Vector3> _strokeVertices = null; |
|
|
|
uiList<Vector2> _strokeUV = null; |
|
|
|
if (aa > 0.0f) { |
|
|
|
_strokeVertices = ObjectPool<uiList<Vector3>>.alloc(); |
|
|
|
_strokeUV = ObjectPool<uiList<Vector2>>.alloc(); |
|
|
|
cvertices = 0; |
|
|
|
for (var i = 0; i < paths.Count; i++) { |
|
|
|
var path = paths[i]; |
|
|
|
if (path.count <= 2) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
cvertices += path.count * 2; |
|
|
|
} |
|
|
|
_strokeVertices.SetCapacity(cvertices); |
|
|
|
_strokeUV.SetCapacity(cvertices); |
|
|
|
|
|
|
|
float woff = aa * 0.5f; |
|
|
|
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.Count; i++) { |
|
|
|
var path = paths[i]; |
|
|
|
if (path.count <= 2) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
path.istroke = _strokeVertices.Count; |
|
|
|
for (var j = 0; j < path.count; j++) { |
|
|
|
var p = points[path.first + j]; |
|
|
|
_strokeVertices.Add(new Vector2(p.x + p.dmx * lw, p.y + p.dmy * lw)); |
|
|
|
_strokeUV.Add(new Vector2(lu, 1.0f)); |
|
|
|
_strokeVertices.Add(new Vector2(p.x - p.dmx * rw, p.y - p.dmy * rw)); |
|
|
|
_strokeUV.Add(new Vector2(ru, 1.0f)); |
|
|
|
} |
|
|
|
|
|
|
|
path.nstroke = _strokeVertices.Count - path.istroke; |
|
|
|
paths[i] = path; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return new VertexUV { |
|
|
|
fillVertices = _vertices, |
|
|
|
fillUV = _uv, |
|
|
|
strokeVertices = _strokeVertices, |
|
|
|
strokeUV = _strokeUV, |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
public uiMeshMesh computeStrokeMesh(float strokeWidth, float fringe, StrokeCap lineCap, StrokeJoin lineJoin, float miterLimit) { |
|
|
|
if (this._strokeMesh != null && |
|
|
|
this._strokeWidth == strokeWidth && |
|
|
|
this._lineCap == lineCap && |
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
var vertices = this._expandStroke(strokeWidth, lineCap, lineJoin, miterLimit); |
|
|
|
var verticesUV = this._expandStroke(strokeWidth, fringe, lineCap, lineJoin, miterLimit); |
|
|
|
|
|
|
|
var paths = this._paths; |
|
|
|
|
|
|
|
|
|
|
D.assert(indices.Count == cindices); |
|
|
|
|
|
|
|
ObjectPool<uiMeshMesh>.release(this._strokeMesh); |
|
|
|
this._strokeMesh = uiMeshMesh.create(null, vertices, indices); |
|
|
|
this._strokeMesh = uiMeshMesh.create(null, verticesUV.strokeVertices, indices, verticesUV.strokeUV); |
|
|
|
} |
|
|
|
|
|
|
|
public void computeFillMesh(float fringe, out bool convex) { |
|
|
|
if (this._fillMesh != null && (fringe != 0.0f || this._strokeMesh != null)) { |
|
|
|
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.Count; i++) { |
|
|
|
var path = paths[i]; |
|
|
|
if (path.count <= 2) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
if (path.nfill > 0) { |
|
|
|
D.assert(path.nfill >= 2); |
|
|
|
cindices += (path.nfill - 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 <= 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.Count; i++) { |
|
|
|
var path = paths[i]; |
|
|
|
if (path.count <= 2) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
if (path.nstroke > 0) { |
|
|
|
D.assert(path.nstroke >= 6); |
|
|
|
cindices += path.nstroke * 3; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
var strokeIndices = ObjectPool<uiList<int>>.alloc(); |
|
|
|
strokeIndices.SetCapacity(cindices); |
|
|
|
for (var i = 0; i < paths.Count; i++) { |
|
|
|
var path = paths[i]; |
|
|
|
if (path.count <= 2) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
if (path.nstroke > 0) { |
|
|
|
strokeIndices.Add(path.nstroke - 1); |
|
|
|
strokeIndices.Add(path.nstroke - 2); |
|
|
|
strokeIndices.Add(path.istroke); |
|
|
|
strokeIndices.Add(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); |
|
|
|
|
|
|
|
ObjectPool<uiMeshMesh>.release(this._strokeMesh); |
|
|
|
this._strokeMesh = uiMeshMesh.create(null, verticesUV.strokeVertices, strokeIndices, verticesUV.strokeUV); |
|
|
|
} |
|
|
|
|
|
|
|
var mesh = uiMeshMesh.create(null, verticesUV.fillVertices, indices, verticesUV.fillUV); |
|
|
|
this._fillMesh = mesh; |
|
|
|
} |
|
|
|
} |
|
|
|
} |