浏览代码

add MaskFilter to canvas.

/main
kg 6 年前
当前提交
b5a9692b
共有 7 个文件被更改,包括 678 次插入113 次删除
  1. 56
      Runtime/Resources/UIWidgets_canvas.shader
  2. 2
      Runtime/painting/box_shadow.cs
  3. 5
      Runtime/painting/decoration_image.cs
  4. 477
      Runtime/ui/painting/canvas_impl.cs
  5. 157
      Runtime/ui/painting/painting.cs
  6. 46
      Runtime/ui/painting/path.cs
  7. 48
      Tests/Editor/CanvasAndLayers.cs

56
Runtime/Resources/UIWidgets_canvas.shader


}
CGINCLUDE
float2 _viewSize;
float4 _viewport;
float4 _innerCol;
float4 _outerCol;
half4 _innerCol;
half4 _outerCol;
half2 _mf_imgInc; // _mf stands for mask filter
int _mf_radius;
half _mf_kernel[25];
struct appdata_t {
float4 vertex : POSITION;
float2 tcoord : TEXCOORD0;

v2f o;
o.ftcoord = v.tcoord;
o.fpos = v.vertex;
float x = v.vertex.x - _viewport.x;
float y = v.vertex.y - _viewport.y;
o.vertex = float4(2.0 * v.vertex.x / _viewSize.x - 1.0, 2.0 * v.vertex.y / _viewSize.y - 1.0, 0, 1);
o.vertex = float4(2.0 * x / _viewport.z - 1.0, 2.0 * y / _viewport.w - 1.0, 0, 1);
o.vertex = float4(2.0 * v.vertex.x / _viewSize.x - 1.0, 1.0 - 2.0 * v.vertex.y / _viewSize.y, 0, 1);
o.vertex = float4(2.0 * x / _viewport.z - 1.0, 1.0 - 2.0 * y / _viewport.w, 0, 1);
#endif
return o;

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);
float4 color = lerp(_innerCol, _outerCol, d);
half4 color = lerp(_innerCol, _outerCol, d);
return float4(0, 0, 0, 0);
return half4(0, 0, 0, 0);
float4 color = tex2D(_tex, i.ftcoord);
half4 color = tex2D(_tex, i.ftcoord);
color = float4(color.xyz * color.w, color.w);
color = half4(color.xyz * color.w, color.w);
float4 color = tex2D(_tex, i.ftcoord);
half4 color = tex2D(_tex, i.ftcoord);
color = float4(color.xyz * _innerCol.w, color.w);
color = half4(color.xyz * _innerCol.w, color.w);
float4 color = tex2D(_tex, i.ftcoord);
color = float4(1, 1, 1, color.w) * _innerCol; // tint color
color = float4(color.xyz * color.w, color.w);
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;
}

CGPROGRAM
#pragma fragment frag_texfont
ENDCG
}
Pass { // 11, mask filter
CGPROGRAM
#pragma fragment frag_mf
ENDCG
}
}

2
Runtime/painting/box_shadow.cs


public Paint toPaint() {
return new Paint {
color = this.color,
//blurSigma = this.blurSigma, TODO
maskFilter = MaskFilter.blur(BlurStyle.normal, this.blurSigma)
};
}

5
Runtime/painting/decoration_image.cs


}
fit = fit ?? (centerSlice == null ? BoxFit.scaleDown : BoxFit.fill);
D.assert(centerSlice == null || (fit != BoxFit.none && fit != BoxFit.cover));
D.assert(centerSlice == null || (fit != BoxFit.none && fit != BoxFit.cover),
$"centerSlice was used with a BoxFit {fit} that is not supported.");
FittedSizes fittedSizes = FittedSizes.applyBoxFit(fit.Value, inputSize / scale, outputSize);
Size sourceSize = fittedSizes.source * scale;
Size destinationSize = fittedSizes.destination;

