浏览代码

Merge branch 'kgdev' into 'master'

add gradient.

See merge request upm-packages/ui-widgets/com.unity.uiwidgets!44
/main
Shenhua Gu 6 年前
当前提交
8a64a781
共有 6 个文件被更改,包括 559 次插入8 次删除
  1. 8
      Runtime/Resources/UIWidgets_canvas.cginc
  2. 39
      Runtime/foundation/basic_types.cs
  3. 2
      Runtime/painting/box_decoration.cs
  4. 508
      Runtime/painting/gradient.cs
  5. 1
      Runtime/ui/painting/shader.cs
  6. 9
      Tests/Editor/Widgets.cs

8
Runtime/Resources/UIWidgets_canvas.cginc


half4 shader_gradient_colorize(half pt) {
if (_tileMode == 0) { // clamp
if (pt <= 0.001) {
if (pt <= 0.0) {
} else if (pt >= 0.999) {
} else if (pt >= 1.0) {
return _rightColor;
}

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);
pt.x = clamp(pt.x, 0.0, 1.0);
pt.y = clamp(pt.y, 0.0, 1.0);
} else if (_tileMode == 1) { // mirror
pt.x = pt.x - 1;
pt.x = pt.x - 2 * floor(pt.x * 0.5) - 1;

39
Runtime/foundation/basic_types.cs


using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Object = UnityEngine.Object;

var result = it[lastIndex];
it.RemoveAt(lastIndex);
return result;
}
public static int hashList<T>(this IList<T> it) {
unchecked {
var hashCode = 0;
if (it != null) {
foreach (var item in it) {
hashCode = (hashCode * 397) ^ item.GetHashCode();
}
}
return hashCode;
}
}
public static bool equalsList<T>(this IList<T> it, IList<T> list) {
if (it == null && list == null) {
return true;
}
if (it == null || list == null) {
return false;
}
if (it.Count != list.Count) {
return false;
}
for (int i = it.Count - 1; i >= 0; --i) {
if (!Equals(it[i], list[i])) {
return false;
}
}
return true;
}
public static string toStringList<T>(this IList<T> it) {
return "{ " + string.Join(", ", it.Select(item => item.ToString())) + " }";
}
}
}

2
Runtime/painting/box_decoration.cs


}
if (this._decoration.gradient != null) {
//paint.shader = this._decoration.gradient.createShader(rect);
paint.shader = this._decoration.gradient.createShader(rect);
this._rectForCachedBackgroundPaint = rect;
}

508
Runtime/painting/gradient.cs


