浏览代码

refactor canvas.

/main
kg 6 年前
当前提交
c5d11ddb
共有 43 个文件被更改,包括 2421 次插入1327 次删除
  1. 2
      Runtime/editor/rasterizer.cs
  2. 9
      Runtime/material/text_selection.cs
  3. 20
      Runtime/painting/matrix_utils.cs
  4. 13
      Runtime/ui/geometry.cs
  5. 40
      Runtime/ui/matrix.cs
  6. 30
      Runtime/ui/painting/canvas.cs
  7. 30
      Runtime/ui/painting/canvas_clip.cs
  8. 900
      Runtime/ui/painting/canvas_impl.cs
  9. 112
      Runtime/ui/painting/painting.cs
  10. 136
      Runtime/ui/painting/path.cs
  11. 296
      Runtime/ui/painting/picture.cs
  12. 27
      Runtime/ui/painting/txt/font_manager.cs
  13. 2
      Runtime/ui/painting/txt/mesh_generator.cs
  14. 105
      Tests/Editor/CanvasAndLayers.cs
  15. 2
      Tests/Editor/Widgets.cs
  16. 178
      Runtime/Resources/UIWidgets_canvas.cginc
  17. 9
      Runtime/Resources/UIWidgets_canvas.cginc.meta
  18. 63
      Runtime/Resources/UIWidgets_canvas_convexFill.shader
  19. 9
      Runtime/Resources/UIWidgets_canvas_convexfill.shader.meta
  20. 30
      Runtime/Resources/UIWidgets_canvas_fill0.shader
  21. 9
      Runtime/Resources/UIWidgets_canvas_fill0.shader.meta
  22. 66
      Runtime/Resources/UIWidgets_canvas_fill1.shader
  23. 9
      Runtime/Resources/UIWidgets_canvas_fill1.shader.meta
  24. 18
      Runtime/Resources/UIWidgets_canvas_filter.shader
  25. 9
      Runtime/Resources/UIWidgets_canvas_filter.shader.meta
  26. 56
      Runtime/Resources/UIWidgets_canvas_stencil.shader
  27. 9
      Runtime/Resources/UIWidgets_canvas_stencil.shader.meta
  28. 64
      Runtime/Resources/UIWidgets_canvas_stroke0.shader
  29. 9
      Runtime/Resources/UIWidgets_canvas_stroke0.shader.meta
  30. 27
      Runtime/Resources/UIWidgets_canvas_stroke1.shader
  31. 9
      Runtime/Resources/UIWidgets_canvas_stroke1.shader.meta
  32. 63
      Runtime/Resources/UIWidgets_canvas_tex.shader
  33. 9
      Runtime/Resources/UIWidgets_canvas_tex.shader.meta
  34. 393
      Runtime/ui/painting/canvas_shader.cs
  35. 11
      Runtime/ui/painting/canvas_shader.cs.meta
  36. 602
      Runtime/ui/painting/shader.cs
  37. 11
      Runtime/ui/painting/shader.cs.meta
  38. 8
      Tests/Resources.meta
  39. 3
      Tests/Resources/6.png
  40. 88
      Tests/Resources/6.png.meta
  41. 3
      Runtime/Resources/UIWidgets_canvas.shader.meta
  42. 259
      Runtime/Resources/UIWidgets_canvas.shader

2
Runtime/editor/rasterizer.cs


var canvas = frame.getCanvas();
using (var compositorFrame = this._compositorContext.acquireFrame(canvas)) {
if (compositorFrame != null && compositorFrame.raster(layerTree, true)) {
if (compositorFrame != null && compositorFrame.raster(layerTree, false)) {
frame.submit();
this._fireNextFrameCallbackIfPresent();
return true;

9
Runtime/material/text_selection.cs


using Unity.UIWidgets.service;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
using UnityEngine;
using Canvas = Unity.UIWidgets.ui.Canvas;
using Color = Unity.UIWidgets.ui.Color;
using Rect = Unity.UIWidgets.ui.Rect;
using Transform = Unity.UIWidgets.widgets.Transform;
// todo using material components: FlatButton & Material ...

switch (type) {
case TextSelectionHandleType.left: // points up-right
return new Transform(
transform: Matrix3.makeRotate(90),
transform: Matrix3.makeRotate(Mathf.PI / 2),
child: handle
);
case TextSelectionHandleType.right: // points up-left

transform: Matrix3.makeRotate(45),
transform: Matrix3.makeRotate(Mathf.PI / 4),
child: handle
);
}

20
Runtime/painting/matrix_utils.cs


using System.Collections.Generic;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;
using UnityEngine;
namespace Unity.UIWidgets.painting {
public static class MatrixUtils {

return result;
}
public static Matrix4x4 toMatrix4x4(this Matrix3 matrix3) {
var matrix = Matrix4x4.identity;
matrix[0, 0] = matrix3[0]; // row 0
matrix[0, 1] = matrix3[1];
matrix[0, 3] = matrix3[2];
matrix[1, 0] = matrix3[3]; // row 1
matrix[1, 1] = matrix3[4];
matrix[1, 3] = matrix3[5];
matrix[3, 0] = matrix3[6]; // row 2
matrix[3, 1] = matrix3[7];
matrix[3, 3] = matrix3[8];
return matrix;
}
}
public class TransformProperty : DiagnosticsProperty<Matrix3> {

13
Runtime/ui/geometry.cs


public static readonly Offset zero = new Offset(0.0, 0.0);
public static readonly Offset infinite = new Offset(double.PositiveInfinity, double.PositiveInfinity);
public Offset scale(double scaleX, double scaleY) {
return new Offset(this.dx * scaleX, this.dy * scaleY);
public Offset scale(double scaleX, double? scaleY = null) {
scaleY = scaleY ?? scaleX;
return new Offset(this.dx * scaleX, this.dy * scaleY.Value);
}
public Offset translate(double translateX, double translateY) {

public static readonly Rect zero = new Rect(0, 0, 0, 0);
public static readonly Rect one = new Rect(0, 0, 1, 1);
public static readonly Rect infinity = new Rect(double.NegativeInfinity, double.NegativeInfinity,
double.PositiveInfinity, double.PositiveInfinity);

return fromLTRB(
Math.Floor(this.left), Math.Floor(this.top),
Math.Ceiling(this.right), Math.Ceiling(this.bottom));
}
public Rect roundIn() {
return fromLTRB(
Math.Ceiling(this.left), Math.Ceiling(this.top),
Math.Floor(this.right), Math.Floor(this.bottom));
}
public static Rect lerp(Rect a, Rect b, double t) {

40
Runtime/ui/matrix.cs


return m;
}
public static Matrix3 makeRotate(float degree) {
public static Matrix3 makeRotate(float radians) {
m.setRotate(degree);
m.setRotate(radians);
public static Matrix3 makeRotate(float degree, float px, float py) {
public static Matrix3 makeRotate(float radians, float px, float py) {
m.setRotate(degree, px, py);
m.setRotate(radians, px, py);
return m;
}

return m;
}
public static Matrix3 makeSkew(float dx, float dy) {
var m = new Matrix3();
m.setSkew(dx, dy);
return m;
}

}
}
public void setRotate(float degrees, float px, float py) {
public void setRotate(float radians, float px, float py) {
sinV = ScalarUtils.ScalarSinCos(ScalarUtils.DegreesToRadians(degrees), out cosV);
sinV = ScalarUtils.ScalarSinCos(radians, out cosV);
public void setRotate(float degrees) {
public void setRotate(float radians) {
sinV = ScalarUtils.ScalarSinCos(ScalarUtils.DegreesToRadians(degrees), out cosV);
sinV = ScalarUtils.ScalarSinCos(radians, out cosV);
this.setSinCos(sinV, cosV);
}

}
}
public void preRotate(float degrees, float px, float py) {
public void preRotate(float radians, float px, float py) {
m.setRotate(degrees, px, py);
m.setRotate(radians, px, py);
public void preRotate(float degrees) {
public void preRotate(float radians) {
m.setRotate(degrees);
m.setRotate(radians);
this.preConcat(m);
}

this.postConcat(m);
}
public void postRotate(float degrees, float px, float py) {
public void postRotate(float radians, float px, float py) {
m.setRotate(degrees, px, py);
m.setRotate(radians, px, py);
public void postRotate(float degrees) {
public void postRotate(float radians) {
m.setRotate(degrees);
m.setRotate(radians);
this.postConcat(m);
}

TypeMask.kPerspective_Mask) |
kRectStaysRect_Mask;
readonly float[] fMat = new float[9];
internal readonly float[] fMat = new float[9];
int fTypeMask = 0;
Matrix3() {

30
Runtime/ui/painting/canvas.cs


this._saveCount++;
this._recorder.addDrawCmd(new DrawSaveLayer {
rect = rect,
paint = paint,
paint = new Paint(paint),
});
}

this._recorder.addDrawCmd(new DrawPath {
path = path,
paint = paint,
paint = new Paint(paint),
});
}

this._recorder.addDrawCmd(new DrawPath {
path = path,
paint = paint,
paint = new Paint(paint),
});
}

this._recorder.addDrawCmd(new DrawPath {
path = path,
paint = paint,
paint = new Paint(paint),
});
}

this._recorder.addDrawCmd(new DrawPath {
path = path,
paint = paint,
paint = new Paint(paint),
});
}

this._recorder.addDrawCmd(new DrawPath {
path = path,
paint = paint,
paint = new Paint(paint),
});
}

this._recorder.addDrawCmd(new DrawPath {
path = path,
paint = paint,
paint = new Paint(paint),
});
}

this._recorder.addDrawCmd(new DrawPath {
path = path,
paint = paint,
paint = new Paint(paint),
});
}

paint = paint,
paint = new Paint(paint),
});
}

offset = offset,
paint = paint,
paint = new Paint(paint),
});
}

dst = dst,
paint = paint,
paint = new Paint(paint),
});
}

src = src,
dst = dst,
paint = paint,
paint = new Paint(paint),
});
}

center = center,
dst = dst,
paint = paint,
paint = new Paint(paint),
});
}

src = src,
center = center,
dst = dst,
paint = paint,
paint = new Paint(paint),
});
}

this._recorder.addDrawCmd(new DrawTextBlob {
textBlob = textBlob,
offset = offset,
paint = paint,
paint = new Paint(paint),
});
}

30
Runtime/ui/painting/canvas_clip.cs