D.assert(sourceSize == inputSize,
"centerSlice was used with a BoxFit that does not guarantee that the image is fully visible.");
$"centerSlice was used with a BoxFit {fit} that does not guarantee that the image is fully visible.");
}
if (repeat != ImageRepeat.noRepeat && destinationSize == outputSize) {

477
Runtime/ui/painting/canvas_impl.cs


readonly MeshPool _meshPool;
readonly List<RenderLayer> _layers = new List<RenderLayer>();
int _saveCount;
0, 4, 1, 1, 4, 5,
0, 1, 4, 1, 5, 4,
1, 5, 2, 2, 5, 6,
1, 2, 5, 2, 6, 5,
2, 6, 3, 3, 6, 7,
2, 3, 6, 3, 7, 6,
4, 8, 5, 5, 8, 9,
4, 5, 8, 5, 9, 8,
5, 9, 6, 6, 9, 10,
5, 6, 9, 6, 10, 9,
6, 10, 7, 7, 10, 11,
6, 7, 10, 7, 11, 10,
8, 12, 9, 9, 12, 13,
8, 9, 12, 9, 13, 12,
9, 13, 10, 10, 13, 14,
9, 10, 13, 10, 14, 13,
10, 14, 11, 11, 14, 15,
10, 11, 14, 11, 15, 14,
0, 4, 1, 1, 4, 5,
0, 1, 4, 1, 5, 4,
1, 5, 2, 2, 5, 6,
1, 2, 5, 2, 6, 5,
2, 6, 3, 3, 6, 7,
2, 3, 6, 3, 7, 6,
4, 8, 5, 5, 8, 9,
4, 5, 8, 5, 9, 8,
5, 9, 6, 6, 9, 10,
5, 6, 9, 6, 10, 9,
6, 10, 7, 7, 10, 11,
6, 7, 10, 7, 11, 10,
8, 12, 9, 9, 12, 13,
8, 9, 12, 9, 13, 12,
9, 13, 10, 10, 13, 14,
9, 10, 13, 10, 14, 13,
10, 14, 11, 11, 14, 15,
10, 11, 14, 11, 15, 14,
};
public CommandBufferCanvas(RenderTexture renderTexture, float devicePixelRatio, MeshPool meshPool) {

}
public void saveLayer(Rect bounds, Paint paint) {
D.assert(bounds != null);
D.assert(bounds.width > 0);
D.assert(bounds.height > 0);
D.assert(paint != null);
(float) bounds.width * XformUtils.getScaleX(state.xform) * this._devicePixelRatio);
(float) bounds.width *
XformUtils.getScaleX(state.xform) *
this._devicePixelRatio);
textureWidth = Mathf.Max(textureWidth, 1);
(float) bounds.height * XformUtils.getScaleY(state.xform) * this._devicePixelRatio);
(float) bounds.height *
XformUtils.getScaleY(state.xform) *
this._devicePixelRatio);
textureHeight = Mathf.Max(textureHeight, 1);
var parentLayer = this._getLayer();
var layer = new RenderLayer {

parentLayer.layers.Add(layer);
this._layers.Add(layer);
state = this._getState();
XformUtils.transformTranslate(state.xform, (float) -bounds.left, (float) -bounds.top);
}
public void restore() {

var vertices = new List<Vector3>(4);
var uv = new List<Vector2>(4);
float uvx0 = 0.0f;
float uvx1 = 1.0f;
float uvy0 = 1.0f;
float uvy1 = 0.0f;
const float uvx0 = 0.0f;
const float uvx1 = 1.0f;
const float uvy0 = 1.0f;
const float uvy1 = 0.0f;
float x, y;
var bounds = layer.layerBounds;

(float) bounds.right, (float) bounds.top);
vertices.Add(new Vector2(x, y));
uv.Add(new Vector2(uvx1, uvy0));
var mesh = new MeshMesh(vertices, _imageTriangles, uv);
if (!this._applyClip(mesh.bounds)) {

MaterialPropertyBlock _getMatProps(Paint paint, float alpha = 1.0f) {
var properties = new MaterialPropertyBlock();
properties.SetVector("_viewSize", this._getViewSize());
if (paint.shader is Gradient) {
var gradient = (Gradient) paint.shader;
properties.SetVector("_viewport", this._getViewport());
if (paint.shader is Gradient gradient) {
var innerCol = gradient.innerColor;
var outerCol = gradient.outerColor;

bool _applyClip(Rect queryBounds) {
var layer = this._getLayer();
var layerBounds = Rect.fromLTRB(0, 0, layer.layerBounds.width, layer.layerBounds.height);
var layerBounds = layer.layerBounds;
ReducedClip reducedClip = new ReducedClip(layer.clipStack, layerBounds, queryBounds);
if (reducedClip.isEmpty()) {
return false;

var deviceScissor = Rect.fromLTRB(
scissor.left, layerBounds.height - scissor.bottom,
scissor.right, layerBounds.height - scissor.top
scissor.left - layerBounds.left, layerBounds.bottom - scissor.bottom,
scissor.right - layerBounds.left, layerBounds.bottom - scissor.top
deviceScissor = deviceScissor,
deviceScissor = deviceScissor.roundOut(),
properties.SetVector("_viewSize", this._getViewSize());
properties.SetVector("_viewport", this._getViewport());
var boundsMesh = new MeshMesh(reducedClip.scissor);
this._getLayer().draws.Add(new RenderDraw {

return true;
}
public void drawPath(Path path, Paint paint) {
RenderLayer _createMaskLayer(Path path, Paint paint, RenderLayer parentLayer, Rect maskBounds) {
var textureWidth = Mathf.CeilToInt(
(float) maskBounds.width * this._devicePixelRatio);
textureWidth = Mathf.Max(1, textureWidth);
var textureHeight = Mathf.
CeilToInt((float) maskBounds.height * this._devicePixelRatio);
textureHeight = Mathf.Max(1, textureHeight);
var maskLayer = new RenderLayer {
rtID = Shader.PropertyToID("_rtID_" + this._layers.Count + "_" + parentLayer.layers.Count),
width = textureWidth,
height = textureHeight,
layerBounds = maskBounds,
};
parentLayer.layers.Add(maskLayer);
this._layers.Add(maskLayer);
var parentState = parentLayer.states.Last();
var maskState = maskLayer.states.Last();
XformUtils.transformCopy(maskState.xform, parentState.xform);
var maskPaint = Paint.shapeOnly(paint);
this._drawPath(path, maskPaint);
var removed = this._layers.removeLast();
D.assert(removed == maskLayer);
return maskLayer;
}
RenderLayer _createBlurLayer(RenderLayer maskLayer, float sigma, RenderLayer parentLayer) {
sigma = BlurUtils.adjustSigma(sigma, out var scaleFactor, out var radius);
var textureWidth = Mathf.CeilToInt((float) maskLayer.width / scaleFactor);
textureWidth = Mathf.Max(1, textureWidth);
var textureHeight = Mathf.CeilToInt((float) maskLayer.height / scaleFactor);
textureHeight = Mathf.Max(1, textureHeight);
var blurXLayer = new RenderLayer {
rtID = Shader.PropertyToID("_rtID_" + this._layers.Count + "_" + parentLayer.layers.Count),
width = textureWidth,
height = textureHeight,
layerBounds = maskLayer.layerBounds,
};
parentLayer.layers.Add(blurXLayer);
var blurYLayer = new RenderLayer {
rtID = Shader.PropertyToID("_rtID_" + this._layers.Count + "_" + parentLayer.layers.Count),
width = textureWidth,
height = textureHeight,
layerBounds = maskLayer.layerBounds,
};
parentLayer.layers.Add(blurYLayer);
var vertices = new List<Vector3>(4);
var uv = new List<Vector2>(4);
const float uvx0 = 0.0f;
const float uvx1 = 1.0f;
const float uvy0 = 1.0f;
const float uvy1 = 0.0f;
vertices.Add(new Vector2((float) maskLayer.layerBounds.left, (float) maskLayer.layerBounds.top));
uv.Add(new Vector2(uvx0, uvy0));
vertices.Add(new Vector2((float) maskLayer.layerBounds.left, (float) maskLayer.layerBounds.bottom));
uv.Add(new Vector2(uvx0, uvy1));
vertices.Add(new Vector2((float) maskLayer.layerBounds.right, (float) maskLayer.layerBounds.bottom));
uv.Add(new Vector2(uvx1, uvy1));
vertices.Add(new Vector2((float) maskLayer.layerBounds.right, (float) maskLayer.layerBounds.top));
uv.Add(new Vector2(uvx1, uvy0));
var blurMesh = new MeshMesh(vertices, _imageTriangles, uv);
var emptyPaint = new Paint();
var kernel = BlurUtils.get1DGaussianKernel(sigma, radius);
this._layers.Add(blurXLayer);
{
var mat = this._getMat(emptyPaint);
var properties = this._getMatPropsForImage(null, emptyPaint);
properties.SetFloat("_mf_radius", radius);
properties.SetVector("_mf_imgInc", new Vector2(1f / textureWidth, 0));
properties.SetFloatArray("_mf_kernel", kernel);
blurXLayer.draws.Add(
new RenderDraw {
mesh = blurMesh,
pass = CanvasShaderPass.mfPass0,
material = mat,
properties = properties,
layer = maskLayer
}
);
}
var removed = this._layers.removeLast();
D.assert(removed == blurXLayer);
this._layers.Add(blurYLayer);
{
var mat = this._getMat(emptyPaint);
var properties = this._getMatPropsForImage(null, emptyPaint);
properties.SetFloat("_mf_radius", radius);
properties.SetVector("_mf_imgInc", new Vector2(0, -1f / textureHeight));
properties.SetFloatArray("_mf_kernel", kernel);
blurYLayer.draws.Add(
new RenderDraw {
mesh = blurMesh,
pass = CanvasShaderPass.mfPass0,
material = mat,
properties = properties,
layer = blurXLayer
}
);
}
removed = this._layers.removeLast();
D.assert(removed == blurYLayer);
return blurYLayer;
}
void _drawPathWithMaskFilter(Path path, Paint paint, MaskFilter maskFilter) {
var layer = this._getLayer();
var clipBounds = layer.layerBounds;
Rect stackBounds;
bool iior;
layer.clipStack.getBounds(out stackBounds, out iior);
if (stackBounds != null) {
clipBounds = clipBounds.intersect(stackBounds);
}
if (clipBounds.isEmpty) {
return;
}
var state = this._getState();
var cache = path.flatten(state.xform, this._devicePixelRatio);
bool convex;
var mesh = cache.getFillMesh(out convex);
var meshBounds = mesh.bounds;
float sigma = XformUtils.mapRadius(state.xform, (float) maskFilter.sigma);
if (sigma <= 0) {
return;
}
float sigma3 = 3 * sigma;
var maskBounds = meshBounds.inflate(sigma3);
maskBounds = maskBounds.intersect(clipBounds.inflate(sigma3));
if (maskBounds.isEmpty) {
return;
}
var maskLayer = this._createMaskLayer(path, paint, layer, maskBounds);
var blurLayer = this._createBlurLayer(maskLayer, sigma, layer);
var vertices = new List<Vector3>(4);
var uv = new List<Vector2>(4);
const float uvx0 = 0.0f;
const float uvx1 = 1.0f;
const float uvy0 = 1.0f;
const float uvy1 = 0.0f;
vertices.Add(new Vector2((float) maskBounds.left, (float) maskBounds.top));
uv.Add(new Vector2(uvx0, uvy0));
vertices.Add(new Vector2((float) maskBounds.left, (float) maskBounds.bottom));
uv.Add(new Vector2(uvx0, uvy1));
vertices.Add(new Vector2((float) maskBounds.right, (float) maskBounds.bottom));
uv.Add(new Vector2(uvx1, uvy1));
vertices.Add(new Vector2((float) maskBounds.right, (float) maskBounds.top));
uv.Add(new Vector2(uvx1, uvy0));
var blurMesh = new MeshMesh(vertices, _imageTriangles, uv);
if (!this._applyClip(blurMesh.bounds)) {
return;
}
var mat = this._getMat(paint);
var properties = this._getMatPropsForImage(null, paint);
layer.draws.Add(
new RenderDraw {
mesh = blurMesh,
pass = CanvasShaderPass.texrtPass0,
material = mat,
properties = properties,
layer = blurLayer
}
);
}
void _drawPath(Path path, Paint paint) {
D.assert(path != null);
D.assert(paint != null);

}
}
public void drawPath(Path path, Paint paint) {
D.assert(path != null);
D.assert(paint != null);
if (paint.maskFilter != null) {
this._drawPathWithMaskFilter(path, paint, paint.maskFilter);
return;
}
this._drawPath(path, paint);
}
public void drawImage(Image image, Offset offset, Paint paint) {
D.assert(image != null);
D.assert(offset != null);

paint);
}
Vector2 _getViewSize() {
Vector4 _getViewport() {
return new Vector2((float) layer.layerBounds.width, (float) layer.layerBounds.height);
return new Vector4(
(float) layer.layerBounds.left,
(float) layer.layerBounds.top,
(float) layer.layerBounds.width,
(float) layer.layerBounds.height);
}
static Dictionary<BlendMode, Material> _materials = new Dictionary<BlendMode, Material>();

MaterialPropertyBlock _getMatPropsForImage(Texture image, Paint paint) {
var properties = new MaterialPropertyBlock();
properties.SetVector("_viewSize", this._getViewSize());
properties.SetVector("_viewport", this._getViewport());
properties.SetVector("_innerCol", _color(paint.color));
if (image != null) {
image.filterMode = paint.filterMode;

XformUtils.transformTranslate(xform, (float) offset.dx, (float) offset.dy);
XformUtils.transformMultiply(xform, state.xform); // xform = state.xform * xform
var scale = XformUtils.getAverageScale(xform) * this._devicePixelRatio;
var scale = XformUtils.getAverageScale(xform) * this._devicePixelRatio;
var mesh = MeshGenerator.generateMesh(textBlob, scale).transform(xform);
if (!this._applyClip(mesh.bounds)) {

this._layers.Clear();
this._layers.Add(firstLayer);
}
void _drawLayer(RenderLayer layer, CommandBuffer cmdBuf) {
foreach (var subLayer in layer.layers) {
cmdBuf.GetTemporaryRT(subLayer.rtID, new RenderTextureDescriptor(

useMipMap = false,
autoGenerateMips = false,
});
}, FilterMode.Bilinear);
this._drawLayer(subLayer, cmdBuf);
}

if (!this.meshObj) {
this.meshObj = canvas._meshPool.getMesh();
this.meshObj.SetVertices(this.mesh.vertices);
this.meshObj.SetTriangles(this.mesh.triangles, 0, false);
this.meshObj.SetUVs(0, this.mesh.uv);

public const int stencilIntersect0 = 8;
public const int stencilIntersect1 = 9;
public const int texfontPass0 = 10;
public const int mfPass0 = 11;
public static void transformCopy(float[] t, float[] s) {
t[0] = s[0];
t[1] = s[1];
t[2] = s[2];
t[3] = s[3];
t[4] = s[4];
t[5] = s[5];
}
public static void transformIdentity(float[] t) {
t[0] = 1.0f;
t[1] = 0.0f;

t[5] = 0.0f;
}
// t = s * t;
public static void transformMultiply(float[] t, float[] s) {
float t0 = t[0] * s[0] + t[1] * s[2];

t[4] = t4;
}
// t = t * s;
public static void transformPremultiply(float[] t, float[] s) {
float[] s2 = {s[0], s[1], s[2], s[3], s[4], s[5]};
transformMultiply(s2, t);

return (getScaleX(t) + getScaleY(t)) * 0.5f;
}
public static float getMaxScale(float[] t) {
return Mathf.Max(getScaleX(t), getScaleY(t));
}
public static float getScaleX(float[] t) {
return Mathf.Sqrt(t[0] * t[0] + t[2] * t[2]);
}

}
public static float mapRadius(float[] t, float radius) {
// mapped point of (radius, 0) and (0, radius)
var x0 = radius * t[0] + t[4];
var y0 = radius * t[1] + t[5];
var x1 = radius * t[2] + t[4];
var y1 = radius * t[3] + t[5];
// geometric mean of len0 and len1.
return Mathf.Sqrt(Mathf.Sqrt((x0 * x0 + y0 * y0) * (x1 * x1 + y1 * y1)));
}
public static void transformPoint(out float dx, out float dy, float[] t, float sx, float sy) {
dx = sx * t[0] + sy * t[2] + t[4];
dy = sx * t[1] + sy * t[3] + t[5];
}
public static float[] fromMatrix3(Matrix3 matrix) {
return new[] {
matrix.getScaleX(), matrix.getSkewY(),

xform[1], xform[3], xform[5],
0, 0, 1
);
}
}
static class BlurUtils {
static readonly Dictionary<_GaussianKernelKey, float[]> _gaussianKernels
= new Dictionary<_GaussianKernelKey, float[]>();
public static float[] get1DGaussianKernel(float gaussianSigma, int radius) {
var width = 2 * radius + 1;
D.assert(width <= 25);
var key = new _GaussianKernelKey(gaussianSigma, radius);
return _gaussianKernels.putIfAbsent(key, () => {
var kernel = new float[25];
float twoSigmaSqrd = 2.0f * gaussianSigma * gaussianSigma;
if (ScalarUtils.ScalarNearlyZero(twoSigmaSqrd)) {
for (int i = 0; i < width; ++i) {
kernel[i] = 0.0f;
}
return kernel;
}
float denom = 1.0f / twoSigmaSqrd;
float sum = 0.0f;
for (int i = 0; i < width; ++i) {
float x = i - radius;
// Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
// is dropped here, since we renormalize the kernel below.
kernel[i] = Mathf.Exp(-x * x * denom);
sum += kernel[i];
}
// Normalize the kernel
float scale = 1.0f / sum;
for (int i = 0; i < width; ++i) {
kernel[i] *= scale;
}
return kernel;
});
}
public static float adjustSigma(float sigma, out int scaleFactor, out int radius) {
scaleFactor = 1;
const int maxTextureSize = 16384;
const float MAX_BLUR_SIGMA = 4.0f;
while (sigma > MAX_BLUR_SIGMA) {
scaleFactor *= 2;
sigma *= 0.5f;
if (scaleFactor > maxTextureSize) {
scaleFactor = maxTextureSize;
sigma = MAX_BLUR_SIGMA;
}
}
radius = Mathf.CeilToInt(sigma * 3.0f);
D.assert(radius <= 3 * MAX_BLUR_SIGMA);
return sigma;
}
class _GaussianKernelKey : IEquatable<_GaussianKernelKey> {
public readonly float gaussianSigma;
public readonly int radius;
public _GaussianKernelKey(float gaussianSigma, int radius) {
this.gaussianSigma = gaussianSigma;
this.radius = radius;
}
public bool Equals(_GaussianKernelKey other) {
if (ReferenceEquals(null, other)) {
return false;
}
if (ReferenceEquals(this, other)) {
return true;
}
return this.gaussianSigma.Equals(other.gaussianSigma) &&
this.radius == other.radius;
}
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((_GaussianKernelKey) obj);
}
public override int GetHashCode() {
unchecked {
var hashCode = this.gaussianSigma.GetHashCode();
hashCode = (hashCode * 397) ^ this.radius;
return hashCode;
}
}
public static bool operator ==(_GaussianKernelKey left, _GaussianKernelKey right) {
return Equals(left, right);
}
public static bool operator !=(_GaussianKernelKey left, _GaussianKernelKey right) {
return !Equals(left, right);
}
public override string ToString() {
return $"_GaussianKernelKey(gaussianSigma: {this.gaussianSigma:F1}, radius: {this.radius})";
}
}
}
}

157
Runtime/ui/painting/painting.cs


using System;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.painting;
using UnityEngine;

this.value = value & 0xFFFFFFFF;
}
public static readonly Color clear = new Color(0x00000000);
public static readonly Color black = new Color(0xFF000000);

bevel,
}
public class ColorFilter {
public Color color;
public BlendMode blendMode;
public enum BlurStyle {
normal, // only normal for now.
solid,
outer,
inner,
}
public class MaskFilter : IEquatable<MaskFilter> {
MaskFilter(BlurStyle style, double sigma) {
this.style = style;
this.sigma = sigma;
}
public static MaskFilter blur(BlurStyle style, double sigma) {
return new MaskFilter(style, sigma);
}
public readonly BlurStyle style;
public readonly double sigma;
public bool Equals(MaskFilter other) {
if (ReferenceEquals(null, other)) {
return false;
}
if (ReferenceEquals(this, other)) {
return true;
}
return this.style == other.style && this.sigma.Equals(other.sigma);
}
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((MaskFilter) obj);
}
public override int GetHashCode() {
unchecked {
return ((int) this.style * 397) ^ this.sigma.GetHashCode();
}
}
public static bool operator ==(MaskFilter left, MaskFilter right) {
return Equals(left, right);
}
public static bool operator !=(MaskFilter left, MaskFilter right) {
return !Equals(left, right);
}
public override string ToString() {
return $"MaskFilter.blur(${this.style}, ${this.sigma:F1})";
}
}
public class ColorFilter : IEquatable<ColorFilter> {
ColorFilter(Color color, BlendMode blendMode) {
D.assert(color != null);
this.color = color;
this.blendMode = blendMode;
}
public static ColorFilter mode(Color color, BlendMode blendMode) {
return new ColorFilter(color, blendMode);
}
public readonly Color color;
public readonly BlendMode blendMode;
public bool Equals(ColorFilter other) {
if (ReferenceEquals(null, other)) {
return false;
}
if (ReferenceEquals(this, other)) {
return true;
}
return Equals(this.color, other.color) && this.blendMode == other.blendMode;
}
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((ColorFilter) obj);
}
public override int GetHashCode() {
unchecked {
return ((this.color != null ? this.color.GetHashCode() : 0) * 397) ^ (int) this.blendMode;
}
}
public static bool operator ==(ColorFilter left, ColorFilter right) {
return Equals(left, right);
}
public static bool operator !=(ColorFilter left, ColorFilter right) {
return !Equals(left, right);
}
public override string ToString() {
return $"ColorFilter({this.color}, {this.blendMode})";
}
}
public enum TileMode {

public ColorFilter colorFilter = null;
public MaskFilter maskFilter = null;
public double blurSigma;
public bool invertColors;
public Paint() {
}
public Paint(Paint paint) {
D.assert(paint != null);
public bool invertColors;
this.color = paint.color;
this.blendMode = paint.blendMode;
this.style = paint.style;
this.strokeWidth = paint.strokeWidth;
this.strokeCap = paint.strokeCap;
this.strokeJoin = paint.strokeJoin;
this.strokeMiterLimit = paint.strokeMiterLimit;
this.filterMode = paint.filterMode;
this.colorFilter = paint.colorFilter;
this.maskFilter = paint.maskFilter;
this.shader = paint.shader;
this.invertColors = paint.invertColors;
}
public static Paint shapeOnly(Paint paint) {
return new Paint {
style = paint.style,
strokeWidth = paint.strokeWidth,
strokeCap = paint.strokeCap,
strokeJoin = paint.strokeJoin,
strokeMiterLimit = paint.strokeMiterLimit,
};
}
}
public static class Conversions {

46
Runtime/ui/painting/path.cs


public MeshMesh(List<Vector3> vertices, List<int> triangles, List<Vector2> uv = null) {
D.assert(vertices != null);
D.assert(vertices.Count > 0);
D.assert(vertices.Count >= 0);
D.assert(triangles.Count > 0);
D.assert(triangles.Count >= 0);
D.assert(uv == null || uv.Count == vertices.Count);
this.vertices = vertices;

double minX = vertices[0].x;
double maxX = vertices[0].x;
double minY = vertices[0].y;
double maxY = vertices[0].y;
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;
}
if (vertex.x > maxX) {
maxX = vertex.x;
}
if (vertex.y < minY) {
minY = vertex.y;
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.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;
this.bounds = Rect.fromLTRB(minX, minY, maxX, maxY);
}
public MeshMesh transform(float[] xform) {

48
Tests/Editor/CanvasAndLayers.cs


var widthPaint = new Paint {
color = new Color(0xFFFF0000),
style = PaintingStyle.stroke,
strokeWidth = 4,
};

}
void drawRectShadow() {
// var canvas = new CanvasImpl();
//
// var paint = new Paint {
// color = new Color(0xFF00FF00),
// blurSigma = 3.0,
// };
//
// canvas.drawRectShadow(
// Rect.fromLTWH(10, 10, 100, 100),
// paint);
//
// paint = new Paint {
// color = new Color(0xFFFFFF00),
// blurSigma = 2.0,
// };
//
// canvas.drawRectShadow(
// Rect.fromLTWH(10, 150, 100, 100),
// paint);
var canvas = new CommandBufferCanvas(this._renderTexture, (float) Window.instance.devicePixelRatio, this._meshPool);
var paint = new Paint {
color = new Color(0xFF00FF00),
maskFilter = MaskFilter.blur(BlurStyle.normal, 3),
};
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),
paint);
paint = new Paint {
color = new Color(0xFFFFFF00),
maskFilter = MaskFilter.blur(BlurStyle.normal, 15),
};
canvas.drawRect(
Unity.UIWidgets.ui.Rect.fromLTWH(10, 150, 200, 200),
paint);
canvas.flush();
}
void drawPicture() {

paint = new Paint {
color = new Color(0xFF00FFFF),
blurSigma = 3,
maskFilter = MaskFilter.blur(BlurStyle.normal, 3),
};
canvas.drawRect(
Unity.UIWidgets.ui.Rect.fromLTWH(150, 150, 110, 120),

正在加载...
取消
保存