using System;
using System.Collections.Generic;
using System.Linq;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.ui;
class _ColorsAndStops {
public _ColorsAndStops(List<Color> colors, List<double> stops) {
this.colors = colors;
this.stops = stops;
}
public readonly List<Color> colors;
public readonly List<double> stops;
public static _ColorsAndStops _interpolateColorsAndStops(
List<Color> aColors, List<double> aStops, List<Color> bColors, List<double> bStops, double t) {
D.assert(aColors.Count == bColors.Count,
"Cannot interpolate between two gradients with a different number of colors.");
D.assert((aStops == null && aColors.Count == 2) || (aStops != null && aStops.Count == aColors.Count));
D.assert((bStops == null && bColors.Count == 2) || (bStops != null && bStops.Count == bColors.Count));
List<Color> interpolatedColors = new List<Color>();
for (int i = 0; i < aColors.Count; i += 1) {
interpolatedColors.Add(Color.lerp(aColors[i], bColors[i], t));
}
List<double> interpolatedStops = null;
if (aStops != null || bStops != null) {
aStops = aStops ?? new List<double> {0.0, 1.0};
bStops = bStops ?? new List<double> {0.0, 1.0};
D.assert(aStops.Count == bStops.Count);
interpolatedStops = new List<double>();
for (int i = 0; i < aStops.Count; i += 1) {
interpolatedStops.Add(MathUtils.lerpDouble(aStops[i], bStops[i], t).clamp(0.0, 1.0));
}
}
return new _ColorsAndStops(interpolatedColors, interpolatedStops);
}
}
public Gradient(
List<Color> colors = null,
List<double> stops = null
) {
D.assert(colors != null);
this.colors = colors;
this.stops = stops;
}
public readonly List<Color> colors;
public readonly List<double> stops;
protected List<double> _impliedStops() {
if (this.stops != null) {
return this.stops;
}
if (this.colors.Count == 2) {
return null;
}
D.assert(this.colors.Count >= 2, "colors list must have at least two colors");
double separation = 1.0 / (this.colors.Count - 1);
return Enumerable.Range(0, this.colors.Count).Select(i => i * separation).ToList();
}
public abstract PaintShader createShader(Rect rect);
protected virtual Gradient lerpFrom(Gradient a, double t) {
if (a == null) {
return this.scale(t);
}
return null;
}
protected virtual Gradient lerpTo(Gradient b, double t) {
if (b == null) {
return this.scale(1.0 - t);
}
return null;
}
return null;
Gradient result = null;
if (b != null) {
result = b.lerpFrom(a, t); // if a is null, this must return non-null
}
if (result == null && a != null) {
result = a.lerpTo(b, t); // if b is null, this must return non-null
}
if (result != null) {
return result;
}
if (a == null && b == null) {
return null;
}
D.assert(a != null && b != null);
return t < 0.5 ? a.scale(1.0 - (t * 2.0)) : b.scale((t - 0.5) * 2.0);
}
}
public class LinearGradient : Gradient, IEquatable<LinearGradient> {
public LinearGradient(
Alignment begin = null,
Alignment end = null,
List<Color> colors = null,
List<double> stops = null,
TileMode tileMode = TileMode.clamp
) : base(colors: colors, stops: stops) {
this.begin = begin ?? Alignment.centerLeft;
this.end = end ?? Alignment.centerRight;
this.tileMode = tileMode;
}
public readonly Alignment begin;
public readonly Alignment end;
public readonly TileMode tileMode;
public override PaintShader createShader(Rect rect) {
return ui.Gradient.linear(
this.begin.withinRect(rect),
this.end.withinRect(rect),
this.colors, this._impliedStops(),
this.tileMode
);
}
public override Gradient scale(double factor) {
return new LinearGradient(
begin: this.begin,
end: this.end,
colors: this.colors.Select(color => Color.lerp(null, color, factor)).ToList(),
stops: this.stops,
tileMode: this.tileMode
);
}
protected override Gradient lerpFrom(Gradient a, double t) {
if (a == null || (a is LinearGradient && a.colors.Count == this.colors.Count)) {
return LinearGradient.lerp((LinearGradient) a, this, t);
}
return base.lerpFrom(a, t);
}
protected override Gradient lerpTo(Gradient b, double t) {
if (b == null || (b is LinearGradient && b.colors.Count == this.colors.Count)) {
return LinearGradient.lerp(this, (LinearGradient) b, t);
}
return base.lerpTo(b, t);
}
public static LinearGradient lerp(LinearGradient a, LinearGradient b, double t) {
if (a == null && b == null) {
return null;
}
if (a == null) {
return (LinearGradient) b.scale(t);
}
if (b == null) {
return (LinearGradient) a.scale(1.0 - t);
}
_ColorsAndStops interpolated =
_ColorsAndStops._interpolateColorsAndStops(a.colors, a.stops, b.colors, b.stops, t);
return new LinearGradient(
begin: Alignment.lerp(a.begin, b.begin, t),
end: Alignment.lerp(a.end, b.end, t),
colors: interpolated.colors,
stops: interpolated.stops,
tileMode: t < 0.5 ? a.tileMode : b.tileMode
);
}
public bool Equals(LinearGradient other) {
if (ReferenceEquals(null, other)) {
return false;
}
if (ReferenceEquals(this, other)) {
return true;
}
return
this.colors.equalsList(other.colors) &&
this.stops.equalsList(other.stops) &&
Equals(this.begin, other.begin) &&
Equals(this.end, other.end) &&
this.tileMode == other.tileMode;
}
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((LinearGradient) obj);
}
public override int GetHashCode() {
unchecked {
var hashCode = this.colors.hashList();
hashCode = (hashCode * 397) ^ this.stops.hashList();
hashCode = (hashCode * 397) ^ (this.begin != null ? this.begin.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (this.end != null ? this.end.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (int) this.tileMode;
return hashCode;
}
}
public static bool operator ==(LinearGradient left, LinearGradient right) {
return Equals(left, right);
}
public static bool operator !=(LinearGradient left, LinearGradient right) {
return !Equals(left, right);
}
public override String ToString() {
return $"{this.GetType()}({this.begin}, {this.end}," +
$"{this.colors.toStringList()}, {this.stops.toStringList()}, {this.tileMode})";
}
}
public class RadialGradient : Gradient, IEquatable<RadialGradient> {
public RadialGradient(
Alignment center = null,
double radius = 0.5,
List<Color> colors = null,
List<double> stops = null,
TileMode tileMode = TileMode.clamp
) : base(colors: colors, stops: stops) {
this.center = center ?? Alignment.center;
this.radius = radius;
this.tileMode = tileMode;
}
public readonly Alignment center;
public readonly double radius;
public readonly TileMode tileMode;
public override PaintShader createShader(Rect rect) {
return ui.Gradient.radial(
this.center.withinRect(rect),
this.radius * rect.shortestSide,
this.colors, this._impliedStops(),
this.tileMode
);
}
public override Gradient scale(double factor) {
return new RadialGradient(
center: this.center,
radius: this.radius,
colors: this.colors.Select(color => Color.lerp(null, color, factor)).ToList(),
stops: this.stops,
tileMode: this.tileMode
);
}
protected override Gradient lerpFrom(Gradient a, double t) {
if (a == null || (a is RadialGradient && a.colors.Count == this.colors.Count)) {
return RadialGradient.lerp((RadialGradient) a, this, t);
}
return base.lerpFrom(a, t);
}
protected override Gradient lerpTo(Gradient b, double t) {
if (b == null || (b is RadialGradient && b.colors.Count == this.colors.Count)) {
return RadialGradient.lerp(this, (RadialGradient) b, t);
}
return base.lerpTo(b, t);
}
public static RadialGradient lerp(RadialGradient a, RadialGradient b, double t) {
if (a == null && b == null) {
return null;
}
if (a == null) {
return (RadialGradient) b.scale(t);
}
if (b == null) {
return (RadialGradient) a.scale(1.0 - t);
}
_ColorsAndStops interpolated =
_ColorsAndStops._interpolateColorsAndStops(a.colors, a.stops, b.colors, b.stops, t);
return new RadialGradient(
center: Alignment.lerp(a.center, b.center, t),
radius: Math.Max(0.0, MathUtils.lerpDouble(a.radius, b.radius, t)),
colors: interpolated.colors,
stops: interpolated.stops,
tileMode: t < 0.5 ? a.tileMode : b.tileMode
);
}
public bool Equals(RadialGradient other) {
if (ReferenceEquals(null, other)) {
return false;
}
if (ReferenceEquals(this, other)) {
return true;
}
return
this.colors.equalsList(other.colors) &&
this.stops.equalsList(other.stops) &&
Equals(this.center, other.center) &&
Equals(this.radius, other.radius) &&
this.tileMode == other.tileMode;
}
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((RadialGradient) obj);
}
public override int GetHashCode() {
unchecked {
var hashCode = this.colors.hashList();
hashCode = (hashCode * 397) ^ this.stops.hashList();
hashCode = (hashCode * 397) ^ (this.center != null ? this.center.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ this.radius.GetHashCode();
hashCode = (hashCode * 397) ^ (int) this.tileMode;
return hashCode;
}
}
public static bool operator ==(RadialGradient left, RadialGradient right) {
return Equals(left, right);
}
public static bool operator !=(RadialGradient left, RadialGradient right) {
return !Equals(left, right);
}
public override String ToString() {
return $"{this.GetType()}({this.center}, {this.radius}," +
$"{this.colors.toStringList()}, {this.stops.toStringList()}, {this.tileMode})";
}
}
public class SweepGradient : Gradient, IEquatable<SweepGradient> {
public SweepGradient(
Alignment center = null,
double startAngle = 0.0,
double endAngle = Math.PI * 2,
List<Color> colors = null,
List<double> stops = null,
TileMode tileMode = TileMode.clamp
) : base(colors: colors, stops: stops) {
this.center = center ?? Alignment.center;
this.startAngle = startAngle;
this.endAngle = endAngle;
this.tileMode = tileMode;
}
public readonly Alignment center;
public readonly double startAngle;
public readonly double endAngle;
public readonly TileMode tileMode;
public override PaintShader createShader(Rect rect) {
return ui.Gradient.sweep(
this.center.withinRect(rect),
this.colors, this._impliedStops(),
this.tileMode,
this.startAngle, this.endAngle
);
}
public override Gradient scale(double factor) {
return new SweepGradient(
center: this.center,
startAngle: this.startAngle,
endAngle: this.endAngle,
colors: this.colors.Select(color => Color.lerp(null, color, factor)).ToList(),
stops: this.stops,
tileMode: this.tileMode
);
}
protected override Gradient lerpFrom(Gradient a, double t) {
if (a == null || (a is SweepGradient && a.colors.Count == this.colors.Count)) {
return SweepGradient.lerp((SweepGradient) a, this, t);
}
return base.lerpFrom(a, t);
}
protected override Gradient lerpTo(Gradient b, double t) {
if (b == null || (b is SweepGradient && b.colors.Count == this.colors.Count)) {
return SweepGradient.lerp(this, (SweepGradient) b, t);
}
return base.lerpTo(b, t);
}
public static SweepGradient lerp(SweepGradient a, SweepGradient b, double t) {
if (a == null && b == null) {
return null;
}
if (a == null) {
return (SweepGradient) b.scale(t);
}
if (b == null) {
return (SweepGradient) a.scale(1.0 - t);
}
_ColorsAndStops interpolated =
_ColorsAndStops._interpolateColorsAndStops(a.colors, a.stops, b.colors, b.stops, t);
return new SweepGradient(
center: Alignment.lerp(a.center, b.center, t),
startAngle: Math.Max(0.0, MathUtils.lerpDouble(a.startAngle, b.startAngle, t)),
endAngle: Math.Max(0.0, MathUtils.lerpDouble(a.endAngle, b.endAngle, t)),
colors: interpolated.colors,
stops: interpolated.stops,
tileMode: t < 0.5 ? a.tileMode : b.tileMode
);
}
public bool Equals(SweepGradient other) {
if (ReferenceEquals(null, other)) {
return false;
}
if (ReferenceEquals(this, other)) {
return true;
}
return
this.colors.equalsList(other.colors) &&
this.stops.equalsList(other.stops) &&
Equals(this.center, other.center) &&
Equals(this.startAngle, other.startAngle) &&
Equals(this.endAngle, other.endAngle) &&
this.tileMode == other.tileMode;
}
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((SweepGradient) obj);
}
public override int GetHashCode() {
unchecked {
var hashCode = this.colors.hashList();
hashCode = (hashCode * 397) ^ this.stops.hashList();
hashCode = (hashCode * 397) ^ (this.center != null ? this.center.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ this.startAngle.GetHashCode();
hashCode = (hashCode * 397) ^ this.endAngle.GetHashCode();
hashCode = (hashCode * 397) ^ (int) this.tileMode;
return hashCode;
}
}
public static bool operator ==(SweepGradient left, SweepGradient right) {
return Equals(left, right);
}
public static bool operator !=(SweepGradient left, SweepGradient right) {
return !Equals(left, right);
}
public override String ToString() {
return $"{this.GetType()}({this.center}, {this.startAngle}, {this.endAngle}, " +
$"{this.colors.toStringList()}, {this.stops.toStringList()}, {this.tileMode})";
}
}
}

1
Runtime/ui/painting/shader.cs


Image fillGradient(List<Color> colors, List<double> positions) {
Texture2D tex = new Texture2D(this.resolution, 1, TextureFormat.RGBA32, false);
tex.hideFlags = HideFlags.HideAndDontSave;
tex.wrapMode = TextureWrapMode.Clamp;
var bytes = new byte[this.resolution * 4];

9
Tests/Editor/Widgets.cs


height: 200,
margin: EdgeInsets.all(30.0),
padding: EdgeInsets.all(15.0),
color: Color.fromARGB(255, 244, 190, 85),
child: image
child: image,
decoration: new BoxDecoration(
color: CLColors.white,
borderRadius: BorderRadius.all(30),
gradient: new LinearGradient(colors: new List<Color>{CLColors.blue, CLColors.red, CLColors.green})
)
);
return container;

正在加载...
取消
保存