您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
427 行
16 KiB
427 行
16 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using UIWidgets.painting;
|
|
using UIWidgets.ui.painting.txt;
|
|
using UIWidgets.ui.txt;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
|
|
namespace UIWidgets.ui {
|
|
public class CanvasImpl : Canvas {
|
|
static CanvasImpl() {
|
|
var shader = Shader.Find("UIWidgets/2D Handles Lines");
|
|
if (shader == null) {
|
|
throw new Exception("UIWidgets/2D Handles Lines not found");
|
|
}
|
|
|
|
CanvasImpl.linesMat = new Material(shader);
|
|
CanvasImpl.linesMat.hideFlags = HideFlags.HideAndDontSave;
|
|
|
|
shader = Shader.Find("UIWidgets/GUIRoundedRect");
|
|
if (shader == null) {
|
|
throw new Exception("UIWidgets/GUIRoundedRect not found");
|
|
}
|
|
|
|
CanvasImpl.guiRoundedRectMat = new Material(shader);
|
|
CanvasImpl.guiRoundedRectMat.hideFlags = HideFlags.HideAndDontSave;
|
|
|
|
shader = Shader.Find("UIWidgets/GUITextureClip");
|
|
if (shader == null) {
|
|
throw new Exception("UIWidgets/GUITextureClip not found");
|
|
}
|
|
|
|
CanvasImpl.guiTextureClipMat = new Material(shader);
|
|
CanvasImpl.guiTextureClipMat.hideFlags = HideFlags.HideAndDontSave;
|
|
|
|
shader = Shader.Find("UIWidgets/ShadowRect");
|
|
if (shader == null) {
|
|
throw new Exception("UIWidgets/ShadowRect not found");
|
|
}
|
|
|
|
CanvasImpl.shadowRectMat = new Material(shader);
|
|
CanvasImpl.shadowRectMat.hideFlags = HideFlags.HideAndDontSave;
|
|
}
|
|
|
|
private static readonly Material linesMat;
|
|
private static readonly Material guiRoundedRectMat;
|
|
private static readonly Material guiTextureClipMat;
|
|
private static readonly Material shadowRectMat;
|
|
|
|
private Matrix4x4 _transform;
|
|
private ClipRec _clipRec;
|
|
private LayerRec _layerRec;
|
|
private Stack<CanvasRec> _stack;
|
|
private RenderTexture _defaultTexture;
|
|
|
|
private Stack<CanvasRec> stack {
|
|
get { return this._stack ?? (this._stack = new Stack<CanvasRec>()); }
|
|
}
|
|
|
|
public CanvasImpl() {
|
|
this._transform = Matrix4x4.Scale(new Vector3(
|
|
1.0f / EditorGUIUtility.pixelsPerPoint,
|
|
1.0f / EditorGUIUtility.pixelsPerPoint,
|
|
1.0f));
|
|
|
|
this._defaultTexture = RenderTexture.active;
|
|
}
|
|
|
|
public void drawPloygon4(Offset[] points, Paint paint) {
|
|
var color = paint.color;
|
|
if (color.alpha > 0) {
|
|
Vector3[] verts = new Vector3 [points.Length];
|
|
for (int i = 0; i < points.Length; i++) {
|
|
verts[i] = points[i].toVector();
|
|
}
|
|
|
|
this.prepareGL(CanvasImpl.linesMat);
|
|
CanvasImpl.linesMat.SetPass(0);
|
|
|
|
GL.Begin(GL.TRIANGLES);
|
|
GL.Color(color.toColor());
|
|
for (int index = 0; index < 2; ++index) {
|
|
GL.Vertex(verts[index * 2]);
|
|
GL.Vertex(verts[index * 2 + 1]);
|
|
GL.Vertex(verts[(index * 2 + 2) % 4]);
|
|
GL.Vertex(verts[index * 2]);
|
|
GL.Vertex(verts[(index * 2 + 2) % 4]);
|
|
GL.Vertex(verts[index * 2 + 1]);
|
|
}
|
|
|
|
GL.End();
|
|
}
|
|
}
|
|
|
|
public void drawRect(Rect rect, BorderWidth borderWidth, BorderRadius borderRadius, Paint paint) {
|
|
this.prepareGL(CanvasImpl.guiRoundedRectMat);
|
|
|
|
CanvasImpl.guiRoundedRectMat.SetFloatArray("UIWidgets_BorderWidth",
|
|
borderWidth == null ? new[] {0f, 0f, 0f, 0f} : borderWidth.toFloatArray());
|
|
CanvasImpl.guiRoundedRectMat.SetFloatArray("UIWidgets_CornerRadius",
|
|
borderRadius == null ? new[] {0f, 0f, 0f, 0f} : borderRadius.toFloatArray());
|
|
|
|
Graphics.DrawTexture(rect.toRect(), EditorGUIUtility.whiteTexture,
|
|
new UnityEngine.Rect(0.0f, 0.0f, 1f, 1f), 0, 0, 0, 0,
|
|
paint.color.toColor(), CanvasImpl.guiRoundedRectMat);
|
|
}
|
|
|
|
|
|
public void drawRectShadow(Rect rect, Paint paint) {
|
|
this.prepareGL(CanvasImpl.shadowRectMat);
|
|
|
|
CanvasImpl.shadowRectMat.SetFloat("UIWidgets_sigma", (float) paint.blurSigma);
|
|
|
|
Graphics.DrawTexture(rect.toRect(), EditorGUIUtility.whiteTexture,
|
|
new UnityEngine.Rect(0.0f, 0.0f, 1f, 1f), 0, 0, 0, 0,
|
|
paint.color.toColor(), CanvasImpl.shadowRectMat);
|
|
}
|
|
|
|
public void drawPicture(Picture picture) {
|
|
this.save();
|
|
|
|
int saveCount = 0;
|
|
|
|
var drawCmds = picture.drawCmds;
|
|
foreach (var drawCmd in drawCmds) {
|
|
if (drawCmd is DrawPloygon4) {
|
|
var drawPloygon4 = (DrawPloygon4) drawCmd;
|
|
this.drawPloygon4(drawPloygon4.points, drawPloygon4.paint);
|
|
}
|
|
else if (drawCmd is DrawRect) {
|
|
var drawRect = (DrawRect) drawCmd;
|
|
this.drawRect(drawRect.rect, drawRect.borderWidth, drawRect.borderRadius, drawRect.paint);
|
|
} else if (drawCmd is DrawLine)
|
|
{
|
|
var drawLine = (DrawLine) drawCmd;
|
|
this.drawLine(drawLine.from, drawLine.to, drawLine.paint);
|
|
}
|
|
else if (drawCmd is DrawRectShadow) {
|
|
var drawRectShadow = (DrawRectShadow) drawCmd;
|
|
this.drawRectShadow(drawRectShadow.rect, drawRectShadow.paint);
|
|
}
|
|
else if (drawCmd is DrawPicture) {
|
|
var drawPicture = (DrawPicture) drawCmd;
|
|
this.drawPicture(drawPicture.picture);
|
|
}
|
|
else if (drawCmd is DrawConcat) {
|
|
this.concat(((DrawConcat) drawCmd).transform);
|
|
}
|
|
else if (drawCmd is DrawSave) {
|
|
saveCount++;
|
|
this.save();
|
|
}
|
|
else if (drawCmd is DrawSaveLayer) {
|
|
saveCount++;
|
|
var drawSaveLayer = (DrawSaveLayer) drawCmd;
|
|
this.saveLayer(drawSaveLayer.rect, drawSaveLayer.paint);
|
|
}
|
|
else if (drawCmd is DrawRestore) {
|
|
saveCount--;
|
|
if (saveCount < 0) {
|
|
throw new Exception("unmatched save/restore in picture");
|
|
}
|
|
|
|
this.restore();
|
|
}
|
|
else if (drawCmd is DrawClipRect) {
|
|
var drawClipRect = (DrawClipRect) drawCmd;
|
|
this.clipRect(drawClipRect.rect);
|
|
}
|
|
else if (drawCmd is DrawClipRRect) {
|
|
var drawClipRRect = (DrawClipRRect) drawCmd;
|
|
this.clipRRect(drawClipRRect.rrect);
|
|
} else if (drawCmd is DrawTextBlob) {
|
|
var drawTextBlob = (DrawTextBlob) drawCmd;
|
|
this.drawTextBlob(drawTextBlob.textBlob, drawTextBlob.x, drawTextBlob.y);
|
|
} else if (drawCmd is DrawImageRect) {
|
|
var drawImageProperties = (DrawImageRect) drawCmd;
|
|
this.drawImageRect(drawImageProperties.src, drawImageProperties.dst, drawImageProperties.paint, drawImageProperties.image);
|
|
}
|
|
else {
|
|
throw new Exception("unknown drawCmd: " + drawCmd);
|
|
}
|
|
}
|
|
|
|
if (saveCount != 0) {
|
|
throw new Exception("unmatched save/restore in picture");
|
|
}
|
|
|
|
this.restore();
|
|
}
|
|
|
|
public void drawImageRect(Rect src, Rect dst, Paint paint, Image image) {
|
|
if (image != null && image.texture != null) {
|
|
// convert src rect to Unity rect in normalized coordinates with (0,0) in the bottom-left corner.
|
|
var textureHeight = image.texture.height;
|
|
var textureWidth = image.texture.width;
|
|
var srcRect = new UnityEngine.Rect(
|
|
(float) (src.left / textureWidth),
|
|
(float) ((textureHeight - src.bottom) / textureHeight),
|
|
(float) (src.width / textureWidth),
|
|
(float) (src.height / textureHeight)
|
|
);
|
|
Graphics.DrawTexture(dst.toRect(), image.texture, srcRect, 0, 0 ,0 ,0);
|
|
}
|
|
}
|
|
|
|
public void drawLine(Offset from, Offset to, Paint paint)
|
|
{
|
|
var color = paint.color;
|
|
Offset vect = to - from;
|
|
var distance = vect.distance;
|
|
|
|
if (color.alpha > 0 && distance > 0)
|
|
{
|
|
var halfWidth = paint.strokeWidth * 0.5;
|
|
var diff = vect / distance * halfWidth;
|
|
diff = new Offset(diff.dy, -diff.dx);
|
|
this.prepareGL(CanvasImpl.linesMat);
|
|
CanvasImpl.linesMat.SetPass(0);
|
|
var points = new[]
|
|
{
|
|
(from + diff).toVector(),
|
|
(from - diff).toVector(),
|
|
(to - diff).toVector(),
|
|
(to + diff).toVector(),
|
|
};
|
|
GL.Begin(GL.QUADS);
|
|
GL.Color(color.toColor());
|
|
for (int i = 0; i < points.Length; ++i)
|
|
{
|
|
GL.Vertex(points[i]);
|
|
}
|
|
GL.End();
|
|
}
|
|
}
|
|
|
|
public void concat(Matrix4x4 transform) {
|
|
this._transform = transform * this._transform;
|
|
}
|
|
|
|
public void save() {
|
|
var state = new CanvasRec {
|
|
transform = this._transform,
|
|
clipRect = this._clipRec,
|
|
layerRec = this._layerRec,
|
|
};
|
|
this.stack.Push(state);
|
|
}
|
|
|
|
public void saveLayer(Rect bounds, Paint paint) {
|
|
this.save();
|
|
|
|
var textureWidth = (int) Math.Round(bounds.width * EditorGUIUtility.pixelsPerPoint);
|
|
var textureHeight = (int) Math.Round(bounds.height * EditorGUIUtility.pixelsPerPoint);
|
|
|
|
var texture = RenderTexture.GetTemporary(
|
|
textureWidth, textureHeight, 32,
|
|
RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB);
|
|
|
|
RenderTexture.active = texture;
|
|
|
|
GL.PushMatrix();
|
|
GL.LoadPixelMatrix((float) bounds.left, (float) bounds.right, (float) bounds.bottom, (float) bounds.top);
|
|
GL.Clear(true, true, new UnityEngine.Color(0, 0, 0, 0));
|
|
|
|
this._layerRec = new LayerRec {
|
|
bounds = bounds,
|
|
paint = paint,
|
|
texture = texture,
|
|
};
|
|
|
|
this._transform = Matrix4x4.identity;
|
|
this._clipRec = null;
|
|
}
|
|
|
|
public void restore() {
|
|
var layerRec = this._layerRec;
|
|
|
|
var state = this._stack.Pop();
|
|
this._transform = state.transform;
|
|
this._clipRec = state.clipRect;
|
|
this._layerRec = state.layerRec;
|
|
|
|
if (layerRec != this._layerRec) {
|
|
var targetTexture = this._layerRec != null ? this._layerRec.texture : this._defaultTexture;
|
|
RenderTexture.active = targetTexture;
|
|
|
|
GL.PopMatrix();
|
|
|
|
this.prepareGL(CanvasImpl.guiTextureClipMat);
|
|
|
|
Graphics.DrawTexture(layerRec.bounds.toRect(), layerRec.texture,
|
|
new UnityEngine.Rect(0.0f, 0.0f, 1f, 1f), 0, 0, 0, 0,
|
|
layerRec.paint.color.toColor(), CanvasImpl.guiTextureClipMat);
|
|
|
|
RenderTexture.ReleaseTemporary(layerRec.texture);
|
|
layerRec.texture = null;
|
|
}
|
|
}
|
|
|
|
public int getSaveCount() {
|
|
return this._stack.Count + 1;
|
|
}
|
|
|
|
public void clipRect(Rect rect, bool doAntiAlias = true) {
|
|
if (rect.isInfinite) {
|
|
return;
|
|
}
|
|
|
|
this.pushClipRect(rect, this._transform);
|
|
}
|
|
|
|
public void clipRRect(RRect rect, bool doAntiAlias = true) {
|
|
if (rect.isInfinite) {
|
|
return;
|
|
}
|
|
|
|
this.pushClipRRect(rect, this._transform);
|
|
}
|
|
|
|
public void drawTextBlob(TextBlob textBlob, double x, double y)
|
|
{
|
|
var mesh = MeshGenrator.generateMesh(textBlob, x, y);
|
|
var font = FontManager.instance.getOrCreate(textBlob.style.fontFamily, textBlob.style.UnityFontSize);
|
|
prepareGL(font.material);
|
|
font.material.SetPass(0);
|
|
Matrix4x4 cameraMat = Matrix4x4.identity;
|
|
|
|
if (Camera.current != null) // draw mesh will use camera matrix, set to identity before draw mesh
|
|
{
|
|
cameraMat = Camera.current.worldToCameraMatrix;
|
|
Camera.current.worldToCameraMatrix = Matrix4x4.identity;
|
|
}
|
|
|
|
Graphics.DrawMeshNow(mesh, this._transform);
|
|
if (Camera.current != null)
|
|
{
|
|
Camera.current.worldToCameraMatrix = cameraMat;
|
|
Camera.current.ResetWorldToCameraMatrix();
|
|
}
|
|
}
|
|
|
|
private void pushClipRect(Rect clipRect, Matrix4x4 transform) {
|
|
if (this._clipRec != null) {
|
|
throw new Exception("already a clipRec, considering using saveLayer.");
|
|
}
|
|
|
|
this._clipRec = new ClipRec(transform, rect: clipRect);
|
|
}
|
|
|
|
private void pushClipRRect(RRect clipRRect, Matrix4x4 transform) {
|
|
if (this._clipRec != null) {
|
|
throw new Exception("already a clipRec, considering using saveLayer.");
|
|
}
|
|
|
|
this._clipRec = new ClipRec(transform, rrect: clipRRect);
|
|
}
|
|
|
|
private void prepareGL(Material mat) {
|
|
if (this._clipRec != null) {
|
|
mat.SetMatrix("UIWidgets_GUIClipMatrix", this._clipRec.transform.inverse);
|
|
if (this._clipRec.rect != null) {
|
|
var rect = this._clipRec.rect;
|
|
mat.SetVector("UIWidgets_GUIClipRect", new Vector4(
|
|
(float) rect.left,
|
|
(float) rect.top,
|
|
(float) rect.width,
|
|
(float) rect.height));
|
|
mat.SetVector("UIWidgets_GUIClipRectRadius", new Vector4(0, 0, 0, 0));
|
|
}
|
|
else {
|
|
var rrect = this._clipRec.rrect;
|
|
var rect = rrect.outerRect;
|
|
mat.SetVector("UIWidgets_GUIClipRect", new Vector4(
|
|
(float) rect.left,
|
|
(float) rect.top,
|
|
(float) rect.width,
|
|
(float) rect.height));
|
|
mat.SetVector("UIWidgets_GUIClipRectRadius",
|
|
new Vector4(
|
|
(float) rrect.tlRadius,
|
|
(float) rrect.trRadius,
|
|
(float) rrect.brRadius,
|
|
(float) rrect.blRadius));
|
|
}
|
|
}
|
|
else {
|
|
mat.SetMatrix("UIWidgets_GUIClipMatrix", Matrix4x4.identity);
|
|
var rect = Rect.largest;
|
|
mat.SetVector("UIWidgets_GUIClipRect", new Vector4(
|
|
(float) rect.left,
|
|
(float) rect.top,
|
|
(float) rect.width,
|
|
(float) rect.height));
|
|
mat.SetVector("UIWidgets_GUIClipRectRadius", new Vector4(0, 0, 0, 0));
|
|
}
|
|
|
|
GL.MultMatrix(this._transform);
|
|
}
|
|
|
|
private class ClipRec {
|
|
public ClipRec(Matrix4x4 transform, Rect rect = null, RRect rrect = null) {
|
|
this.transform = transform;
|
|
this.rect = rect;
|
|
this.rrect = rrect;
|
|
}
|
|
|
|
public readonly Matrix4x4 transform;
|
|
|
|
public readonly Rect rect;
|
|
|
|
public readonly RRect rrect;
|
|
}
|
|
|
|
private class LayerRec {
|
|
public Rect bounds;
|
|
public Paint paint;
|
|
public RenderTexture texture;
|
|
}
|
|
|
|
private class CanvasRec {
|
|
public Matrix4x4 transform;
|
|
public ClipRec clipRect;
|
|
public LayerRec layerRec;
|
|
}
|
|
}
|
|
}
|