您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
494 行
17 KiB
494 行
17 KiB
using Unity.UIWidgets.foundation;
|
|
using UnityEngine;
|
|
|
|
namespace Unity.UIWidgets.uiOld{
|
|
public partial class uiPath : PoolObject {
|
|
const float _KAPPA90 = 0.5522847493f;
|
|
|
|
uiList<float> _commands;
|
|
float _commandx;
|
|
float _commandy;
|
|
float _minX, _minY;
|
|
float _maxX, _maxY;
|
|
|
|
uiPathCache _cache;
|
|
|
|
public uint pathKey = 0;
|
|
public bool needCache = false;
|
|
|
|
bool _isNaiveRRect = false;
|
|
public bool isNaiveRRect => _isNaiveRRect;
|
|
|
|
uiPathShapeHint _shapeHint = uiPathShapeHint.Other;
|
|
public uiPathShapeHint shapeHint => _shapeHint;
|
|
|
|
float _rRectCorner;
|
|
public float rRectCorner => _rRectCorner;
|
|
|
|
void _updateRRectFlag(bool isNaiveRRect, uiPathShapeHint shapeHint = uiPathShapeHint.Other, float corner = 0) {
|
|
if (_commands.Count > 0 && !_isNaiveRRect) {
|
|
return;
|
|
}
|
|
_isNaiveRRect = isNaiveRRect && _hasOnlyMoveTos();
|
|
_shapeHint = shapeHint;
|
|
_rRectCorner = corner;
|
|
}
|
|
|
|
bool _hasOnlyMoveTos() {
|
|
var i = 0;
|
|
while (i < _commands.Count) {
|
|
var cmd = (PathCommand) _commands[i];
|
|
switch (cmd) {
|
|
case PathCommand.moveTo:
|
|
i += 3;
|
|
break;
|
|
case PathCommand.lineTo:
|
|
return false;
|
|
case PathCommand.bezierTo:
|
|
return false;
|
|
case PathCommand.close:
|
|
i++;
|
|
break;
|
|
case PathCommand.winding:
|
|
i += 2;
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public static uiPath create(int capacity = 128) {
|
|
uiPath newPath = ObjectPool<uiPath>.alloc();
|
|
newPath._reset();
|
|
return newPath;
|
|
}
|
|
|
|
public uiPath() {
|
|
}
|
|
|
|
public override void clear() {
|
|
ObjectPool<uiList<float>>.release(_commands);
|
|
ObjectPool<uiPathCache>.release(_cache);
|
|
_cache = null;
|
|
_commands = null;
|
|
|
|
needCache = false;
|
|
pathKey = 0;
|
|
_isNaiveRRect = false;
|
|
_shapeHint = uiPathShapeHint.Other;
|
|
_rRectCorner = 0;
|
|
}
|
|
|
|
void _reset() {
|
|
_commands = ObjectPool<uiList<float>>.alloc();
|
|
_commandx = 0;
|
|
_commandy = 0;
|
|
_minX = float.MaxValue;
|
|
_minY = float.MaxValue;
|
|
_maxX = float.MinValue;
|
|
_maxY = float.MinValue;
|
|
ObjectPool<uiPathCache>.release(_cache);
|
|
_cache = null;
|
|
_isNaiveRRect = false;
|
|
}
|
|
|
|
internal uiPathCache flatten(float scale) {
|
|
scale = Mathf.Round(scale * 2.0f) / 2.0f; // round to 0.5f
|
|
|
|
if (this._cache != null && this._cache.canReuse(scale)) {
|
|
return this._cache;
|
|
}
|
|
|
|
var _cache = uiPathCache.create(scale, _shapeHint);
|
|
|
|
var i = 0;
|
|
while (i < _commands.Count) {
|
|
var cmd = (uiPathCommand) _commands[i];
|
|
switch (cmd) {
|
|
case uiPathCommand.moveTo:
|
|
_cache.addPath();
|
|
_cache.addPoint(_commands[i + 1], _commands[i + 2], uiPointFlags.corner);
|
|
i += 3;
|
|
break;
|
|
case uiPathCommand.lineTo:
|
|
_cache.addPoint(_commands[i + 1], _commands[i + 2], uiPointFlags.corner);
|
|
i += 3;
|
|
break;
|
|
case uiPathCommand.bezierTo:
|
|
_cache.tessellateBezier(
|
|
_commands[i + 1], _commands[i + 2],
|
|
_commands[i + 3], _commands[i + 4],
|
|
_commands[i + 5], _commands[i + 6], uiPointFlags.corner);
|
|
i += 7;
|
|
break;
|
|
case uiPathCommand.close:
|
|
_cache.closePath();
|
|
i++;
|
|
break;
|
|
case uiPathCommand.winding:
|
|
_cache.pathWinding((uiPathWinding) _commands[i + 1]);
|
|
i += 2;
|
|
break;
|
|
default:
|
|
D.assert(false, () => "unknown cmd: " + cmd);
|
|
break;
|
|
}
|
|
}
|
|
|
|
_cache.normalize();
|
|
ObjectPool<uiPathCache>.release(this._cache);
|
|
this._cache = _cache;
|
|
return _cache;
|
|
}
|
|
|
|
void _expandBounds(float x, float y) {
|
|
if (x < _minX) {
|
|
_minX = x;
|
|
}
|
|
|
|
if (y < _minY) {
|
|
_minY = y;
|
|
}
|
|
|
|
if (x > _maxX) {
|
|
_maxX = x;
|
|
}
|
|
|
|
if (y > _maxY) {
|
|
_maxY = y;
|
|
}
|
|
}
|
|
|
|
public uiRect getBounds() {
|
|
if (_minX >= _maxX || _minY >= _maxY) {
|
|
return uiRectHelper.zero;
|
|
}
|
|
|
|
return uiRectHelper.fromLTRB(_minX, _minY, _maxX, _maxY);
|
|
}
|
|
|
|
public uiRect getBoundsWithMargin(float margin) {
|
|
if (_minX - margin >= _maxX + margin || _minY - margin >= _maxY + margin) {
|
|
return uiRectHelper.zero;
|
|
}
|
|
|
|
return uiRectHelper.fromLTRB(_minX - margin, _minY - margin, _maxX + margin, _maxY + margin);
|
|
}
|
|
|
|
void _appendMoveTo(float x, float y) {
|
|
_commands.Add((float) uiPathCommand.moveTo);
|
|
_commands.Add(x);
|
|
_commands.Add(y);
|
|
|
|
_commandx = x;
|
|
_commandy = y;
|
|
|
|
ObjectPool<uiPathCache>.release(_cache);
|
|
_cache = null;
|
|
}
|
|
|
|
void _appendLineTo(float x, float y) {
|
|
_expandBounds(_commandx, _commandy);
|
|
_expandBounds(x, y);
|
|
|
|
_commands.Add((float) uiPathCommand.lineTo);
|
|
_commands.Add(x);
|
|
_commands.Add(y);
|
|
|
|
_commandx = x;
|
|
_commandy = y;
|
|
|
|
ObjectPool<uiPathCache>.release(_cache);
|
|
_cache = null;
|
|
}
|
|
|
|
void _appendBezierTo(float x1, float y1, float x2, float y2, float x3, float y3) {
|
|
_expandBounds(_commandx, _commandy);
|
|
_expandBounds(x1, y1);
|
|
_expandBounds(x2, y2);
|
|
_expandBounds(x3, y3);
|
|
|
|
_commands.Add((float) uiPathCommand.bezierTo);
|
|
_commands.Add(x1);
|
|
_commands.Add(y1);
|
|
_commands.Add(x2);
|
|
_commands.Add(y2);
|
|
_commands.Add(x3);
|
|
_commands.Add(y3);
|
|
|
|
_commandx = x3;
|
|
_commandy = y3;
|
|
|
|
ObjectPool<uiPathCache>.release(_cache);
|
|
_cache = null;
|
|
}
|
|
|
|
void _appendClose() {
|
|
_commands.Add((float) uiPathCommand.close);
|
|
|
|
ObjectPool<uiPathCache>.release(_cache);
|
|
_cache = null;
|
|
}
|
|
|
|
void _appendWinding(float winding) {
|
|
_commands.Add((float) uiPathCommand.winding);
|
|
_commands.Add(winding);
|
|
|
|
ObjectPool<uiPathCache>.release(_cache);
|
|
_cache = null;
|
|
}
|
|
|
|
public void addRect(uiRect rect) {
|
|
_updateRRectFlag(true, uiPathShapeHint.Rect);
|
|
_appendMoveTo(rect.left, rect.top);
|
|
_appendLineTo(rect.left, rect.bottom);
|
|
_appendLineTo(rect.right, rect.bottom);
|
|
_appendLineTo(rect.right, rect.top);
|
|
_appendClose();
|
|
}
|
|
|
|
public void addRect(Rect rect) {
|
|
_updateRRectFlag(true, uiPathShapeHint.Rect);
|
|
_appendMoveTo(rect.left, rect.top);
|
|
_appendLineTo(rect.left, rect.bottom);
|
|
_appendLineTo(rect.right, rect.bottom);
|
|
_appendLineTo(rect.right, rect.top);
|
|
_appendClose();
|
|
}
|
|
|
|
public void addRRect(RRect rrect) {
|
|
_updateRRectFlag(rrect.isNaiveRRect(), uiPathShapeHint.NaiveRRect, rrect.blRadiusX);
|
|
float w = rrect.width;
|
|
float h = rrect.height;
|
|
float halfw = Mathf.Abs(w) * 0.5f;
|
|
float halfh = Mathf.Abs(h) * 0.5f;
|
|
float signW = Mathf.Sign(w);
|
|
float signH = Mathf.Sign(h);
|
|
|
|
float rxBL = Mathf.Min(rrect.blRadiusX, halfw) * signW;
|
|
float ryBL = Mathf.Min(rrect.blRadiusY, halfh) * signH;
|
|
float rxBR = Mathf.Min(rrect.brRadiusX, halfw) * signW;
|
|
float ryBR = Mathf.Min(rrect.brRadiusY, halfh) * signH;
|
|
float rxTR = Mathf.Min(rrect.trRadiusX, halfw) * signW;
|
|
float ryTR = Mathf.Min(rrect.trRadiusY, halfh) * signH;
|
|
float rxTL = Mathf.Min(rrect.tlRadiusX, halfw) * signW;
|
|
float ryTL = Mathf.Min(rrect.tlRadiusY, halfh) * signH;
|
|
float x = rrect.left;
|
|
float y = rrect.top;
|
|
|
|
_appendMoveTo(x, y + ryTL);
|
|
_appendLineTo(x, y + h - ryBL);
|
|
_appendBezierTo(x, y + h - ryBL * (1 - _KAPPA90),
|
|
x + rxBL * (1 - _KAPPA90), y + h, x + rxBL, y + h);
|
|
_appendLineTo(x + w - rxBR, y + h);
|
|
_appendBezierTo(x + w - rxBR * (1 - _KAPPA90), y + h,
|
|
x + w, y + h - ryBR * (1 - _KAPPA90), x + w, y + h - ryBR);
|
|
_appendLineTo(x + w, y + ryTR);
|
|
_appendBezierTo(x + w, y + ryTR * (1 - _KAPPA90),
|
|
x + w - rxTR * (1 - _KAPPA90), y, x + w - rxTR, y);
|
|
_appendLineTo(x + rxTL, y);
|
|
_appendBezierTo(x + rxTL * (1 - _KAPPA90), y,
|
|
x, y + ryTL * (1 - _KAPPA90), x, y + ryTL);
|
|
_appendClose();
|
|
}
|
|
|
|
public void moveTo(float x, float y) {
|
|
_appendMoveTo(x, y);
|
|
}
|
|
|
|
public void lineTo(float x, float y) {
|
|
_updateRRectFlag(false);
|
|
_appendLineTo(x, y);
|
|
}
|
|
|
|
public void winding(PathWinding dir) {
|
|
_appendWinding((float) dir);
|
|
}
|
|
|
|
public void addEllipse(float cx, float cy, float rx, float ry) {
|
|
_updateRRectFlag(rx == ry, uiPathShapeHint.Circle, rx);
|
|
_appendMoveTo(cx - rx, cy);
|
|
_appendBezierTo(cx - rx, cy + ry * _KAPPA90,
|
|
cx - rx * _KAPPA90, cy + ry, cx, cy + ry);
|
|
_appendBezierTo(cx + rx * _KAPPA90, cy + ry,
|
|
cx + rx, cy + ry * _KAPPA90, cx + rx, cy);
|
|
_appendBezierTo(cx + rx, cy - ry * _KAPPA90,
|
|
cx + rx * _KAPPA90, cy - ry, cx, cy - ry);
|
|
_appendBezierTo(cx - rx * _KAPPA90, cy - ry,
|
|
cx - rx, cy - ry * _KAPPA90, cx - rx, cy);
|
|
_appendClose();
|
|
}
|
|
|
|
public void addCircle(float cx, float cy, float r) {
|
|
addEllipse(cx, cy, r, r);
|
|
}
|
|
|
|
public void arcTo(Rect rect, float startAngle, float sweepAngle, bool forceMoveTo = true) {
|
|
_updateRRectFlag(false);
|
|
var mat = Matrix3.makeScale(rect.width / 2, rect.height / 2);
|
|
var center = rect.center;
|
|
mat.postTranslate(center.dx, center.dy);
|
|
|
|
_addArcCommands(0, 0, 1, startAngle, startAngle + sweepAngle,
|
|
sweepAngle >= 0 ? PathWinding.clockwise : PathWinding.counterClockwise, forceMoveTo, mat);
|
|
}
|
|
|
|
public void close() {
|
|
_appendClose();
|
|
}
|
|
|
|
void _addArcCommands(
|
|
float cx, float cy, float r, float a0, float a1,
|
|
PathWinding dir, bool forceMoveTo, Matrix3 transform = null) {
|
|
// Clamp angles
|
|
float da = a1 - a0;
|
|
if (dir == PathWinding.clockwise) {
|
|
if (Mathf.Abs(da) >= Mathf.PI * 2) {
|
|
da = Mathf.PI * 2;
|
|
}
|
|
else {
|
|
while (da < 0.0f) {
|
|
da += Mathf.PI * 2;
|
|
}
|
|
|
|
if (da <= 1e-5) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (Mathf.Abs(da) >= Mathf.PI * 2) {
|
|
da = -Mathf.PI * 2;
|
|
}
|
|
else {
|
|
while (da > 0.0f) {
|
|
da -= Mathf.PI * 2;
|
|
}
|
|
|
|
if (da >= -1e-5) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
float kappa = Mathf.Abs(4.0f / 3.0f * (1.0f - Mathf.Cos(hda)) / Mathf.Sin(hda));
|
|
|
|
if (dir == PathWinding.counterClockwise) {
|
|
kappa = -kappa;
|
|
}
|
|
|
|
PathCommand move = (forceMoveTo || _commands.Count == 0) ? PathCommand.moveTo : PathCommand.lineTo;
|
|
float px = 0, py = 0, ptanx = 0, ptany = 0;
|
|
|
|
for (int i = 0; i <= ndivs; i++) {
|
|
float a = a0 + da * (i / (float) ndivs);
|
|
float dx = Mathf.Cos(a);
|
|
float dy = Mathf.Sin(a);
|
|
float x = cx + dx * r;
|
|
float y = cy + dy * r;
|
|
float tanx = -dy * r * kappa;
|
|
float tany = dx * r * kappa;
|
|
|
|
if (i == 0) {
|
|
float x1 = x, y1 = y;
|
|
if (transform != null) {
|
|
transform.mapXY(x1, y1, out x1, out y1);
|
|
}
|
|
|
|
if (move == PathCommand.moveTo) {
|
|
_appendMoveTo(x1, y1);
|
|
}
|
|
else {
|
|
_appendLineTo(x1, y1);
|
|
}
|
|
}
|
|
else {
|
|
float c1x = px + ptanx;
|
|
float c1y = py + ptany;
|
|
float c2x = x - tanx;
|
|
float c2y = y - tany;
|
|
float x1 = x;
|
|
float y1 = y;
|
|
if (transform != null) {
|
|
transform.mapXY(c1x, c1y, out c1x, out c1y);
|
|
transform.mapXY(c2x, c2y, out c2x, out c2y);
|
|
transform.mapXY(x1, y1, out x1, out y1);
|
|
}
|
|
|
|
_appendBezierTo(c1x, c1y, c2x, c2y, x1, y1);
|
|
}
|
|
|
|
px = x;
|
|
py = y;
|
|
ptanx = tanx;
|
|
ptany = tany;
|
|
}
|
|
}
|
|
|
|
public static uiPath fromPath(Path path) {
|
|
D.assert(path != null);
|
|
|
|
uiPath uipath;
|
|
bool exists = uiPathCacheManager.tryGetUiPath(path.pathKey, out uipath);
|
|
if (exists) {
|
|
return uipath;
|
|
}
|
|
|
|
uipath._updateRRectFlag(path.isNaiveRRect, (uiPathShapeHint)path.shapeHint, path.rRectCorner);
|
|
|
|
var i = 0;
|
|
var _commands = path.commands;
|
|
while (i < _commands.Count) {
|
|
var cmd = (uiPathCommand) _commands[i];
|
|
switch (cmd) {
|
|
case uiPathCommand.moveTo: {
|
|
float x = _commands[i + 1];
|
|
float y = _commands[i + 2];
|
|
uipath._appendMoveTo(x, y);
|
|
}
|
|
i += 3;
|
|
break;
|
|
case uiPathCommand.lineTo: {
|
|
float x = _commands[i + 1];
|
|
float y = _commands[i + 2];
|
|
|
|
uipath._appendLineTo(x, y);
|
|
}
|
|
i += 3;
|
|
break;
|
|
case uiPathCommand.bezierTo: {
|
|
float c1x = _commands[i + 1];
|
|
float c1y = _commands[i + 2];
|
|
float c2x = _commands[i + 3];
|
|
float c2y = _commands[i + 4];
|
|
float x1 = _commands[i + 5];
|
|
float y1 = _commands[i + 6];
|
|
|
|
uipath._appendBezierTo(c1x, c1y, c2x, c2y, x1, y1);
|
|
}
|
|
i += 7;
|
|
break;
|
|
case uiPathCommand.close:
|
|
uipath._appendClose();
|
|
i++;
|
|
break;
|
|
case uiPathCommand.winding:
|
|
uipath._appendWinding(_commands[i + 1]);
|
|
i += 2;
|
|
break;
|
|
default:
|
|
D.assert(false, () => "unknown cmd: " + cmd);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return uipath;
|
|
}
|
|
}
|
|
}
|