uint _genId;
bool _isIntersectionOfRects;
Rect _bound;
Matrix3 _invMat;
public ClipElement(int saveCount, Path path, float[] xform, float devicePixelRatio) {
public ClipElement(int saveCount, Path path, Matrix3 matrix, float scale) {
var pathCache = path.flatten(xform, devicePixelRatio);
this.mesh = pathCache.getFillMesh(out this.convex);
var pathCache = path.flatten(scale);
this.mesh = pathCache.getFillMesh(out this.convex).transform(matrix);
if (this.convex && vertices.Count == 4 &&
if (this.convex && vertices.Count == 4 && matrix.rectStaysRect() &&
var minx = Mathf.Min(vertices[0].x, vertices[1].x, vertices[2].x, vertices[3].x);
var miny = Mathf.Min(vertices[0].y, vertices[1].y, vertices[2].y, vertices[3].y);
var maxx = Mathf.Max(vertices[0].x, vertices[1].x, vertices[2].x, vertices[3].x);
var maxy = Mathf.Max(vertices[0].y, vertices[1].y, vertices[2].y, vertices[3].y);
this.rect = Rect.fromLTRB(minx, miny, maxx, maxy);
this.rect = this.mesh.bounds;
}
else {
this.isRect = false;

return false;
}
if (this.mesh.matrix != null) {
if (this._invMat == null) {
this._invMat = Matrix3.I();
this.mesh.matrix.invert(this._invMat); // ignore if not invertible for now.
}
var offset = this._invMat.mapXY(x, y);
x = (float) offset.dx;
y = (float) offset.dy;
}
for (var i = 0; i < this.mesh.vertices.Count; i++) {
var p0 = this.mesh.vertices[i];
var p1 = this.mesh.vertices[i == this.mesh.vertices.Count - 1 ? 0 : i + 1];

}
}
public void clipPath(Path path, float[] xform, float devicePixelRatio) {
var element = new ClipElement(this._saveCount, path, xform, devicePixelRatio);
public void clipPath(Path path, Matrix3 matrix, float scale) {
var element = new ClipElement(this._saveCount, path, matrix, scale);
this._pushElement(element);
}

900
Runtime/ui/painting/canvas_impl.cs
文件差异内容过多而无法显示
查看文件

112
Runtime/ui/painting/painting.cs


using UnityEngine;
namespace Unity.UIWidgets.ui {
class PaintingUtils {
internal static bool _offsetIsValid(Offset offset) {
D.assert(offset != null, "Offset argument was null.");
D.assert(!offset.dx.isNaN() && !offset.dy.isNaN(), "Offset argument contained a NaN value.");
return true;
}
internal static bool _radiusIsValid(Radius radius) {
D.assert(radius != null, "Radius argument was null.");
D.assert(!radius.x.isNaN() && !radius.y.isNaN(), "Radius argument contained a NaN value.");
return true;
}
internal static Color _scaleAlpha(Color a, double factor) {
return a.withAlpha((a.alpha * factor).round().clamp(0, 255));
}
}
public class Color : IEquatable<Color> {
public Color(long value) {
this.value = value & 0xFFFFFFFF;

}
}
public enum TileMode {
// todo: implement repeated, mirror.
clamp,
repeated,
mirror
}
public abstract class PaintShader {
}
public class Gradient : PaintShader {
internal float[] invXform;
internal float[] extent;
internal float radius;
internal float feather;
internal Color innerColor;
internal Color outerColor;
public static Gradient linear(
Offset from, Offset to,
Color color0, Color color1, TileMode tileMode = TileMode.clamp) {
const float large = 1e5f;
var dir = to - from;
var dx = (float) dir.dx;
var dy = (float) dir.dy;
var d = (float) dir.distance;
if (d > 0.0001f) {
dx /= d;
dy /= d;
}
else {
dx = 0;
dy = 1;
}
var xform = new[] {dy, -dx, dx, dy, (float) from.dx - dx * large, (float) from.dy - dy * large};
var invXform = new float[6];
XformUtils.transformInverse(invXform, xform);
return new Gradient {
invXform = invXform,
extent = new[] {large, large + d * 0.5f},
radius = 0.0f,
feather = Mathf.Max(1.0f, d),
innerColor = color0,
outerColor = color1
};
}
public static Gradient radial(
Offset center, double radius0, double radius1,
Color color0, Color color1, TileMode tileMode = TileMode.clamp) {
float r = (float) (radius0 + radius1) * 0.5f;
float f = (float) (radius1 - radius0);
var xform = new[] {1, 0, 0, 1, (float) center.dx, (float) center.dy};
var invXform = new float[6];
XformUtils.transformInverse(invXform, xform);
return new Gradient {
invXform = invXform,
extent = new[] {r, r},
radius = r,
feather = Mathf.Max(1.0f, f),
innerColor = color0,
outerColor = color1
};
}
public static Gradient box(
Rect rect, double radius, double feather,
Color color0, Color color1, TileMode tileMode = TileMode.clamp) {
var ext0 = (float) rect.width * 0.5f;
var ext1 = (float) rect.height * 0.5f;
var xform = new[] {1, 0, 0, 1, (float) rect.left + ext0, (float) rect.top + ext1};
var invXform = new float[6];
XformUtils.transformInverse(invXform, xform);
return new Gradient {
invXform = invXform,
extent = new[] {ext0, ext1},
radius = (float) radius,
feather = Mathf.Max(1.0f, (float) feather),
innerColor = color0,
outerColor = color1
};
}
}
public class Paint {
static readonly Color _kColorDefault = new Color(0xFFFFFFFF);

public PaintShader shader = null;
public bool invertColors;
public bool invertColors = false;
public Paint() {
}

136
Runtime/ui/painting/path.cs


PathCache _cache;
internal PathCache flatten(float[] xform, float devicePixelRatio) {
if (this._cache != null && this._cache.canReuse(xform, devicePixelRatio)) {
internal PathCache flatten(float scale) {
if (this._cache != null && this._cache.canReuse(scale)) {
this._cache = new PathCache(xform, devicePixelRatio);
this._cache = new PathCache(scale);
var i = 0;
while (i < this._commands.Count) {

}
class PathCache {
readonly float[] _xform;
readonly float _devicePixelRatio;
readonly float _scale;
readonly float _distTol;
readonly float _tessTol;

StrokeJoin _lineJoin;
float _miterLimit;
public PathCache(float[] xform, float devicePixelRatio) {
D.assert(xform != null && xform.Length == 6);
this._xform = xform;
this._devicePixelRatio = devicePixelRatio;
this._distTol = 0.01f / devicePixelRatio;
this._tessTol = 0.25f / devicePixelRatio;
public PathCache(float scale) {
this._scale = scale;
this._distTol = 0.01f / scale;
this._tessTol = 0.25f / scale;
public bool canReuse(float[] xform, float devicePixelRatio) {
D.assert(xform != null && xform.Length == 6);
for (var i = 0; i < 6; ++i) {
if (this._xform[i] != xform[i]) {
return false;
}
}
if (this._devicePixelRatio != devicePixelRatio) {
public bool canReuse(float scale) {
if (this._scale != scale) {
return false;
}

}
public void addPoint(float x, float y, PointFlags flags) {
PathUtils.transformPoint(out x, out y, this._xform, x, y);
this._addPoint(new PathPoint {x = x, y = y, flags = flags});
}

y1 = pt.y;
}
PathUtils.transformPoint(out x2, out y2, this._xform, x2, y2);
PathUtils.transformPoint(out x3, out y3, this._xform, x3, y3);
PathUtils.transformPoint(out x4, out y4, this._xform, x4, y4);
var points = TessellationGenerator.tessellateBezier(x1, y1, x2, y2, x3, y3, x4, y4, this._tessTol);
points[points.Count - 1].flags = flags;
foreach (var point in points) {

D.assert(indices.Count == cindices);
var mesh = new MeshMesh(this._vertices, indices);
var mesh = new MeshMesh(null, this._vertices, indices);
this._fillMesh = mesh;
this._fillConvex = false;

D.assert(indices.Count == cindices);
this._strokeMesh = new MeshMesh(this._vertices, indices);
this._strokeMesh = new MeshMesh(null, this._vertices, indices);
this._strokeWidth = strokeWidth;
this._lineCap = lineCap;
this._lineJoin = lineJoin;

public readonly List<Vector3> vertices;
public readonly List<int> triangles;
public readonly List<Vector2> uv;
public readonly Rect bounds;
public readonly Matrix3 matrix;
public readonly Rect rawBounds;
Rect _bounds;
public Rect bounds {
get {
if (this._bounds == null) {
this._bounds = this.matrix != null ? this.matrix.mapRect(this.rawBounds) : this.rawBounds;
}
return this._bounds;
}
}
static readonly List<int> _boundsTriangles = new List<int>(6) {0, 2, 1, 1, 2, 3};
static readonly List<int> _boundsTriangles = new List<int>(6) {
0, 2, 1, 1, 2, 3
};
if (this._boundsMesh != null) {
return this._boundsMesh;
if (this._boundsMesh == null) {
this._boundsMesh = new MeshMesh(this.bounds);
this._boundsMesh = new MeshMesh(this.bounds);
return this._boundsMesh;
}
}

};
this.triangles = _boundsTriangles;
this.bounds = rect;
this.rawBounds = rect;
this._bounds = this.rawBounds;
public MeshMesh(List<Vector3> vertices, List<int> triangles, List<Vector2> uv = null) {
public MeshMesh(Matrix3 matrix, List<Vector3> vertices, List<int> triangles, List<Vector2> uv = null, Rect rawBounds = null) {
D.assert(vertices != null);
D.assert(vertices.Count >= 0);
D.assert(triangles != null);

this.matrix = matrix;
if (vertices.Count > 0) {
double minX = vertices[0].x;
double maxX = vertices[0].x;
double minY = vertices[0].y;
double maxY = vertices[0].y;
if (rawBounds == null) {
if (vertices.Count > 0) {
double minX = vertices[0].x;
double maxX = vertices[0].x;
double minY = vertices[0].y;
double maxY = vertices[0].y;
for (int i = 1; i < vertices.Count; i++) {
var vertex = vertices[i];
if (vertex.x < minX) {
minX = vertex.x;
}
for (int i = 1; i < vertices.Count; i++) {
var vertex = vertices[i];
if (vertex.x < minX) {
minX = vertex.x;
}
if (vertex.x > maxX) {
maxX = vertex.x;
}
if (vertex.x > maxX) {
maxX = vertex.x;
}
if (vertex.y < minY) {
minY = vertex.y;
}
if (vertex.y < minY) {
minY = vertex.y;
}
if (vertex.y > maxY) {
maxY = vertex.y;
if (vertex.y > maxY) {
maxY = vertex.y;
}
}
this.bounds = Rect.fromLTRB(minX, minY, maxX, maxY);
}
else {
this.bounds = Rect.zero;
rawBounds = Rect.fromLTRB(minX, minY, maxX, maxY);
} else {
rawBounds = Rect.zero;
}
this.rawBounds = rawBounds;
public MeshMesh transform(float[] xform) {
var transVertices = new List<Vector3>(this.vertices.Count);
foreach (var vertex in this.vertices) {
float x, y;
PathUtils.transformPoint(out x, out y, xform, vertex.x, vertex.y);
transVertices.Add(new Vector3(x, y));
}
return new MeshMesh(transVertices, this.triangles, this.uv);
public MeshMesh transform(Matrix3 matrix) {
return new MeshMesh(matrix, this.vertices, this.triangles, this.uv, this.rawBounds);
}
}

public Mesh getMesh() {
if (this._pool.Count > 0) {
var mesh = this._pool.Dequeue();
D.assert(mesh);
return mesh;
}
else {

}
public void returnMesh(Mesh mesh) {
D.assert(mesh != null);
D.assert(mesh.hideFlags == HideFlags.HideAndDontSave);
this._pool.Enqueue(mesh);
}

296
Runtime/ui/painting/picture.cs


using System.Collections.Generic;
using System.Linq;
using Unity.UIWidgets.foundation;
using UnityEngine;
namespace Unity.UIWidgets.ui {
public class Picture {

public void addDrawCmd(DrawCmd drawCmd) {
this._drawCmds.Add(drawCmd);
if (drawCmd is DrawSave) {
this._states.Add(this._getState().copy());
}
else if (drawCmd is DrawSaveLayer) {
var drawSaveLayer = (DrawSaveLayer) drawCmd;
switch (drawCmd) {
case DrawSave _:
this._states.Add(this._getState().copy());
break;
case DrawSaveLayer cmd: {
this._states.Add(new CanvasState {
xform = Matrix3.I(),
scissor = cmd.rect.shift(-cmd.rect.topLeft),
saveLayer = true,
layerOffset = cmd.rect.topLeft,
paintBounds = Rect.zero,
});
break;
}
case DrawRestore _: {
var stateToRestore = this._getState();
this._states.RemoveAt(this._states.Count - 1);
var state = this._getState();
this._states.Add(new CanvasState {
xform = Matrix3.I(),
scissor = drawSaveLayer.rect.shift(-drawSaveLayer.rect.topLeft),
saveLayer = true,
layerOffset = drawSaveLayer.rect.topLeft,
paintBounds = Rect.zero,
});
}
else if (drawCmd is DrawRestore) {
var stateToRestore = this._getState();
this._states.RemoveAt(this._states.Count - 1);
var state = this._getState();
if (!stateToRestore.saveLayer) {
state.paintBounds = stateToRestore.paintBounds;
if (!stateToRestore.saveLayer) {
state.paintBounds = stateToRestore.paintBounds;
}
else {
var paintBounds = stateToRestore.paintBounds.shift(stateToRestore.layerOffset);
paintBounds = state.xform.mapRect(paintBounds);
this._addPaintBounds(paintBounds);
}
break;
else {
var paintBounds = stateToRestore.paintBounds.shift(stateToRestore.layerOffset);
paintBounds = state.xform.mapRect(paintBounds);
this._addPaintBounds(paintBounds);
case DrawTranslate cmd: {
var state = this._getState();
state.xform.preTranslate((float) cmd.dx, (float) cmd.dy);
break;
}
else if (drawCmd is DrawTranslate) {
var drawTranslate = (DrawTranslate) drawCmd;
var state = this._getState();
state.xform.preTranslate((float) drawTranslate.dx, (float) drawTranslate.dy);
}
else if (drawCmd is DrawScale) {
var drawScale = (DrawScale) drawCmd;
var state = this._getState();
state.xform.preScale((float) drawScale.sx, (float) (drawScale.sy ?? drawScale.sx));
}
else if (drawCmd is DrawRotate) {
var drawRotate = (DrawRotate) drawCmd;
var state = this._getState();
if (drawRotate.offset == null) {
state.xform.preRotate((float) drawRotate.radians * Mathf.PI);
case DrawScale cmd: {
var state = this._getState();
state.xform.preScale((float) cmd.sx, (float) (cmd.sy ?? cmd.sx));
break;
else {
state.xform.preRotate((float) drawRotate.radians * Mathf.PI,
(float) drawRotate.offset.dx,
(float) drawRotate.offset.dy);
case DrawRotate cmd: {
var state = this._getState();
if (cmd.offset == null) {
state.xform.preRotate((float) cmd.radians);
}
else {
state.xform.preRotate((float) cmd.radians,
(float) cmd.offset.dx,
(float) cmd.offset.dy);
}
break;
}
else if (drawCmd is DrawSkew) {
var drawSkew = (DrawSkew) drawCmd;
var state = this._getState();
state.xform.preSkew((float) drawSkew.sx, (float) drawSkew.sy);
}
else if (drawCmd is DrawConcat) {
var drawConcat = (DrawConcat) drawCmd;
var state = this._getState();
state.xform.preConcat(drawConcat.matrix);
}
else if (drawCmd is DrawResetMatrix) {
var state = this._getState();
state.xform.reset();
}
else if (drawCmd is DrawSetMatrix) {
var drawSetMatrix = (DrawSetMatrix) drawCmd;
var state = this._getState();
state.xform = new Matrix3(drawSetMatrix.matrix);
}
else if (drawCmd is DrawClipRect) {
var drawClipRect = (DrawClipRect) drawCmd;
var state = this._getState();
case DrawSkew cmd: {
var state = this._getState();
state.xform.preSkew((float) cmd.sx, (float) cmd.sy);
break;
}
case DrawConcat cmd: {
var state = this._getState();
state.xform.preConcat(cmd.matrix);
break;
}
case DrawResetMatrix _: {
var state = this._getState();
state.xform.reset();
break;
}
case DrawSetMatrix cmd: {
var state = this._getState();
state.xform = new Matrix3(cmd.matrix);
break;
}
case DrawClipRect cmd: {
var state = this._getState();
var rect = state.xform.mapRect(drawClipRect.rect);
state.scissor = state.scissor == null ? rect : state.scissor.intersect(rect);
}
else if (drawCmd is DrawClipRRect) {
var drawClipRRect = (DrawClipRRect) drawCmd;
var state = this._getState();
var rect = state.xform.mapRect(cmd.rect);
state.scissor = state.scissor == null ? rect : state.scissor.intersect(rect);
break;
}
case DrawClipRRect cmd: {
var state = this._getState();
var rect = state.xform.mapRect(drawClipRRect.rrect.outerRect);
state.scissor = state.scissor == null ? rect : state.scissor.intersect(rect);
}
else if (drawCmd is DrawClipPath) {
var drawClipPath = (DrawClipPath) drawCmd;
var state = this._getState();
var rect = state.xform.mapRect(cmd.rrect.outerRect);
state.scissor = state.scissor == null ? rect : state.scissor.intersect(rect);
break;
}
case DrawClipPath cmd: {
var state = this._getState();
var scale = XformUtils.getScale(state.xform);
bool convex;
var rect = drawClipPath.path.flatten(
XformUtils.fromMatrix3(state.xform), (float) Window.instance.devicePixelRatio
).getFillMesh(out convex).bounds;
state.scissor = state.scissor == null ? rect : state.scissor.intersect(rect);
}
else if (drawCmd is DrawPath) {
var drawPath = (DrawPath) drawCmd;
var state = this._getState();
var xform = XformUtils.fromMatrix3(state.xform);
var path = drawPath.path;
var paint = drawPath.paint;
var devicePixelRatio = (float) Window.instance.devicePixelRatio;
var rect = cmd.path.flatten(
scale * (float) Window.instance.devicePixelRatio
).getFillMesh(out _).transform(state.xform).bounds;
state.scissor = state.scissor == null ? rect : state.scissor.intersect(rect);
break;
}
case DrawPath cmd: {
var state = this._getState();
var scale = XformUtils.getScale(state.xform);
var path = cmd.path;
var paint = cmd.paint;
var devicePixelRatio = (float) Window.instance.devicePixelRatio;
MeshMesh mesh;
if (paint.style == PaintingStyle.fill) {
var cache = path.flatten(xform, devicePixelRatio);
MeshMesh mesh;
if (paint.style == PaintingStyle.fill) {
var cache = path.flatten(scale * devicePixelRatio);
mesh = cache.getFillMesh(out _).transform(state.xform);
}
else {
float strokeWidth = ((float) paint.strokeWidth * scale).clamp(0, 200.0f);
float fringeWidth = 1 / devicePixelRatio;
bool convex;
mesh = cache.getFillMesh(out convex);
}
else {
float scale = XformUtils.getAverageScale(xform);
float strokeWidth = ((float) paint.strokeWidth * scale).clamp(0, 200.0f);
float fringeWidth = 1 / devicePixelRatio;
if (strokeWidth < fringeWidth) {
strokeWidth = fringeWidth;
}
if (strokeWidth < fringeWidth) {
strokeWidth = fringeWidth;
var cache = path.flatten(scale * devicePixelRatio);
mesh = cache.getStrokeMesh(
strokeWidth / scale * 0.5f,
paint.strokeCap,
paint.strokeJoin,
(float) paint.strokeMiterLimit).transform(state.xform);
var cache = path.flatten(xform, devicePixelRatio);
mesh = cache.getStrokeMesh(
strokeWidth * 0.5f,
paint.strokeCap,
paint.strokeJoin,
(float) paint.strokeMiterLimit);
this._addPaintBounds(mesh.bounds);
break;
this._addPaintBounds(mesh.bounds);
}
else if (drawCmd is DrawImage) {
var drawImage = (DrawImage) drawCmd;
var state = this._getState();
var rect = Rect.fromLTWH(drawImage.offset.dx, drawImage.offset.dy,
drawImage.image.width, drawImage.image.height);
rect = state.xform.mapRect(rect);
this._addPaintBounds(rect);
}
else if (drawCmd is DrawImageRect) {
var drawImageRect = (DrawImageRect) drawCmd;
var state = this._getState();
var rect = state.xform.mapRect(drawImageRect.dst);
this._addPaintBounds(rect);
}
else if (drawCmd is DrawImageNine) {
var drawImageNine = (DrawImageNine) drawCmd;
var state = this._getState();
var rect = state.xform.mapRect(drawImageNine.dst);
this._addPaintBounds(rect);
}
else if (drawCmd is DrawPicture) {
var drawPicture = (DrawPicture) drawCmd;
var state = this._getState();
var rect = state.xform.mapRect(drawPicture.picture.paintBounds);
this._addPaintBounds(rect);
}
else if (drawCmd is DrawTextBlob) {
var drawTextBlob = (DrawTextBlob) drawCmd;
var state = this._getState();
var rect = drawTextBlob.textBlob.boundsInText.shift(drawTextBlob.offset);
rect = state.xform.mapRect(rect);
this._addPaintBounds(rect);
}
else {
throw new Exception("unknown drawCmd: " + drawCmd);
case DrawImage cmd: {
var state = this._getState();
var rect = Rect.fromLTWH(cmd.offset.dx, cmd.offset.dy,
cmd.image.width, cmd.image.height);
rect = state.xform.mapRect(rect);
this._addPaintBounds(rect);
break;
}
case DrawImageRect cmd: {
var state = this._getState();
var rect = state.xform.mapRect(cmd.dst);
this._addPaintBounds(rect);
break;
}
case DrawImageNine cmd: {
var state = this._getState();
var rect = state.xform.mapRect(cmd.dst);
this._addPaintBounds(rect);
break;
}
case DrawPicture cmd: {
var state = this._getState();
var rect = state.xform.mapRect(cmd.picture.paintBounds);
this._addPaintBounds(rect);
break;
}
case DrawTextBlob cmd: {
var state = this._getState();
var rect = cmd.textBlob.boundsInText.shift(cmd.offset);
rect = state.xform.mapRect(rect);
this._addPaintBounds(rect);
break;
}
default:
throw new Exception("unknown drawCmd: " + drawCmd);
}
}

27
Runtime/ui/painting/txt/font_manager.cs


}
public class FontManager {
readonly List<FontInfo> _fonts = new List<FontInfo>();
readonly Dictionary<string, FontInfo> _fonts = new Dictionary<string, FontInfo>();
static readonly int defaultFontSize = 14;
public static readonly FontManager instance = new FontManager();

}
public bool addFont(Font font) {
var entry = this._fonts.Find(f => f.font == font);
if (entry != null) {
return false;
}
public void addFont(Font font) {
this._fonts.Add(fontInfo);
return true;
foreach (var fontName in font.fontNames) {
this._fonts[fontName] = fontInfo;
}
var founded = this._fonts.Find(info =>
info.font && info.font.fontNames.Contains(name));
if (founded != null) {
return founded;
if (this._fonts.TryGetValue(name, out var fontInfo)) {
return fontInfo;
}
var osFont = Font.CreateDynamicFontFromOSFont(name, defaultFontSize);

var newFont = new FontInfo(osFont);
this._fonts.Add(newFont);
foreach (var fontName in osFont.fontNames) {
this._fonts[fontName] = newFont;
}
var entry = this._fonts.Find(f => f.font == font);
var entry = this._fonts.Values.FirstOrDefault(f => f.font == font);
if (entry != null) {
entry.onTextureRebuilt();
}

2
Runtime/ui/painting/txt/mesh_generator.cs


}
MeshMesh mesh = new MeshMesh(vertices, triangles, uv);
MeshMesh mesh = new MeshMesh(null, vertices, triangles, uv);
_meshes[key] = new MeshInfo(key, mesh);
return mesh;

105
Tests/Editor/CanvasAndLayers.cs


using System.Collections.Generic;
using System.Linq;
using Unity.UIWidgets.editor;
using Unity.UIWidgets.material;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.ui;
using UnityEditor;

using Gradient = Unity.UIWidgets.ui.Gradient;
using Material = UnityEngine.Material;
using TextStyle = Unity.UIWidgets.ui.TextStyle;
namespace UIWidgets.Tests {
public class CanvasAndLayers : EditorWindow {

WindowAdapter _windowAdapter;
MeshPool _meshPool;
static Texture2D texture6;
CanvasAndLayers() {
this._options = new Action[] {
this.drawPloygon4,

this._windowAdapter = new EditorWindowAdapter(this);
this._windowAdapter.OnEnable();
this._meshPool = new MeshPool();
texture6 = Resources.Load<Texture2D>("6");
}
void OnDisable() {

var paint = new Paint {
color = new Color(0xFFFF0000),
shader = Gradient.linear(new Offset(80, 80), new Offset(180, 180), new List<Color>() {
Colors.red, Colors.black, Colors.green
}, null, TileMode.clamp)
};
// canvas.drawRect(

canvas.rotate(Math.PI * 15 / 180);
var path = new Path();
path.moveTo(10, 150);
path.lineTo(10, 160);

}
canvas.drawPath(path, paint);
canvas.translate(100, 100);
paint.shader = Gradient.radial(new Offset(80, 80), 100, new List<Color>() {
Colors.red, Colors.black, Colors.green
}, null, TileMode.clamp);
canvas.drawPath(path, paint);
canvas.translate(100, 100);
paint.shader = Gradient.sweep(new Offset(120, 100), new List<Color>() {
Colors.red, Colors.black, Colors.green, Colors.red,
}, null, TileMode.clamp, 10 * Math.PI / 180, 135 * Math.PI / 180);
canvas.drawPath(path, paint);
canvas.translate(100, 100);
//paint.maskFilter = MaskFilter.blur(BlurStyle.normal, 5);
paint.shader = new ImageShader(new Image(texture6, true), TileMode.mirror);
canvas.drawPath(path, paint);
canvas.flush();
}

color = new Color(0xFFFF0000),
style = PaintingStyle.stroke,
strokeWidth = 10,
shader = Gradient.linear(new Offset(10, 10), new Offset(180, 180), new List<Color>() {
Colors.red, Colors.green, Colors.yellow
}, null, TileMode.clamp)
};
canvas.drawLine(

new Offset(90, 10),
paint);
var widthPaint = new Paint {
color = new Color(0xFFFF0000),
style = PaintingStyle.stroke,
strokeWidth = 4,
};
paint.maskFilter = MaskFilter.blur(BlurStyle.normal, 1);
paint.strokeWidth = 4;
widthPaint);
paint);
canvas.scale(3);
TextBlob textBlob = new TextBlob("This is a text blob", 0, 19, new Vector2d[] {
new Vector2d(10, 0),
new Vector2d(20, 0),
new Vector2d(30, 0),
new Vector2d(40, 0),
new Vector2d(50, 0),
new Vector2d(60, 0),
new Vector2d(70, 0),
new Vector2d(80, 0),
new Vector2d(90, 0),
new Vector2d(100, 0),
new Vector2d(110, 0),
new Vector2d(120, 0),
new Vector2d(130, 0),
new Vector2d(140, 0),
new Vector2d(150, 0),
new Vector2d(160, 0),
new Vector2d(170, 0),
new Vector2d(180, 0),
new Vector2d(190, 0),
}, new TextStyle(), Unity.UIWidgets.ui.Rect.fromLTWH(0 ,0, 200, 50));
canvas.drawTextBlob(textBlob, new Offset(100, 100), paint);
canvas.drawLine(
new Offset(10, 30),
new Offset(10, 60),
new Paint() {style = PaintingStyle.stroke, strokeWidth = 0.1});
canvas.drawLine(
new Offset(20, 30),
new Offset(20, 60),
new Paint() {style = PaintingStyle.stroke, strokeWidth = 0.333});
canvas.flush();
}

canvas.flush();
}
void drawRectShadow() {
var canvas = new CommandBufferCanvas(this._renderTexture, (float) Window.instance.devicePixelRatio, this._meshPool);

canvas.clipRect(Unity.UIWidgets.ui.Rect.fromLTWH(25, 25, 300, 300));
canvas.rotate(-Math.PI/8.0);
canvas.drawRect(
Unity.UIWidgets.ui.Rect.fromLTWH(10, 10, 100, 100),

color = new Color(0xFFFFFF00),
maskFilter = MaskFilter.blur(BlurStyle.normal, 15),
maskFilter = MaskFilter.blur(BlurStyle.normal, 5),
style = PaintingStyle.stroke,
strokeWidth = 55,
shader = Gradient.linear(new Offset(10, 10), new Offset(180, 180), new List<Color>() {
Colors.red, Colors.green, Colors.yellow
}, null, TileMode.clamp)
};
canvas.drawRect(

canvas.drawImage(new Image(texture6, true),
new Offset(50, 150),
paint);
canvas.flush();
}

var canvas = new CommandBufferCanvas(this._renderTexture, (float) Window.instance.devicePixelRatio, this._meshPool);
var paint = new Paint {
color = new Color(0x7FFF0000),
// color = new Color(0x7FFF0000),
shader = Gradient.linear(new Offset(100, 100), new Offset(280, 280), new List<Color>() {
Colors.red, Colors.black, Colors.green
}, null, TileMode.clamp)
};
canvas.drawImageRect(this._stream.completer.currentImage.image,

2
Tests/Editor/Widgets.cs


void OnEnable() {
this.windowAdapter = new EditorWindowAdapter(this);
this.windowAdapter.OnEnable();
FontManager.instance.addFont(Resources.Load<Font>("MaterialIcons-Regular"));
}
void OnDisable() {

178
Runtime/Resources/UIWidgets_canvas.cginc


float4 _viewport;
float _mat[9];
half4 _color;
fixed _alpha;
half4x4 _shaderMat;
sampler2D _shaderTex;
half4 _leftColor;
half4 _rightColor;
half _bias;
half _scale;
int _tileMode; // 0 = clamp, 1 = mirror, 2 = repeated
sampler2D _tex;
int _texMode; // 0 = post alpha, 1 = pre alpha, 2 = alpha only
half2 _mf_imgInc; // _mf stands for mask filter
int _mf_radius;
half _mf_kernel[25];
struct appdata_t {
float4 vertex : POSITION;
float2 tcoord : TEXCOORD0;
};
struct v2f {
float4 vertex : SV_POSITION;
float2 ftcoord : TEXCOORD0;
float2 fpos : TEXCOORD1;
};
half shader_gradient_layout(half2 pos) {
half4 p4 = half4(pos, 0.0, 1.0);
#if defined(UIWIDGETS_LINEAR)
return mul(_shaderMat, p4).x;
#elif defined(UIWIDGETS_RADIAL)
return length(mul(_shaderMat, p4).xy);
#elif defined(UIWIDGETS_SWEEP)
half2 p2 = mul(_shaderMat, p4).xy;
half angle = atan2(-p2.y, -p2.x);
// 0.1591549430918 is 1/(2*pi), used since atan returns values [-pi, pi]
return (angle * 0.1591549430918 + 0.5 + _bias) * _scale;
#else
return 0;
#endif
}
half4 shader_gradient_colorize(half pt) {
if (_tileMode == 0) { // clamp
if (pt <= 0.001) {
return _leftColor;
} else if (pt >= 0.999) {
return _rightColor;
}
half2 coord = half2(pt, 0.5);
return tex2D(_shaderTex, coord);
} else if (_tileMode == 1) { // mirror
pt = pt - 1;
pt = pt - 2 * floor(pt * 0.5) - 1;
pt = abs(pt);
half2 coord = half2(pt, 0.5);
return tex2D(_shaderTex, coord);
} else if (_tileMode == 2) { // repeated
pt = frac(pt);
half2 coord = half2(pt, 0.5);
return tex2D(_shaderTex, coord);
}
return half4(0, 0, 0, 0);
}
half2 shader_image_layout(half2 pos) {
half4 p4 = half4(pos, 0.0, 1.0);
return mul(_shaderMat, p4).xy;
}
half4 shader_image_colorize(half2 pt) {
if (_tileMode == 0) { // clamp
pt.x = clamp(pt.x, 0.001, 0.999);
pt.y = clamp(pt.y, 0.001, 0.999);
} else if (_tileMode == 1) { // mirror
pt.x = pt.x - 1;
pt.x = pt.x - 2 * floor(pt.x * 0.5) - 1;
pt.x = abs(pt.x);
pt.y = pt.y - 1;
pt.y = pt.y - 2 * floor(pt.y * 0.5) - 1;
pt.y = abs(pt.y);
} else if (_tileMode == 2) { // repeated
pt.x = frac(pt.x);
pt.y = frac(pt.y);
}
return tex2D(_shaderTex, pt);
}
half4 prealpha(half4 color) {
return half4(color.x * color.w, color.y * color.w, color.z * color.w, color.w);
}
half4 shader_color (v2f i) {
half4 c;
#if defined(UIWIDGETS_COLOR)
c = _color;
#elif defined(UIWIDGETS_IMAGE)
half2 pt = shader_image_layout(i.fpos);
c = shader_image_colorize(pt);
#else
half pt = shader_gradient_layout(i.fpos);
c = shader_gradient_colorize(pt);
#endif
c.w *= _alpha;
return c;
}
v2f vert (appdata_t v) {
v2f o;
o.ftcoord = v.tcoord;
o.fpos = v.vertex;
float3x3 mat = float3x3(_mat[0], _mat[1], _mat[2], _mat[3], _mat[4], _mat[5], 0, 0, 1);
half2 p = mul(mat, half3(v.vertex.xy, 1.0)).xy - _viewport.xy;
#if UNITY_UV_STARTS_AT_TOP
o.vertex = float4(2.0 * p.x / _viewport.z - 1.0, 2.0 * p.y / _viewport.w - 1.0, 0, 1);
#else
o.vertex = float4(2.0 * p.x / _viewport.z - 1.0, 1.0 - 2.0 * p.y / _viewport.w, 0, 1);
#endif
return o;
}
fixed4 frag (v2f i) : SV_Target {
return prealpha(shader_color(i));
}
fixed4 frag_stencil (v2f i) : SV_Target {
return half4(0, 0, 0, 0);
}
fixed4 frag_tex (v2f i) : SV_Target {
half4 tintColor = shader_color(i);
half4 color = tex2D(_tex, i.ftcoord);
if (_texMode == 0) { // post alpha
color = color * tintColor;
color = prealpha(color);
} else if (_texMode == 1) { // pre alpha
color = color * tintColor;
color = half4(color.x * tintColor.w, color.y * tintColor.w, color.z * tintColor.w, color.w);
} else if (_texMode == 2) { // alpha only
color = half4(1, 1, 1, color.w) * tintColor;
color = prealpha(color);
}
return color;
}
fixed4 frag_mf (v2f i) : SV_Target {
half4 color = half4(0, 0, 0, 0);
float2 coord = i.ftcoord - _mf_radius * _mf_imgInc;
int width = _mf_radius * 2 + 1;
for (int i = 0; i < width; i++) {
color += tex2D(_tex, coord) * _mf_kernel[i];
coord += _mf_imgInc;
}
return color;
}

9
Runtime/Resources/UIWidgets_canvas.cginc.meta


fileFormatVersion: 2
guid: 6565922d18a5e4ee29fa183d2600eccc
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

63
Runtime/Resources/UIWidgets_canvas_convexFill.shader


Shader "UIWidgets/canvas_convexFill"
{
Properties {
_SrcBlend("_SrcBlend", Int) = 1 // One
_DstBlend("_DstBlend", Int) = 10 // OneMinusSrcAlpha
}
SubShader {
ZTest Always
ZWrite Off
Blend [_SrcBlend] [_DstBlend]
Stencil {
Ref 128
Comp Equal
}
Pass { // 0, color
CGPROGRAM
#define UIWIDGETS_COLOR
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag
ENDCG
}
Pass { // 1, linear
CGPROGRAM
#define UIWIDGETS_LINEAR
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag
ENDCG
}
Pass { // 2, radial
CGPROGRAM
#define UIWIDGETS_RADIAL
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag
ENDCG
}
Pass { // 3, sweep
CGPROGRAM
#define UIWIDGETS_SWEEP
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag
ENDCG
}
Pass { // 4, image
CGPROGRAM
#define UIWIDGETS_IMAGE
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag
ENDCG
}
}
}

9
Runtime/Resources/UIWidgets_canvas_convexfill.shader.meta


fileFormatVersion: 2
guid: da4e74e0b377e41699f5c3ed2c7c69e4
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

30
Runtime/Resources/UIWidgets_canvas_fill0.shader


Shader "UIWidgets/canvas_fill0"
{
Properties {
}
SubShader {
ZTest Always
ZWrite Off
Cull Off
ColorMask 0
Stencil {
Ref 128
CompFront Equal
CompBack Equal
ReadMask 128
WriteMask 127
PassFront IncrWrap
PassBack DecrWrap
}
Pass {
CGPROGRAM
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag_stencil
ENDCG
}
}
}

9
Runtime/Resources/UIWidgets_canvas_fill0.shader.meta


fileFormatVersion: 2
guid: e75e9debfc1ad4e1687365932de72aa0
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

66
Runtime/Resources/UIWidgets_canvas_fill1.shader


Shader "UIWidgets/canvas_fill1"
{
Properties {
_SrcBlend("_SrcBlend", Int) = 1 // One
_DstBlend("_DstBlend", Int) = 10 // OneMinusSrcAlpha
}
SubShader {
ZTest Always
ZWrite Off
Blend [_SrcBlend] [_DstBlend]
Stencil {
Ref 0
Comp NotEqual
ReadMask 127
WriteMask 127
Pass Zero
}
Pass { // 0, color
CGPROGRAM
#define UIWIDGETS_COLOR
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag
ENDCG
}
Pass { // 1, linear
CGPROGRAM
#define UIWIDGETS_LINEAR
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag
ENDCG
}
Pass { // 2, radial
CGPROGRAM
#define UIWIDGETS_RADIAL
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag
ENDCG
}
Pass { // 3, sweep
CGPROGRAM
#define UIWIDGETS_SWEEP
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag
ENDCG
}
Pass { // 4, image
CGPROGRAM
#define UIWIDGETS_IMAGE
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag
ENDCG
}
}
}

9
Runtime/Resources/UIWidgets_canvas_fill1.shader.meta


fileFormatVersion: 2
guid: 7dbfb4eecc7a84ddc90c53891aa77e0b
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

18
Runtime/Resources/UIWidgets_canvas_filter.shader


Shader "UIWidgets/canvas_filter"
{
Properties {
}
SubShader {
ZTest Always
ZWrite Off
Pass { // 0, mask filter
CGPROGRAM
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag_mf
ENDCG
}
}
}

9
Runtime/Resources/UIWidgets_canvas_filter.shader.meta


fileFormatVersion: 2
guid: 756de2a3eb91745ba853728245a033d9
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

56
Runtime/Resources/UIWidgets_canvas_stencil.shader


Shader "UIWidgets/canvas_stencil"
{
Properties {
}
SubShader {
ZTest Always
ZWrite Off
Pass { // 0, stencil clear
ColorMask 0
Stencil {
Ref 128
Pass Replace
}
CGPROGRAM
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag_stencil
ENDCG
}
Pass { // 1, stencil intersect 0
Cull Off
ColorMask 0
Stencil {
WriteMask 127
PassFront IncrWrap
PassBack DecrWrap
}
CGPROGRAM
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag_stencil
ENDCG
}
Pass { // 2, stencil intersect 1
ColorMask 0
Stencil {
Ref 128
Comp Less
Pass Replace
Fail Zero
}
CGPROGRAM
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag_stencil
ENDCG
}
}
}

9
Runtime/Resources/UIWidgets_canvas_stencil.shader.meta


fileFormatVersion: 2
guid: b4673a8cf87214fdb8643b32e0ec3316
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

64
Runtime/Resources/UIWidgets_canvas_stroke0.shader


Shader "UIWidgets/canvas_stroke0"
{
Properties {
_SrcBlend("_SrcBlend", Int) = 1 // One
_DstBlend("_DstBlend", Int) = 10 // OneMinusSrcAlpha
}
SubShader {
ZTest Always
ZWrite Off
Blend [_SrcBlend] [_DstBlend]
Stencil {
Ref 128
Comp Equal
Pass IncrSat
}
Pass { // 0, color
CGPROGRAM
#define UIWIDGETS_COLOR
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag
ENDCG
}
Pass { // 1, linear
CGPROGRAM
#define UIWIDGETS_LINEAR
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag
ENDCG
}
Pass { // 2, radial
CGPROGRAM
#define UIWIDGETS_RADIAL
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag
ENDCG
}
Pass { // 3, sweep
CGPROGRAM
#define UIWIDGETS_SWEEP
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag
ENDCG
}
Pass { // 4, image
CGPROGRAM
#define UIWIDGETS_IMAGE
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag
ENDCG
}
}
}

9
Runtime/Resources/UIWidgets_canvas_stroke0.shader.meta


fileFormatVersion: 2
guid: 7e33032771e1e46a6b5eda923148503f
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

27
Runtime/Resources/UIWidgets_canvas_stroke1.shader


Shader "UIWidgets/canvas_stroke1"
{
Properties {
}
SubShader {
ZTest Always
ZWrite Off
ColorMask 0
Stencil {
Ref 0
Comp NotEqual
ReadMask 127
WriteMask 127
Pass Zero
}
Pass {
CGPROGRAM
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag_stencil
ENDCG
}
}
}

9
Runtime/Resources/UIWidgets_canvas_stroke1.shader.meta


fileFormatVersion: 2
guid: ee8a29ca6a09f4510bbf6e3b70922edc
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

63
Runtime/Resources/UIWidgets_canvas_tex.shader


Shader "UIWidgets/canvas_tex"
{
Properties {
_SrcBlend("_SrcBlend", Int) = 1 // One
_DstBlend("_DstBlend", Int) = 10 // OneMinusSrcAlpha
}
SubShader {
ZTest Always
ZWrite Off
Blend [_SrcBlend] [_DstBlend]
Stencil {
Ref 128
Comp Equal
}
Pass { // 0, color
CGPROGRAM
#define UIWIDGETS_COLOR
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag_tex
ENDCG
}
Pass { // 1, linear
CGPROGRAM
#define UIWIDGETS_LINEAR
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag_tex
ENDCG
}
Pass { // 2, radial
CGPROGRAM
#define UIWIDGETS_RADIAL
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag_tex
ENDCG
}
Pass { // 3, sweep
CGPROGRAM
#define UIWIDGETS_SWEEP
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag_tex
ENDCG
}
Pass { // 4, image
CGPROGRAM
#define UIWIDGETS_IMAGE
#include "UIWidgets_canvas.cginc"
#pragma vertex vert
#pragma fragment frag_tex
ENDCG
}
}
}

9
Runtime/Resources/UIWidgets_canvas_tex.shader.meta


fileFormatVersion: 2
guid: 1702a648d08de40d9aacd9bbab1188b3
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

393
Runtime/ui/painting/canvas_shader.cs


using System;
using Unity.UIWidgets.painting;
using UnityEngine;
namespace Unity.UIWidgets.ui {
class MaterialByBlendMode {
static readonly int _srcBlend = Shader.PropertyToID("_SrcBlend");
static readonly int _dstBlend = Shader.PropertyToID("_DstBlend");
public MaterialByBlendMode(Shader shader) {
this._shader = shader;
}
readonly Shader _shader;
readonly Material[] _materials = new Material[30];
public Material getMaterial(BlendMode op) {
var mat = this._materials[(int) op];
if (mat) {
return mat;
}
mat = new Material(this._shader) {hideFlags = HideFlags.HideAndDontSave};
this._materials[(int) op] = mat;
if (op == BlendMode.srcOver) {
mat.SetInt(_srcBlend, (int) UnityEngine.Rendering.BlendMode.One);
mat.SetInt(_dstBlend, (int) UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
} else if (op == BlendMode.srcIn) {
mat.SetInt(_srcBlend, (int) UnityEngine.Rendering.BlendMode.DstAlpha);
mat.SetInt(_dstBlend, (int) UnityEngine.Rendering.BlendMode.Zero);
} else if (op == BlendMode.srcOut) {
mat.SetInt(_srcBlend, (int) UnityEngine.Rendering.BlendMode.OneMinusDstAlpha);
mat.SetInt(_dstBlend, (int) UnityEngine.Rendering.BlendMode.Zero);
} else if (op == BlendMode.srcATop) {
mat.SetInt(_srcBlend, (int) UnityEngine.Rendering.BlendMode.DstAlpha);
mat.SetInt(_dstBlend, (int) UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
} else if (op == BlendMode.dstOver) {
mat.SetInt(_srcBlend, (int) UnityEngine.Rendering.BlendMode.OneMinusDstAlpha);
mat.SetInt(_dstBlend, (int) UnityEngine.Rendering.BlendMode.One);
} else if (op == BlendMode.dstIn) {
mat.SetInt(_srcBlend, (int) UnityEngine.Rendering.BlendMode.Zero);
mat.SetInt(_dstBlend, (int) UnityEngine.Rendering.BlendMode.SrcAlpha);
} else if (op == BlendMode.dstOut) {
mat.SetInt(_srcBlend, (int) UnityEngine.Rendering.BlendMode.Zero);
mat.SetInt(_dstBlend, (int) UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
} else if (op == BlendMode.dstATop) {
mat.SetInt(_srcBlend, (int) UnityEngine.Rendering.BlendMode.OneMinusDstAlpha);
mat.SetInt(_dstBlend, (int) UnityEngine.Rendering.BlendMode.SrcAlpha);
} else if (op == BlendMode.plus) {
mat.SetInt(_srcBlend, (int) UnityEngine.Rendering.BlendMode.One);
mat.SetInt(_dstBlend, (int) UnityEngine.Rendering.BlendMode.One);
} else if (op == BlendMode.src) {
mat.SetInt(_srcBlend, (int) UnityEngine.Rendering.BlendMode.One);
mat.SetInt(_dstBlend, (int) UnityEngine.Rendering.BlendMode.Zero);
} else if (op == BlendMode.dst) {
mat.SetInt(_srcBlend, (int) UnityEngine.Rendering.BlendMode.Zero);
mat.SetInt(_dstBlend, (int) UnityEngine.Rendering.BlendMode.One);
} else if (op == BlendMode.xor) {
mat.SetInt(_srcBlend, (int) UnityEngine.Rendering.BlendMode.OneMinusDstAlpha);
mat.SetInt(_dstBlend, (int) UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
} else if (op == BlendMode.clear) {
mat.SetInt(_srcBlend, (int) UnityEngine.Rendering.BlendMode.Zero);
mat.SetInt(_dstBlend, (int) UnityEngine.Rendering.BlendMode.Zero);
} else {
Debug.LogWarning("Not supported BlendMode: " + op + ". Defaults to srcOver");
mat.SetInt(_srcBlend, (int) UnityEngine.Rendering.BlendMode.One);
mat.SetInt(_dstBlend, (int) UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
}
return mat;
}
}
static class CanvasShader {
static readonly MaterialByBlendMode _convexFillMat;
static readonly Material _fill0Mat;
static readonly MaterialByBlendMode _fill1Mat;
static readonly MaterialByBlendMode _stroke0Mat;
static readonly Material _stroke1Mat;
static readonly MaterialByBlendMode _texMat;
static readonly Material _stencilMat;
static readonly Material _filterMat;
static CanvasShader() {
var convexFillShader = Shader.Find("UIWidgets/canvas_convexFill");
if (convexFillShader == null) {
throw new Exception("UIWidgets/canvas_convexFill not found");
}
var fill0Shader = Shader.Find("UIWidgets/canvas_fill0");
if (fill0Shader == null) {
throw new Exception("UIWidgets/canvas_fill0 not found");
}
var fill1Shader = Shader.Find("UIWidgets/canvas_fill1");
if (fill1Shader == null) {
throw new Exception("UIWidgets/canvas_fill1 not found");
}
var stroke0Shader = Shader.Find("UIWidgets/canvas_stroke0");
if (stroke0Shader == null) {
throw new Exception("UIWidgets/canvas_stroke0 not found");
}
var stroke1Shader = Shader.Find("UIWidgets/canvas_stroke1");
if (stroke1Shader == null) {
throw new Exception("UIWidgets/canvas_stroke1 not found");
}
var texShader = Shader.Find("UIWidgets/canvas_tex");
if (texShader == null) {
throw new Exception("UIWidgets/canvas_tex not found");
}
var stencilShader = Shader.Find("UIWidgets/canvas_stencil");
if (stencilShader == null) {
throw new Exception("UIWidgets/canvas_stencil not found");
}
var filterShader = Shader.Find("UIWidgets/canvas_filter");
if (filterShader == null) {
throw new Exception("UIWidgets/canvas_filter not found");
}
_convexFillMat = new MaterialByBlendMode(convexFillShader);
_fill0Mat = new Material(fill0Shader) {hideFlags = HideFlags.HideAndDontSave};
_fill1Mat = new MaterialByBlendMode(fill1Shader);
_stroke0Mat = new MaterialByBlendMode(stroke0Shader);
_stroke1Mat = new Material(stroke1Shader) {hideFlags = HideFlags.HideAndDontSave};
_texMat = new MaterialByBlendMode(texShader);
_stencilMat = new Material(stencilShader) {hideFlags = HideFlags.HideAndDontSave};
_filterMat = new Material(filterShader) {hideFlags = HideFlags.HideAndDontSave};
}
static Vector4 _colorToVector4(Color c) {
return new Vector4(
c.red / 255f,
c.green / 255f,
c.blue / 255f,
c.alpha / 255f
);
}
static void _getShaderPassAndProps(Vector4 viewport, Matrix3 ctm, Paint paint, float alpha,
out int pass, out MaterialPropertyBlock props) {
props = new MaterialPropertyBlock();
props.SetVector("_viewport", viewport);
props.SetFloat("_alpha", alpha);
switch (paint.shader) {
case null:
pass = 0;
props.SetVector("_color", _colorToVector4(paint.color));
return;
case _LinearGradient linear:
pass = 1;
props.SetMatrix("_shaderMat", linear.getGradientMat(ctm).toMatrix4x4());
props.SetTexture("_shaderTex", linear.gradientTex.texture);
props.SetVector("_leftColor", _colorToVector4(linear.leftColor));
props.SetVector("_rightColor", _colorToVector4(linear.rightColor));
props.SetInt("_tileMode", (int) linear.tileMode);
return;
case _RadialGradient radial:
pass = 2;
props.SetMatrix("_shaderMat", radial.getGradientMat(ctm).toMatrix4x4());
props.SetTexture("_shaderTex", radial.gradientTex.texture);
props.SetVector("_leftColor", _colorToVector4(radial.leftColor));
props.SetVector("_rightColor", _colorToVector4(radial.rightColor));
props.SetInt("_tileMode", (int) radial.tileMode);
return;
case _SweepGradient sweep:
pass = 3;
props.SetMatrix("_shaderMat", sweep.getGradientMat(ctm).toMatrix4x4());
props.SetTexture("_shaderTex", sweep.gradientTex.texture);
props.SetVector("_leftColor", _colorToVector4(sweep.leftColor));
props.SetVector("_rightColor", _colorToVector4(sweep.rightColor));
props.SetInt("_tileMode", (int) sweep.tileMode);
props.SetFloat("_bias", (float) sweep.bias);
props.SetFloat("_scale", (float) sweep.scale);
return;
case ImageShader image:
pass = 4;
props.SetMatrix("_shaderMat", image.getShaderMat(ctm).toMatrix4x4());
props.SetTexture("_shaderTex", image.image.texture);
props.SetInt("_tileMode", (int) image.tileMode);
return;
default:
throw new Exception("Unknown paint.shader: " + paint.shader);
}
}
public static CommandBufferCanvas.RenderDraw convexFill(CommandBufferCanvas.RenderLayer layer, Paint paint,
MeshMesh mesh) {
Vector4 viewport = layer.viewport;
Matrix3 ctm = layer.states[layer.states.Count - 1].matrix;
var mat = _convexFillMat.getMaterial(paint.blendMode);
_getShaderPassAndProps(viewport, ctm, paint, 1.0f, out var pass, out var props);
return new CommandBufferCanvas.RenderDraw {
mesh = mesh,
pass = pass,
material = mat,
properties = props,
};
}
public static CommandBufferCanvas.RenderDraw fill0(CommandBufferCanvas.RenderLayer layer, MeshMesh mesh) {
Vector4 viewport = layer.viewport;
var mat = _fill0Mat;
var pass = 0;
var props = new MaterialPropertyBlock();
props.SetVector("_viewport", viewport);
return new CommandBufferCanvas.RenderDraw {
mesh = mesh,
pass = pass,
material = mat,
properties = props,
};
}
public static CommandBufferCanvas.RenderDraw fill1(CommandBufferCanvas.RenderLayer layer, Paint paint,
MeshMesh mesh) {
Vector4 viewport = layer.viewport;
Matrix3 ctm = layer.states[layer.states.Count - 1].matrix;
var mat = _fill1Mat.getMaterial(paint.blendMode);
_getShaderPassAndProps(viewport, ctm, paint, 1.0f, out var pass, out var props);
return new CommandBufferCanvas.RenderDraw {
mesh = mesh.boundsMesh,
pass = pass,
material = mat,
properties = props,
};
}
public static CommandBufferCanvas.RenderDraw stroke0(CommandBufferCanvas.RenderLayer layer, Paint paint,
float alpha, MeshMesh mesh) {
Vector4 viewport = layer.viewport;
Matrix3 ctm = layer.states[layer.states.Count - 1].matrix;
var mat = _stroke0Mat.getMaterial(paint.blendMode);
_getShaderPassAndProps(viewport, ctm, paint, alpha, out var pass, out var props);
return new CommandBufferCanvas.RenderDraw {
mesh = mesh,
pass = pass,
material = mat,
properties = props,
};
}
public static CommandBufferCanvas.RenderDraw stroke1(CommandBufferCanvas.RenderLayer layer, MeshMesh mesh) {
Vector4 viewport = layer.viewport;
var mat = _stroke1Mat;
var pass = 0;
var props = new MaterialPropertyBlock();
props.SetVector("_viewport", viewport);
return new CommandBufferCanvas.RenderDraw {
mesh = mesh,
pass = pass,
material = mat,
properties = props,
};
}
public static CommandBufferCanvas.RenderDraw stencilClear(
CommandBufferCanvas.RenderLayer layer, MeshMesh mesh) {
Vector4 viewport = layer.viewport;
var mat = _stencilMat;
var pass = 0;
var props = new MaterialPropertyBlock();
props.SetVector("_viewport", viewport);
return new CommandBufferCanvas.RenderDraw {
mesh = mesh,
pass = pass,
material = mat,
properties = props,
};
}
public static CommandBufferCanvas.RenderDraw stencil0(CommandBufferCanvas.RenderLayer layer, MeshMesh mesh) {
Vector4 viewport = layer.viewport;
var mat = _stencilMat;
var pass = 1;
var props = new MaterialPropertyBlock();
props.SetVector("_viewport", viewport);
return new CommandBufferCanvas.RenderDraw {
mesh = mesh,
pass = pass,
material = mat,
properties = props,
};
}
public static CommandBufferCanvas.RenderDraw stencil1(CommandBufferCanvas.RenderLayer layer, MeshMesh mesh) {
Vector4 viewport = layer.viewport;
var mat = _stencilMat;
var pass = 2;
var props = new MaterialPropertyBlock();
props.SetVector("_viewport", viewport);
return new CommandBufferCanvas.RenderDraw {
mesh = mesh,
pass = pass,
material = mat,
properties = props,
};
}
public static CommandBufferCanvas.RenderDraw tex(CommandBufferCanvas.RenderLayer layer, Paint paint,
MeshMesh mesh, Image image) {
Vector4 viewport = layer.viewport;
Matrix3 ctm = layer.states[layer.states.Count - 1].matrix;
var mat = _texMat.getMaterial(paint.blendMode);
_getShaderPassAndProps(viewport, ctm, paint, 1.0f, out var pass, out var props);
props.SetTexture("_tex", image.texture);
props.SetInt("_texMode", image.texture is RenderTexture ? 1 : 0); // pre alpha if RT else post alpha
return new CommandBufferCanvas.RenderDraw {
mesh = mesh,
pass = pass,
material = mat,
properties = props,
image = image, // keep a reference to avoid GC.
};
}
public static CommandBufferCanvas.RenderDraw texRT(CommandBufferCanvas.RenderLayer layer, Paint paint,
MeshMesh mesh, CommandBufferCanvas.RenderLayer renderLayer) {
Vector4 viewport = layer.viewport;
Matrix3 ctm = layer.states[layer.states.Count - 1].matrix;
var mat = _texMat.getMaterial(paint.blendMode);
_getShaderPassAndProps(viewport, ctm, paint, 1.0f, out var pass, out var props);
props.SetInt("_texMode", 1); // pre alpha
return new CommandBufferCanvas.RenderDraw {
mesh = mesh,
pass = pass,
material = mat,
properties = props,
layer = renderLayer,
};
}
public static CommandBufferCanvas.RenderDraw texAlpha(CommandBufferCanvas.RenderLayer layer, Paint paint,
MeshMesh mesh, Texture tex) {
Vector4 viewport = layer.viewport;
Matrix3 ctm = layer.states[layer.states.Count - 1].matrix;
var mat = _texMat.getMaterial(paint.blendMode);
_getShaderPassAndProps(viewport, ctm, paint, 1.0f, out var pass, out var props);
props.SetTexture("_tex", tex);
props.SetInt("_texMode", 2); // alpha only
return new CommandBufferCanvas.RenderDraw {
mesh = mesh,
pass = pass,
material = mat,
properties = props,
};
}
public static CommandBufferCanvas.RenderDraw maskFilter(CommandBufferCanvas.RenderLayer layer, MeshMesh mesh,
CommandBufferCanvas.RenderLayer renderLayer, float radius, Vector2 imgInc, float[] kernel) {
Vector4 viewport = layer.viewport;
var mat = _filterMat;
var pass = 0;
var props = new MaterialPropertyBlock();
props.SetVector("_viewport", viewport);
props.SetFloat("_mf_radius", radius);
props.SetVector("_mf_imgInc", imgInc);
props.SetFloatArray("_mf_kernel", kernel);
return new CommandBufferCanvas.RenderDraw {
mesh = mesh,
pass = pass,
material = mat,
properties = props,
layer = renderLayer,
};
}
}
}

11
Runtime/ui/painting/canvas_shader.cs.meta


fileFormatVersion: 2
guid: 6c897b209ded34c03ac522c5f76ae23d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

602
Runtime/ui/painting/shader.cs


using System;
using System.Collections.Generic;
using Unity.UIWidgets.foundation;
using UnityEngine;
namespace Unity.UIWidgets.ui {
public enum TileMode : int {
clamp = 0,
mirror = 1,
repeated = 2,
}
public abstract class PaintShader {
}
public class Gradient : PaintShader {
public static Gradient linear(
Offset start, Offset end, List<Color> colors,
List<double> colorStops = null, TileMode tileMode = TileMode.clamp,
Matrix3 matrix = null) {
D.assert(PaintingUtils._offsetIsValid(start));
D.assert(PaintingUtils._offsetIsValid(end));
D.assert(colors != null && colors.Count >= 2);
_validateColorStops(ref colors, ref colorStops);
return new _LinearGradient(start, end, colors, colorStops, tileMode, matrix);
}
public static Gradient radial(
Offset center, double radius, List<Color> colors,
List<double> colorStops = null, TileMode tileMode = TileMode.clamp,
Matrix3 matrix = null) {
D.assert(PaintingUtils._offsetIsValid(center));
D.assert(colors != null && colors.Count >= 2);
_validateColorStops(ref colors, ref colorStops);
return new _RadialGradient(center, radius, colors, colorStops, tileMode, matrix);
}
public static Gradient sweep(
Offset center, List<Color> colors,
List<double> colorStops = null, TileMode tileMode = TileMode.clamp,
double startAngle = 0.0, double endAngle = Math.PI * 2,
Matrix3 matrix = null) {
D.assert(PaintingUtils._offsetIsValid(center));
D.assert(colors != null && colors.Count >= 2);
D.assert(startAngle < endAngle);
_validateColorStops(ref colors, ref colorStops);
return new _SweepGradient(center, colors, colorStops, tileMode, startAngle, endAngle, matrix);
}
static void _validateColorStops(ref List<Color> colors, ref List<double> colorStops) {
if (colorStops == null) {
colors = new List<Color>(colors);
colorStops = new List<double>(colors.Count);
colorStops.Add(0);
var stepCount = colors.Count - 1;
var step = 1.0 / stepCount;
for (int i = 1; i < stepCount; i++) {
colorStops.Add(colorStops[i - 1] + step);
}
colorStops.Add(1);
return;
}
if (colors.Count != colorStops.Count) {
throw new ArgumentException("\"colors\" and \"colorStops\" arguments must have equal length.");
}
var dummyFirst = colorStops[0] != 0;
var dummyLast = colorStops[colorStops.Count - 1] != 1;
var count = colors.Count + (dummyFirst ? 1 : 0) + (dummyFirst ? 1 : 0);
var newColors = new List<Color>(count);
if (dummyFirst) {
newColors.Add(colors[0]);
}
for (int i = 0; i < colors.Count; i++) {
newColors.Add(colors[i]);
}
if (dummyLast) {
newColors.Add(colors[colors.Count - 1]);
}
var newColorStops = new List<double>(count);
if (dummyFirst) {
newColorStops.Add(0.0);
}
var prevStop = 0.0;
for (int i = 0; i < colorStops.Count; i++) {
var stop = Math.Max(Math.Min(colorStops[i], 1.0), prevStop);
newColorStops.Add(stop);
prevStop = stop;
}
if (dummyLast) {
newColorStops.Add(1.0);
}
colors = newColors;
colorStops = newColorStops;
}
static readonly GradientBitmapCache _cache = new GradientBitmapCache();
internal static Image makeTexturedColorizer(List<Color> colors, List<double> positions) {
int count = colors.Count;
D.assert(count >= 2);
bool bottomHardStop = ScalarUtils.ScalarNearlyEqual((float) positions[0], (float) positions[1]);
bool topHardStop = ScalarUtils.ScalarNearlyEqual((float) positions[count - 2], (float) positions[count - 1]);
int offset = 0;
if (bottomHardStop) {
offset += 1;
count--;
}
if (topHardStop) {
count--;
}
if (offset != 0 || count != colors.Count) {
colors = colors.GetRange(offset, count);
positions = positions.GetRange(offset, count);
}
return _cache.getGradient(colors, positions);
}
}
class GradientBitmapCache : IDisposable {
public GradientBitmapCache(int maxEntries = 32, int resolution = 256) {
this.maxEntries = maxEntries;
this.resolution = resolution;
this._entryCount = 0;
this._head = this._tail = null;
D.assert(this.validate);
}
public readonly int maxEntries;
public readonly int resolution;
int _entryCount;
_Entry _head;
_Entry _tail;
public Image getGradient(List<Color> colors, List<double> positions) {
var key = new _Key(colors, positions);
if (!this.find(key, out var image)) {
image = this.fillGradient(colors, positions);
this.add(key, image);
}
return image;
}
public void Dispose() {
D.assert(this.validate);
// just remove the references, Image will dispose by themselves.
this._entryCount = 0;
this._head = this._tail = null;
}
_Entry release(_Entry entry) {
if (entry.prev != null) {
D.assert(this._head != entry);
entry.prev.next = entry.next;
} else {
D.assert(this._head == entry);
this._head = entry.next;
}
if (entry.next != null) {
D.assert(this._tail != entry);
entry.next.prev = entry.prev;
} else {
D.assert(this._tail == entry);
this._tail = entry.prev;
}
return entry;
}
void attachToHead(_Entry entry) {
entry.prev = null;
entry.next = this._head;
if (this._head != null) {
this._head.prev = entry;
} else {
this._tail = entry;
}
this._head = entry;
}
bool find(_Key key, out Image image) {
D.assert(this.validate);
var entry = this._head;
while (entry != null) {
if (entry.key == key) {
image = entry.image;
// move to the head of our list, so we purge it last
this.release(entry);
this.attachToHead(entry);
D.assert(this.validate);
return true;
}
entry = entry.next;
}
D.assert(this.validate);
image = null;
return false;
}
void add(_Key key, Image image) {
if (this._entryCount == this.maxEntries) {
D.assert(this._tail != null);
this.release(this._tail);
this._entryCount--;
}
var entry = new _Entry {key = key, image = image};
this.attachToHead(entry);
this._entryCount++;
}
Image fillGradient(List<Color> colors, List<double> positions) {
Texture2D tex = new Texture2D(this.resolution, 1, TextureFormat.RGBA32, false);
tex.hideFlags = HideFlags.HideAndDontSave;
var bytes = new byte[this.resolution * 4];
int count = colors.Count;
int prevIndex = 0;
for (int i = 1; i < count; i++) {
// Historically, stops have been mapped to [0, 256], with 256 then nudged to the next
// smaller value, then truncate for the texture index. This seems to produce the best
// results for some common distributions, so we preserve the behavior.
int nextIndex = (int) Mathf.Min((float) positions[i] * this.resolution, this.resolution - 1);
if (nextIndex > prevIndex) {
var c0 = colors[i - 1];
var c1 = colors[i];
var step = 1.0f / (nextIndex - prevIndex);
var t = 0.0;
for (int curIndex = prevIndex; curIndex <= nextIndex; ++curIndex) {
var c = Color.lerp(c0, c1, t);
var baseIndex = curIndex << 2;
bytes[baseIndex] = (byte) c.red;
bytes[baseIndex + 1] = (byte) c.green;
bytes[baseIndex + 2] = (byte) c.blue;
bytes[baseIndex + 3] = (byte) c.alpha;
t += step;
}
}
prevIndex = nextIndex;
}
D.assert(prevIndex == this.resolution - 1);
tex.LoadRawTextureData(bytes);
tex.Apply();
return new Image(tex);
}
bool validate() {
D.assert(this._entryCount >= 0 && this._entryCount <= this.maxEntries);
if (this._entryCount > 0) {
D.assert(null == this._head.prev);
D.assert(null == this._tail.next);
if (this._entryCount == 1) {
D.assert(this._head == this._tail);
} else {
D.assert(this._head != this._tail);
}
var entry = this._head;
int count = 0;
while (entry != null) {
count += 1;
entry = entry.next;
}
D.assert(count == this._entryCount);
entry = this._tail;
while (entry != null) {
count -= 1;
entry = entry.prev;
}
D.assert(0 == count);
} else {
D.assert(null == this._head);
D.assert(null == this._tail);
}
return true;
}
class _Entry {
public _Entry prev;
public _Entry next;
public _Key key;
public Image image;
}
class _Key : IEquatable<_Key> {
public _Key(List<Color> colors, List<double> positions) {
D.assert(colors != null);
D.assert(positions != null);
D.assert(colors.Count == positions.Count);
this.colors = colors;
this.positions = positions;
this._hashCode = _getHashCode(this.colors) ^ _getHashCode(this.positions);
;
}
public readonly List<Color> colors;
public readonly List<double> positions;
readonly int _hashCode;
public bool Equals(_Key other) {
if (ReferenceEquals(null, other)) {
return false;
}
if (ReferenceEquals(this, other)) {
return true;
}
return _listEquals(this.colors, other.colors) &&
_listEquals(this.positions, other.positions);
}
public override bool Equals(object obj) {
if (ReferenceEquals(null, obj)) {
return false;
}
if (ReferenceEquals(this, obj)) {
return true;
}
if (obj.GetType() != this.GetType()) {
return false;
}
return this.Equals((_Key) obj);
}
public override int GetHashCode() {
return this._hashCode;
}
public static bool operator ==(_Key left, _Key right) {
return Equals(left, right);
}
public static bool operator !=(_Key left, _Key right) {
return !Equals(left, right);
}
static int _getHashCode<T>(List<T> list) {
unchecked {
var hashCode = 0;
foreach (var item in list) {
hashCode = (hashCode * 397) ^ item.GetHashCode();
}
return hashCode;
}
}
static bool _listEquals<T>(List<T> left, List<T> right) {
if (left.Count != right.Count) {
return false;
}
for (int i = 0; i < left.Count; i++) {
if (!left[i].Equals(right[i])) {
return false;
}
}
return true;
}
}
}
class _LinearGradient : Gradient {
public _LinearGradient(
Offset start, Offset end, List<Color> colors,
List<double> colorStops, TileMode tileMode,
Matrix3 matrix = null) {
this.start = start;
this.end = end;
this.colors = colors;
this.colorStops = colorStops;
this.tileMode = tileMode;
this.matrix = matrix;
this.ptsToUnit = ptsToUnitMatrix(start, end);
this.gradientTex = makeTexturedColorizer(colors, colorStops);
}
public readonly Offset start;
public readonly Offset end;
public readonly List<Color> colors;
public readonly List<double> colorStops;
public readonly TileMode tileMode;
public readonly Matrix3 matrix;
public readonly Matrix3 ptsToUnit;
public readonly Image gradientTex;
public Color leftColor {
get { return this.colors[0]; }
}
public Color rightColor {
get { return this.colors[this.colors.Count - 1]; }
}
public Matrix3 getGradientMat(Matrix3 ctm) {
var mat = Matrix3.I();
ctm.invert(mat); // just use I() if not invertible.
if (this.matrix != null) {
mat.postConcat(this.matrix);
}
mat.postConcat(this.ptsToUnit);
return mat;
}
static Matrix3 ptsToUnitMatrix(Offset start, Offset end) {
var vec = end - start;
var mag = vec.distance;
var inv = mag != 0 ? 1 / mag : 0;
vec = vec.scale(inv);
var matrix = Matrix3.I();
matrix.setSinCos((float) -vec.dy, (float) vec.dx, (float) start.dx, (float) start.dy);
matrix.postTranslate((float) -start.dx, (float) -start.dy);
matrix.postScale((float) inv, (float) inv);
return matrix;
}
}
class _RadialGradient : Gradient {
public _RadialGradient(
Offset center, double radius, List<Color> colors,
List<double> colorStops = null, TileMode tileMode = TileMode.clamp,
Matrix3 matrix = null
) {
this.center = center;
this.radius = radius;
this.colors = colors;
this.colorStops = colorStops;
this.tileMode = tileMode;
this.matrix = matrix;
this.ptsToUnit = radToUnitMatrix(center, radius);
this.gradientTex = makeTexturedColorizer(colors, colorStops);
}
public readonly Offset center;
public readonly double radius;
public readonly List<Color> colors;
public readonly List<double> colorStops;
public readonly TileMode tileMode;
public readonly Matrix3 matrix;
public readonly Matrix3 ptsToUnit;
public readonly Image gradientTex;
public Color leftColor {
get { return this.colors[0]; }
}
public Color rightColor {
get { return this.colors[this.colors.Count - 1]; }
}
public Matrix3 getGradientMat(Matrix3 ctm) {
var mat = Matrix3.I();
ctm.invert(mat); // just use I() if not invertible.
if (this.matrix != null) {
mat.postConcat(this.matrix);
}
mat.postConcat(this.ptsToUnit);
return mat;
}
static Matrix3 radToUnitMatrix(Offset center, double radius) {
var inv = radius != 0 ? 1 / radius : 0;
var matrix = Matrix3.I();
matrix.setTranslate((float) -center.dx, (float) -center.dy);
matrix.postScale((float) inv, (float) inv);
return matrix;
}
}
class _SweepGradient : Gradient {
public _SweepGradient(
Offset center, List<Color> colors,
List<double> colorStops = null, TileMode tileMode = TileMode.clamp,
double startAngle = 0.0, double endAngle = Math.PI * 2,
Matrix3 matrix = null
) {
this.center = center;
this.colors = colors;
this.colorStops = colorStops;
this.tileMode = tileMode;
this.startAngle = startAngle;
this.endAngle = endAngle;
this.matrix = matrix;
var t0 = startAngle / (Math.PI * 2f);
var t1 = endAngle / (Math.PI * 2f);
this.bias = -t0;
this.scale = 1f / (t1 - t0);
var ptsToUnit = Matrix3.I();
ptsToUnit.setTranslate((float) -center.dx, (float) -center.dy);
this.ptsToUnit = ptsToUnit;
this.gradientTex = makeTexturedColorizer(colors, colorStops);
}
public readonly Offset center;
public readonly List<Color> colors;
public readonly List<double> colorStops;
public readonly TileMode tileMode;
public readonly double startAngle;
public readonly double endAngle;
public readonly Matrix3 matrix;
public readonly Matrix3 ptsToUnit;
public readonly Image gradientTex;
public readonly double bias;
public readonly double scale;
public Color leftColor {
get { return this.colors[0]; }
}
public Color rightColor {
get { return this.colors[this.colors.Count - 1]; }
}
public Matrix3 getGradientMat(Matrix3 ctm) {
var mat = Matrix3.I();
ctm.invert(mat); // just use I() if not invertible.
if (this.matrix != null) {
mat.postConcat(this.matrix);
}
mat.postConcat(this.ptsToUnit);
return mat;
}
}
public class ImageShader : PaintShader {
public ImageShader(Image image,
TileMode tileMode = TileMode.clamp, Matrix3 matrix = null) {
this.image = image;
this.tileMode = tileMode;
this.matrix = matrix;
}
public readonly Image image;
public readonly TileMode tileMode;
public readonly Matrix3 matrix;
public Matrix3 getShaderMat(Matrix3 ctm) {
var mat = Matrix3.I();
ctm.invert(mat); // just use I() if not invertible.
if (this.matrix != null) {
mat.postConcat(this.matrix);
}
mat.postScale(1f / this.image.width, 1f / this.image.height);
return mat;
}
}
}

11
Runtime/ui/painting/shader.cs.meta


fileFormatVersion: 2
guid: 740926ff13f534c8d8ec44b0b017ff61
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

8
Tests/Resources.meta


fileFormatVersion: 2
guid: a4bf4806dd96141b189111637bb1f450
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

3
Tests/Resources/6.png

之前 之后
宽度: 64  |  高度: 64  |  大小: 183 B

88
Tests/Resources/6.png.meta


fileFormatVersion: 2
guid: d8fa175306ac44f8ea120cf256fd21d9
TextureImporter:
fileIDToRecycleName: {}
externalObjects: {}
serializedVersion: 7
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: -1
wrapV: -1
wrapW: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
vertices: []
indices:
edges: []
weights: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

3
Runtime/Resources/UIWidgets_canvas.shader.meta


fileFormatVersion: 2
guid: baf507ab371c4f4c9eb9ce70a004ba0d
timeCreated: 1543832597

259
Runtime/Resources/UIWidgets_canvas.shader


Shader "UIWidgets/canvas"
{
Properties {
_SrcBlend("_SrcBlend", Int) = 1 // One
_DstBlend("_DstBlend", Int) = 10 // OneMinusSrcAlpha
}
CGINCLUDE
float4 _viewport;
float4x4 _paintMat;
half4 _innerCol;
half4 _outerCol;
float2 _extent;
float _radius;
float _feather;
sampler2D _tex;
half2 _mf_imgInc; // _mf stands for mask filter
int _mf_radius;
half _mf_kernel[25];
struct appdata_t {
float4 vertex : POSITION;
float2 tcoord : TEXCOORD0;
};
struct v2f {
float4 vertex : SV_POSITION;
float2 ftcoord : TEXCOORD0;
float2 fpos : TEXCOORD1;
};
float sdroundrect (float2 pt, float2 ext, float rad) {
float2 ext2 = ext - float2(rad, rad);
float2 d = abs(pt) - ext2;
return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)) - rad;
}
#pragma vertex vert
v2f vert (appdata_t v) {
v2f o;
o.ftcoord = v.tcoord;
o.fpos = v.vertex;
float x = v.vertex.x - _viewport.x;
float y = v.vertex.y - _viewport.y;
#if UNITY_UV_STARTS_AT_TOP
o.vertex = float4(2.0 * x / _viewport.z - 1.0, 2.0 * y / _viewport.w - 1.0, 0, 1);
#else
o.vertex = float4(2.0 * x / _viewport.z - 1.0, 1.0 - 2.0 * y / _viewport.w, 0, 1);
#endif
return o;
}
fixed4 frag (v2f i) : SV_Target {
float2 pt = (mul(_paintMat, float3(i.fpos, 1.0))).xy;
float d = clamp((sdroundrect(pt, _extent, _radius) + _feather * 0.5) / _feather, 0.0, 1.0);
half4 color = lerp(_innerCol, _outerCol, d);
return color;
}
fixed4 frag_stencil (v2f i) : SV_Target {
return half4(0, 0, 0, 0);
}
fixed4 frag_tex (v2f i) : SV_Target {
half4 color = tex2D(_tex, i.ftcoord);
color = color * _innerCol; // tint color
color = half4(color.xyz * color.w, color.w);
return color;
}
fixed4 frag_texrt (v2f i) : SV_Target {
half4 color = tex2D(_tex, i.ftcoord);
color = color * _innerCol; // tint color
color = half4(color.xyz * _innerCol.w, color.w);
return color;
}
fixed4 frag_texfont (v2f i) : SV_Target {
half4 color = tex2D(_tex, i.ftcoord);
color = half4(1, 1, 1, color.w) * _innerCol; // tint color
color = half4(color.xyz * color.w, color.w);
return color;
}
fixed4 frag_mf (v2f i) : SV_Target {
half4 color = half4(0, 0, 0, 0);
float2 coord = i.ftcoord - _mf_radius * _mf_imgInc;
int width = _mf_radius * 2 + 1;
for (int i = 0; i < width; i++) {
color += tex2D(_tex, coord) * _mf_kernel[i];
coord += _mf_imgInc;
}
color = color * _innerCol; // tint color
color = half4(color.xyz * _innerCol.w, color.w);
return color;
}
ENDCG
SubShader {
ZTest Always
ZWrite Off
Blend [_SrcBlend] [_DstBlend]
Pass { // 0, fill pass 0
Cull Off
ColorMask 0
Stencil {
Ref 128
CompFront Equal
CompBack Equal
ReadMask 128
WriteMask 127
PassFront IncrWrap
PassBack DecrWrap
}
CGPROGRAM
#pragma fragment frag_stencil
ENDCG
}
Pass { // 1, fill pass 1
Stencil {
Ref 0
Comp NotEqual
ReadMask 127
WriteMask 127
Pass Zero
}
CGPROGRAM
#pragma fragment frag
ENDCG
}
Pass { // 2, convex fill
Stencil {
Ref 128
Comp Equal
}
CGPROGRAM
#pragma fragment frag
ENDCG
}
Pass { // 3, stroke pass 0
Stencil {
Ref 128
Comp Equal
Pass IncrSat
}
CGPROGRAM
#pragma fragment frag
ENDCG
}
Pass { // 4, stroke pass 1
ColorMask 0
Stencil {
Ref 0
Comp NotEqual
ReadMask 127
WriteMask 127
Pass Zero
}
CGPROGRAM
#pragma fragment frag_stencil
ENDCG
}
Pass { // 5, texture pass 0
Stencil {
Ref 128
Comp Equal
}
CGPROGRAM
#pragma fragment frag_tex
ENDCG
}
Pass { // 6, render texture pass 0
Stencil {
Ref 128
Comp Equal
}
CGPROGRAM
#pragma fragment frag_texrt
ENDCG
}
Pass { // 7, stencil clear
ColorMask 0
Stencil {
Ref 128
Pass Replace
}
CGPROGRAM
#pragma fragment frag_stencil
ENDCG
}
Pass { // 8, stencil intersect 0
Cull Off
ColorMask 0
Stencil {
WriteMask 127
PassFront IncrWrap
PassBack DecrWrap
}
CGPROGRAM
#pragma fragment frag_stencil
ENDCG
}
Pass { // 9, stencil intersect 1
ColorMask 0
Stencil {
Ref 128
Comp Less
Pass Replace
Fail Zero
}
CGPROGRAM
#pragma fragment frag_stencil
ENDCG
}
Pass { // 10, font texture pass 0
Stencil {
Ref 128
Comp Equal
}
CGPROGRAM
#pragma fragment frag_texfont
ENDCG
}
Pass { // 11, mask filter
CGPROGRAM
#pragma fragment frag_mf
ENDCG
}
}
}
正在加载...
取消
保存